From d6686a5e29234a518e8bda4e1f790df6ea48e976 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 13 Nov 2007 10:10:11 +0000 Subject: [PATCH] 2007-11-13 Tatsuhiro Tsujikawa Recalculates download progress when loading a control file, if the piece length of DownloadContext is different from the one saved in the control file. Currently in-flight pieces are ignored. * src/DefaultBtProgressInfoFile.cc * test/DefaultBtProgressInfoFileTest.cc * src/Util.{h, cc} * test/UtilTest.cc --- ChangeLog | 10 ++++ TODO | 3 +- src/DefaultBtProgressInfoFile.cc | 85 ++++++++++++++------------- src/Util.cc | 11 ++++ src/Util.h | 3 + test/DefaultBtProgressInfoFileTest.cc | 47 +++++++++++---- test/UtilTest.cc | 17 ++++++ 7 files changed, 123 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6b2f2218..5ab48102 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-11-13 Tatsuhiro Tsujikawa + + Recalculates download progress when loading a control file, + if the piece length of DownloadContext is different from the one saved + in the control file. Currently in-flight pieces are ignored. + * src/DefaultBtProgressInfoFile.cc + * test/DefaultBtProgressInfoFileTest.cc + * src/Util.{h, cc} + * test/UtilTest.cc + 2007-11-12 Tatsuhiro Tsujikawa Do not rotate tiers in announce-list. diff --git a/TODO b/TODO index 3bd03c54..c80738f0 100644 --- a/TODO +++ b/TODO @@ -56,6 +56,5 @@ FatalException .... Program should abort. -- remaining features to be implemented for 0.12.0 release -* Implement duplicate download checking in Bt +* Implement duplicate download checking * improve --metalink-location field -* Piece length conversion when loading file \ No newline at end of file diff --git a/src/DefaultBtProgressInfoFile.cc b/src/DefaultBtProgressInfoFile.cc index dae5a404..a1dde4cc 100644 --- a/src/DefaultBtProgressInfoFile.cc +++ b/src/DefaultBtProgressInfoFile.cc @@ -190,13 +190,8 @@ void DefaultBtProgressInfoFile::load() savedInfoHash = 0; } - // TODO implement the conversion mechanism between different piece length. int32_t pieceLength; in.read(reinterpret_cast(&pieceLength), sizeof(pieceLength)); - if(pieceLength != _dctx->getPieceLength()) { - throw new DlAbortEx("piece length mismatch. expected: %d, actual: %d", - _dctx->getPieceLength(), pieceLength); - } int64_t totalLength; in.read(reinterpret_cast(&totalLength), sizeof(totalLength)); @@ -214,51 +209,61 @@ void DefaultBtProgressInfoFile::load() // TODO implement the conversion mechanism between different piece length. int32_t bitfieldLength; in.read(reinterpret_cast(&bitfieldLength), sizeof(bitfieldLength)); - if(_pieceStorage->getBitfieldLength() != bitfieldLength) { + int32_t expectedBitfieldLength = ((totalLength+pieceLength-1)/pieceLength+7)/8; + if(expectedBitfieldLength != bitfieldLength) { throw new DlAbortEx("bitfield length mismatch. expected: %d, actual: %d", - _pieceStorage->getBitfieldLength(), + expectedBitfieldLength, bitfieldLength); } - // TODO implement the conversion mechanism between different piece length. savedBitfield = new unsigned char[bitfieldLength]; in.read(reinterpret_cast(savedBitfield), bitfieldLength); - _pieceStorage->setBitfield(savedBitfield, bitfieldLength); - delete [] savedBitfield; - savedBitfield = 0; - int32_t numInFlightPiece; - in.read(reinterpret_cast(&numInFlightPiece), sizeof(numInFlightPiece)); - - Pieces inFlightPieces; - while(numInFlightPiece--) { - int32_t index; - in.read(reinterpret_cast(&index), sizeof(index)); - if(!(0 <= index && index < _dctx->getNumPieces())) { - throw new DlAbortEx("piece index out of range: %d", index); - } - int32_t length; - in.read(reinterpret_cast(&length), sizeof(length)); - if(!(0 < length && length <=_dctx->getPieceLength())) { - throw new DlAbortEx("piece length out of range: %d", length); - } - PieceHandle piece = new Piece(index, length); - int32_t bitfieldLength; - in.read(reinterpret_cast(&bitfieldLength), sizeof(bitfieldLength)); - if(piece->getBitfieldLength() != bitfieldLength) { - throw new DlAbortEx("piece bitfield length mismatch. expected: %d actual: %d", - piece->getBitfieldLength(), bitfieldLength); - } - savedBitfield = new unsigned char[bitfieldLength]; - in.read(reinterpret_cast(savedBitfield), bitfieldLength); - piece->setBitfield(savedBitfield, bitfieldLength); + if(pieceLength == _dctx->getPieceLength()) { + _pieceStorage->setBitfield(savedBitfield, bitfieldLength); delete [] savedBitfield; savedBitfield = 0; - - inFlightPieces.push_back(piece); - } - _pieceStorage->addInFlightPiece(inFlightPieces); + int32_t numInFlightPiece; + in.read(reinterpret_cast(&numInFlightPiece), sizeof(numInFlightPiece)); + + Pieces inFlightPieces; + while(numInFlightPiece--) { + int32_t index; + in.read(reinterpret_cast(&index), sizeof(index)); + if(!(0 <= index && index < _dctx->getNumPieces())) { + throw new DlAbortEx("piece index out of range: %d", index); + } + int32_t length; + in.read(reinterpret_cast(&length), sizeof(length)); + if(!(0 < length && length <=_dctx->getPieceLength())) { + throw new DlAbortEx("piece length out of range: %d", length); + } + PieceHandle piece = new Piece(index, length); + int32_t bitfieldLength; + in.read(reinterpret_cast(&bitfieldLength), sizeof(bitfieldLength)); + if(piece->getBitfieldLength() != bitfieldLength) { + throw new DlAbortEx("piece bitfield length mismatch. expected: %d actual: %d", + piece->getBitfieldLength(), bitfieldLength); + } + savedBitfield = new unsigned char[bitfieldLength]; + in.read(reinterpret_cast(savedBitfield), bitfieldLength); + piece->setBitfield(savedBitfield, bitfieldLength); + delete [] savedBitfield; + savedBitfield = 0; + + inFlightPieces.push_back(piece); + } + _pieceStorage->addInFlightPiece(inFlightPieces); + } else { + BitfieldMan src(pieceLength, totalLength); + src.setBitfield(savedBitfield, bitfieldLength); + BitfieldMan dest(_dctx->getPieceLength(), totalLength); + Util::convertBitfield(&dest, &src); + _pieceStorage->setBitfield(dest.getBitfield(), dest.getBitfieldLength()); + delete [] savedBitfield; + savedBitfield = 0; + } _logger->info(MSG_LOADED_SEGMENT_FILE); } catch(ios::failure const& exception) { delete [] savedBitfield; diff --git a/src/Util.cc b/src/Util.cc index 00f84399..c7704605 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -39,6 +39,7 @@ #include "a2netcompat.h" #include "a2time.h" #include "DlAbortEx.h" +#include "BitfieldMan.h" #include #include #include @@ -782,3 +783,13 @@ void Util::mkdirs(const string& dirpath) throw new DlAbortEx(EX_MAKE_DIR, dir.getPath().c_str(), strerror(errno)); } } + +void Util::convertBitfield(BitfieldMan* dest, const BitfieldMan* src) +{ + for(int32_t index = 0; index < dest->countBlock(); ++index) { + if(src->isBitSetOffsetRange((int64_t)index*dest->getBlockLength(), + dest->getBlockLength())) { + dest->setBit(index); + } + } +} diff --git a/src/Util.h b/src/Util.h index f49219fa..0cfac8ea 100644 --- a/src/Util.h +++ b/src/Util.h @@ -44,6 +44,7 @@ class Randomizer; extern typedef SharedHandle RandomizerHandle; +class BitfieldMan; #define STRTOLL(X) strtoll(X, (char**)NULL, 10) @@ -153,6 +154,8 @@ public: static int32_t alphaToNum(const string& alphabets); static void mkdirs(const string& dirpath); + + static void convertBitfield(BitfieldMan* dest, const BitfieldMan* src); }; #endif // _D_UTIL_H_ diff --git a/test/DefaultBtProgressInfoFileTest.cc b/test/DefaultBtProgressInfoFileTest.cc index f18f64fb..c704e696 100644 --- a/test/DefaultBtProgressInfoFileTest.cc +++ b/test/DefaultBtProgressInfoFileTest.cc @@ -24,6 +24,7 @@ class DefaultBtProgressInfoFileTest:public CppUnit::TestFixture { CPPUNIT_TEST(testSave_nonBt); CPPUNIT_TEST(testLoad); CPPUNIT_TEST(testLoad_nonBt); + CPPUNIT_TEST(testLoad_nonBt_pieceLengthShorter); CPPUNIT_TEST_SUITE_END(); private: MockBtContextHandle _btContext; @@ -35,19 +36,22 @@ public: void setUp() { BtRegistry::unregisterAll(); - + } + + void initializeMembers(int32_t pieceLength, int64_t totalLength) + { static unsigned char infoHash[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, }; - + _option = new Option(); _option->put(PREF_DIR, "."); _btContext = new MockBtContext(); _btContext->setInfoHash(infoHash); - _bitfield = new BitfieldMan(1024, 80*1024); + _bitfield = new BitfieldMan(pieceLength, totalLength); _pieceStorage = new MockPieceStorage(); _pieceStorage->setBitfield(_bitfield.get()); @@ -75,6 +79,7 @@ public: void testLoad(); void testSave_nonBt(); void testLoad_nonBt(); + void testLoad_nonBt_pieceLengthShorter(); }; #undef BLOCK_LENGTH @@ -84,7 +89,8 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtProgressInfoFileTest); void DefaultBtProgressInfoFileTest::testLoad() { - try { + initializeMembers(1024, 81920); + _btContext->setName("load"); _btContext->setPieceLength(1024); _btContext->setTotalLength(81920); @@ -121,16 +127,11 @@ void DefaultBtProgressInfoFileTest::testLoad() PieceHandle piece2 = inFlightPieces[1]; CPPUNIT_ASSERT_EQUAL((int32_t)2, piece2->getIndex()); CPPUNIT_ASSERT_EQUAL((int32_t)512, piece2->getLength()); - - } catch(Exception* e) { - cerr << e->getMsg() << endl; - delete e; - } } void DefaultBtProgressInfoFileTest::testLoad_nonBt() { - BtRegistry::unregisterAll(); + initializeMembers(1024, 81920); SingleFileDownloadContextHandle dctx = new SingleFileDownloadContext(1024, 81920, "load-nonBt"); @@ -165,9 +166,31 @@ void DefaultBtProgressInfoFileTest::testLoad_nonBt() } +void DefaultBtProgressInfoFileTest::testLoad_nonBt_pieceLengthShorter() +{ + initializeMembers(512, 81920); + + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(512, 81920, "load-nonBt"); + + DefaultBtProgressInfoFile infoFile(dctx, _pieceStorage, _option.get()); + CPPUNIT_ASSERT_EQUAL(string("./load-nonBt.aria2"), infoFile.getFilename()); + infoFile.load(); + + // check the contents of objects + + // bitfield + CPPUNIT_ASSERT_EQUAL(string("fffffffffffffffffffffffffffffffffffffffc"), + Util::toHex(_bitfield->getBitfield(), _bitfield->getBitfieldLength())); + + // the number of in-flight pieces + CPPUNIT_ASSERT_EQUAL((int32_t)0, + _pieceStorage->countInFlightPiece()); +} + void DefaultBtProgressInfoFileTest::testSave_nonBt() { - BtRegistry::unregisterAll(); + initializeMembers(1024, 81920); SingleFileDownloadContextHandle dctx = new SingleFileDownloadContext(1024, 81920, "save-temp"); @@ -261,6 +284,8 @@ void DefaultBtProgressInfoFileTest::testSave_nonBt() void DefaultBtProgressInfoFileTest::testSave() { + initializeMembers(1024, 81920); + _btContext->setName("save-temp"); _btContext->setPieceLength(1024); _btContext->setTotalLength(81920); diff --git a/test/UtilTest.cc b/test/UtilTest.cc index 61ae104b..2ac556f9 100644 --- a/test/UtilTest.cc +++ b/test/UtilTest.cc @@ -1,6 +1,7 @@ #include "Util.h" #include "FixedNumberRandomizer.h" #include "DlAbortEx.h" +#include "BitfieldMan.h" #include #include @@ -30,6 +31,7 @@ class UtilTest:public CppUnit::TestFixture { CPPUNIT_TEST(testIsUppercase); CPPUNIT_TEST(testAlphaToNum); CPPUNIT_TEST(testMkdirs); + CPPUNIT_TEST(testConvertBitfield); CPPUNIT_TEST_SUITE_END(); private: @@ -58,6 +60,7 @@ public: void testIsUppercase(); void testAlphaToNum(); void testMkdirs(); + void testConvertBitfield(); }; @@ -390,3 +393,17 @@ void UtilTest::testMkdirs() delete ex; } } + +void UtilTest::testConvertBitfield() +{ + BitfieldMan srcBitfield(384*1024, 256*1024*256+1); + BitfieldMan destBitfield(512*1024, srcBitfield.getTotalLength()); + srcBitfield.setAllBit(); + srcBitfield.unsetBit(2);// <- range [768, 1152) + // which corresponds to the index [1,2] in destBitfield + Util::convertBitfield(&destBitfield, &srcBitfield); + + CPPUNIT_ASSERT_EQUAL(string("9fffffffffffffffffffffffffffffff80"), + Util::toHex(destBitfield.getBitfield(), + destBitfield.getBitfieldLength())); +}