Преглед на файлове

2007-09-02 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	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.
Tatsuhiro Tsujikawa преди 18 години
родител
ревизия
57471aac9c
променени са 6 файла, в които са добавени 103 реда и са изтрити 16 реда
  1. 10 0
      ChangeLog
  2. 7 1
      src/DefaultBtProgressInfoFile.cc
  3. 8 1
      src/SegmentMan.cc
  4. 59 0
      test/DefaultBtProgressInfoFileTest.cc
  5. 1 0
      test/Makefile.am
  6. 18 14
      test/Makefile.in

+ 10 - 0
ChangeLog

@@ -1,3 +1,13 @@
+2007-09-02  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	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  <tujikawa at rednoah dot com>
 
 	Reduced the fragmentation of bitfield in http/ftp download.

+ 7 - 1
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() {

+ 8 - 1
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 {

+ 59 - 0
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 <cppunit/extensions/HelperMacros.h>
 
 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());
 }

+ 1 - 0
test/Makefile.am

@@ -1,6 +1,7 @@
 TESTS = aria2c
 check_PROGRAMS = $(TESTS)
 aria2c_SOURCES = AllTest.cc\
+	DefaultBtProgressInfoFileTest.cc\
 	RequestGroupTest.cc\
 	PStringBuildVisitorTest.cc\
 	ParameterizedStringParserTest.cc\

+ 18 - 14
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@