Browse Source

2010-08-29 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added a sets of overloaded functions for
	PieceStorage::getMissingPiece() and getMissingFastPiece() to get
	multiple pieces more efficiently.
	* src/DefaultBtInteractive.cc
	* src/DefaultPieceStorage.cc
	* src/DefaultPieceStorage.h
	* src/PieceStorage.h
	* src/UnknownLengthPieceStorage.cc
	* src/UnknownLengthPieceStorage.h
	* test/DefaultPieceStorageTest.cc
	* test/MockPieceStorage.h
Tatsuhiro Tsujikawa 15 years ago
parent
commit
e997903e5d

+ 14 - 0
ChangeLog

@@ -1,3 +1,17 @@
+2010-08-29  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added a sets of overloaded functions for
+	PieceStorage::getMissingPiece() and getMissingFastPiece() to get
+	multiple pieces more efficiently.
+	* src/DefaultBtInteractive.cc
+	* src/DefaultPieceStorage.cc
+	* src/DefaultPieceStorage.h
+	* src/PieceStorage.h
+	* src/UnknownLengthPieceStorage.cc
+	* src/UnknownLengthPieceStorage.h
+	* test/DefaultPieceStorageTest.cc
+	* test/MockPieceStorage.h
+
 2010-08-28  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Changed signature of util::executeHook().

+ 27 - 28
src/DefaultBtInteractive.cc

@@ -355,42 +355,41 @@ void DefaultBtInteractive::decideInterest() {
 
 void DefaultBtInteractive::fillPiece(size_t maxMissingBlock) {
   if(pieceStorage_->hasMissingPiece(peer_)) {
-
     size_t numMissingBlock = btRequestFactory_->countMissingBlock();
-
+    if(numMissingBlock >= maxMissingBlock) {
+      return;
+    }
+    size_t diffMissingBlock = maxMissingBlock-numMissingBlock;
+    std::vector<SharedHandle<Piece> > pieces;
     if(peer_->peerChoking()) {
       if(peer_->isFastExtensionEnabled()) {
-        std::vector<size_t> excludedIndexes;
-        excludedIndexes.reserve(btRequestFactory_->countTargetPiece());
-        btRequestFactory_->getTargetPieceIndexes(excludedIndexes);
-        while(numMissingBlock < maxMissingBlock) {
-          SharedHandle<Piece> piece =
-            pieceStorage_->getMissingFastPiece(peer_, excludedIndexes);
-          if(piece.isNull()) {
-            break;
-          } else {
-            btRequestFactory_->addTargetPiece(piece);
-            numMissingBlock += piece->countMissingBlock();
-            excludedIndexes.push_back(piece->getIndex());
-          }
+        if(pieceStorage_->isEndGame()) {
+          std::vector<size_t> excludedIndexes;
+          excludedIndexes.reserve(btRequestFactory_->countTargetPiece());
+          btRequestFactory_->getTargetPieceIndexes(excludedIndexes);
+          pieceStorage_->getMissingFastPiece
+            (pieces, diffMissingBlock, peer_, excludedIndexes);
+        } else {
+          pieces.reserve(diffMissingBlock);
+          pieceStorage_->getMissingFastPiece(pieces, diffMissingBlock, peer_);
         }
       }
     } else {
-      std::vector<size_t> excludedIndexes;
-      excludedIndexes.reserve(btRequestFactory_->countTargetPiece());
-      btRequestFactory_->getTargetPieceIndexes(excludedIndexes);
-      while(numMissingBlock < maxMissingBlock) {
-        SharedHandle<Piece> piece =
-          pieceStorage_->getMissingPiece(peer_, excludedIndexes);
-        if(piece.isNull()) {
-          break;
-        } else {
-          btRequestFactory_->addTargetPiece(piece);
-          numMissingBlock += piece->countMissingBlock();
-          excludedIndexes.push_back(piece->getIndex());
-        }
+      if(pieceStorage_->isEndGame()) {
+        std::vector<size_t> excludedIndexes;
+        excludedIndexes.reserve(btRequestFactory_->countTargetPiece());
+        btRequestFactory_->getTargetPieceIndexes(excludedIndexes);
+        pieceStorage_->getMissingPiece
+          (pieces, diffMissingBlock, peer_, excludedIndexes);
+      } else {        
+        pieces.reserve(diffMissingBlock);
+        pieceStorage_->getMissingPiece(pieces, diffMissingBlock, peer_);
       }
     }
+    for(std::vector<SharedHandle<Piece> >::const_iterator i =
+          pieces.begin(), eoi = pieces.end(); i != eoi; ++i) {
+      btRequestFactory_->addTargetPiece(*i);
+    }
   }
 }
 

+ 133 - 64
src/DefaultPieceStorage.cc

@@ -59,6 +59,7 @@
 #include "array_fun.h"
 #include "PieceStatMan.h"
 #include "wallclock.h"
+#include "bitfield.h"
 #ifdef ENABLE_BITTORRENT
 # include "bittorrent_helper.h"
 #endif // ENABLE_BITTORRENT
@@ -83,29 +84,6 @@ DefaultPieceStorage::~DefaultPieceStorage() {
   delete bitfieldMan_;
 }
 
-bool DefaultPieceStorage::getMissingPieceIndex(size_t& index,
-                                               const unsigned char* bitfield,
-                                               size_t length)
-{
-  const size_t mislen = bitfieldMan_->getBitfieldLength();
-  array_ptr<unsigned char> misbitfield(new unsigned char[mislen]);
-  bool r;
-  if(isEndGame()) {
-    r = bitfieldMan_->getAllMissingIndexes(misbitfield, mislen,
-                                           bitfield, length);
-  } else {
-    r = bitfieldMan_->getAllMissingUnusedIndexes(misbitfield, mislen,
-                                                 bitfield, length);
-  }
-  if(r) {
-    // We assume indexes is sorted using comparator less.
-    return
-      pieceSelector_->select(index, misbitfield,bitfieldMan_->countBlock());
-  } else {
-    return false;
-  }
-}
-
 SharedHandle<Piece> DefaultPieceStorage::checkOutPiece(size_t index)
 {
   bitfieldMan_->setUseBit(index);
@@ -172,23 +150,6 @@ SharedHandle<Piece> DefaultPieceStorage::findUsedPiece(size_t index) const
   }
 }
 
-SharedHandle<Piece> DefaultPieceStorage::getMissingPiece
-(const unsigned char* bitfield, size_t length)
-{
-  size_t index;
-  if(getMissingPieceIndex(index, bitfield, length)) {
-    return checkOutPiece(index);
-  } else {
-    return SharedHandle<Piece>();
-  }
-}
-
-SharedHandle<Piece> DefaultPieceStorage::getMissingPiece
-(const BitfieldMan& bitfield)
-{
-  return getMissingPiece(bitfield.getBitfield(), bitfield.getBitfieldLength());
-}
-
 #ifdef ENABLE_BITTORRENT
 
 bool DefaultPieceStorage::hasMissingPiece(const SharedHandle<Peer>& peer)
@@ -197,10 +158,58 @@ bool DefaultPieceStorage::hasMissingPiece(const SharedHandle<Peer>& peer)
                                        peer->getBitfieldLength());
 }
 
-SharedHandle<Piece>
-DefaultPieceStorage::getMissingPiece(const SharedHandle<Peer>& peer)
+void DefaultPieceStorage::getMissingPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const unsigned char* bitfield,
+ size_t length)
 {
-  return getMissingPiece(peer->getBitfield(), peer->getBitfieldLength());
+  const size_t mislen = bitfieldMan_->getBitfieldLength();
+  array_ptr<unsigned char> misbitfield(new unsigned char[mislen]);
+  size_t blocks = bitfieldMan_->countBlock();
+  size_t misBlock = 0;
+  if(isEndGame()) {
+    bool r = bitfieldMan_->getAllMissingIndexes
+      (misbitfield, mislen, bitfield, length);
+    if(!r) {
+      return;
+    }
+    std::vector<size_t> indexes;
+    for(size_t i = 0; i < blocks; ++i) {
+      if(bitfield::test(misbitfield, blocks, i)) {
+        indexes.push_back(i);
+      }
+    }
+    std::random_shuffle(indexes.begin(), indexes.end());
+    for(std::vector<size_t>::const_iterator i = indexes.begin(),
+          eoi = indexes.end(); i != eoi && misBlock < minMissingBlocks; ++i) {
+      pieces.push_back(checkOutPiece(*i));
+      misBlock += pieces.back()->countMissingBlock();
+    }
+  } else {
+    bool r = bitfieldMan_->getAllMissingUnusedIndexes
+      (misbitfield, mislen, bitfield, length);
+    if(!r) {
+      return;
+    }
+    while(misBlock < minMissingBlocks) {
+      size_t index;
+      if(pieceSelector_->select(index, misbitfield, blocks)) {
+        pieces.push_back(checkOutPiece(index));
+        bitfield::flipBit(misbitfield, blocks, index);
+        misBlock += pieces.back()->countMissingBlock();
+      } else {
+        break;
+      }
+    }
+  }
+}
+
+static void unsetExcludedIndexes(BitfieldMan& bitfield,
+                                 const std::vector<size_t>& excludedIndexes)
+{
+  std::for_each(excludedIndexes.begin(), excludedIndexes.end(),
+                std::bind1st(std::mem_fun(&BitfieldMan::unsetBit), &bitfield));
 }
 
 void DefaultPieceStorage::createFastIndexBitfield
@@ -215,47 +224,107 @@ void DefaultPieceStorage::createFastIndexBitfield
   }
 }
 
-SharedHandle<Piece> DefaultPieceStorage::getMissingFastPiece
-(const SharedHandle<Peer>& peer)
+void DefaultPieceStorage::getMissingPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer)
+{
+  getMissingPiece(pieces, minMissingBlocks,
+                  peer->getBitfield(), peer->getBitfieldLength());
+}
+
+
+void DefaultPieceStorage::getMissingPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer,
+ const std::vector<size_t>& excludedIndexes)
+{
+  BitfieldMan tempBitfield(bitfieldMan_->getBlockLength(),
+                           bitfieldMan_->getTotalLength());
+  tempBitfield.setBitfield(peer->getBitfield(), peer->getBitfieldLength());
+  unsetExcludedIndexes(tempBitfield, excludedIndexes);
+  getMissingPiece(pieces, minMissingBlocks,
+                  tempBitfield.getBitfield(), tempBitfield.getBitfieldLength());
+}
+
+void DefaultPieceStorage::getMissingFastPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer)
 {
   if(peer->isFastExtensionEnabled() && peer->countPeerAllowedIndexSet() > 0) {
     BitfieldMan tempBitfield(bitfieldMan_->getBlockLength(),
                              bitfieldMan_->getTotalLength());
     createFastIndexBitfield(tempBitfield, peer);
-    return getMissingPiece(tempBitfield);
-  } else {
-    return SharedHandle<Piece>();
+    getMissingPiece(pieces, minMissingBlocks,
+                    tempBitfield.getBitfield(),
+                    tempBitfield.getBitfieldLength());
   }
 }
 
-static void unsetExcludedIndexes(BitfieldMan& bitfield,
-                                 const std::vector<size_t>& excludedIndexes)
+void DefaultPieceStorage::getMissingFastPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer,
+ const std::vector<size_t>& excludedIndexes)
 {
-  std::for_each(excludedIndexes.begin(), excludedIndexes.end(),
-                std::bind1st(std::mem_fun(&BitfieldMan::unsetBit), &bitfield));
+  if(peer->isFastExtensionEnabled() && peer->countPeerAllowedIndexSet() > 0) {
+    BitfieldMan tempBitfield(bitfieldMan_->getBlockLength(),
+                             bitfieldMan_->getTotalLength());
+    createFastIndexBitfield(tempBitfield, peer);
+    unsetExcludedIndexes(tempBitfield, excludedIndexes);
+    getMissingPiece(pieces, minMissingBlocks,
+                    tempBitfield.getBitfield(),
+                    tempBitfield.getBitfieldLength());
+  }
+}
+
+SharedHandle<Piece>
+DefaultPieceStorage::getMissingPiece(const SharedHandle<Peer>& peer)
+{
+  std::vector<SharedHandle<Piece> > pieces;
+  getMissingPiece(pieces, 1, peer);
+  if(pieces.empty()) {
+    return SharedHandle<Piece>();
+  } else {
+    return pieces.front();
+  }
 }
 
 SharedHandle<Piece> DefaultPieceStorage::getMissingPiece
 (const SharedHandle<Peer>& peer, const std::vector<size_t>& excludedIndexes)
 {
-  BitfieldMan tempBitfield(bitfieldMan_->getBlockLength(),
-                           bitfieldMan_->getTotalLength());
-  tempBitfield.setBitfield(peer->getBitfield(), peer->getBitfieldLength());
-  unsetExcludedIndexes(tempBitfield, excludedIndexes);
-  return getMissingPiece(tempBitfield);
+  std::vector<SharedHandle<Piece> > pieces;
+  getMissingPiece(pieces, 1, peer, excludedIndexes);
+  if(pieces.empty()) {
+    return SharedHandle<Piece>();
+  } else {
+    return pieces.front();
+  }
 }
 
 SharedHandle<Piece> DefaultPieceStorage::getMissingFastPiece
-(const SharedHandle<Peer>& peer, const std::vector<size_t>& excludedIndexes)
+(const SharedHandle<Peer>& peer)
 {
-  if(peer->isFastExtensionEnabled() && peer->countPeerAllowedIndexSet() > 0) {
-    BitfieldMan tempBitfield(bitfieldMan_->getBlockLength(),
-                             bitfieldMan_->getTotalLength());
-    createFastIndexBitfield(tempBitfield, peer);
-    unsetExcludedIndexes(tempBitfield, excludedIndexes);
-    return getMissingPiece(tempBitfield);
+  std::vector<SharedHandle<Piece> > pieces;
+  getMissingFastPiece(pieces, 1, peer);
+  if(pieces.empty()) {
+    return SharedHandle<Piece>();
   } else {
+    return pieces.front();
+  }
+}
+
+SharedHandle<Piece> DefaultPieceStorage::getMissingFastPiece
+(const SharedHandle<Peer>& peer, const std::vector<size_t>& excludedIndexes)
+{
+  std::vector<SharedHandle<Piece> > pieces;
+  getMissingFastPiece(pieces, 1, peer, excludedIndexes);
+  if(pieces.empty()) {
     return SharedHandle<Piece>();
+  } else {
+    return pieces.front();
   }
 }
 

+ 28 - 8
src/DefaultPieceStorage.h

@@ -88,15 +88,13 @@ private:
 
   SharedHandle<PieceSelector> pieceSelector_;
 
-  bool getMissingPieceIndex(size_t& index,
-                            const unsigned char* bitfield, size_t length);
-
-  SharedHandle<Piece> getMissingPiece(const unsigned char* bitfield,
-                                      size_t length);
-
-  SharedHandle<Piece> getMissingPiece(const BitfieldMan& bitfield);
-
 #ifdef ENABLE_BITTORRENT
+  void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const unsigned char* bitfield,
+   size_t length);
+
   void createFastIndexBitfield(BitfieldMan& bitfield,
                                const SharedHandle<Peer>& peer);
 #endif // ENABLE_BITTORRENT
@@ -123,6 +121,28 @@ public:
 
   virtual bool hasMissingPiece(const SharedHandle<Peer>& peer);
 
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes);
+
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer);
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes);
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer);
+
   virtual SharedHandle<Piece> getMissingPiece(const SharedHandle<Peer>& peer);
 
   virtual SharedHandle<Piece> getMissingFastPiece

+ 22 - 0
src/PieceStorage.h

@@ -63,6 +63,28 @@ public:
    */
   virtual bool hasMissingPiece(const SharedHandle<Peer>& peer) = 0;
 
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes) = 0;
+
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer) = 0;
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes) = 0;
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer) = 0;
+
   /**
    * Returns a piece that the peer has but localhost doesn't.
    * The piece will be marked "used" status in order to prevent other command

+ 34 - 0
src/UnknownLengthPieceStorage.cc

@@ -78,6 +78,40 @@ bool UnknownLengthPieceStorage::hasMissingPiece(const SharedHandle<Peer>& peer)
   abort();
 }
 
+void UnknownLengthPieceStorage::getMissingPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer,
+ const std::vector<size_t>& excludedIndexes)
+{
+  abort();
+}
+
+void UnknownLengthPieceStorage::getMissingPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer)
+{
+  abort();
+}
+
+void UnknownLengthPieceStorage::getMissingFastPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer,
+ const std::vector<size_t>& excludedIndexes)
+{
+  abort();
+}
+
+void UnknownLengthPieceStorage::getMissingFastPiece
+(std::vector<SharedHandle<Piece> >& pieces,
+ size_t minMissingBlocks,
+ const SharedHandle<Peer>& peer)
+{
+  abort();
+}
+
 SharedHandle<Piece> UnknownLengthPieceStorage::getMissingPiece(const SharedHandle<Peer>& peer)
 {
   abort();

+ 22 - 0
src/UnknownLengthPieceStorage.h

@@ -73,6 +73,28 @@ public:
    */
   virtual bool hasMissingPiece(const SharedHandle<Peer>& peer);
 
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes);
+
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer);
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes);
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer);
+
   /**
    * Returns a piece that the peer has but localhost doesn't.
    * The piece will be marked "used" status in order to prevent other command

+ 43 - 2
test/DefaultPieceStorageTest.cc

@@ -12,6 +12,9 @@
 #include "InOrderPieceSelector.h"
 #include "DownloadContext.h"
 #include "bittorrent_helper.h"
+#include "DiskAdaptor.h"
+#include "DiskWriterFactory.h"
+#include "PieceStatMan.h"
 
 namespace aria2 {
 
@@ -20,7 +23,9 @@ class DefaultPieceStorageTest:public CppUnit::TestFixture {
   CPPUNIT_TEST_SUITE(DefaultPieceStorageTest);
   CPPUNIT_TEST(testGetTotalLength);
   CPPUNIT_TEST(testGetMissingPiece);
+  CPPUNIT_TEST(testGetMissingPiece_many);
   CPPUNIT_TEST(testGetMissingPiece_excludedIndexes);
+  CPPUNIT_TEST(testGetMissingPiece_manyWithExcludedIndexes);
   CPPUNIT_TEST(testGetMissingFastPiece);
   CPPUNIT_TEST(testGetMissingFastPiece_excludedIndexes);
   CPPUNIT_TEST(testHasMissingPiece);
@@ -57,7 +62,9 @@ public:
 
   void testGetTotalLength();
   void testGetMissingPiece();
+  void testGetMissingPiece_many();
   void testGetMissingPiece_excludedIndexes();
+  void testGetMissingPiece_manyWithExcludedIndexes();
   void testGetMissingFastPiece();
   void testGetMissingFastPiece_excludedIndexes();
   void testHasMissingPiece();
@@ -83,8 +90,6 @@ void DefaultPieceStorageTest::testGetTotalLength() {
 void DefaultPieceStorageTest::testGetMissingPiece() {
   DefaultPieceStorage pss(dctx_, option);
   pss.setPieceSelector(pieceSelector_);
-  pss.setEndGamePieceNum(0);
-
   peer->setAllBitfield();
 
   SharedHandle<Piece> piece = pss.getMissingPiece(peer);
@@ -100,6 +105,24 @@ void DefaultPieceStorageTest::testGetMissingPiece() {
   CPPUNIT_ASSERT(piece.isNull());
 }
 
+void DefaultPieceStorageTest::testGetMissingPiece_many() {
+  DefaultPieceStorage pss(dctx_, option);
+  pss.setPieceSelector(pieceSelector_);
+  peer->setAllBitfield();
+  std::vector<SharedHandle<Piece> > pieces;
+  pss.getMissingPiece(pieces, 2, peer);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, pieces.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("piece: index=0, length=128"),
+                       pieces[0]->toString());
+  CPPUNIT_ASSERT_EQUAL(std::string("piece: index=1, length=128"),
+                       pieces[1]->toString());
+  pieces.clear();
+  pss.getMissingPiece(pieces, 2, peer);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, pieces.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("piece: index=2, length=128"),
+                       pieces[0]->toString());
+}
+
 void DefaultPieceStorageTest::testGetMissingPiece_excludedIndexes()
 {
   DefaultPieceStorage pss(dctx_, option);
@@ -123,6 +146,24 @@ void DefaultPieceStorageTest::testGetMissingPiece_excludedIndexes()
   CPPUNIT_ASSERT(piece.isNull());
 }
 
+void DefaultPieceStorageTest::testGetMissingPiece_manyWithExcludedIndexes() {
+  DefaultPieceStorage pss(dctx_, option);
+  pss.setPieceSelector(pieceSelector_);
+  peer->setAllBitfield();
+  std::vector<size_t> excludedIndexes;
+  excludedIndexes.push_back(1);
+  std::vector<SharedHandle<Piece> > pieces;
+  pss.getMissingPiece(pieces, 2, peer, excludedIndexes);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, pieces.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("piece: index=0, length=128"),
+                       pieces[0]->toString());
+  CPPUNIT_ASSERT_EQUAL(std::string("piece: index=2, length=128"),
+                       pieces[1]->toString());
+  pieces.clear();
+  pss.getMissingPiece(pieces, 2, peer, excludedIndexes);
+  CPPUNIT_ASSERT(pieces.empty());
+}
+
 void DefaultPieceStorageTest::testGetMissingFastPiece() {
   DefaultPieceStorage pss(dctx_, option);
   pss.setPieceSelector(pieceSelector_);

+ 26 - 0
test/MockPieceStorage.h

@@ -48,6 +48,32 @@ public:
     return SharedHandle<Piece>(new Piece());
   }
 
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes)
+  {}
+
+  virtual void getMissingPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer)
+  {}
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer,
+   const std::vector<size_t>& excludedIndexes)
+  {}
+
+  virtual void getMissingFastPiece
+  (std::vector<SharedHandle<Piece> >& pieces,
+   size_t minMissingBlocks,
+   const SharedHandle<Peer>& peer)
+  {}
+
   virtual SharedHandle<Piece> getMissingPiece
   (const SharedHandle<Peer>& peer, const std::vector<size_t>& excludedIndexes)
   {