diff options
Diffstat (limited to 'src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp')
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp | 355 |
1 files changed, 20 insertions, 335 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp index 75b5c11e673..5261cfc73ba 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp @@ -45,7 +45,6 @@ #include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h" #include "mongo/db/storage/wiredtiger/wiredtiger_record_store_oplog_stones.h" #include "mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h" -#include "mongo/db/storage/wiredtiger/wiredtiger_session_cache.h" #include "mongo/db/storage/wiredtiger/wiredtiger_size_storer.h" #include "mongo/db/storage/wiredtiger/wiredtiger_util.h" #include "mongo/stdx/memory.h" @@ -222,179 +221,6 @@ StatusWith<RecordId> insertBSON(ServiceContext::UniqueOperationContext& opCtx, return res; } -// TODO make generic -TEST(WiredTigerRecordStoreTest, OplogHack) { - std::unique_ptr<RecordStoreHarnessHelper> harnessHelper = newRecordStoreHarnessHelper(); - // Use a large enough cappedMaxSize so that the limit is not reached by doing the inserts within - // the test itself. - const int64_t cappedMaxSize = 10 * 1024; // 10KB - unique_ptr<RecordStore> rs( - harnessHelper->newCappedRecordStore("local.oplog.foo", cappedMaxSize, -1)); - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - - // always illegal - ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(2, -1)).getStatus(), ErrorCodes::BadValue); - - { - BSONObj obj = BSON("not_ts" << Timestamp(2, 1)); - ASSERT_EQ( - rs->insertRecord(opCtx.get(), obj.objdata(), obj.objsize(), false).getStatus(), - ErrorCodes::BadValue); - - obj = BSON("ts" - << "not a Timestamp"); - ASSERT_EQ( - rs->insertRecord(opCtx.get(), obj.objdata(), obj.objsize(), false).getStatus(), - ErrorCodes::BadValue); - } - - // currently dasserts - // ASSERT_EQ(insertBSON(opCtx, rs, BSON("ts" << Timestamp(-2,1))).getStatus(), - // ErrorCodes::BadValue); - - // success cases - ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(1, 1)).getValue(), RecordId(1, 1)); - - ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(1, 2)).getValue(), RecordId(1, 2)); - - ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(2, 2)).getValue(), RecordId(2, 2)); - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - // find start - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(0, 1)), RecordId()); // nothing <= - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 1)), RecordId(1, 2)); // between - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 2)), RecordId(2, 2)); // == - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 3)), RecordId(2, 2)); // > highest - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - rs->cappedTruncateAfter(opCtx.get(), RecordId(2, 2), false); // no-op - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 3)), RecordId(2, 2)); - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - rs->cappedTruncateAfter(opCtx.get(), RecordId(1, 2), false); // deletes 2,2 - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 3)), RecordId(1, 2)); - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - rs->cappedTruncateAfter(opCtx.get(), RecordId(1, 2), true); // deletes 1,2 - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 3)), RecordId(1, 1)); - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - WriteUnitOfWork wuow(opCtx.get()); - ASSERT_OK(rs->truncate(opCtx.get())); // deletes 1,1 and leaves collection empty - wuow.commit(); - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(2, 3)), RecordId()); - } -} - -TEST(WiredTigerRecordStoreTest, OplogHackOnNonOplog) { - std::unique_ptr<RecordStoreHarnessHelper> harnessHelper = newRecordStoreHarnessHelper(); - unique_ptr<RecordStore> rs(harnessHelper->newNonCappedRecordStore("local.NOT_oplog.foo")); - - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - - BSONObj obj = BSON("ts" << Timestamp(2, -1)); - { - WriteUnitOfWork wuow(opCtx.get()); - ASSERT_OK(rs->insertRecord(opCtx.get(), obj.objdata(), obj.objsize(), false).getStatus()); - wuow.commit(); - } - ASSERT_EQ(rs->oplogStartHack(opCtx.get(), RecordId(0, 1)), boost::none); -} - -TEST(WiredTigerRecordStoreTest, CappedOrder) { - unique_ptr<RecordStoreHarnessHelper> harnessHelper(newRecordStoreHarnessHelper()); - unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("a.b", 100000, 10000)); - - RecordId id1; - - { // first insert a document - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - { - WriteUnitOfWork uow(opCtx.get()); - StatusWith<RecordId> res = rs->insertRecord(opCtx.get(), "a", 2, false); - ASSERT_OK(res.getStatus()); - id1 = res.getValue(); - uow.commit(); - } - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(!cursor->next()); - } - - { - // now we insert 2 docs, but commit the 2nd one fiirst - // we make sure we can't find the 2nd until the first is commited - ServiceContext::UniqueOperationContext t1(harnessHelper->newOperationContext()); - unique_ptr<WriteUnitOfWork> w1(new WriteUnitOfWork(t1.get())); - rs->insertRecord(t1.get(), "b", 2, false).status_with_transitional_ignore(); - // do not commit yet - - { // create 2nd doc - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto t2 = harnessHelper->newOperationContext(client2.get()); - { - WriteUnitOfWork w2(t2.get()); - rs->insertRecord(t2.get(), "c", 2, false).status_with_transitional_ignore(); - w2.commit(); - } - } - - { // state should be the same - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto opCtx = harnessHelper->newOperationContext(client2.get()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(!cursor->next()); - } - - w1->commit(); - } - - { // now all 3 docs should be visible - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto opCtx = harnessHelper->newOperationContext(client2.get()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(cursor->next()); - ASSERT(cursor->next()); - ASSERT(!cursor->next()); - } -} - TEST(WiredTigerRecordStoreTest, CappedCursorRollover) { unique_ptr<RecordStoreHarnessHelper> harnessHelper(newRecordStoreHarnessHelper()); unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("a.b", 10000, 5)); @@ -438,8 +264,7 @@ RecordId _oplogOrderInsertOplog(OperationContext* opCtx, const unique_ptr<RecordStore>& rs, int inc) { Timestamp opTime = Timestamp(5, inc); - WiredTigerRecordStore* wrs = checked_cast<WiredTigerRecordStore*>(rs.get()); - Status status = wrs->oplogDiskLocRegister(opCtx, opTime); + Status status = rs->oplogDiskLocRegister(opCtx, opTime); ASSERT_OK(status); BSONObj obj = BSON("ts" << opTime); StatusWith<RecordId> res = rs->insertRecord(opCtx, obj.objdata(), obj.objsize(), false); @@ -447,149 +272,6 @@ RecordId _oplogOrderInsertOplog(OperationContext* opCtx, return res.getValue(); } -TEST(WiredTigerRecordStoreTest, OplogOrder) { - unique_ptr<RecordStoreHarnessHelper> harnessHelper(newRecordStoreHarnessHelper()); - unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("local.oplog.foo", 100000, -1)); - - { - const WiredTigerRecordStore* wrs = checked_cast<WiredTigerRecordStore*>(rs.get()); - ASSERT(wrs->isOplog()); - ASSERT(wrs->usingOplogHack()); - } - - RecordId id1; - - { // first insert a document - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - { - WriteUnitOfWork uow(opCtx.get()); - id1 = _oplogOrderInsertOplog(opCtx.get(), rs, 1); - uow.commit(); - } - } - - { - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(!cursor->next()); - } - - { - // now we insert 2 docs, but commit the 2nd one first. - // we make sure we can't find the 2nd until the first is commited. - ServiceContext::UniqueOperationContext earlyReader(harnessHelper->newOperationContext()); - auto earlyCursor = rs->getCursor(earlyReader.get()); - ASSERT_EQ(earlyCursor->seekExact(id1)->id, id1); - earlyCursor->save(); - earlyReader->recoveryUnit()->abandonSnapshot(); - - auto client1 = harnessHelper->serviceContext()->makeClient("c1"); - auto t1 = harnessHelper->newOperationContext(client1.get()); - WriteUnitOfWork w1(t1.get()); - _oplogOrderInsertOplog(t1.get(), rs, 20); - // do not commit yet - - { // create 2nd doc - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto t2 = harnessHelper->newOperationContext(client2.get()); - { - WriteUnitOfWork w2(t2.get()); - _oplogOrderInsertOplog(t2.get(), rs, 30); - w2.commit(); - } - } - - { // Other operations should not be able to see 2nd doc until w1 commits. - earlyCursor->restore(); - ASSERT(!earlyCursor->next()); - - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto opCtx = harnessHelper->newOperationContext(client2.get()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(!cursor->next()); - } - - w1.commit(); - } - - rs->waitForAllEarlierOplogWritesToBeVisible(harnessHelper->newOperationContext().get()); - - { // now all 3 docs should be visible - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto opCtx = harnessHelper->newOperationContext(client2.get()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(cursor->next()); - ASSERT(cursor->next()); - ASSERT(!cursor->next()); - } - - // Rollback the last two oplog entries, then insert entries with older optimes and ensure that - // the visibility rules aren't violated. See SERVER-21645 - { - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto opCtx = harnessHelper->newOperationContext(client2.get()); - rs->cappedTruncateAfter(opCtx.get(), id1, /*inclusive*/ false); - } - - { - // Now we insert 2 docs with timestamps earlier than before, but commit the 2nd one first. - // We make sure we can't find the 2nd until the first is commited. - ServiceContext::UniqueOperationContext earlyReader(harnessHelper->newOperationContext()); - auto earlyCursor = rs->getCursor(earlyReader.get()); - ASSERT_EQ(earlyCursor->seekExact(id1)->id, id1); - earlyCursor->save(); - earlyReader->recoveryUnit()->abandonSnapshot(); - - auto client1 = harnessHelper->serviceContext()->makeClient("c1"); - auto t1 = harnessHelper->newOperationContext(client1.get()); - WriteUnitOfWork w1(t1.get()); - _oplogOrderInsertOplog(t1.get(), rs, 2); - // do not commit yet - - { // create 2nd doc - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto t2 = harnessHelper->newOperationContext(client2.get()); - { - WriteUnitOfWork w2(t2.get()); - _oplogOrderInsertOplog(t2.get(), rs, 3); - w2.commit(); - } - } - - { // Other operations should not be able to see 2nd doc until w1 commits. - ASSERT(earlyCursor->restore()); - ASSERT(!earlyCursor->next()); - - auto client2 = harnessHelper->serviceContext()->makeClient("c2"); - auto opCtx = harnessHelper->newOperationContext(client2.get()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(!cursor->next()); - } - - w1.commit(); - } - - rs->waitForAllEarlierOplogWritesToBeVisible(harnessHelper->newOperationContext().get()); - - { // now all 3 docs should be visible - ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); - auto cursor = rs->getCursor(opCtx.get()); - auto record = cursor->seekExact(id1); - ASSERT_EQ(id1, record->id); - ASSERT(cursor->next()); - ASSERT(cursor->next()); - ASSERT(!cursor->next()); - } -} - // Test that even when the oplog durability loop is paused, we can still advance the commit point as // long as the commit for each insert comes before the next insert starts. TEST(WiredTigerRecordStoreTest, OplogDurableVisibilityInOrder) { @@ -597,25 +279,25 @@ TEST(WiredTigerRecordStoreTest, OplogDurableVisibilityInOrder) { WTPausePrimaryOplogDurabilityLoop.setMode(FailPoint::alwaysOn); unique_ptr<RecordStoreHarnessHelper> harnessHelper(newRecordStoreHarnessHelper()); - unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("local.oplog.foo", 100000, -1)); + unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("local.oplog.rs", 100000, -1)); auto wtrs = checked_cast<WiredTigerRecordStore*>(rs.get()); { ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); WriteUnitOfWork uow(opCtx.get()); RecordId id = _oplogOrderInsertOplog(opCtx.get(), rs, 1); - ASSERT(wtrs->isCappedHidden(id)); + ASSERT(wtrs->isOpHidden_forTest(id)); uow.commit(); - ASSERT(!wtrs->isCappedHidden(id)); + ASSERT(wtrs->isOpHidden_forTest(id)); } { ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); WriteUnitOfWork uow(opCtx.get()); RecordId id = _oplogOrderInsertOplog(opCtx.get(), rs, 2); - ASSERT(wtrs->isCappedHidden(id)); + ASSERT(wtrs->isOpHidden_forTest(id)); uow.commit(); - ASSERT(!wtrs->isCappedHidden(id)); + ASSERT(wtrs->isOpHidden_forTest(id)); } } @@ -626,14 +308,14 @@ TEST(WiredTigerRecordStoreTest, OplogDurableVisibilityOutOfOrder) { WTPausePrimaryOplogDurabilityLoop.setMode(FailPoint::alwaysOn); unique_ptr<RecordStoreHarnessHelper> harnessHelper(newRecordStoreHarnessHelper()); - unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("local.oplog.foo", 100000, -1)); + unique_ptr<RecordStore> rs(harnessHelper->newCappedRecordStore("local.oplog.rs", 100000, -1)); auto wtrs = checked_cast<WiredTigerRecordStore*>(rs.get()); ServiceContext::UniqueOperationContext longLivedOp(harnessHelper->newOperationContext()); WriteUnitOfWork uow(longLivedOp.get()); RecordId id1 = _oplogOrderInsertOplog(longLivedOp.get(), rs, 1); - ASSERT(wtrs->isCappedHidden(id1)); + ASSERT(wtrs->isOpHidden_forTest(id1)); RecordId id2; @@ -643,29 +325,29 @@ TEST(WiredTigerRecordStoreTest, OplogDurableVisibilityOutOfOrder) { harnessHelper->newOperationContext(innerClient.get())); WriteUnitOfWork uow(opCtx.get()); id2 = _oplogOrderInsertOplog(opCtx.get(), rs, 2); - ASSERT(wtrs->isCappedHidden(id2)); + ASSERT(wtrs->isOpHidden_forTest(id2)); uow.commit(); } - ASSERT(wtrs->isCappedHidden(id1)); - ASSERT(wtrs->isCappedHidden(id2)); + ASSERT(wtrs->isOpHidden_forTest(id1)); + ASSERT(wtrs->isOpHidden_forTest(id2)); uow.commit(); - ASSERT(wtrs->isCappedHidden(id1)); - ASSERT(wtrs->isCappedHidden(id2)); + ASSERT(wtrs->isOpHidden_forTest(id1)); + ASSERT(wtrs->isOpHidden_forTest(id2)); // Wait a bit and check again to make sure they don't become visible automatically. sleepsecs(1); - ASSERT(wtrs->isCappedHidden(id1)); - ASSERT(wtrs->isCappedHidden(id2)); + ASSERT(wtrs->isOpHidden_forTest(id1)); + ASSERT(wtrs->isOpHidden_forTest(id2)); WTPausePrimaryOplogDurabilityLoop.setMode(FailPoint::off); rs->waitForAllEarlierOplogWritesToBeVisible(longLivedOp.get()); - ASSERT(!wtrs->isCappedHidden(id1)); - ASSERT(!wtrs->isCappedHidden(id2)); + ASSERT(!wtrs->isOpHidden_forTest(id1)); + ASSERT(!wtrs->isOpHidden_forTest(id2)); } TEST(WiredTigerRecordStoreTest, AppendCustomStatsMetadata) { @@ -963,6 +645,9 @@ TEST(WiredTigerRecordStoreTest, OplogStones_CappedTruncateAfter) { ASSERT_EQ(300, oplogStones->currentBytes()); } + // Make sure all are visible. + rs->waitForAllEarlierOplogWritesToBeVisible(harnessHelper->newOperationContext().get()); + // Truncate data using an inclusive RecordId that exists inside the stone currently being // filled. { |