diff options
-rw-r--r-- | src/mongo/db/structure/record_store_v1_base.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/structure/record_store_v1_simple_test.cpp | 32 |
2 files changed, 40 insertions, 14 deletions
diff --git a/src/mongo/db/structure/record_store_v1_base.cpp b/src/mongo/db/structure/record_store_v1_base.cpp index fa767bfb39d..b3c844687e2 100644 --- a/src/mongo/db/structure/record_store_v1_base.cpp +++ b/src/mongo/db/structure/record_store_v1_base.cpp @@ -568,12 +568,9 @@ namespace mongo { } if ( r->lengthWithHeaders() == - quantizePowerOf2AllocationSpace( r->lengthWithHeaders() - 1 ) ) { + quantizePowerOf2AllocationSpace( r->lengthWithHeaders() ) ) { // Count the number of records having a size consistent with the // quantizePowerOf2AllocationSpace quantization implementation. - // Because of SERVER-8311, power of 2 quantization is not idempotent and - // r->lengthWithHeaders() - 1 must be checked instead of the record - // length itself. ++nPowerOf2QuantizedSize; } @@ -792,13 +789,18 @@ namespace mongo { } int RecordStoreV1Base::quantizePowerOf2AllocationSpace(int allocSize) { - int allocationSize = bucketSizes[ bucket( allocSize ) ]; - if ( allocationSize == bucketSizes[MaxBucket] ) { - // if we get here, it means we're allocating more than 4mb, so round - // to the nearest megabyte - allocationSize = 1 + ( allocSize | ( ( 1 << 20 ) - 1 ) ); + for ( int i = 0; i < MaxBucket; i++ ) { // skips the largest (16MB) bucket + if ( bucketSizes[i] >= allocSize ) { + // Return the size of the first bucket sized >= the requested size. + return bucketSizes[i]; + } } - return allocationSize; + + // if we get here, it means we're allocating more than 4mb, so round up + // to the nearest megabyte >= allocSize + const int MB = 1024*1024; + invariant(allocSize > 4*MB); + return (allocSize + (MB - 1)) & ~(MB - 1); // round up to MB alignment } int RecordStoreV1Base::bucket(int size) { diff --git a/src/mongo/db/structure/record_store_v1_simple_test.cpp b/src/mongo/db/structure/record_store_v1_simple_test.cpp index 79578272876..c515cde0d8d 100644 --- a/src/mongo/db/structure/record_store_v1_simple_test.cpp +++ b/src/mongo/db/structure/record_store_v1_simple_test.cpp @@ -88,6 +88,32 @@ namespace { } /** + * For buckets up to 4MB powerOf2 allocation should round up to next power of 2. It should be + * return the input unmodified if it is already a power of 2. + */ + TEST( SimpleRecordStoreV1, quantizePowerOf2Small ) { + // only tests buckets <= 4MB. Higher buckets quatize to 1MB even with powerOf2 + for (int bucket = 0; bucket < RecordStoreV1Base::MaxBucket; bucket++) { + const int size = RecordStoreV1Base::bucketSizes[bucket]; + const int nextSize = RecordStoreV1Base::bucketSizes[bucket + 1]; + + // size - 1 is quantized to size. + ASSERT_EQUALS( size, + RecordStoreV1Base::quantizePowerOf2AllocationSpace( size - 1 ) ); + + // size is quantized to size. + ASSERT_EQUALS( size, + RecordStoreV1Base::quantizePowerOf2AllocationSpace( size ) ); + + // size + 1 is quantized to nextSize (unless > 4MB which is covered by next test) + if (size < 4*1024*1024) { + ASSERT_EQUALS( nextSize, + RecordStoreV1Base::quantizePowerOf2AllocationSpace( size + 1 ) ); + } + } + } + + /** * Within the largest bucket, quantizePowerOf2AllocationSpace quantizes to the nearest * megabyte boundary. */ @@ -102,10 +128,8 @@ namespace { ASSERT_EQUALS( iSize, RecordStoreV1Base::quantizePowerOf2AllocationSpace( iSize - 1 ) ); - // iSize is quantized to iSize + 1mb. - // Descriptive rather than normative test. - // SERVER-8311 A pre quantized size is rounded to the next quantum level. - ASSERT_EQUALS( iSize + 0x100000, + // iSize is quantized to iSize. + ASSERT_EQUALS( iSize, RecordStoreV1Base::quantizePowerOf2AllocationSpace( iSize ) ); // iSize + 1 is quantized to iSize + 1mb. |