Prechádzať zdrojové kódy

Fix file length information in RPC response when length > 2GB is unknown

This commit fixes the bug that aria2.tellStopped RPC method returns
total length and completedLength as 0 when file size is unknown in
advance and turns out > 2GB in the end.  This commit and addresses the
performance degradation in this case.
Tatsuhiro Tsujikawa 11 rokov pred
rodič
commit
3aaa5a7344
4 zmenil súbory, kde vykonal 26 pridanie a 20 odobranie
  1. 13 7
      src/Piece.cc
  2. 8 8
      src/Piece.h
  3. 4 4
      test/DefaultBtProgressInfoFileTest.cc
  4. 1 1
      test/PieceTest.cc

+ 13 - 7
src/Piece.cc

@@ -60,7 +60,7 @@ Piece::Piece()
     usedBySegment_(false)
 {}
 
-Piece::Piece(size_t index, int32_t length, int32_t blockLength)
+Piece::Piece(size_t index, int64_t length, int32_t blockLength)
  : bitfield_(new BitfieldMan(blockLength, length)),
    wrCache_(nullptr),
    index_(index),
@@ -181,15 +181,21 @@ bool Piece::getAllMissingBlockIndexes
 }
 
 std::string Piece::toString() const {
-  return fmt("piece: index=%lu, length=%d",
+  return fmt("piece: index=%lu, length=%" PRId64,
              static_cast<unsigned long>(index_), length_);
 }
 
-void Piece::reconfigure(int32_t length)
+void Piece::reconfigure(int64_t length)
 {
   delete bitfield_;
   length_ = length;
-  bitfield_ = new BitfieldMan(blockLength_, length_);
+  // TODO currently, this function is only called from
+  // GrowSegment::updateWrittenLength().  If we use default block
+  // length (16K), and length_ gets large (e.g., 4GB), creating
+  // BitfieldMan for each call is very expensive.  Therefore, we use
+  // maximum block length for now to reduce the overhead.  Ideally, we
+  // check the code thoroughly and remove bitfield_ if we can.
+  bitfield_ = new BitfieldMan(std::numeric_limits<int32_t>::max(), length_);
 }
 
 void Piece::setBitfield(const unsigned char* bitfield, size_t len)
@@ -197,7 +203,7 @@ void Piece::setBitfield(const unsigned char* bitfield, size_t len)
   bitfield_->setBitfield(bitfield, len);
 }
 
-int32_t Piece::getCompletedLength()
+int64_t Piece::getCompletedLength()
 {
   return bitfield_->getCompletedLength();
 }
@@ -208,13 +214,13 @@ void Piece::setHashType(const std::string& hashType)
 }
 
 bool Piece::updateHash
-(int32_t begin, const unsigned char* data, size_t dataLength)
+(int64_t begin, const unsigned char* data, size_t dataLength)
 {
   if(hashType_.empty()) {
     return false;
   }
   if(begin == nextBegin_ &&
-     nextBegin_+dataLength <= static_cast<size_t>(length_)) {
+     nextBegin_ + static_cast<int64_t>(dataLength) <= length_) {
     if(!mdctx_) {
       mdctx_ = MessageDigest::create(hashType_);
     }

+ 8 - 8
src/Piece.h

@@ -62,9 +62,9 @@ private:
 
   size_t index_;
 
-  int32_t length_;
+  int64_t length_;
   int32_t blockLength_;
-  int32_t nextBegin_;
+  int64_t nextBegin_;
 
   bool usedBySegment_;
 
@@ -75,7 +75,7 @@ public:
   static const int32_t BLOCK_LENGTH  = 16*1024;
 
   Piece();
-  Piece(size_t index, int32_t length, int32_t blockLength = BLOCK_LENGTH);
+  Piece(size_t index, int64_t length, int32_t blockLength = BLOCK_LENGTH);
 
   ~Piece();
 
@@ -127,9 +127,9 @@ public:
 
   void setIndex(size_t index) { index_ = index; }
 
-  int32_t getLength() const { return length_; }
+  int64_t getLength() const { return length_; }
 
-  void setLength(int32_t length) { length_ = length; }
+  void setLength(int64_t length) { length_ = length; }
 
   const unsigned char* getBitfield() const;
 
@@ -145,14 +145,14 @@ public:
   bool isBlockUsed(size_t index) const;
 
   // Calculates completed length
-  int32_t getCompletedLength();
+  int64_t getCompletedLength();
 
   void setHashType(const std::string& hashType);
 
   // Updates hash value. This function compares begin and private variable
   // nextBegin_ and only when they are equal, hash is updated eating data and
   // returns true. Otherwise returns false.
-  bool updateHash(int32_t begin, const unsigned char* data, size_t dataLength);
+  bool updateHash(int64_t begin, const unsigned char* data, size_t dataLength);
 
   bool isHashCalculated() const;
 
@@ -171,7 +171,7 @@ public:
   /**
    * Loses current bitfield state.
    */
-  void reconfigure(int32_t length);
+  void reconfigure(int64_t length);
 
   void addUser(cuid_t cuid);
   void removeUser(cuid_t cuid);

+ 4 - 4
test/DefaultBtProgressInfoFileTest.cc

@@ -361,7 +361,7 @@ void DefaultBtProgressInfoFileTest::testLoad_nonBt_compat()
 
   std::shared_ptr<Piece> piece1 = inFlightPieces[0];
   CPPUNIT_ASSERT_EQUAL((size_t)1, piece1->getIndex());
-  CPPUNIT_ASSERT_EQUAL(1024, piece1->getLength());
+  CPPUNIT_ASSERT_EQUAL((int64_t)1024, piece1->getLength());
   CPPUNIT_ASSERT_EQUAL((size_t)1, piece1->getBitfieldLength());
   CPPUNIT_ASSERT_EQUAL(std::string("00"), util::toHex(piece1->getBitfield(),
                                                       piece1->getBitfieldLength()));
@@ -369,7 +369,7 @@ void DefaultBtProgressInfoFileTest::testLoad_nonBt_compat()
   // piece index 2
   std::shared_ptr<Piece> piece2 = inFlightPieces[1];
   CPPUNIT_ASSERT_EQUAL((size_t)2, piece2->getIndex());
-  CPPUNIT_ASSERT_EQUAL(512, piece2->getLength());
+  CPPUNIT_ASSERT_EQUAL((int64_t)512, piece2->getLength());
 }
 #endif // !WORDS_BIGENDIAN
 
@@ -406,7 +406,7 @@ void DefaultBtProgressInfoFileTest::testLoad_nonBt()
 
   std::shared_ptr<Piece> piece1 = inFlightPieces[0];
   CPPUNIT_ASSERT_EQUAL((size_t)1, piece1->getIndex());
-  CPPUNIT_ASSERT_EQUAL(1024, piece1->getLength());
+  CPPUNIT_ASSERT_EQUAL((int64_t)1024, piece1->getLength());
   CPPUNIT_ASSERT_EQUAL((size_t)1, piece1->getBitfieldLength());
   CPPUNIT_ASSERT_EQUAL(std::string("00"), util::toHex(piece1->getBitfield(),
                                                       piece1->getBitfieldLength()));
@@ -414,7 +414,7 @@ void DefaultBtProgressInfoFileTest::testLoad_nonBt()
   // piece index 2
   std::shared_ptr<Piece> piece2 = inFlightPieces[1];
   CPPUNIT_ASSERT_EQUAL((size_t)2, piece2->getIndex());
-  CPPUNIT_ASSERT_EQUAL(512, piece2->getLength());
+  CPPUNIT_ASSERT_EQUAL((int64_t)512, piece2->getLength());
 }
 
 void DefaultBtProgressInfoFileTest::testLoad_nonBt_pieceLengthShorter()

+ 1 - 1
test/PieceTest.cc

@@ -67,7 +67,7 @@ void PieceTest::testGetCompletedLength()
   p.completeBlock(9);
   p.completeBlock(10); // <-- 100 bytes
 
-  CPPUNIT_ASSERT_EQUAL(blockLength*3+100, p.getCompletedLength());
+  CPPUNIT_ASSERT_EQUAL((int64_t)(blockLength*3+100), p.getCompletedLength());
 }
 
 void PieceTest::testFlushWrCache()