diff options
Diffstat (limited to 'src/mongo/db/storage/mmap_v1/record_store_v1_capped_test.cpp')
-rw-r--r-- | src/mongo/db/storage/mmap_v1/record_store_v1_capped_test.cpp | 1274 |
1 files changed, 586 insertions, 688 deletions
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_capped_test.cpp b/src/mongo/db/storage/mmap_v1/record_store_v1_capped_test.cpp index 0c369587f9b..1089d243467 100644 --- a/src/mongo/db/storage/mmap_v1/record_store_v1_capped_test.cpp +++ b/src/mongo/db/storage/mmap_v1/record_store_v1_capped_test.cpp @@ -42,773 +42,671 @@ using namespace mongo; namespace { - using std::string; - using std::vector; - - // Provides data to be inserted. Must be large enough for largest possible record. - // Should be in BSS so unused portions should be free. - char zeros[20*1024*1024] = {}; - - class DummyCappedDocumentDeleteCallback : public CappedDocumentDeleteCallback { - public: - Status aboutToDeleteCapped( OperationContext* txn, const RecordId& loc, RecordData data) { - deleted.push_back( DiskLoc::fromRecordId(loc) ); - return Status::OK(); - } - vector<DiskLoc> deleted; - }; - - void simpleInsertTest( const char* buf, int size ) { - - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - - string myns = "test.simple1"; - CappedRecordStoreV1 rs( &txn, &cb, myns, md, &em, false ); +using std::string; +using std::vector; + +// Provides data to be inserted. Must be large enough for largest possible record. +// Should be in BSS so unused portions should be free. +char zeros[20 * 1024 * 1024] = {}; + +class DummyCappedDocumentDeleteCallback : public CappedDocumentDeleteCallback { +public: + Status aboutToDeleteCapped(OperationContext* txn, const RecordId& loc, RecordData data) { + deleted.push_back(DiskLoc::fromRecordId(loc)); + return Status::OK(); + } + vector<DiskLoc> deleted; +}; - rs.increaseStorageSize( &txn, 1024, false ); +void simpleInsertTest(const char* buf, int size) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; - ASSERT_NOT_OK( rs.insertRecord( &txn, buf, 3, 1000 ).getStatus() ); + string myns = "test.simple1"; + CappedRecordStoreV1 rs(&txn, &cb, myns, md, &em, false); - rs.insertRecord( &txn, buf, size, 10000 ); + rs.increaseStorageSize(&txn, 1024, false); - { - BSONObjBuilder b; - int64_t storageSize = rs.storageSize( &txn, &b ); - BSONObj obj = b.obj(); - ASSERT_EQUALS( 1, obj["numExtents"].numberInt() ); - ASSERT_EQUALS( storageSize, em.quantizeExtentSize( 1024 ) ); - } + ASSERT_NOT_OK(rs.insertRecord(&txn, buf, 3, 1000).getStatus()); - for ( int i = 0; i < 1000; i++ ) { - ASSERT_OK( rs.insertRecord( &txn, buf, size, 10000 ).getStatus() ); - } + rs.insertRecord(&txn, buf, size, 10000); - long long start = md->numRecords(); - for ( int i = 0; i < 1000; i++ ) { - ASSERT_OK( rs.insertRecord( &txn, buf, size, 10000 ).getStatus() ); - } - ASSERT_EQUALS( start, md->numRecords() ); - ASSERT_GREATER_THAN( start, 100 ); - ASSERT_LESS_THAN( start, 1000 ); + { + BSONObjBuilder b; + int64_t storageSize = rs.storageSize(&txn, &b); + BSONObj obj = b.obj(); + ASSERT_EQUALS(1, obj["numExtents"].numberInt()); + ASSERT_EQUALS(storageSize, em.quantizeExtentSize(1024)); } - TEST(CappedRecordStoreV1, SimpleInsertSize4) { - simpleInsertTest("abcd", 4); - } - TEST(CappedRecordStoreV1, SimpleInsertSize8) { - simpleInsertTest("abcdefgh", 8); + for (int i = 0; i < 1000; i++) { + ASSERT_OK(rs.insertRecord(&txn, buf, size, 10000).getStatus()); } - TEST(CappedRecordStoreV1, EmptySingleExtent) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); - - { - LocAndSize records[] = { - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1000), 1000}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } - - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - - { - LocAndSize recs[] = { - {DiskLoc(0, 1000), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1100), 900}, - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc().setInvalid()); // unlooped - } + long long start = md->numRecords(); + for (int i = 0; i < 1000; i++) { + ASSERT_OK(rs.insertRecord(&txn, buf, size, 10000).getStatus()); } + ASSERT_EQUALS(start, md->numRecords()); + ASSERT_GREATER_THAN(start, 100); + ASSERT_LESS_THAN(start, 1000); +} - TEST(CappedRecordStoreV1, FirstLoopWithSingleExtentExactSize) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); - - { - LocAndSize records[] = { - {DiskLoc(0, 1000), 100}, - {DiskLoc(0, 1100), 100}, - {DiskLoc(0, 1200), 100}, - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1500), 50}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } - - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); +TEST(CappedRecordStoreV1, SimpleInsertSize4) { + simpleInsertTest("abcd", 4); +} +TEST(CappedRecordStoreV1, SimpleInsertSize8) { + simpleInsertTest("abcdefgh", 8); +} - { - LocAndSize recs[] = { - {DiskLoc(0, 1200), 100}, // first old record - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, // last old record - {DiskLoc(0, 1000), 100}, // first new record - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1100), 100}, // gap after newest record XXX this is probably a bug - {DiskLoc(0, 1500), 50}, // gap at end of extent - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); - } +TEST(CappedRecordStoreV1, EmptySingleExtent) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{}}; + LocAndSize drecs[] = {{DiskLoc(0, 1000), 1000}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); + initializeV1RS(&txn, records, drecs, NULL, &em, md); } - TEST(CappedRecordStoreV1, NonFirstLoopWithSingleExtentExactSize) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - { - LocAndSize records[] = { - {DiskLoc(0, 1000), 100}, - {DiskLoc(0, 1100), 100}, - {DiskLoc(0, 1200), 100}, - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1500), 50}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } - - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - - { - LocAndSize recs[] = { - {DiskLoc(0, 1200), 100}, // first old record - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, // last old record - {DiskLoc(0, 1000), 100}, // first new record - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1100), 100}, // gap after newest record XXX this is probably a bug - {DiskLoc(0, 1500), 50}, // gap at end of extent - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); - } + { + LocAndSize recs[] = {{DiskLoc(0, 1000), 100}, {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1100), 900}, {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc().setInvalid()); // unlooped } +} - /** - * Current code always tries to leave 24 bytes to create a DeletedRecord. - */ - TEST(CappedRecordStoreV1, WillLoopWithout24SpareBytes) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); +TEST(CappedRecordStoreV1, FirstLoopWithSingleExtentExactSize) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{DiskLoc(0, 1000), 100}, + {DiskLoc(0, 1100), 100}, + {DiskLoc(0, 1200), 100}, + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1500), 50}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - LocAndSize records[] = { - {DiskLoc(0, 1000), 100}, - {DiskLoc(0, 1100), 100}, - {DiskLoc(0, 1200), 100}, - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1500), 123}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + + { + LocAndSize recs[] = {{DiskLoc(0, 1200), 100}, // first old record + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, // last old record + {DiskLoc(0, 1000), 100}, // first new record + {}}; + LocAndSize drecs[] = { + {DiskLoc(0, 1100), 100}, // gap after newest record XXX this is probably a bug + {DiskLoc(0, 1500), 50}, // gap at end of extent + {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); + } +} - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); +TEST(CappedRecordStoreV1, NonFirstLoopWithSingleExtentExactSize) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{DiskLoc(0, 1000), 100}, + {DiskLoc(0, 1100), 100}, + {DiskLoc(0, 1200), 100}, + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1500), 50}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - LocAndSize recs[] = { - {DiskLoc(0, 1200), 100}, // first old record - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, // last old record - {DiskLoc(0, 1000), 100}, // first new record - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1100), 100}, // gap after newest record - {DiskLoc(0, 1500), 123}, // gap at end of extent - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); - } + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + + { + LocAndSize recs[] = {{DiskLoc(0, 1200), 100}, // first old record + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, // last old record + {DiskLoc(0, 1000), 100}, // first new record + {}}; + LocAndSize drecs[] = { + {DiskLoc(0, 1100), 100}, // gap after newest record XXX this is probably a bug + {DiskLoc(0, 1500), 50}, // gap at end of extent + {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } +} - TEST(CappedRecordStoreV1, WontLoopWith24SpareBytes) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); +/** + * Current code always tries to leave 24 bytes to create a DeletedRecord. + */ +TEST(CappedRecordStoreV1, WillLoopWithout24SpareBytes) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{DiskLoc(0, 1000), 100}, + {DiskLoc(0, 1100), 100}, + {DiskLoc(0, 1200), 100}, + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1500), 123}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - LocAndSize records[] = { - {DiskLoc(0, 1000), 100}, - {DiskLoc(0, 1100), 100}, - {DiskLoc(0, 1200), 100}, - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1500), 124}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + + { + LocAndSize recs[] = {{DiskLoc(0, 1200), 100}, // first old record + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, // last old record + {DiskLoc(0, 1000), 100}, // first new record + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1100), 100}, // gap after newest record + {DiskLoc(0, 1500), 123}, // gap at end of extent + {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); + } +} - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); +TEST(CappedRecordStoreV1, WontLoopWith24SpareBytes) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{DiskLoc(0, 1000), 100}, + {DiskLoc(0, 1100), 100}, + {DiskLoc(0, 1200), 100}, + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1500), 124}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - LocAndSize recs[] = { - {DiskLoc(0, 1000), 100}, - {DiskLoc(0, 1100), 100}, - {DiskLoc(0, 1200), 100}, - {DiskLoc(0, 1300), 100}, - {DiskLoc(0, 1400), 100}, - {DiskLoc(0, 1500), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1600), 24}, // gap at end of extent - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); - } + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + + { + LocAndSize recs[] = {{DiskLoc(0, 1000), 100}, + {DiskLoc(0, 1100), 100}, + {DiskLoc(0, 1200), 100}, + {DiskLoc(0, 1300), 100}, + {DiskLoc(0, 1400), 100}, + {DiskLoc(0, 1500), 100}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1600), 24}, // gap at end of extent + {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } +} - TEST(CappedRecordStoreV1, MoveToSecondExtentUnLooped) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); +TEST(CappedRecordStoreV1, MoveToSecondExtentUnLooped) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + // Two extents, each with 1000 bytes. + LocAndSize records[] = { + {DiskLoc(0, 1000), 500}, {DiskLoc(0, 1500), 300}, {DiskLoc(0, 1800), 100}, {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1900), 100}, {DiskLoc(1, 1000), 1000}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - // Two extents, each with 1000 bytes. - LocAndSize records[] = { - {DiskLoc(0, 1000), 500}, - {DiskLoc(0, 1500), 300}, - {DiskLoc(0, 1800), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1900), 100}, - {DiskLoc(1, 1000), 1000}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + { + LocAndSize recs[] = {{DiskLoc(0, 1000), 500}, + {DiskLoc(0, 1500), 300}, + {DiskLoc(0, 1800), 100}, - { - LocAndSize recs[] = { - {DiskLoc(0, 1000), 500}, - {DiskLoc(0, 1500), 300}, - {DiskLoc(0, 1800), 100}, - - {DiskLoc(1, 1000), 100}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1900), 100}, - {DiskLoc(1, 1100), 900}, - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(1, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc().setInvalid()); // unlooped - } + {DiskLoc(1, 1000), 100}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1900), 100}, {DiskLoc(1, 1100), 900}, {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(1, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc().setInvalid()); // unlooped } +} - TEST(CappedRecordStoreV1, MoveToSecondExtentLooped) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); +TEST(CappedRecordStoreV1, MoveToSecondExtentLooped) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + // Two extents, each with 1000 bytes. + LocAndSize records[] = {{DiskLoc(0, 1800), 100}, // old + {DiskLoc(0, 1000), 500}, // first new + {DiskLoc(0, 1500), 400}, + + {DiskLoc(1, 1000), 300}, + {DiskLoc(1, 1300), 600}, + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1900), 100}, {DiskLoc(1, 1900), 100}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - // Two extents, each with 1000 bytes. - LocAndSize records[] = { - {DiskLoc(0, 1800), 100}, // old - {DiskLoc(0, 1000), 500}, // first new - {DiskLoc(0, 1500), 400}, - - {DiskLoc(1, 1000), 300}, - {DiskLoc(1, 1300), 600}, - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1900), 100}, - {DiskLoc(1, 1900), 100}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc(0, 1000)); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } + rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); + { + LocAndSize recs[] = {{DiskLoc(0, 1000), 500}, + {DiskLoc(0, 1500), 400}, - { - LocAndSize recs[] = { - {DiskLoc(0, 1000), 500}, - {DiskLoc(0, 1500), 400}, - - {DiskLoc(1, 1300), 600}, // old - {DiskLoc(1, 1000), 200}, // first new - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1800), 200}, - {DiskLoc(1, 1200), 100}, - {DiskLoc(1, 1900), 100}, - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(1, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(1, 1000)); - } + {DiskLoc(1, 1300), 600}, // old + {DiskLoc(1, 1000), 200}, // first new + {}}; + LocAndSize drecs[] = { + {DiskLoc(0, 1800), 200}, {DiskLoc(1, 1200), 100}, {DiskLoc(1, 1900), 100}, {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(1, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(1, 1000)); } +} - // Larger than storageSize (fails early) - TEST(CappedRecordStoreV1, OversizedRecordHuge) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); +// Larger than storageSize (fails early) +TEST(CappedRecordStoreV1, OversizedRecordHuge) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{}}; + LocAndSize drecs[] = {{DiskLoc(0, 1000), 1000}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); + initializeV1RS(&txn, records, drecs, NULL, &em, md); + } - { - LocAndSize records[] = { - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1000), 1000}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } + StatusWith<RecordId> status = rs.insertRecord(&txn, zeros, 16000, false); + ASSERT_EQUALS(status.getStatus(), ErrorCodes::DocTooLargeForCapped); + ASSERT_EQUALS(status.getStatus().location(), 16328); +} - StatusWith<RecordId> status = rs.insertRecord(&txn, zeros, 16000, false); - ASSERT_EQUALS(status.getStatus(), ErrorCodes::DocTooLargeForCapped); - ASSERT_EQUALS(status.getStatus().location(), 16328); +// Smaller than storageSize, but larger than usable space (fails late) +TEST(CappedRecordStoreV1, OversizedRecordMedium) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + LocAndSize records[] = {{}}; + LocAndSize drecs[] = {{DiskLoc(0, 1000), 1000}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); + initializeV1RS(&txn, records, drecs, NULL, &em, md); } - // Smaller than storageSize, but larger than usable space (fails late) - TEST(CappedRecordStoreV1, OversizedRecordMedium) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + StatusWith<RecordId> status = + rs.insertRecord(&txn, zeros, 1004 - MmapV1RecordHeader::HeaderSize, false); + ASSERT_EQUALS(status.getStatus(), ErrorCodes::DocTooLargeForCapped); + ASSERT_EQUALS(status.getStatus().location(), 28575); +} - { - LocAndSize records[] = { - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1000), 1000}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } +// +// XXX The CappedRecordStoreV1Scrambler suite of tests describe existing behavior that is less +// than ideal. Any improved implementation will need to be able to handle a collection that has +// been scrambled like this. +// - StatusWith<RecordId> status = rs.insertRecord(&txn, zeros, 1004 - MmapV1RecordHeader::HeaderSize, false); - ASSERT_EQUALS(status.getStatus(), ErrorCodes::DocTooLargeForCapped); - ASSERT_EQUALS(status.getStatus().location(), 28575); +/** + * This is a minimal example that shows the current allocator laying out records out-of-order. + */ +TEST(CappedRecordStoreV1Scrambler, Minimal) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + // Starting with a single empty 1000 byte extent. + LocAndSize records[] = {{}}; + LocAndSize drecs[] = {{DiskLoc(0, 1000), 1000}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped + initializeV1RS(&txn, records, drecs, NULL, &em, md); } - // - // XXX The CappedRecordStoreV1Scrambler suite of tests describe existing behavior that is less - // than ideal. Any improved implementation will need to be able to handle a collection that has - // been scrambled like this. - // - - /** - * This is a minimal example that shows the current allocator laying out records out-of-order. - */ - TEST(CappedRecordStoreV1Scrambler, Minimal) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); - - { - // Starting with a single empty 1000 byte extent. - LocAndSize records[] = { - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1000), 1000}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped - initializeV1RS(&txn, records, drecs, NULL, &em, md); - } - - rs.insertRecord(&txn, zeros, 500 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 300 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 400 - MmapV1RecordHeader::HeaderSize, false); // won't fit at end so wraps - rs.insertRecord(&txn, zeros, 120 - MmapV1RecordHeader::HeaderSize, false); // fits at end - rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); // fits in earlier hole + rs.insertRecord(&txn, zeros, 500 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 300 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord( + &txn, zeros, 400 - MmapV1RecordHeader::HeaderSize, false); // won't fit at end so wraps + rs.insertRecord(&txn, zeros, 120 - MmapV1RecordHeader::HeaderSize, false); // fits at end + rs.insertRecord( + &txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); // fits in earlier hole + + { + LocAndSize recs[] = {{DiskLoc(0, 1500), 300}, // 2nd insert + {DiskLoc(0, 1000), 400}, // 3rd (1st new) + {DiskLoc(0, 1800), 120}, // 4th + {DiskLoc(0, 1400), 60}, // 5th + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1460), 40}, {DiskLoc(0, 1920), 80}, {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); + } +} - { - LocAndSize recs[] = { - {DiskLoc(0, 1500), 300}, // 2nd insert - {DiskLoc(0, 1000), 400}, // 3rd (1st new) - {DiskLoc(0, 1800), 120}, // 4th - {DiskLoc(0, 1400), 60}, // 5th - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1460), 40}, - {DiskLoc(0, 1920), 80}, - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); - } +/** + * This tests a specially crafted set of inserts that scrambles a capped collection in a way + * that leaves 4 deleted records in a single extent. + */ +TEST(CappedRecordStoreV1Scrambler, FourDeletedRecordsInSingleExtent) { + OperationContextNoop txn; + DummyExtentManager em; + DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData(true, 0); + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + + { + // Starting with a single empty 1000 byte extent. + LocAndSize records[] = {{}}; + LocAndSize drecs[] = {{DiskLoc(0, 1000), 1000}, {}}; + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped + initializeV1RS(&txn, records, drecs, NULL, &em, md); } - /** - * This tests a specially crafted set of inserts that scrambles a capped collection in a way - * that leaves 4 deleted records in a single extent. - */ - TEST(CappedRecordStoreV1Scrambler, FourDeletedRecordsInSingleExtent) { - OperationContextNoop txn; - DummyExtentManager em; - DummyRecordStoreV1MetaData* md = new DummyRecordStoreV1MetaData( true, 0 ); - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs(&txn, &cb, "test.foo", md, &em, false); + // This list of sizes was empirically generated to achieve this outcome. Don't think too + // much about them. + rs.insertRecord(&txn, zeros, 500 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 300 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 304 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 76 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 76 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 56 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 104 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 146 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 146 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 40 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 40 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 36 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); + rs.insertRecord(&txn, zeros, 64 - MmapV1RecordHeader::HeaderSize, false); + + { + LocAndSize recs[] = {{DiskLoc(0, 1148), 148}, + {DiskLoc(0, 1936), 40}, + {DiskLoc(0, 1712), 40}, + {DiskLoc(0, 1296), 36}, + {DiskLoc(0, 1752), 100}, + {DiskLoc(0, 1332), 96}, + {DiskLoc(0, 1428), 200}, + {DiskLoc(0, 1852), 60}, + {DiskLoc(0, 1000), 64}, // (1st new) + {}}; + LocAndSize drecs[] = {{DiskLoc(0, 1064), 84}, + {DiskLoc(0, 1976), 24}, + {DiskLoc(0, 1912), 24}, + {DiskLoc(0, 1628), 84}, + {}}; + assertStateV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); + ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); + } +} - { - // Starting with a single empty 1000 byte extent. - LocAndSize records[] = { - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1000), 1000}, - {} - }; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped - initializeV1RS(&txn, records, drecs, NULL, &em, md); +// +// The CappedRecordStoreV1QueryStage tests some nitty-gritty capped +// collection details. Ported and polished from pdfiletests.cpp. +// + +class CollscanHelper { +public: + CollscanHelper(int nExtents) + : md(new DummyRecordStoreV1MetaData(true, 0)), rs(&txn, &cb, ns(), md, &em, false) { + LocAndSize recs[] = {{}}; + LocAndSize drecs[8]; + ASSERT_LESS_THAN(nExtents, 8); + for (int j = 0; j < nExtents; ++j) { + drecs[j].loc = DiskLoc(j, 1000); + drecs[j].size = 1000; } + drecs[nExtents].loc = DiskLoc(); + drecs[nExtents].size = 0; - // This list of sizes was empirically generated to achieve this outcome. Don't think too - // much about them. - rs.insertRecord(&txn, zeros, 500 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 300 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 304 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 76 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 76 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 56 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 104 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 146 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 146 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 40 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 40 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 36 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 100 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 96 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 200 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 60 - MmapV1RecordHeader::HeaderSize, false); - rs.insertRecord(&txn, zeros, 64 - MmapV1RecordHeader::HeaderSize, false); + md->setCapExtent(&txn, DiskLoc(0, 0)); + md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped + initializeV1RS(&txn, recs, drecs, NULL, &em, md); + } - { - LocAndSize recs[] = { - {DiskLoc(0, 1148), 148}, - {DiskLoc(0, 1936), 40}, - {DiskLoc(0, 1712), 40}, - {DiskLoc(0, 1296), 36}, - {DiskLoc(0, 1752), 100}, - {DiskLoc(0, 1332), 96}, - {DiskLoc(0, 1428), 200}, - {DiskLoc(0, 1852), 60}, - {DiskLoc(0, 1000), 64}, // (1st new) - {} - }; - LocAndSize drecs[] = { - {DiskLoc(0, 1064), 84}, - {DiskLoc(0, 1976), 24}, - {DiskLoc(0, 1912), 24}, - {DiskLoc(0, 1628), 84}, - {} - }; - assertStateV1RS(&txn, recs, drecs, NULL, &em, md); - ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); - ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); + // Insert bypasses standard alloc/insert routines to use the extent we want. + // TODO: Directly declare resulting record store state instead of procedurally creating it + DiskLoc insert(const DiskLoc& ext, int i) { + // Copied verbatim. + BSONObjBuilder b; + b.append("a", i); + BSONObj o = b.done(); + int len = o.objsize(); + Extent* e = em.getExtent(ext); + e = txn.recoveryUnit()->writing(e); + int ofs; + if (e->lastRecord.isNull()) { + ofs = ext.getOfs() + (e->_extentData - (char*)e); + } else { + ofs = e->lastRecord.getOfs() + em.recordForV1(e->lastRecord)->lengthWithHeaders(); } + DiskLoc dl(ext.a(), ofs); + MmapV1RecordHeader* r = em.recordForV1(dl); + r = (MmapV1RecordHeader*)txn.recoveryUnit()->writingPtr( + r, MmapV1RecordHeader::HeaderSize + len); + r->lengthWithHeaders() = MmapV1RecordHeader::HeaderSize + len; + r->extentOfs() = e->myLoc.getOfs(); + r->nextOfs() = DiskLoc::NullOfs; + r->prevOfs() = e->lastRecord.isNull() ? DiskLoc::NullOfs : e->lastRecord.getOfs(); + memcpy(r->data(), o.objdata(), len); + if (e->firstRecord.isNull()) + e->firstRecord = dl; + else + txn.recoveryUnit()->writingInt(em.recordForV1(e->lastRecord)->nextOfs()) = ofs; + e->lastRecord = dl; + return dl; } - // - // The CappedRecordStoreV1QueryStage tests some nitty-gritty capped - // collection details. Ported and polished from pdfiletests.cpp. - // - - class CollscanHelper { - public: - CollscanHelper(int nExtents) - : md(new DummyRecordStoreV1MetaData( true, 0 )), - rs(&txn, &cb, ns(), md, &em, false) + // TODO: Directly assert the desired record store state instead of just walking it + void walkAndCount(int expectedCount) { + // Walk the collection going forward. { - LocAndSize recs[] = { - {} - }; - LocAndSize drecs[8]; - ASSERT_LESS_THAN(nExtents, 8); - for (int j = 0; j < nExtents; ++j) { - drecs[j].loc = DiskLoc(j, 1000); - drecs[j].size = 1000; + CappedRecordStoreV1Iterator cursor(&txn, &rs, /*forward=*/true); + int resultCount = 0; + while (auto record = cursor.next()) { + ++resultCount; } - drecs[nExtents].loc = DiskLoc(); - drecs[nExtents].size = 0; - md->setCapExtent(&txn, DiskLoc(0, 0)); - md->setCapFirstNewRecord(&txn, DiskLoc().setInvalid()); // unlooped - initializeV1RS(&txn, recs, drecs, NULL, &em, md); + ASSERT_EQUALS(resultCount, expectedCount); } - // Insert bypasses standard alloc/insert routines to use the extent we want. - // TODO: Directly declare resulting record store state instead of procedurally creating it - DiskLoc insert( const DiskLoc& ext, int i ) { - // Copied verbatim. - BSONObjBuilder b; - b.append( "a", i ); - BSONObj o = b.done(); - int len = o.objsize(); - Extent *e = em.getExtent(ext); - e = txn.recoveryUnit()->writing(e); - int ofs; - if ( e->lastRecord.isNull() ) { - ofs = ext.getOfs() + ( e->_extentData - (char *)e ); - } - else { - ofs = e->lastRecord.getOfs() - + em.recordForV1(e->lastRecord)->lengthWithHeaders(); - } - DiskLoc dl( ext.a(), ofs ); - MmapV1RecordHeader *r = em.recordForV1(dl); - r = (MmapV1RecordHeader*) txn.recoveryUnit()->writingPtr(r, MmapV1RecordHeader::HeaderSize + len); - r->lengthWithHeaders() = MmapV1RecordHeader::HeaderSize + len; - r->extentOfs() = e->myLoc.getOfs(); - r->nextOfs() = DiskLoc::NullOfs; - r->prevOfs() = e->lastRecord.isNull() ? DiskLoc::NullOfs : e->lastRecord.getOfs(); - memcpy( r->data(), o.objdata(), len ); - if ( e->firstRecord.isNull() ) - e->firstRecord = dl; - else - txn.recoveryUnit()->writingInt(em.recordForV1(e->lastRecord)->nextOfs()) = ofs; - e->lastRecord = dl; - return dl; - } - - // TODO: Directly assert the desired record store state instead of just walking it - void walkAndCount (int expectedCount) { - // Walk the collection going forward. - { - CappedRecordStoreV1Iterator cursor(&txn, &rs, /*forward=*/true); - int resultCount = 0; - while (auto record = cursor.next()) { - ++resultCount; - } - - ASSERT_EQUALS(resultCount, expectedCount); + // Walk the collection going backwards. + { + CappedRecordStoreV1Iterator cursor(&txn, &rs, /*forward=*/false); + int resultCount = expectedCount; + while (auto record = cursor.next()) { + --resultCount; } - // Walk the collection going backwards. - { - CappedRecordStoreV1Iterator cursor(&txn, &rs, /*forward=*/false); - int resultCount = expectedCount; - while (auto record = cursor.next()) { - --resultCount; - } - - ASSERT_EQUALS(resultCount, 0); - } + ASSERT_EQUALS(resultCount, 0); } + } - static const char *ns() { return "unittests.QueryStageCollectionScanCapped"; } + static const char* ns() { + return "unittests.QueryStageCollectionScanCapped"; + } - OperationContextNoop txn; - DummyRecordStoreV1MetaData* md; - DummyExtentManager em; + OperationContextNoop txn; + DummyRecordStoreV1MetaData* md; + DummyExtentManager em; - private: - DummyCappedDocumentDeleteCallback cb; - CappedRecordStoreV1 rs; - }; +private: + DummyCappedDocumentDeleteCallback cb; + CappedRecordStoreV1 rs; +}; - TEST(CappedRecordStoreV1QueryStage, CollscanCappedBase) { - CollscanHelper h(1); - h.walkAndCount(0); - } +TEST(CappedRecordStoreV1QueryStage, CollscanCappedBase) { + CollscanHelper h(1); + h.walkAndCount(0); +} - TEST(CappedRecordStoreV1QueryStage, CollscanEmptyLooped) { - CollscanHelper h(1); - h.md->setCapFirstNewRecord( &h.txn, DiskLoc() ); - h.walkAndCount(0); - } +TEST(CappedRecordStoreV1QueryStage, CollscanEmptyLooped) { + CollscanHelper h(1); + h.md->setCapFirstNewRecord(&h.txn, DiskLoc()); + h.walkAndCount(0); +} - TEST(CappedRecordStoreV1QueryStage, CollscanEmptyMultiExtentLooped) { - CollscanHelper h(3); - h.md->setCapFirstNewRecord( &h.txn, DiskLoc() ); - h.walkAndCount(0); - } +TEST(CappedRecordStoreV1QueryStage, CollscanEmptyMultiExtentLooped) { + CollscanHelper h(3); + h.md->setCapFirstNewRecord(&h.txn, DiskLoc()); + h.walkAndCount(0); +} - TEST(CappedRecordStoreV1QueryStage, CollscanSingle) { - CollscanHelper h(1); +TEST(CappedRecordStoreV1QueryStage, CollscanSingle) { + CollscanHelper h(1); - h.md->setCapFirstNewRecord(&h.txn, h.insert( h.md->capExtent(), 0 )); - h.walkAndCount(1); - } + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 0)); + h.walkAndCount(1); +} - TEST(CappedRecordStoreV1QueryStage, CollscanNewCapFirst) { - CollscanHelper h(1); - DiskLoc x = h.insert(h.md->capExtent(), 0 ); - h.md->setCapFirstNewRecord( &h.txn, x ); - h.insert(h.md->capExtent(), 1 ); - h.walkAndCount(2); - } +TEST(CappedRecordStoreV1QueryStage, CollscanNewCapFirst) { + CollscanHelper h(1); + DiskLoc x = h.insert(h.md->capExtent(), 0); + h.md->setCapFirstNewRecord(&h.txn, x); + h.insert(h.md->capExtent(), 1); + h.walkAndCount(2); +} - TEST(CappedRecordStoreV1QueryStage, CollscanNewCapMiddle) { - CollscanHelper h(1); - h.insert(h.md->capExtent(), 0 ); - h.md->setCapFirstNewRecord(&h.txn, h.insert( h.md->capExtent(), 1 ) ); - h.insert( h.md->capExtent(), 2 ); - h.walkAndCount(3); - } +TEST(CappedRecordStoreV1QueryStage, CollscanNewCapMiddle) { + CollscanHelper h(1); + h.insert(h.md->capExtent(), 0); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 1)); + h.insert(h.md->capExtent(), 2); + h.walkAndCount(3); +} - TEST(CappedRecordStoreV1QueryStage, CollscanFirstExtent) { - CollscanHelper h(2); - h.insert(h.md->capExtent(), 0 ); - h.insert(h.md->lastExtent(&h.txn), 1 ); - h.md->setCapFirstNewRecord(&h.txn, h.insert( h.md->capExtent(), 2 ) ); - h.insert( h.md->capExtent(), 3 ); - h.walkAndCount(4); - } +TEST(CappedRecordStoreV1QueryStage, CollscanFirstExtent) { + CollscanHelper h(2); + h.insert(h.md->capExtent(), 0); + h.insert(h.md->lastExtent(&h.txn), 1); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 2)); + h.insert(h.md->capExtent(), 3); + h.walkAndCount(4); +} - TEST(CappedRecordStoreV1QueryStage, CollscanLastExtent) { - CollscanHelper h(2); - h.md->setCapExtent( &h.txn, h.md->lastExtent(&h.txn) ); - h.insert( h.md->capExtent(), 0 ); - h.insert( h.md->firstExtent(&h.txn), 1 ); - h.md->setCapFirstNewRecord( &h.txn, h.insert( h.md->capExtent(), 2 ) ); - h.insert( h.md->capExtent(), 3 ); - h.walkAndCount(4); - } +TEST(CappedRecordStoreV1QueryStage, CollscanLastExtent) { + CollscanHelper h(2); + h.md->setCapExtent(&h.txn, h.md->lastExtent(&h.txn)); + h.insert(h.md->capExtent(), 0); + h.insert(h.md->firstExtent(&h.txn), 1); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 2)); + h.insert(h.md->capExtent(), 3); + h.walkAndCount(4); +} - TEST(CappedRecordStoreV1QueryStage, CollscanMidExtent) { - CollscanHelper h(3); - h.md->setCapExtent( &h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext ); - h.insert( h.md->capExtent(), 0 ); - h.insert( h.md->lastExtent(&h.txn), 1 ); - h.insert( h.md->firstExtent(&h.txn), 2 ); - h.md->setCapFirstNewRecord( &h.txn, h.insert( h.md->capExtent(), 3 ) ); - h.insert( h.md->capExtent(), 4 ); - h.walkAndCount(5); - } +TEST(CappedRecordStoreV1QueryStage, CollscanMidExtent) { + CollscanHelper h(3); + h.md->setCapExtent(&h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext); + h.insert(h.md->capExtent(), 0); + h.insert(h.md->lastExtent(&h.txn), 1); + h.insert(h.md->firstExtent(&h.txn), 2); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 3)); + h.insert(h.md->capExtent(), 4); + h.walkAndCount(5); +} - TEST(CappedRecordStoreV1QueryStage, CollscanAloneInExtent) { - CollscanHelper h(3); - h.md->setCapExtent( &h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext ); - h.insert( h.md->lastExtent(&h.txn), 0 ); - h.insert( h.md->firstExtent(&h.txn), 1 ); - h.md->setCapFirstNewRecord( &h.txn, h.insert( h.md->capExtent(), 2 ) ); - h.walkAndCount(3); - } +TEST(CappedRecordStoreV1QueryStage, CollscanAloneInExtent) { + CollscanHelper h(3); + h.md->setCapExtent(&h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext); + h.insert(h.md->lastExtent(&h.txn), 0); + h.insert(h.md->firstExtent(&h.txn), 1); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 2)); + h.walkAndCount(3); +} - TEST(CappedRecordStoreV1QueryStage, CollscanFirstInExtent) { - CollscanHelper h(3); - h.md->setCapExtent( &h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext ); - h.insert( h.md->lastExtent(&h.txn), 0 ); - h.insert( h.md->firstExtent(&h.txn), 1 ); - h.md->setCapFirstNewRecord( &h.txn, h.insert( h.md->capExtent(), 2 ) ); - h.insert( h.md->capExtent(), 3 ); - h.walkAndCount(4); - } +TEST(CappedRecordStoreV1QueryStage, CollscanFirstInExtent) { + CollscanHelper h(3); + h.md->setCapExtent(&h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext); + h.insert(h.md->lastExtent(&h.txn), 0); + h.insert(h.md->firstExtent(&h.txn), 1); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 2)); + h.insert(h.md->capExtent(), 3); + h.walkAndCount(4); +} - TEST(CappedRecordStoreV1QueryStage, CollscanLastInExtent) { - CollscanHelper h(3); - h.md->setCapExtent( &h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext ); - h.insert( h.md->capExtent(), 0 ); - h.insert( h.md->lastExtent(&h.txn), 1 ); - h.insert( h.md->firstExtent(&h.txn), 2 ); - h.md->setCapFirstNewRecord( &h.txn, h.insert( h.md->capExtent(), 3 ) ); - h.walkAndCount(4); - } +TEST(CappedRecordStoreV1QueryStage, CollscanLastInExtent) { + CollscanHelper h(3); + h.md->setCapExtent(&h.txn, h.em.getExtent(h.md->firstExtent(&h.txn))->xnext); + h.insert(h.md->capExtent(), 0); + h.insert(h.md->lastExtent(&h.txn), 1); + h.insert(h.md->firstExtent(&h.txn), 2); + h.md->setCapFirstNewRecord(&h.txn, h.insert(h.md->capExtent(), 3)); + h.walkAndCount(4); +} } |