diff --git a/ChangeLog b/ChangeLog index 9ebc19e6..6654c83a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-09-02 Tatsuhiro Tsujikawa + + Now *.aria2 contorol file is first saved to *.aria2__temp and if + it is successful, then renamed to *.aria2. + This prevents *.aria2 file from being truncated or corrupted when + file system becomes out of space. + * src/DefaultBtProgressInfoFile.cc (save) + * src/SegmentMan.cc (save) + * test/DefaultBtProgressInfoFileTest.cc (testSave): Implemented. + 2007-09-01 Tatsuhiro Tsujikawa Reduced the fragmentation of bitfield in http/ftp download. diff --git a/src/DefaultBtProgressInfoFile.cc b/src/DefaultBtProgressInfoFile.cc index 4fc0156f..7c0c9a77 100644 --- a/src/DefaultBtProgressInfoFile.cc +++ b/src/DefaultBtProgressInfoFile.cc @@ -60,7 +60,8 @@ DefaultBtProgressInfoFile::~DefaultBtProgressInfoFile() {} void DefaultBtProgressInfoFile::save() { logger->info(MSG_SAVING_SEGMENT_FILE, filename.c_str()); - FILE* file = openFile(filename, "wb"); + string filenameTemp = filename+"__temp"; + FILE* file = openFile(filenameTemp, "wb"); try { if(fwrite(btContext->getInfoHash(), btContext->getInfoHashLength(), 1, file) < 1) { @@ -90,6 +91,11 @@ void DefaultBtProgressInfoFile::save() { throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, filename.c_str(), strerror(errno)); } + + if(rename(filenameTemp.c_str(), filename.c_str()) == -1) { + throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, + filename.c_str(), strerror(errno)); + } } void DefaultBtProgressInfoFile::load() { diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 9b88585a..0240bc2d 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -99,7 +99,9 @@ void SegmentMan::save() const { } string segFilename = getSegmentFilePath(); logger->info(MSG_SAVING_SEGMENT_FILE, segFilename.c_str()); - FILE* segFile = openSegFile(segFilename, "wb"); + + string segFilenameTemp = segFilename+"__temp"; + FILE* segFile = openSegFile(segFilenameTemp, "wb"); try { if(fwrite(&totalSize, sizeof(totalSize), 1, segFile) < 1) { throw string("writeError"); @@ -140,6 +142,11 @@ void SegmentMan::save() const { throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, segFilename.c_str(), strerror(errno)); } + + if(rename(segFilenameTemp.c_str(), segFilename.c_str()) == -1) { + throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, + segFilename.c_str(), strerror(errno)); + } } FILE* SegmentMan::openSegFile(const string& segFilename, const string& mode) const { diff --git a/test/DefaultBtProgressInfoFileTest.cc b/test/DefaultBtProgressInfoFileTest.cc index 5613f95c..3cea93fb 100644 --- a/test/DefaultBtProgressInfoFileTest.cc +++ b/test/DefaultBtProgressInfoFileTest.cc @@ -3,6 +3,10 @@ #include "Option.h" #include "Util.h" #include "Exception.h" +#include "MockBtContext.h" +#include "MockPeerStorage.h" +#include "MockPieceStorage.h" +#include "prefs.h" #include using namespace std; @@ -31,4 +35,59 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtProgressInfoFileTest); void DefaultBtProgressInfoFileTest::testSave() { + unsigned char infoHash[] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, + 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + }; + + Option option; + option.put(PREF_DIR, "."); + + MockBtContextHandle btContext = new MockBtContext(); + btContext->setInfoHash(infoHash); + btContext->setName("save-temp"); + + BitfieldMan bitfield(1024, 80*1024); + bitfield.setAllBit(); + bitfield.unsetBit(79); + MockPieceStorageHandle pieceStorage = new MockPieceStorage(); + pieceStorage->setBitfield(&bitfield); + pieceStorage->setCompletedLength(80896); + + MockPeerStorageHandle peerStorage = new MockPeerStorage(); + TransferStat stat; + stat.sessionUploadLength = 1024; + peerStorage->setStat(stat); + + BtRuntimeHandle btRuntime = new BtRuntime(); + + DefaultBtProgressInfoFile infoFile(btContext, &option); + infoFile.setPieceStorage(pieceStorage); + infoFile.setPeerStorage(peerStorage); + infoFile.setBtRuntime(btRuntime); + + infoFile.save(); + + // read and validate + ifstream in(string(option.get(PREF_DIR)+"/"+btContext->getName()+".aria2").c_str()); + unsigned char infoHashRead[20]; + in.read((char*)infoHashRead, sizeof(infoHashRead)); + CPPUNIT_ASSERT_EQUAL(string("112233445566778899aabbccddeeff00ffffffff"), + Util::toHex(infoHashRead, sizeof(infoHashRead))); + unsigned char bitfieldRead[10]; + in.read((char*)bitfieldRead, sizeof(bitfieldRead)); + CPPUNIT_ASSERT_EQUAL(string("fffffffffffffffffffe"), + Util::toHex(bitfieldRead, sizeof(bitfieldRead))); + int64_t allTimeDownloadLengthRead = 0; + in.read((char*)&allTimeDownloadLengthRead, sizeof(allTimeDownloadLengthRead)); + CPPUNIT_ASSERT_EQUAL((int64_t)80896, allTimeDownloadLengthRead); + + int64_t allTimeUploadLengthRead = 0; + in.read((char*)&allTimeUploadLengthRead, sizeof(allTimeUploadLengthRead)); + CPPUNIT_ASSERT_EQUAL((int64_t)1024, allTimeUploadLengthRead); + + string temp; + getline(in, temp); + CPPUNIT_ASSERT_EQUAL(string(""), temp); + CPPUNIT_ASSERT(in.eof()); } diff --git a/test/Makefile.am b/test/Makefile.am index 16308915..402d76f9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,7 @@ TESTS = aria2c check_PROGRAMS = $(TESTS) aria2c_SOURCES = AllTest.cc\ + DefaultBtProgressInfoFileTest.cc\ RequestGroupTest.cc\ PStringBuildVisitorTest.cc\ ParameterizedStringParserTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index 4346d2f2..935d62b2 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -110,12 +110,13 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = am__EXEEXT_1 = aria2c$(EXEEXT) -am__aria2c_SOURCES_DIST = AllTest.cc RequestGroupTest.cc \ - PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \ - UtilTest.cc AlphaNumberDecoratorTest.cc \ - FileUriListParserTest.cc StreamUriListParserTest.cc \ - HttpHeaderProcessorTest.cc CookieBoxTest.cc RequestTest.cc \ - CookieParserTest.cc HttpRequestTest.cc CookieBoxFactoryTest.cc \ +am__aria2c_SOURCES_DIST = AllTest.cc DefaultBtProgressInfoFileTest.cc \ + RequestGroupTest.cc PStringBuildVisitorTest.cc \ + ParameterizedStringParserTest.cc UtilTest.cc \ + AlphaNumberDecoratorTest.cc FileUriListParserTest.cc \ + StreamUriListParserTest.cc HttpHeaderProcessorTest.cc \ + CookieBoxTest.cc RequestTest.cc CookieParserTest.cc \ + HttpRequestTest.cc CookieBoxFactoryTest.cc \ RequestGroupManTest.cc RequestFactoryTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \ OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \ @@ -195,8 +196,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc RequestGroupTest.cc \ @ENABLE_METALINK_TRUE@am__objects_3 = MetalinkerTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ Xml2MetalinkProcessorTest.$(OBJEXT) -am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestGroupTest.$(OBJEXT) \ - PStringBuildVisitorTest.$(OBJEXT) \ +am_aria2c_OBJECTS = AllTest.$(OBJEXT) \ + DefaultBtProgressInfoFileTest.$(OBJEXT) \ + RequestGroupTest.$(OBJEXT) PStringBuildVisitorTest.$(OBJEXT) \ ParameterizedStringParserTest.$(OBJEXT) UtilTest.$(OBJEXT) \ AlphaNumberDecoratorTest.$(OBJEXT) \ FileUriListParserTest.$(OBJEXT) \ @@ -403,12 +405,13 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ TESTS = aria2c -aria2c_SOURCES = AllTest.cc RequestGroupTest.cc \ - PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \ - UtilTest.cc AlphaNumberDecoratorTest.cc \ - FileUriListParserTest.cc StreamUriListParserTest.cc \ - HttpHeaderProcessorTest.cc CookieBoxTest.cc RequestTest.cc \ - CookieParserTest.cc HttpRequestTest.cc CookieBoxFactoryTest.cc \ +aria2c_SOURCES = AllTest.cc DefaultBtProgressInfoFileTest.cc \ + RequestGroupTest.cc PStringBuildVisitorTest.cc \ + ParameterizedStringParserTest.cc UtilTest.cc \ + AlphaNumberDecoratorTest.cc FileUriListParserTest.cc \ + StreamUriListParserTest.cc HttpHeaderProcessorTest.cc \ + CookieBoxTest.cc RequestTest.cc CookieParserTest.cc \ + HttpRequestTest.cc CookieBoxFactoryTest.cc \ RequestGroupManTest.cc RequestFactoryTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \ OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \ @@ -516,6 +519,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounceTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtContextTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageDispatcherTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtProgressInfoFileTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtRequestFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriterTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessorTest.Po@am__quote@