Explorar o código

Don't sum in-flight piece which does not intersect filtered ranges

When calculating completed length, don't sum the completed length of
piece which does not intersect filtered ranges.
Tatsuhiro Tsujikawa %!s(int64=13) %!d(string=hai) anos
pai
achega
c30ea8adeb

+ 8 - 0
src/BitfieldMan.cc

@@ -609,6 +609,14 @@ bool BitfieldMan::isAllFilterBitSet() const
   return testAllBitSet(filterBitfield_, bitfieldLength_, blocks_);
 }
 
+bool BitfieldMan::isFilterBitSet(size_t index) const {
+  if(filterBitfield_) {
+    return bitfield::test(filterBitfield_, blocks_, index);
+  } else {
+    return false;
+  }
+}
+
 bool BitfieldMan::isBitSet(size_t index) const
 {
   return bitfield::test(bitfield_, blocks_, index);

+ 3 - 0
src/BitfieldMan.h

@@ -200,6 +200,9 @@ public:
   bool isAllBitSet() const;
 
   bool isAllFilterBitSet() const;
+  // Returns true if index bit is set in filterBitfield_.  If
+  // filterBitfield_ is NULL, returns false.
+  bool isFilterBitSet(size_t index) const;
 
   const unsigned char* getBitfield() const
   {

+ 20 - 5
src/DefaultPieceStorage.cc

@@ -537,14 +537,29 @@ int64_t DefaultPieceStorage::getCompletedLength()
 int64_t DefaultPieceStorage::getFilteredCompletedLength()
 {
   return bitfieldMan_->getFilteredCompletedLength()+
-    getInFlightPieceCompletedLength();
+    getInFlightPieceFilteredCompletedLength();
 }
 
-size_t DefaultPieceStorage::getInFlightPieceCompletedLength() const
+int64_t DefaultPieceStorage::getInFlightPieceCompletedLength() const
 {
-  return std::accumulate(usedPieces_.begin(), usedPieces_.end(),
-                         0, adopt2nd(std::plus<size_t>(),
-                                     mem_fun_sh(&Piece::getCompletedLength)));
+  int64_t len = 0;
+  for(UsedPieceSet::const_iterator i = usedPieces_.begin(),
+        eoi = usedPieces_.end(); i != eoi; ++i) {
+    len += (*i)->getCompletedLength();
+  }
+  return len;
+}
+
+int64_t DefaultPieceStorage::getInFlightPieceFilteredCompletedLength() const
+{
+  int64_t len = 0;
+  for(UsedPieceSet::const_iterator i = usedPieces_.begin(),
+        eoi = usedPieces_.end(); i != eoi; ++i) {
+    if(bitfieldMan_->isFilterBitSet((*i)->getIndex())) {
+      len += (*i)->getCompletedLength();
+    }
+  }
+  return len;
 }
 
 // not unittested

+ 5 - 2
src/DefaultPieceStorage.h

@@ -110,8 +110,11 @@ private:
   void deleteUsedPiece(const SharedHandle<Piece>& piece);
   SharedHandle<Piece> findUsedPiece(size_t index) const;
 
-  size_t getInFlightPieceCompletedLength() const;
-
+  // Returns the sum of completed length of in-flight pieces
+  int64_t getInFlightPieceCompletedLength() const;
+  // Returns the sum of completed length of in-flight pieces
+  // intersecting filter ranges.
+  int64_t getInFlightPieceFilteredCompletedLength() const;
 public:
   // Setting randomPieceStatsOrdering to true means a piece is chosen in
   // random when more than 2 pieces has the same rarity.

+ 13 - 0
test/BitfieldManTest.cc

@@ -18,6 +18,7 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testGetFirstMissingIndex);
   CPPUNIT_TEST(testIsAllBitSet);
   CPPUNIT_TEST(testFilter);
+  CPPUNIT_TEST(testIsFilterBitSet);
   CPPUNIT_TEST(testAddFilter_zeroLength);
   CPPUNIT_TEST(testAddNotFilter);
   CPPUNIT_TEST(testAddNotFilter_zeroLength);
@@ -51,6 +52,7 @@ public:
   
   void testIsAllBitSet();
   void testFilter();
+  void testIsFilterBitSet();
   void testAddFilter_zeroLength();
   void testAddNotFilter();
   void testAddNotFilter_zeroLength();
@@ -244,6 +246,17 @@ void BitfieldManTest::testFilter()
   CPPUNIT_ASSERT_EQUAL((int64_t)31ULL, btman2.getFilteredTotalLength());
 }
 
+void BitfieldManTest::testIsFilterBitSet()
+{
+  BitfieldMan btman(2, 32);
+  CPPUNIT_ASSERT(!btman.isFilterBitSet(0));
+  btman.addFilter(0, 2);
+  CPPUNIT_ASSERT(btman.isFilterBitSet(0));
+  CPPUNIT_ASSERT(!btman.isFilterBitSet(1));
+  btman.addFilter(2, 4);
+  CPPUNIT_ASSERT(btman.isFilterBitSet(1));
+}
+
 void BitfieldManTest::testAddFilter_zeroLength()
 {
   BitfieldMan bits(1024, 1024*1024);

+ 32 - 0
test/DefaultPieceStorageTest.cc

@@ -37,6 +37,7 @@ class DefaultPieceStorageTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testCancelPiece);
   CPPUNIT_TEST(testMarkPiecesDone);
   CPPUNIT_TEST(testGetCompletedLength);
+  CPPUNIT_TEST(testGetFilteredCompletedLength);
   CPPUNIT_TEST(testGetNextUsedIndex);
   CPPUNIT_TEST_SUITE_END();
 private:
@@ -71,6 +72,7 @@ public:
   void testCancelPiece();
   void testMarkPiecesDone();
   void testGetCompletedLength();
+  void testGetFilteredCompletedLength();
   void testGetNextUsedIndex();
 };
 
@@ -345,6 +347,36 @@ void DefaultPieceStorageTest::testGetCompletedLength()
   CPPUNIT_ASSERT_EQUAL((int64_t)256*1024*1024, ps.getCompletedLength());
 }
 
+void DefaultPieceStorageTest::testGetFilteredCompletedLength()
+{
+  const size_t pieceLength = 1024*1024;
+  SharedHandle<DownloadContext> dctx(new DownloadContext());
+  dctx->setPieceLength(pieceLength);
+  SharedHandle<FileEntry> files[] = {
+    SharedHandle<FileEntry>(new FileEntry("foo", 2*pieceLength, 0)),
+    SharedHandle<FileEntry>(new FileEntry("bar", 4*pieceLength, 2*pieceLength))
+  };
+  files[1]->setRequested(false);
+  dctx->setFileEntries(&files[0], &files[2]);
+
+  DefaultPieceStorage ps(dctx, option_.get());
+  std::vector<SharedHandle<Piece> > inflightPieces(2);
+  inflightPieces[0] = SharedHandle<Piece>(new Piece(1, pieceLength));
+  inflightPieces[0]->completeBlock(0);
+  inflightPieces[1] = SharedHandle<Piece>(new Piece(2, pieceLength));
+  inflightPieces[1]->completeBlock(1);
+  inflightPieces[1]->completeBlock(2);
+
+  ps.addInFlightPiece(inflightPieces);
+  ps.setupFileFilter();
+
+  SharedHandle<Piece> piece = ps.getMissingPiece(0, 1);
+  ps.completePiece(piece);
+
+  CPPUNIT_ASSERT_EQUAL((int64_t)pieceLength+16*1024,
+                       ps.getFilteredCompletedLength());
+}
+
 void DefaultPieceStorageTest::testGetNextUsedIndex()
 {
   DefaultPieceStorage pss(dctx_, option_.get());