Browse Source

2009-05-06 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Moved piece statistics stuff to new PieceStatMan class.
	Refactored PieceSelector interface.
	* src/DefaultPieceStorage.cc
	* src/DefaultPieceStorage.h
	* src/LongestSequencePieceSelector.cc
	* src/LongestSequencePieceSelector.h
	* src/Makefile.am
	* src/PieceSelector.h
	* src/PieceStatMan.cc
	* src/PieceStatMan.h
	* src/RarestPieceSelector.cc
	* src/RarestPieceSelector.h
	* src/RequestGroup.cc
	* test/DefaultPieceStorageTest.cc
	* test/InOrderPieceSelector.h
	* test/Makefile.am
	* test/PieceStatManTest.cc
	* test/RarestPieceSelectorTest.cc
Tatsuhiro Tsujikawa 16 years ago
parent
commit
4da631bef6

+ 21 - 0
ChangeLog

@@ -1,3 +1,24 @@
+2009-05-06  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Moved piece statistics stuff to new PieceStatMan class.
+	Refactored PieceSelector interface.
+	* src/DefaultPieceStorage.cc
+	* src/DefaultPieceStorage.h
+	* src/LongestSequencePieceSelector.cc
+	* src/LongestSequencePieceSelector.h
+	* src/Makefile.am
+	* src/PieceSelector.h
+	* src/PieceStatMan.cc
+	* src/PieceStatMan.h
+	* src/RarestPieceSelector.cc
+	* src/RarestPieceSelector.h
+	* src/RequestGroup.cc
+	* test/DefaultPieceStorageTest.cc
+	* test/InOrderPieceSelector.h
+	* test/Makefile.am
+	* test/PieceStatManTest.cc
+	* test/RarestPieceSelectorTest.cc
+	
 2009-05-06  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Added static member _protocolFamily to SocketCore.  By default,

+ 9 - 14
src/DefaultPieceStorage.cc

@@ -58,13 +58,12 @@
 #include "StringFormat.h"
 #include "RarestPieceSelector.h"
 #include "array_fun.h"
+#include "PieceStatMan.h"
 
 namespace aria2 {
 
 DefaultPieceStorage::DefaultPieceStorage
-(const DownloadContextHandle& downloadContext,
- const Option* option,
- const SharedHandle<PieceSelector>& pieceSelector):
+(const DownloadContextHandle& downloadContext, const Option* option):
   downloadContext(downloadContext),
   bitfieldMan(BitfieldManFactory::getFactoryInstance()->
 	      createBitfieldMan(downloadContext->getPieceLength(),
@@ -73,13 +72,9 @@ DefaultPieceStorage::DefaultPieceStorage
   endGamePieceNum(END_GAME_PIECE_NUM),
   logger(LogFactory::getInstance()),
   option(option),
-  _pieceSelector(pieceSelector)
-{
-  if(_pieceSelector.isNull()) {
-    _pieceSelector.reset
-      (new RarestPieceSelector(downloadContext->getNumPieces(), true));
-  }
-}
+  _pieceStatMan(new PieceStatMan(downloadContext->getNumPieces(), true)),
+  _pieceSelector(new RarestPieceSelector(_pieceStatMan))
+{}
 
 DefaultPieceStorage::~DefaultPieceStorage() {
   delete bitfieldMan;
@@ -653,26 +648,26 @@ void DefaultPieceStorage::setDiskWriterFactory(const DiskWriterFactoryHandle& di
 void DefaultPieceStorage::addPieceStats(const unsigned char* bitfield,
 					size_t bitfieldLength)
 {
-  _pieceSelector->addPieceStats(bitfield, bitfieldLength);
+  _pieceStatMan->addPieceStats(bitfield, bitfieldLength);
 }
 
 void DefaultPieceStorage::subtractPieceStats(const unsigned char* bitfield,
 					     size_t bitfieldLength)
 {
-  _pieceSelector->subtractPieceStats(bitfield, bitfieldLength);
+  _pieceStatMan->subtractPieceStats(bitfield, bitfieldLength);
 }
 
 void DefaultPieceStorage::updatePieceStats(const unsigned char* newBitfield,
 					   size_t newBitfieldLength,
 					   const unsigned char* oldBitfield)
 {
-  _pieceSelector->updatePieceStats(newBitfield, newBitfieldLength,
+  _pieceStatMan->updatePieceStats(newBitfield, newBitfieldLength,
 				   oldBitfield);
 }
 
 void DefaultPieceStorage::addPieceStats(size_t index)
 {
-  _pieceSelector->addPieceStats(index);
+  _pieceStatMan->addPieceStats(index);
 }
 
 } // namespace aria2

+ 14 - 3
src/DefaultPieceStorage.h

@@ -45,6 +45,7 @@ class Logger;
 class Option;
 class DiskWriterFactory;
 class FileEntry;
+class PieceStatMan;
 class PieceSelector;
 
 #define END_GAME_PIECE_NUM 20
@@ -81,6 +82,8 @@ private:
   const Option* option;
   Haves haves;
 
+  SharedHandle<PieceStatMan> _pieceStatMan;
+
   SharedHandle<PieceSelector> _pieceSelector;
 
   bool getMissingPieceIndex(size_t& index,
@@ -108,9 +111,7 @@ public:
   // If it is set to false, a piece whose index is smallest has the highest
   // priority.
   DefaultPieceStorage(const SharedHandle<DownloadContext>& downloadContext,
-		      const Option* option,
-		      const SharedHandle<PieceSelector>& pieceSelector
-		      = SharedHandle<PieceSelector>());
+		      const Option* option);
 		      
   virtual ~DefaultPieceStorage();
 
@@ -223,6 +224,16 @@ public:
   void addUsedPiece(const SharedHandle<Piece>& piece);
 
   void setDiskWriterFactory(const SharedHandle<DiskWriterFactory>& diskWriterFactory);
+
+  const SharedHandle<PieceStatMan>& getPieceStatMan() const
+  {
+    return _pieceStatMan;
+  }
+
+  void setPieceSelector(const SharedHandle<PieceSelector>& pieceSelector)
+  {
+    _pieceSelector = pieceSelector;
+  }
 };
 
 typedef SharedHandle<DefaultPieceStorage> DefaultPieceStorageHandle;

+ 0 - 12
src/LongestSequencePieceSelector.cc

@@ -85,16 +85,4 @@ bool LongestSequencePieceSelector::select
   }
 }
 
-void LongestSequencePieceSelector::addPieceStats
-(const unsigned char* bitfield, size_t bitfieldLength) {}
-
-void LongestSequencePieceSelector::subtractPieceStats
-(const unsigned char* bitfield, size_t bitfieldLength) {}
-
-void LongestSequencePieceSelector::updatePieceStats
-(const unsigned char* newBitfield, size_t newBitfieldLength,
- const unsigned char* oldBitfield) {}
-
-void LongestSequencePieceSelector::addPieceStats(size_t index) {}
-
 } // namespace aria2

+ 0 - 12
src/LongestSequencePieceSelector.h

@@ -47,18 +47,6 @@ public:
   // returns 15 because { 10, 11, 12, 13, 14, 15 } is the longest sequence.
   virtual bool select
   (size_t& index, const unsigned char* bitfield, size_t nbits) const;
-
-  virtual void addPieceStats(size_t index);
-
-  virtual void addPieceStats(const unsigned char* bitfield,
-			     size_t bitfieldLength);
-  
-  virtual void subtractPieceStats(const unsigned char* bitfield,
-				  size_t bitfieldLength);
-
-  virtual void updatePieceStats(const unsigned char* newBitfield,
-				size_t newBitfieldLength,
-				const unsigned char* oldBitfield);
 };
 
 } // namespace aria2

+ 1 - 0
src/Makefile.am

@@ -117,6 +117,7 @@ SRCS =  Socket.h\
 	PieceStorage.h\
 	DefaultPieceStorage.cc DefaultPieceStorage.h\
 	UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h\
+	PieceStatMan.cc PieceStatMan.h\
 	StatCalc.h\
 	ConsoleStatCalc.cc ConsoleStatCalc.h\
 	TransferStat.cc TransferStat.h\

+ 13 - 10
src/Makefile.in

@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.10.2 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -355,8 +355,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	AutoSaveCommand.cc AutoSaveCommand.h PieceStorage.h \
 	DefaultPieceStorage.cc DefaultPieceStorage.h \
 	UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h \
-	StatCalc.h ConsoleStatCalc.cc ConsoleStatCalc.h \
-	TransferStat.cc TransferStat.h Dependency.h \
+	PieceStatMan.cc PieceStatMan.h StatCalc.h ConsoleStatCalc.cc \
+	ConsoleStatCalc.h TransferStat.cc TransferStat.h Dependency.h \
 	BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \
 	DefaultBtProgressInfoFile.h NullProgressInfoFile.h \
 	FileAllocationIterator.h SingleFileAllocationIterator.cc \
@@ -768,8 +768,9 @@ am__objects_23 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	PStringSegment.$(OBJEXT) PStringBuildVisitor.$(OBJEXT) \
 	ParameterizedStringParser.$(OBJEXT) TimeBasedCommand.$(OBJEXT) \
 	AutoSaveCommand.$(OBJEXT) DefaultPieceStorage.$(OBJEXT) \
-	UnknownLengthPieceStorage.$(OBJEXT) ConsoleStatCalc.$(OBJEXT) \
-	TransferStat.$(OBJEXT) DefaultBtProgressInfoFile.$(OBJEXT) \
+	UnknownLengthPieceStorage.$(OBJEXT) PieceStatMan.$(OBJEXT) \
+	ConsoleStatCalc.$(OBJEXT) TransferStat.$(OBJEXT) \
+	DefaultBtProgressInfoFile.$(OBJEXT) \
 	SingleFileAllocationIterator.$(OBJEXT) \
 	ContentTypeRequestGroupCriteria.$(OBJEXT) \
 	DownloadHandler.$(OBJEXT) DownloadHandlerConstants.$(OBJEXT) \
@@ -1008,6 +1009,7 @@ target_alias = @target_alias@
 target_cpu = @target_cpu@
 target_os = @target_os@
 target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 aria2c_SOURCES = main.cc\
@@ -1084,8 +1086,8 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
 	AutoSaveCommand.cc AutoSaveCommand.h PieceStorage.h \
 	DefaultPieceStorage.cc DefaultPieceStorage.h \
 	UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h \
-	StatCalc.h ConsoleStatCalc.cc ConsoleStatCalc.h \
-	TransferStat.cc TransferStat.h Dependency.h \
+	PieceStatMan.cc PieceStatMan.h StatCalc.h ConsoleStatCalc.cc \
+	ConsoleStatCalc.h TransferStat.cc TransferStat.h Dependency.h \
 	BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \
 	DefaultBtProgressInfoFile.h NullProgressInfoFile.h \
 	FileAllocationIterator.h SingleFileAllocationIterator.cc \
@@ -1169,8 +1171,8 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	    *$$dep*) \
-	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
-		&& exit 0; \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
 	      exit 1;; \
 	  esac; \
 	done; \
@@ -1466,6 +1468,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Piece.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceHashCheckIntegrityEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceHashMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceStatMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PiecedSegment.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PiecesMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Platform.Po@am__quote@
@@ -1568,7 +1571,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	unique=`for i in $$list; do \
 	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
 	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
 	mkid -fID $$unique
 tags: TAGS

+ 1 - 15
src/PieceSelector.h

@@ -37,9 +37,7 @@
 
 #include "common.h"
 
-#include <deque>
-
-#include "SharedHandle.h"
+#include <cstdlib>
 
 namespace aria2 {
 
@@ -49,18 +47,6 @@ public:
 
   virtual bool select
   (size_t& index, const unsigned char* bitfield, size_t nbits) const = 0;
-
-  virtual void addPieceStats(size_t index) = 0;
-
-  virtual void addPieceStats(const unsigned char* bitfield,
-			     size_t bitfieldLength) = 0;
-  
-  virtual void subtractPieceStats(const unsigned char* bitfield,
-				  size_t bitfieldLength) = 0;
-
-  virtual void updatePieceStats(const unsigned char* newBitfield,
-				size_t newBitfieldLength,
-				const unsigned char* oldBitfield) = 0;
 };
 
 } // namespace aria2

+ 218 - 0
src/PieceStatMan.cc

@@ -0,0 +1,218 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "PieceStatMan.h"
+
+#include <algorithm>
+
+#include "SimpleRandomizer.h"
+
+namespace aria2 {
+
+PieceStat::PieceStat(size_t index):_order(0), _index(index), _count(0) {}
+
+bool PieceStat::operator<(const PieceStat& pieceStat) const
+{
+  if(_count == pieceStat._count) {
+    return _order < pieceStat._order;
+  } else {
+    return _count < pieceStat._count;
+  }
+}
+
+void PieceStat::addCount()
+{
+  if(_count < SIZE_MAX) {
+    ++_count;
+  }
+}
+
+void PieceStat::subCount()
+{
+  if(_count > 0) {
+    --_count;
+  }
+}
+
+size_t PieceStat::getIndex() const
+{
+  return _index;
+}
+
+size_t PieceStat::getCount() const
+{
+  return _count;
+}
+
+void PieceStat::setOrder(size_t order)
+{
+  _order = order;
+}
+
+size_t PieceStat::getOrder() const
+{
+  return _order;
+}
+
+class GenPieceStat {
+private:
+  size_t _index;
+public:
+  GenPieceStat():_index(0) {}
+
+  SharedHandle<PieceStat> operator()()
+  {
+    return SharedHandle<PieceStat>(new PieceStat(_index++));
+  }
+};
+
+PieceStatMan::PieceStatMan(size_t pieceNum, bool randomShuffle):
+  _pieceStats(pieceNum),
+  _sortedPieceStatIndexes(pieceNum)
+{
+  std::generate(_pieceStats.begin(), _pieceStats.end(), GenPieceStat());
+  std::vector<SharedHandle<PieceStat> > sortedPieceStats(_pieceStats);
+  // we need some randomness in ordering.
+  if(randomShuffle) {
+    std::random_shuffle(sortedPieceStats.begin(), sortedPieceStats.end(),
+			*(SimpleRandomizer::getInstance().get()));
+  }
+  {
+    size_t order = 0;
+    for(std::vector<SharedHandle<PieceStat> >::iterator i =
+	  sortedPieceStats.begin(); i != sortedPieceStats.end(); ++i) {
+      _sortedPieceStatIndexes[order] = (*i)->getIndex();
+      (*i)->setOrder(order++);
+    }
+  }  
+}
+
+class PieceStatRarer {
+private:
+  const std::vector<SharedHandle<PieceStat> >& _pieceStats;
+public:
+  PieceStatRarer(const std::vector<SharedHandle<PieceStat> >& ps):
+    _pieceStats(ps) {}
+
+  bool operator()(size_t lhs, size_t rhs) const
+  {
+    return _pieceStats[lhs] < _pieceStats[rhs];
+  }
+};
+
+void PieceStatMan::addPieceStats(const unsigned char* bitfield,
+					size_t bitfieldLength)
+{
+  size_t index = 0;
+  for(size_t bi = 0; bi < bitfieldLength; ++bi) {
+    
+    for(size_t i = 0; i < 8; ++i, ++index) {
+      unsigned char mask = 128 >> i;
+      if(bitfield[bi]&mask) {
+	_pieceStats[index]->addCount();
+      }
+    }
+
+  }
+  std::sort(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
+	    PieceStatRarer(_pieceStats));
+}
+
+void PieceStatMan::subtractPieceStats(const unsigned char* bitfield,
+					     size_t bitfieldLength)
+{
+  size_t index = 0;
+  for(size_t bi = 0; bi < bitfieldLength; ++bi) {
+    
+    for(size_t i = 0; i < 8; ++i, ++index) {
+      unsigned char mask = 128 >> i;
+      if(bitfield[bi]&mask) {
+	_pieceStats[index]->subCount();
+      }
+    }
+
+  }
+  std::sort(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
+	    PieceStatRarer(_pieceStats));
+}
+
+void PieceStatMan::updatePieceStats(const unsigned char* newBitfield,
+					   size_t newBitfieldLength,
+					   const unsigned char* oldBitfield)
+{
+  size_t index = 0;
+  for(size_t bi = 0; bi < newBitfieldLength; ++bi) {
+    
+    for(size_t i = 0; i < 8; ++i, ++index) {
+      unsigned char mask = 128 >> i;
+      if((newBitfield[bi]&mask) && !(oldBitfield[bi]&mask)) {
+	_pieceStats[index]->addCount();
+      } else if(!(newBitfield[bi]&mask) && (oldBitfield[bi]&mask)) {
+	_pieceStats[index]->subCount();
+      }
+    }
+
+  }
+  std::sort(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
+	    PieceStatRarer(_pieceStats));
+}
+
+void PieceStatMan::addPieceStats(size_t index)
+{
+  std::vector<size_t>::iterator cur =
+    std::lower_bound(_sortedPieceStatIndexes.begin(),
+		     _sortedPieceStatIndexes.end(),
+		     index, PieceStatRarer(_pieceStats));
+
+  _pieceStats[index]->addCount();
+
+  std::vector<size_t>::iterator to =
+    std::upper_bound(cur+1, _sortedPieceStatIndexes.end(),
+		     index, PieceStatRarer(_pieceStats));
+  
+  std::rotate(cur, cur+1, to);
+}
+
+const std::vector<size_t>& PieceStatMan::getRarerPieceIndexes() const
+{
+  return _sortedPieceStatIndexes;
+}
+
+const std::vector<SharedHandle<PieceStat> >&
+PieceStatMan::getPieceStats() const
+{
+  return _pieceStats;
+}
+
+} // namespace aria2

+ 93 - 0
src/PieceStatMan.h

@@ -0,0 +1,93 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_PIECE_STAT_MAN_H_
+#define _D_PIECE_STAT_MAN_H_
+
+#include "common.h"
+
+#include <vector>
+
+#include "SharedHandle.h"
+
+namespace aria2 {
+
+class PieceStat {
+private:
+  size_t _order;
+  size_t _index;
+  size_t _count;
+public:
+  PieceStat(size_t index);
+
+  bool operator<(const PieceStat& pieceStat) const;
+
+  void addCount();
+  void subCount();
+
+  size_t getOrder() const;
+  void setOrder(size_t order);
+  size_t getIndex() const;
+  size_t getCount() const;
+};
+
+class PieceStatMan {
+private:
+  std::vector<SharedHandle<PieceStat> > _pieceStats;
+
+  std::vector<size_t> _sortedPieceStatIndexes;
+public:
+  PieceStatMan(size_t pieceNum, bool randomShuffle);
+
+  void addPieceStats(size_t index);
+
+  void addPieceStats(const unsigned char* bitfield,
+		     size_t bitfieldLength);
+  
+  void subtractPieceStats(const unsigned char* bitfield,
+			  size_t bitfieldLength);
+
+  void updatePieceStats(const unsigned char* newBitfield,
+			size_t newBitfieldLength,
+			const unsigned char* oldBitfield);
+
+  // Returns piece index in rarest first order.
+  const std::vector<size_t>& getRarerPieceIndexes() const;
+
+  const std::vector<SharedHandle<PieceStat> >& getPieceStats() const;
+};
+
+} // namespace aria2
+
+#endif // _D_PIECE_STAT_MAN_H_

+ 7 - 178
src/RarestPieceSelector.cc

@@ -37,87 +37,12 @@
 #include <cassert>
 #include <algorithm>
 
-#include "SimpleRandomizer.h"
+#include "PieceStatMan.h"
 
 namespace aria2 {
 
-PieceStat::PieceStat(size_t index):_order(0), _index(index), _count(0) {}
-
-bool PieceStat::operator<(const PieceStat& pieceStat) const
-{
-  if(_count == pieceStat._count) {
-    return _order < pieceStat._order;
-  } else {
-    return _count < pieceStat._count;
-  }
-}
-
-void PieceStat::addCount()
-{
-  if(_count < SIZE_MAX) {
-    ++_count;
-  }
-}
-
-void PieceStat::subCount()
-{
-  if(_count > 0) {
-    --_count;
-  }
-}
-
-size_t PieceStat::getIndex() const
-{
-  return _index;
-}
-
-size_t PieceStat::getCount() const
-{
-  return _count;
-}
-
-void PieceStat::setOrder(size_t order)
-{
-  _order = order;
-}
-
-size_t PieceStat::getOrder() const
-{
-  return _order;
-}
-
-class GenPieceStat {
-private:
-  size_t _index;
-public:
-  GenPieceStat():_index(0) {}
-
-  SharedHandle<PieceStat> operator()()
-  {
-    return SharedHandle<PieceStat>(new PieceStat(_index++));
-  }
-};
-
-RarestPieceSelector::RarestPieceSelector(size_t pieceNum, bool randomShuffle):
-  _pieceStats(pieceNum),
-  _sortedPieceStatIndexes(pieceNum)
-{
-  std::generate(_pieceStats.begin(), _pieceStats.end(), GenPieceStat());
-  std::vector<SharedHandle<PieceStat> > sortedPieceStats(_pieceStats);
-  // we need some randomness in ordering.
-  if(randomShuffle) {
-    std::random_shuffle(sortedPieceStats.begin(), sortedPieceStats.end(),
-			*(SimpleRandomizer::getInstance().get()));
-  }
-  {
-    size_t order = 0;
-    for(std::vector<SharedHandle<PieceStat> >::iterator i =
-	  sortedPieceStats.begin(); i != sortedPieceStats.end(); ++i) {
-      _sortedPieceStatIndexes[order] = (*i)->getIndex();
-      (*i)->setOrder(order++);
-    }
-  }  
-}
+RarestPieceSelector::RarestPieceSelector
+(const SharedHandle<PieceStatMan>& pieceStatMan):_pieceStatMan(pieceStatMan) {}
 
 class FindRarestPiece
 {
@@ -139,10 +64,12 @@ public:
 bool RarestPieceSelector::select
 (size_t& index, const unsigned char* bitfield, size_t nbits) const
 {
+  const std::vector<size_t>& pieceIndexes =
+    _pieceStatMan->getRarerPieceIndexes();
   std::vector<size_t>::const_iterator i =
-    std::find_if(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
+    std::find_if(pieceIndexes.begin(), pieceIndexes.end(),
 		 FindRarestPiece(bitfield, nbits));
-  if(i == _sortedPieceStatIndexes.end()) {
+  if(i == pieceIndexes.end()) {
     return false;
   } else {
     index = *i;
@@ -150,102 +77,4 @@ bool RarestPieceSelector::select
   }
 }
 
-class PieceStatRarer {
-private:
-  const std::vector<SharedHandle<PieceStat> >& _pieceStats;
-public:
-  PieceStatRarer(const std::vector<SharedHandle<PieceStat> >& ps):
-    _pieceStats(ps) {}
-
-  bool operator()(size_t lhs, size_t rhs) const
-  {
-    return _pieceStats[lhs] < _pieceStats[rhs];
-  }
-};
-
-void RarestPieceSelector::addPieceStats(const unsigned char* bitfield,
-					size_t bitfieldLength)
-{
-  size_t index = 0;
-  for(size_t bi = 0; bi < bitfieldLength; ++bi) {
-    
-    for(size_t i = 0; i < 8; ++i, ++index) {
-      unsigned char mask = 128 >> i;
-      if(bitfield[bi]&mask) {
-	_pieceStats[index]->addCount();
-      }
-    }
-
-  }
-  std::sort(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
-	    PieceStatRarer(_pieceStats));
-}
-
-void RarestPieceSelector::subtractPieceStats(const unsigned char* bitfield,
-					     size_t bitfieldLength)
-{
-  size_t index = 0;
-  for(size_t bi = 0; bi < bitfieldLength; ++bi) {
-    
-    for(size_t i = 0; i < 8; ++i, ++index) {
-      unsigned char mask = 128 >> i;
-      if(bitfield[bi]&mask) {
-	_pieceStats[index]->subCount();
-      }
-    }
-
-  }
-  std::sort(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
-	    PieceStatRarer(_pieceStats));
-}
-
-void RarestPieceSelector::updatePieceStats(const unsigned char* newBitfield,
-					   size_t newBitfieldLength,
-					   const unsigned char* oldBitfield)
-{
-  size_t index = 0;
-  for(size_t bi = 0; bi < newBitfieldLength; ++bi) {
-    
-    for(size_t i = 0; i < 8; ++i, ++index) {
-      unsigned char mask = 128 >> i;
-      if((newBitfield[bi]&mask) && !(oldBitfield[bi]&mask)) {
-	_pieceStats[index]->addCount();
-      } else if(!(newBitfield[bi]&mask) && (oldBitfield[bi]&mask)) {
-	_pieceStats[index]->subCount();
-      }
-    }
-
-  }
-  std::sort(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
-	    PieceStatRarer(_pieceStats));
-}
-
-void RarestPieceSelector::addPieceStats(size_t index)
-{
-  std::vector<size_t>::iterator cur =
-    std::lower_bound(_sortedPieceStatIndexes.begin(),
-		     _sortedPieceStatIndexes.end(),
-		     index, PieceStatRarer(_pieceStats));
-
-  _pieceStats[index]->addCount();
-
-  std::vector<size_t>::iterator to =
-    std::upper_bound(cur+1, _sortedPieceStatIndexes.end(),
-		     index, PieceStatRarer(_pieceStats));
-  
-  std::rotate(cur, cur+1, to);
-}
-
-const std::vector<size_t>&
-RarestPieceSelector::getSortedPieceStatIndexes() const
-{
-  return _sortedPieceStatIndexes;
-}
-
-const std::vector<SharedHandle<PieceStat> >&
-RarestPieceSelector::getPieceStats() const
-{
-  return _pieceStats;
-}
-
 } // namespace aria2

+ 4 - 40
src/RarestPieceSelector.h

@@ -36,56 +36,20 @@
 #define _D_RAREST_PIECE_SELECTOR_H_
 
 #include "PieceSelector.h"
-
-#include <vector>
+#include "SharedHandle.h"
 
 namespace aria2 {
 
-class PieceStat {
-private:
-  size_t _order;
-  size_t _index;
-  size_t _count;
-public:
-  PieceStat(size_t index);
-
-  bool operator<(const PieceStat& pieceStat) const;
-
-  void addCount();
-  void subCount();
-
-  size_t getOrder() const;
-  void setOrder(size_t order);
-  size_t getIndex() const;
-  size_t getCount() const;
-};
+class PieceStatMan;
 
 class RarestPieceSelector:public PieceSelector {
 private:
-  std::vector<SharedHandle<PieceStat> > _pieceStats;
-
-  std::vector<size_t> _sortedPieceStatIndexes;
+  SharedHandle<PieceStatMan> _pieceStatMan;
 public:
-  RarestPieceSelector(size_t pieceNum, bool randomShuffle);
+  RarestPieceSelector(const SharedHandle<PieceStatMan>& pieceStatMan);
 
   virtual bool select
   (size_t& index, const unsigned char* bitfield, size_t nbits) const;
-
-  virtual void addPieceStats(size_t index);
-
-  virtual void addPieceStats(const unsigned char* bitfield,
-			     size_t bitfieldLength);
-  
-  virtual void subtractPieceStats(const unsigned char* bitfield,
-				  size_t bitfieldLength);
-
-  virtual void updatePieceStats(const unsigned char* newBitfield,
-				size_t newBitfieldLength,
-				const unsigned char* oldBitfield);
-
-  const std::vector<size_t>& getSortedPieceStatIndexes() const;
-
-  const std::vector<SharedHandle<PieceStat> >& getPieceStats() const;
 };
 
 } // namespace aria2

+ 4 - 4
src/RequestGroup.cc

@@ -396,17 +396,17 @@ void RequestGroup::initPieceStorage()
 {
   if(_downloadContext->knowsTotalLength()) {
 #ifdef ENABLE_BITTORRENT
-    SharedHandle<DefaultPieceStorage> ps;
-    SharedHandle<PieceSelector> selector;
+    SharedHandle<DefaultPieceStorage> ps
+      (new DefaultPieceStorage(_downloadContext, _option));
     // Use LongestSequencePieceSelector when HTTP/FTP/BitTorrent integrated
     // downloads. Currently multi-file integrated download is not supported.
     if(!_uris.empty() &&
        _downloadContext->getFileEntries().size() == 1 &&
        !dynamic_pointer_cast<BtContext>(_downloadContext).isNull()) {
       _logger->debug("Using LongestSequencePieceSelector");
-      selector.reset(new LongestSequencePieceSelector());
+      ps->setPieceSelector
+	(SharedHandle<PieceSelector>(new LongestSequencePieceSelector()));
     }
-    ps.reset(new DefaultPieceStorage(_downloadContext, _option, selector));
 #else // !ENABLE_BITTORRENT
     SharedHandle<DefaultPieceStorage> ps
       (new DefaultPieceStorage(_downloadContext, _option));

+ 13 - 7
test/DefaultPieceStorageTest.cc

@@ -13,6 +13,7 @@
 #include "FileEntry.h"
 #include "MockBtContext.h"
 #include "RarestPieceSelector.h"
+#include "InOrderPieceSelector.h"
 
 namespace aria2 {
 
@@ -37,7 +38,7 @@ private:
   SharedHandle<BtContext> btContext;
   SharedHandle<Peer> peer;
   Option* option;
-  SharedHandle<RarestPieceSelector> _selector;
+  SharedHandle<PieceSelector> _pieceSelector;
 public:
   DefaultPieceStorageTest() {
     SharedHandle<FixedNumberRandomizer> randomizer
@@ -53,7 +54,7 @@ public:
     peer->allocateSessionResource(btContext->getPieceLength(),
 				  btContext->getTotalLength());
     option = new Option();
-    _selector.reset(new RarestPieceSelector(btContext->getNumPieces(), false));
+    _pieceSelector.reset(new InOrderPieceSelector());
   }
 
   void tearDown()
@@ -87,7 +88,8 @@ void DefaultPieceStorageTest::testGetTotalLength() {
 }
 
 void DefaultPieceStorageTest::testGetMissingPiece() {
-  DefaultPieceStorage pss(btContext, option, _selector);
+  DefaultPieceStorage pss(btContext, option);
+  pss.setPieceSelector(_pieceSelector);
   pss.setEndGamePieceNum(0);
 
   peer->setAllBitfield();
@@ -107,7 +109,8 @@ void DefaultPieceStorageTest::testGetMissingPiece() {
 
 void DefaultPieceStorageTest::testGetMissingPiece_excludedIndexes()
 {
-  DefaultPieceStorage pss(btContext, option, _selector);
+  DefaultPieceStorage pss(btContext, option);
+  pss.setPieceSelector(_pieceSelector);
   pss.setEndGamePieceNum(0);
 
   peer->setAllBitfield();
@@ -128,7 +131,8 @@ void DefaultPieceStorageTest::testGetMissingPiece_excludedIndexes()
 }
 
 void DefaultPieceStorageTest::testGetMissingFastPiece() {
-  DefaultPieceStorage pss(btContext, option, _selector);
+  DefaultPieceStorage pss(btContext, option);
+  pss.setPieceSelector(_pieceSelector);
   pss.setEndGamePieceNum(0);
 
   peer->setAllBitfield();
@@ -144,7 +148,8 @@ void DefaultPieceStorageTest::testGetMissingFastPiece() {
 
 void DefaultPieceStorageTest::testGetMissingFastPiece_excludedIndexes()
 {
-  DefaultPieceStorage pss(btContext, option, _selector);
+  DefaultPieceStorage pss(btContext, option);
+  pss.setPieceSelector(_pieceSelector);
   pss.setEndGamePieceNum(0);
 
   peer->setAllBitfield();
@@ -173,7 +178,8 @@ void DefaultPieceStorageTest::testHasMissingPiece() {
 }
 
 void DefaultPieceStorageTest::testCompletePiece() {
-  DefaultPieceStorage pss(btContext, option, _selector);
+  DefaultPieceStorage pss(btContext, option);
+  pss.setPieceSelector(_pieceSelector);
   pss.setEndGamePieceNum(0);
 
   peer->setAllBitfield();

+ 26 - 0
test/InOrderPieceSelector.h

@@ -0,0 +1,26 @@
+#ifndef _D_IN_ORDER_PIECE_SELECTOR_H_
+#define _D_IN_ORDER_PIECE_SELECTOR_H_
+
+#include "PieceSelector.h"
+#include "bitfield.h"
+
+namespace aria2 {
+
+class InOrderPieceSelector:public PieceSelector {
+public:
+  virtual bool select
+  (size_t& index, const unsigned char* bitfield, size_t nbits) const
+  {
+    for(size_t i = 0; i < nbits; ++i) {
+      if(bitfield::test(bitfield, nbits, i)) {
+	index = i;
+	return true;
+      }
+    }
+    return false;
+  }
+};
+
+} // namespace aria2
+
+#endif // _D_IN_ORDER_PIECE_SELECTOR_H_

+ 2 - 0
test/Makefile.am

@@ -66,6 +66,8 @@ aria2c_SOURCES = AllTest.cc\
 	BencodeTest.cc\
 	SequentialPickerTest.cc\
 	RarestPieceSelectorTest.cc\
+	PieceStatManTest.cc\
+	InOrderPieceSelector.h\
 	LongestSequencePieceSelectorTest.cc\
 	a2algoTest.cc\
 	bitfieldTest.cc\

+ 30 - 13
test/Makefile.in

@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.10.2 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -193,6 +193,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
 	TimeTest.cc FtpConnectionTest.cc OptionParserTest.cc \
 	SimpleDNSCacheTest.cc DownloadHelperTest.cc BencodeTest.cc \
 	SequentialPickerTest.cc RarestPieceSelectorTest.cc \
+	PieceStatManTest.cc InOrderPieceSelector.h \
 	LongestSequencePieceSelectorTest.cc a2algoTest.cc \
 	bitfieldTest.cc BDETest.cc FallocFileAllocationIteratorTest.cc \
 	GZipDecoderTest.cc Sqlite3MozCookieParserTest.cc \
@@ -363,7 +364,7 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
 	OptionParserTest.$(OBJEXT) SimpleDNSCacheTest.$(OBJEXT) \
 	DownloadHelperTest.$(OBJEXT) BencodeTest.$(OBJEXT) \
 	SequentialPickerTest.$(OBJEXT) \
-	RarestPieceSelectorTest.$(OBJEXT) \
+	RarestPieceSelectorTest.$(OBJEXT) PieceStatManTest.$(OBJEXT) \
 	LongestSequencePieceSelectorTest.$(OBJEXT) \
 	a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) BDETest.$(OBJEXT) \
 	$(am__objects_1) $(am__objects_2) $(am__objects_3) \
@@ -561,6 +562,7 @@ target_alias = @target_alias@
 target_cpu = @target_cpu@
 target_os = @target_os@
 target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
@@ -591,6 +593,7 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
 	TimeTest.cc FtpConnectionTest.cc OptionParserTest.cc \
 	SimpleDNSCacheTest.cc DownloadHelperTest.cc BencodeTest.cc \
 	SequentialPickerTest.cc RarestPieceSelectorTest.cc \
+	PieceStatManTest.cc InOrderPieceSelector.h \
 	LongestSequencePieceSelectorTest.cc a2algoTest.cc \
 	bitfieldTest.cc BDETest.cc $(am__append_1) $(am__append_2) \
 	$(am__append_3) $(am__append_4) $(am__append_5) \
@@ -646,8 +649,8 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	    *$$dep*) \
-	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
-		&& exit 0; \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
 	      exit 1;; \
 	  esac; \
 	done; \
@@ -799,6 +802,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtilTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerSessionResourceTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceStatManTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProtocolDetectorTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarestPieceSelectorTest.Po@am__quote@
@@ -853,7 +857,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	unique=`for i in $$list; do \
 	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
 	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
 	mkid -fID $$unique
 tags: TAGS
@@ -896,7 +900,7 @@ distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 check-TESTS: $(TESTS)
-	@failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[	 ]'; \
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
 	srcdir=$(srcdir); export srcdir; \
 	list=' $(TESTS) '; \
 	if test -n "$$list"; then \
@@ -907,7 +911,7 @@ check-TESTS: $(TESTS)
 	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
 	      all=`expr $$all + 1`; \
 	      case " $(XFAIL_TESTS) " in \
-	      *$$ws$$tst$$ws*) \
+	      *[\ \	]$$tst[\ \	]*) \
 		xpass=`expr $$xpass + 1`; \
 		failed=`expr $$failed + 1`; \
 		echo "XPASS: $$tst"; \
@@ -919,7 +923,7 @@ check-TESTS: $(TESTS)
 	    elif test $$? -ne 77; then \
 	      all=`expr $$all + 1`; \
 	      case " $(XFAIL_TESTS) " in \
-	      *$$ws$$tst$$ws*) \
+	      *[\ \	]$$tst[\ \	]*) \
 		xfail=`expr $$xfail + 1`; \
 		echo "XFAIL: $$tst"; \
 	      ;; \
@@ -933,23 +937,36 @@ check-TESTS: $(TESTS)
 	      echo "SKIP: $$tst"; \
 	    fi; \
 	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
 	  if test "$$failed" -eq 0; then \
 	    if test "$$xfail" -eq 0; then \
-	      banner="All $$all tests passed"; \
+	      banner="$$All$$all $$tests passed"; \
 	    else \
-	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
 	    fi; \
 	  else \
 	    if test "$$xpass" -eq 0; then \
-	      banner="$$failed of $$all tests failed"; \
+	      banner="$$failed of $$all $$tests failed"; \
 	    else \
-	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
 	    fi; \
 	  fi; \
 	  dashes="$$banner"; \
 	  skipped=""; \
 	  if test "$$skip" -ne 0; then \
-	    skipped="($$skip tests were not run)"; \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
 	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
 	      dashes="$$skipped"; \
 	  fi; \

+ 194 - 0
test/PieceStatManTest.cc

@@ -0,0 +1,194 @@
+#include "PieceStatMan.h"
+
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace aria2 {
+
+class PieceStatManTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(PieceStatManTest);
+  CPPUNIT_TEST(testAddPieceStats_index);
+  CPPUNIT_TEST(testAddPieceStats_bitfield);
+  CPPUNIT_TEST(testUpdatePieceStats);
+  CPPUNIT_TEST(testSubtractPieceStats);
+  CPPUNIT_TEST_SUITE_END();
+public:
+  void setUp() {}
+
+  void tearDown() {}
+
+  void testAddPieceStats_index();
+  void testAddPieceStats_bitfield();
+  void testUpdatePieceStats();
+  void testSubtractPieceStats();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(PieceStatManTest);
+
+void PieceStatManTest::testAddPieceStats_index()
+{
+  PieceStatMan pieceStatMan(10, false);
+  pieceStatMan.addPieceStats(1);
+  {
+    size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
+    size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+    
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
+    
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+
+  pieceStatMan.addPieceStats(1);
+
+  {
+    size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
+    size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
+
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+
+  pieceStatMan.addPieceStats(3);
+  pieceStatMan.addPieceStats(9);
+  pieceStatMan.addPieceStats(3);
+  pieceStatMan.addPieceStats(0);
+
+  {
+    size_t indexes[] = { 2, 4, 5, 6, 7, 8, 0, 9, 1, 3 };
+    size_t counts[] = {  0, 0, 0, 0, 0, 0, 1, 1, 2, 2 };
+
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+
+}
+
+void PieceStatManTest::testAddPieceStats_bitfield()
+{
+  PieceStatMan pieceStatMan(10, false);
+  const unsigned char bitfield[] = { 0xaa, 0x80 };
+  pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
+  {
+    size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 };
+    size_t counts[] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };
+
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
+    
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+
+  pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
+
+  {
+    size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 };
+    size_t counts[] = { 0, 0, 0, 0, 0, 2, 2, 2, 2, 2 };
+
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
+    
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+}
+
+void PieceStatManTest::testUpdatePieceStats()
+{
+  PieceStatMan pieceStatMan(10, false);
+
+  const unsigned char bitfield[] = { 0xff, 0xc0 };
+  pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
+
+  const unsigned char oldBitfield[] = { 0xf0, 0x00 };
+  const unsigned char newBitfield[] = { 0x1f, 0x00 };
+
+  pieceStatMan.updatePieceStats(newBitfield, sizeof(newBitfield), oldBitfield);
+  {
+    // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+    // bf : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+    // old: 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
+    // new: 0, 0, 0, 1, 1, 1, 1, 1, 0, 0
+    // ---------------------------------
+    // res: 0, 0, 0, 1, 2, 2, 2, 2, 1, 1
+
+    size_t indexes[] = { 0, 1, 2, 3, 8, 9, 4, 5, 6, 7 };
+    size_t counts[] =  { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2 };
+
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
+    
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+}
+
+void PieceStatManTest::testSubtractPieceStats()
+{
+  PieceStatMan pieceStatMan(10, false);
+
+  const unsigned char bitfield[] = { 0xf0, 0x00 };
+  pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
+
+  const unsigned char newBitfield[] = { 0x3f, 0x00 };
+
+  pieceStatMan.subtractPieceStats(newBitfield, sizeof(newBitfield));
+  {
+    // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+    // bf : 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
+    // new: 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
+    // ---------------------------------
+    // res: 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
+
+    size_t indexes[] = { 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 };
+    size_t counts[] =  { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+
+    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
+    const std::vector<SharedHandle<PieceStat> >& stats
+      (pieceStatMan.getPieceStats());
+
+    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
+    
+    for(size_t i = 0; i < 10; ++i) {
+      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
+      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+    }
+  }
+}
+
+} // namespace aria2

+ 5 - 169
test/RarestPieceSelectorTest.cc

@@ -1,23 +1,15 @@
 #include "RarestPieceSelector.h"
 
-#include <cstring>
-#include <iostream>
-
 #include <cppunit/extensions/HelperMacros.h>
 
-#include "Exception.h"
-#include "Util.h"
 #include "BitfieldMan.h"
+#include "PieceStatMan.h"
 
 namespace aria2 {
 
 class RarestPieceSelectorTest:public CppUnit::TestFixture {
 
   CPPUNIT_TEST_SUITE(RarestPieceSelectorTest);
-  CPPUNIT_TEST(testAddPieceStats_index);
-  CPPUNIT_TEST(testAddPieceStats_bitfield);
-  CPPUNIT_TEST(testUpdatePieceStats);
-  CPPUNIT_TEST(testSubtractPieceStats);
   CPPUNIT_TEST(testSelect);
   CPPUNIT_TEST_SUITE_END();
 public:
@@ -35,177 +27,21 @@ public:
 
 CPPUNIT_TEST_SUITE_REGISTRATION(RarestPieceSelectorTest);
 
-void RarestPieceSelectorTest::testAddPieceStats_index()
-{
-  RarestPieceSelector selector(10, false);
-  selector.addPieceStats(1);
-  {
-    size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-    
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-
-  selector.addPieceStats(1);
-
-  {
-    size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
-
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-
-  selector.addPieceStats(3);
-  selector.addPieceStats(9);
-  selector.addPieceStats(3);
-  selector.addPieceStats(0);
-
-  {
-    size_t indexes[] = { 2, 4, 5, 6, 7, 8, 0, 9, 1, 3 };
-    size_t counts[] = {  0, 0, 0, 0, 0, 0, 1, 1, 2, 2 };
-
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-
-}
-
-void RarestPieceSelectorTest::testAddPieceStats_bitfield()
-{
-  RarestPieceSelector selector(10, false);
-  const unsigned char bitfield[] = { 0xaa, 0x80 };
-  selector.addPieceStats(bitfield, sizeof(bitfield));
-  {
-    size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };
-
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-
-  selector.addPieceStats(bitfield, sizeof(bitfield));
-
-  {
-    size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 2, 2, 2, 2, 2 };
-
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-}
-
-void RarestPieceSelectorTest::testUpdatePieceStats()
-{
-  RarestPieceSelector selector(10, false);
-
-  const unsigned char bitfield[] = { 0xff, 0xc0 };
-  selector.addPieceStats(bitfield, sizeof(bitfield));
-
-  const unsigned char oldBitfield[] = { 0xf0, 0x00 };
-  const unsigned char newBitfield[] = { 0x1f, 0x00 };
-
-  selector.updatePieceStats(newBitfield, sizeof(newBitfield), oldBitfield);
-  {
-    // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
-    // bf : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
-    // old: 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
-    // new: 0, 0, 0, 1, 1, 1, 1, 1, 0, 0
-    // ---------------------------------
-    // res: 0, 0, 0, 1, 2, 2, 2, 2, 1, 1
-
-    size_t indexes[] = { 0, 1, 2, 3, 8, 9, 4, 5, 6, 7 };
-    size_t counts[] =  { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2 };
-
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-}
-
-void RarestPieceSelectorTest::testSubtractPieceStats()
-{
-  RarestPieceSelector selector(10, false);
-
-  const unsigned char bitfield[] = { 0xf0, 0x00 };
-  selector.addPieceStats(bitfield, sizeof(bitfield));
-
-  const unsigned char newBitfield[] = { 0x3f, 0x00 };
-
-  selector.subtractPieceStats(newBitfield, sizeof(newBitfield));
-  {
-    // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
-    // bf : 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
-    // new: 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
-    // ---------------------------------
-    // res: 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
-
-    size_t indexes[] = { 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 };
-    size_t counts[] =  { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
-
-    const std::vector<size_t>& statsidx(selector.getSortedPieceStatIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats(selector.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
-    for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
-    }
-  }
-}
-
 void RarestPieceSelectorTest::testSelect()
 {
-  RarestPieceSelector selector(10, false);
+  SharedHandle<PieceStatMan> pieceStatMan(new PieceStatMan(10, false));
+  RarestPieceSelector selector(pieceStatMan);
   BitfieldMan bf(1024, 10*1024);
   bf.setBitRange(0, 2);
   size_t index;
 
-  selector.addPieceStats(0);
+  pieceStatMan->addPieceStats(0);
 
   CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(),
 				 bf.countBlock()));
   CPPUNIT_ASSERT_EQUAL((size_t)1, index);
 
-  selector.addPieceStats(1);
+  pieceStatMan->addPieceStats(1);
 
   CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(),
 				 bf.countBlock()));