Selaa lähdekoodia

2007-02-06 Tatsuhiro Tsujikawa <tujikawa dot rednoah dot com>

	To fix the bug that causes crash on Max OS X:
	
	* src/SimpleRandomizer.h
	(getInstance): Create new instance if the static variable is 
null.
	* src/SimpleRandomizer.cc
	(randomizer): Initialized to 0.
	* src/BitfieldManFactory.h
	(getNewFactory): Removed the call to setRandomizer().
	
	To fix the miscalculation of the range of checksum:
	
	* src/BitfieldMan.h
	(isBitSetOffsetRange): New function.
	* src/BitfieldMan.cc
	(isBitSetOffsetRange): New function.
	* src/SegmentMan.cc
	(tryChunkChecksumValidation): Use 
BitfieldMan::isBitSetOffsetRange().
	Use bitfield->getBlockLength() instead of segment.segmentLength.
Tatsuhiro Tsujikawa 18 vuotta sitten
vanhempi
commit
5b2f8f036e

+ 21 - 0
ChangeLog

@@ -1,3 +1,24 @@
+2007-02-06  Tatsuhiro Tsujikawa  <tujikawa dot rednoah dot com>
+
+	To fix the bug that causes crash on Max OS X:
+	
+	* src/SimpleRandomizer.h
+	(getInstance): Create new instance if the static variable is null.
+	* src/SimpleRandomizer.cc
+	(randomizer): Initialized to 0.
+	* src/BitfieldManFactory.h
+	(getNewFactory): Removed the call to setRandomizer().
+	
+	To fix the miscalculation of the range of checksum:
+	
+	* src/BitfieldMan.h
+	(isBitSetOffsetRange): New function.
+	* src/BitfieldMan.cc
+	(isBitSetOffsetRange): New function.
+	* src/SegmentMan.cc
+	(tryChunkChecksumValidation): Use BitfieldMan::isBitSetOffsetRange().
+	Use bitfield->getBlockLength() instead of segment.segmentLength.
+	
 2007-02-03  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	To lower CPU usage in BitTorrent download when --max-upload-limit

+ 21 - 0
src/BitfieldMan.cc

@@ -644,3 +644,24 @@ void BitfieldMan::unsetBitRange(int32_t startIndex, int32_t endIndex)
   }
   updateCache();
 }
+
+bool BitfieldMan::isBitSetOffsetRange(int64_t offset, int64_t length) const
+{
+  if(length <= 0) {
+    return false;
+  }
+  if(totalLength <= offset) {
+    return false;
+  }
+  if(totalLength < offset+length) {
+    length = totalLength-offset;
+  }
+  int32_t startBlock = offset/blockLength;
+  int32_t endBlock = (offset+length-1)/blockLength;
+  for(int32_t i = startBlock; i <= endBlock; i++) {
+    if(!isBitSet(i)) {
+      return false;
+    }
+  }
+  return true;
+}

+ 3 - 0
src/BitfieldMan.h

@@ -254,6 +254,9 @@ public:
   bool isBitRangeSet(int32_t startIndex, int32_t endIndex) const;
 
   void unsetBitRange(int32_t startIndex, int32_t endIndex);
+
+  bool isBitSetOffsetRange(int64_t offset, int64_t length) const;
+
 };
 
 #endif // _D_BITFIELD_MAN_H_

+ 1 - 3
src/BitfieldManFactory.h

@@ -53,9 +53,7 @@ public:
   ~BitfieldManFactory() {}
 
   static BitfieldManFactoryHandle getNewFactory() {
-    BitfieldManFactoryHandle factory =
-      BitfieldManFactoryHandle(new BitfieldManFactory());
-    factory->setRandomizer(defaultRandomizer);
+    BitfieldManFactoryHandle factory = new BitfieldManFactory();
     return factory;
   }
 

+ 5 - 3
src/SegmentMan.cc

@@ -497,10 +497,12 @@ void SegmentMan::tryChunkChecksumValidation(const Segment& segment)
 		   segment.getPosition(),
 		   segment.writtenLength,
 		   chunkHashLength);
-  if(hashStartIndex*chunkHashLength < segment.getPosition() && !bitfield->isBitSet(segment.index-1)) {
+  if(!bitfield->isBitSetOffsetRange((int64_t)hashStartIndex*chunkHashLength,
+				    chunkHashLength)) {
     ++hashStartIndex;
   }
-  if(hashEndIndex*(chunkHashLength+1) > segment.getPosition()+segment.segmentLength && !bitfield->isBitSet(segment.index+1)) {
+  if(!bitfield->isBitSetOffsetRange((int64_t)hashEndIndex*chunkHashLength,
+				    chunkHashLength)) {
     --hashEndIndex;
   }
   logger->debug("hashStartIndex=%d, hashEndIndex=%d",
@@ -515,7 +517,7 @@ void SegmentMan::tryChunkChecksumValidation(const Segment& segment)
   Util::indexRange(startIndex, endIndex,
 		   hashOffset,
 		   (hashEndIndex-hashStartIndex+1)*chunkHashLength,
-		   segment.segmentLength);
+		   bitfield->getBlockLength());
   logger->debug("startIndex=%d, endIndex=%d", startIndex, endIndex);
   if(bitfield->isBitRangeSet(startIndex, endIndex)) {
     for(int32_t index = hashStartIndex; index <= hashEndIndex; ++index) {

+ 1 - 1
src/SimpleRandomizer.cc

@@ -34,4 +34,4 @@
 /* copyright --> */
 #include "SimpleRandomizer.h"
 
-RandomizerHandle SimpleRandomizer::randomizer = RandomizerHandle(new SimpleRandomizer());
+RandomizerHandle SimpleRandomizer::randomizer = 0;

+ 4 - 1
src/SimpleRandomizer.h

@@ -47,11 +47,14 @@ private:
 public:
 
   static RandomizerHandle getInstance() {
+    if(randomizer.isNull()) {
+      randomizer = new SimpleRandomizer();
+    }
     return randomizer;
   }
   
   static void init() {
-    srandom(time(NULL));
+    srandom(time(0));
   }
 
   virtual ~SimpleRandomizer() {}

+ 34 - 0
test/BitfieldManTest.cc

@@ -15,6 +15,7 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testFilter);
   CPPUNIT_TEST(testGetMissingIndex);
   CPPUNIT_TEST(testGetSparceMissingUnusedIndex);
+  CPPUNIT_TEST(testIsBitSetOffsetRange);
   CPPUNIT_TEST_SUITE_END();
 private:
   RandomizerHandle fixedNumberRandomizer;
@@ -35,6 +36,7 @@ public:
   void testFilter();
   void testGetMissingIndex();
   void testGetSparceMissingUnusedIndex();
+  void testIsBitSetOffsetRange();
 };
 
 
@@ -233,3 +235,35 @@ void BitfieldManTest::testGetSparceMissingUnusedIndex() {
   bitfield.setBit(9);
   CPPUNIT_ASSERT_EQUAL(-1, bitfield.getSparseMissingUnusedIndex());
 }
+
+void BitfieldManTest::testIsBitSetOffsetRange()
+{
+  int64_t totalLength = (int64_t)4*1024*1024*1024;
+  int32_t pieceLength = 4*1024*1024;
+  BitfieldMan bitfield(pieceLength, totalLength);
+  bitfield.setAllBit();
+
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(0, 0));
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(0, -1));
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(totalLength, 100));
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(totalLength+1, 100));
+
+  CPPUNIT_ASSERT(bitfield.isBitSetOffsetRange(0, totalLength));
+  CPPUNIT_ASSERT(bitfield.isBitSetOffsetRange(0, totalLength+1));
+
+  bitfield.clearAllBit();
+
+  bitfield.setBit(100);
+  bitfield.setBit(101);
+  
+  CPPUNIT_ASSERT(bitfield.isBitSetOffsetRange(pieceLength*100, pieceLength*2));
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(pieceLength*100-10, pieceLength*2));
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(pieceLength*100, pieceLength*2+1));
+    
+  bitfield.clearAllBit();
+
+  bitfield.setBit(100);
+  bitfield.setBit(102);
+
+  CPPUNIT_ASSERT(!bitfield.isBitSetOffsetRange(pieceLength*100, pieceLength*3));
+}