Bladeren bron

2010-02-11 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added BitfieldMan::getFirstNMissingUnusedIndex() to get multiple
	unused block indexes at once instead of calling
	getFirstMissingUnusedIndex() multiple times. Made use of it in
	Piece class and DefaultBtRequestFactory class via Piece class.
	* src/BitfieldMan.cc
	* src/BitfieldMan.h
	* src/DefaultBtRequestFactory.cc
	* src/Piece.cc
	* src/Piece.h
	* test/BitfieldManTest.cc
Tatsuhiro Tsujikawa 15 jaren geleden
bovenliggende
commit
ccc552cec9
7 gewijzigde bestanden met toevoegingen van 130 en 19 verwijderingen
  1. 13 0
      ChangeLog
  2. 41 0
      src/BitfieldMan.cc
  3. 6 2
      src/BitfieldMan.h
  4. 22 12
      src/DefaultBtRequestFactory.cc
  5. 7 3
      src/Piece.cc
  6. 12 2
      src/Piece.h
  7. 29 0
      test/BitfieldManTest.cc

+ 13 - 0
ChangeLog

@@ -1,3 +1,16 @@
+2010-02-11  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added BitfieldMan::getFirstNMissingUnusedIndex() to get multiple
+	unused block indexes at once instead of calling
+	getFirstMissingUnusedIndex() multiple times. Made use of it in
+	Piece class and DefaultBtRequestFactory class via Piece class.
+	* src/BitfieldMan.cc
+	* src/BitfieldMan.h
+	* src/DefaultBtRequestFactory.cc
+	* src/Piece.cc
+	* src/Piece.h
+	* test/BitfieldManTest.cc
+
 2010-02-10  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Use std::make_pair(...)

+ 41 - 0
src/BitfieldMan.cc

@@ -268,6 +268,47 @@ bool BitfieldMan::getFirstMissingUnusedIndex(size_t& index) const
   }
 }
 
+template<typename Array, typename OutputIterator>
+static bool getFirstNMissingIndex
+(OutputIterator out, size_t n,
+ const Array& bitfield, size_t bitfieldLength, size_t blocks)
+{
+  if(n == 0) {
+    return false;
+  }
+  const size_t origN = n;
+  for(size_t i = 0; i < bitfieldLength; ++i) {
+    unsigned char bits = bitfield[i];
+    unsigned char mask = 128;
+    size_t tindex = i*8;
+    for(size_t bi = 0; bi < 8 && tindex < blocks; ++bi, mask >>= 1, ++tindex) {
+      if(bits & mask) {
+        *out++ = tindex;
+        if(--n == 0) {
+          return true;
+        }
+      }
+    }
+  }
+  return origN > n;
+}
+
+bool BitfieldMan::getFirstNMissingUnusedIndex
+(std::vector<size_t>& out, size_t n) const
+{
+  if(filterEnabled) {
+    return getFirstNMissingIndex
+      (std::back_inserter(out), n,
+       ~array(bitfield)&~array(useBitfield)&array(filterBitfield),
+       bitfieldLength, blocks);
+  } else {
+    return getFirstNMissingIndex
+      (std::back_inserter(out), n,
+       ~array(bitfield)&~array(useBitfield),
+       bitfieldLength, blocks);
+  }
+}
+
 bool BitfieldMan::getFirstMissingIndex(size_t& index) const
 {
   if(filterEnabled) {

+ 6 - 2
src/BitfieldMan.h

@@ -38,6 +38,7 @@
 #include "common.h"
 #include "SharedHandle.h"
 #include <deque>
+#include <vector>
 
 namespace aria2 {
 
@@ -144,11 +145,14 @@ public:
   /**
    * affected by filter
    */
-  bool getFirstMissingUnusedIndex(size_t& index, const unsigned char* bitfield, size_t len) const;
+  bool getFirstMissingUnusedIndex(size_t& index) const;
   /**
+   * Stores at most n missing unused index in out. This function
+   * doesn't delete existing elements in out.
+   *
    * affected by filter
    */
-  bool getFirstMissingUnusedIndex(size_t& index) const;
+  bool getFirstNMissingUnusedIndex(std::vector<size_t>& out, size_t n) const;
   /**
    * affected by filter
    */

+ 22 - 12
src/DefaultBtRequestFactory.cc

@@ -152,20 +152,30 @@ void DefaultBtRequestFactory::removeAllTargetPiece() {
 void DefaultBtRequestFactory::createRequestMessages
 (std::deque<SharedHandle<BtMessage> >& requests, size_t max)
 {
+  if(requests.size() >= max) {
+    return;
+  }
+  size_t getnum = max-requests.size();
+  std::vector<size_t> blockIndexes;
+  blockIndexes.reserve(getnum);
   for(Pieces::iterator itr = pieces.begin();
-      itr != pieces.end() && requests.size() < max; ++itr) {
-    PieceHandle& piece = *itr;
-    size_t blockIndex;
-    while(requests.size() < max &&
-          piece->getMissingUnusedBlockIndex(blockIndex)) {
-      if(_logger->debug()) {
-        _logger->debug("Creating RequestMessage index=%u, begin=%u,"
-                       " blockIndex=%u",
-                       piece->getIndex(),
-                       blockIndex*piece->getBlockLength(),
-                       blockIndex);
+      itr != pieces.end() && getnum; ++itr) {
+    SharedHandle<Piece>& piece = *itr;
+    if(piece->getMissingUnusedBlockIndex(blockIndexes, getnum)) {
+      getnum -= blockIndexes.size();
+      for(std::vector<size_t>::const_iterator i = blockIndexes.begin();
+          i != blockIndexes.end(); ++i) {
+        if(_logger->debug()) {
+          _logger->debug("Creating RequestMessage index=%u, begin=%u,"
+                         " blockIndex=%u",
+                         piece->getIndex(),
+                         (*i)*piece->getBlockLength(),
+                         (*i));
+        }
+        requests.push_back
+          (messageFactory->createRequestMessage(piece, *i));
       }
-      requests.push_back(messageFactory->createRequestMessage(piece, blockIndex));
+      blockIndexes.clear();
     }
   }
 }

+ 7 - 3
src/Piece.cc

@@ -173,10 +173,14 @@ bool Piece::getMissingUnusedBlockIndex(size_t& index) const
   }
 }
 
-bool Piece::getMissingBlockIndex(size_t& index) const
+bool Piece::getMissingUnusedBlockIndex
+(std::vector<size_t>& indexes, size_t n) const
 {
-  if(bitfield->getMissingIndex(index)) {
-    bitfield->setUseBit(index);
+  if(bitfield->getFirstNMissingUnusedIndex(indexes, n)) {
+    for(std::vector<size_t>::const_iterator i = indexes.begin();
+        i != indexes.end(); ++i) {
+      bitfield->setUseBit(*i);
+    }
     return true;
   } else {
     return false;

+ 12 - 2
src/Piece.h

@@ -36,11 +36,14 @@
 #define _D_PIECE_H_
 
 #include "common.h"
-#include "SharedHandle.h"
+
 #include <stdint.h>
 #include <deque>
+#include <vector>
 #include <string>
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 
 class BitfieldMan;
@@ -92,8 +95,15 @@ public:
     return index < piece.index;
   }
 
+  // TODO This function only used by unit tests
   bool getMissingUnusedBlockIndex(size_t& index) const;
-  bool getMissingBlockIndex(size_t& index) const;
+
+  // Stores at most n missing unused block index to indexes. For all i
+  // in indexes, call bitfield->setUseBit(i). This function just add
+  // index to indexes and it doesn't remove anything from
+  // it. Therefore Caller must pass empty indexes.
+  bool getMissingUnusedBlockIndex(std::vector<size_t>& indexes, size_t n) const;
+
   bool getFirstMissingBlockIndexWithoutLock(size_t& index) const;
   bool getAllMissingBlockIndexes(unsigned char* misbitfield,
                                  size_t mislen) const;

+ 29 - 0
test/BitfieldManTest.cc

@@ -1,6 +1,7 @@
 #include "BitfieldMan.h"
 
 #include <cstring>
+#include <vector>
 
 #include <cppunit/extensions/HelperMacros.h>
 
@@ -37,6 +38,7 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testCountFilteredBlock);
   CPPUNIT_TEST(testCountMissingBlock);
   CPPUNIT_TEST(testZeroLengthFilter);
+  CPPUNIT_TEST(testGetFirstNMissingUnusedIndex);
   CPPUNIT_TEST_SUITE_END();
 private:
   SharedHandle<Randomizer> fixedNumberRandomizer;
@@ -77,6 +79,7 @@ public:
   void testCountFilteredBlock();
   void testCountMissingBlock();
   void testZeroLengthFilter();
+  void testGetFirstNMissingUnusedIndex();
 };
 
 
@@ -843,4 +846,30 @@ void BitfieldManTest::testZeroLengthFilter()
   CPPUNIT_ASSERT_EQUAL((size_t)0, bt.countMissingBlock());
 }
 
+void BitfieldManTest::testGetFirstNMissingUnusedIndex()
+{
+  BitfieldMan bt(1024, 1024*10);
+  bt.setUseBit(1);
+  bt.setBit(5);
+  std::vector<size_t> out;
+  bt.getFirstNMissingUnusedIndex(out, 256);
+  CPPUNIT_ASSERT_EQUAL((size_t)8, out.size());
+  const size_t ans[] = {0, 2, 3, 4, 6, 7, 8, 9};
+  for(size_t i = 0; i < out.size(); ++i) {
+    CPPUNIT_ASSERT_EQUAL(ans[i], out[i]);
+  }
+  out.clear();
+  bt.getFirstNMissingUnusedIndex(out, 3);
+  CPPUNIT_ASSERT_EQUAL((size_t)3, out.size());
+  for(size_t i = 0; i < out.size(); ++i) {
+    CPPUNIT_ASSERT_EQUAL(ans[i], out[i]);
+  }  
+  out.clear();
+  bt.addFilter(1024*9, 1024);
+  bt.enableFilter();
+  bt.getFirstNMissingUnusedIndex(out, 256);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, out.size());
+  CPPUNIT_ASSERT_EQUAL((size_t)9, out[0]);
+}
+
 } // namespace aria2