diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2021-02-23 11:15:51 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-23 19:13:50 +0000 |
commit | 8b9744aea1d1bde164d0b0fcf6d184ec5161013f (patch) | |
tree | 21ccc0716218f3c13f45b5e3848a04cabbb5cc41 | |
parent | 326d18d539d19a38df09e77c188401eadf62a25e (diff) | |
download | mongo-8b9744aea1d1bde164d0b0fcf6d184ec5161013f.tar.gz |
SERVER-52833 Perform capped deletes during startup recovery on documents inserted earlier in startup recovery
10 files changed, 442 insertions, 307 deletions
diff --git a/jstests/noPassthrough/capped_deletes_within_rollback.js b/jstests/noPassthrough/capped_deletes_within_rollback.js new file mode 100644 index 00000000000..7cf8c3235f3 --- /dev/null +++ b/jstests/noPassthrough/capped_deletes_within_rollback.js @@ -0,0 +1,39 @@ +/** + * Tests that capped deletes occur during rollback on documents inserted earlier in rollback. + * + * @tags: [ + * requires_replication, + * ] + */ +(function() { +'use strict'; + +load('jstests/replsets/libs/rollback_test.js'); + +const rollbackTest = new RollbackTest(jsTestName()); + +const testDB = function() { + return rollbackTest.getPrimary().getDB('test'); +}; + +const coll = function() { + return testDB().getCollection(jsTestName()); +}; + +assert.commandWorked( + testDB().createCollection(coll().getName(), {capped: true, size: 100, max: 1})); +assert.commandWorked(coll().insert({a: 1})); + +rollbackTest.transitionToRollbackOperations(); +rollbackTest.transitionToSyncSourceOperationsBeforeRollback(); + +assert.commandWorked(coll().insert([{b: 1}, {b: 2}])); + +rollbackTest.transitionToSyncSourceOperationsDuringRollback(); +rollbackTest.transitionToSteadyStateOperations(); + +// Stopping the test fixture runs validate with {enforceFastCount: true}. This will cause collection +// validation to fail if rollback did not perform capped deletes on documents that were inserted +// earlier in rollback. +rollbackTest.stop(); +})();
\ No newline at end of file diff --git a/jstests/noPassthrough/capped_deletes_within_startup_recovery.js b/jstests/noPassthrough/capped_deletes_within_startup_recovery.js new file mode 100644 index 00000000000..9087dfebe67 --- /dev/null +++ b/jstests/noPassthrough/capped_deletes_within_startup_recovery.js @@ -0,0 +1,35 @@ +/** + * Tests that capped deletes occur during statup recovery on documents inserted earlier in startup + * recovery. + * + * @tags: [ + * requires_replication, + * ] + */ +(function() { +'use strict'; + +load('jstests/libs/fail_point_util.js'); + +const replTest = new ReplSetTest({nodes: 1}); +replTest.startSet(); +replTest.initiate(); + +const primary = replTest.getPrimary(); +const testDB = primary.getDB('test'); +const coll = testDB.getCollection(jsTestName()); + +assert.commandWorked(testDB.createCollection(coll.getName(), {capped: true, size: 100, max: 1})); + +const ts = assert.commandWorked(testDB.runCommand({insert: coll.getName(), documents: [{a: 1}]})) + .operationTime; +configureFailPoint(primary, 'holdStableTimestampAtSpecificTimestamp', {timestamp: ts}); + +assert.commandWorked(coll.insert([{b: 1}, {b: 2}])); +replTest.restart(primary); + +// Stopping the test fixture runs validate with {enforceFastCount: true}. This will cause collection +// validation to fail if startup recovery did not perform capped deletes on documents that were +// inserted earlier in startup recovery. +replTest.stopSet(); +})();
\ No newline at end of file diff --git a/src/mongo/db/server_recovery.h b/src/mongo/db/server_recovery.h index 52f9858ce4d..2d6d64206fd 100644 --- a/src/mongo/db/server_recovery.h +++ b/src/mongo/db/server_recovery.h @@ -81,7 +81,7 @@ public: private: mutable Mutex _mutex = MONGO_MAKE_LATCH("SizeRecoveryState::_mutex"); - std::set<std::string> _collectionsAlwaysNeedingSizeAdjustment; + StringSet _collectionsAlwaysNeedingSizeAdjustment; }; /** diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_kv_engine_test.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_kv_engine_test.cpp index 76c5c843ff9..9ba140533fd 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_kv_engine_test.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_kv_engine_test.cpp @@ -44,13 +44,11 @@ namespace mongo { namespace ephemeral_for_test { -class KVHarnessHelper : public mongo::KVHarnessHelper, public ScopedGlobalServiceContextForTest { +class KVHarnessHelper : public mongo::KVHarnessHelper { public: - KVHarnessHelper() { - invariant(hasGlobalServiceContext()); - _engine = std::make_unique<KVEngine>(); + KVHarnessHelper(ServiceContext* svcCtx) : _engine(std::make_unique<KVEngine>()) { repl::ReplicationCoordinator::set( - getGlobalServiceContext(), + svcCtx, std::unique_ptr<repl::ReplicationCoordinator>(new repl::ReplicationCoordinatorMock( getGlobalServiceContext(), repl::ReplSettings()))); } @@ -67,17 +65,17 @@ private: std::unique_ptr<KVEngine> _engine; }; -std::unique_ptr<mongo::KVHarnessHelper> makeHelper() { - return std::make_unique<KVHarnessHelper>(); +std::unique_ptr<mongo::KVHarnessHelper> makeHelper(ServiceContext* svcCtx) { + return std::make_unique<KVHarnessHelper>(svcCtx); } MONGO_INITIALIZER(RegisterEphemeralForTestKVHarnessFactory)(InitializerContext*) { KVHarnessHelper::registerFactory(makeHelper); } -class EphemeralForTestKVEngineTest : public unittest::Test { +class EphemeralForTestKVEngineTest : public ServiceContextTest { public: - EphemeralForTestKVEngineTest() : _helper(), _engine(_helper.getEngine()) {} + EphemeralForTestKVEngineTest() : _helper(getServiceContext()), _engine(_helper.getEngine()) {} protected: std::unique_ptr<KVHarnessHelper> helper; diff --git a/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp b/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp index d5a2594b37c..e7cdf744c35 100644 --- a/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp +++ b/src/mongo/db/storage/kv/durable_catalog_feature_tracker_test.cpp @@ -34,6 +34,7 @@ #include <memory> #include "mongo/db/operation_context_noop.h" +#include "mongo/db/service_context_test_fixture.h" #include "mongo/db/storage/durable_catalog_feature_tracker.h" #include "mongo/db/storage/kv/kv_engine.h" #include "mongo/db/storage/record_store.h" @@ -47,7 +48,7 @@ using NonRepairableFeatureMask = DurableCatalogImpl::FeatureTracker::NonRepairab using RepairableFeature = DurableCatalogImpl::FeatureTracker::RepairableFeature; using RepairableFeatureMask = DurableCatalogImpl::FeatureTracker::RepairableFeatureMask; -class DurableCatalogFeatureTrackerTest : public unittest::Test { +class DurableCatalogFeatureTrackerTest : public ServiceContextTest { public: static const NonRepairableFeature kNonRepairableFeature1 = static_cast<NonRepairableFeature>(1 << 0); @@ -64,10 +65,15 @@ public: static const RepairableFeature kRepairableFeature3 = static_cast<RepairableFeature>(1 << 2); - DurableCatalogFeatureTrackerTest() : _helper(KVHarnessHelper::create()) {} + DurableCatalogFeatureTrackerTest() : _helper(KVHarnessHelper::create(getServiceContext())) {} - std::unique_ptr<OperationContext> newOperationContext() { - return std::make_unique<OperationContextNoop>(_helper->getEngine()->newRecoveryUnit()); + ServiceContext::UniqueOperationContext newOperationContext() { + auto opCtx = makeOperationContext(); + opCtx->setRecoveryUnit( + std::unique_ptr<RecoveryUnit>(_helper->getEngine()->newRecoveryUnit()), + WriteUnitOfWork::RecoveryUnitState::kNotInUnitOfWork); + opCtx->swapLockState(std::make_unique<LockerNoop>(), WithLock::withoutLock()); + return opCtx; } void setUp() final { diff --git a/src/mongo/db/storage/kv/kv_engine_test_harness.cpp b/src/mongo/db/storage/kv/kv_engine_test_harness.cpp index 54e3c8a8e86..093bca82166 100644 --- a/src/mongo/db/storage/kv/kv_engine_test_harness.cpp +++ b/src/mongo/db/storage/kv/kv_engine_test_harness.cpp @@ -32,6 +32,7 @@ #include "mongo/db/catalog/collection_impl.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/operation_context_noop.h" +#include "mongo/db/service_context_test_fixture.h" #include "mongo/db/storage/durable_catalog_impl.h" #include "mongo/db/storage/kv/kv_engine.h" #include "mongo/db/storage/record_store.h" @@ -61,10 +62,10 @@ public: ServiceContext::UniqueOperationContext _opCtx; }; -class DurableCatalogImplTest : public unittest::Test { +class DurableCatalogImplTest : public ServiceContextTest { protected: void setUp() override { - helper = KVHarnessHelper::create(); + helper = KVHarnessHelper::create(getServiceContext()); invariant(hasGlobalServiceContext()); } @@ -115,56 +116,82 @@ protected: namespace { -std::function<std::unique_ptr<KVHarnessHelper>()> basicFactory = - []() -> std::unique_ptr<KVHarnessHelper> { fassertFailed(40355); }; +std::function<std::unique_ptr<KVHarnessHelper>(ServiceContext*)> basicFactory = + [](ServiceContext*) -> std::unique_ptr<KVHarnessHelper> { fassertFailed(40355); }; -class MyOperationContext : public OperationContextNoop { -public: - MyOperationContext(KVEngine* engine) : OperationContextNoop(engine->newRecoveryUnit()) {} +class KVEngineTestHarness : public ServiceContextTest { +protected: + ServiceContext::UniqueOperationContext _makeOperationContext(KVEngine* engine) { + auto opCtx = makeOperationContext(); + opCtx->setRecoveryUnit(std::unique_ptr<RecoveryUnit>(engine->newRecoveryUnit()), + WriteUnitOfWork::RecoveryUnitState::kNotInUnitOfWork); + opCtx->swapLockState(std::make_unique<LockerNoop>(), WithLock::withoutLock()); + return opCtx; + } + + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + _makeOperationContexts(KVEngine* engine, unsigned num) { + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + opCtxs; + opCtxs.reserve(num); + + for (unsigned i = 0; i < num; ++i) { + auto client = getServiceContext()->makeClient(std::to_string(i)); + + auto opCtx = client->makeOperationContext(); + opCtx->setRecoveryUnit(std::unique_ptr<RecoveryUnit>(engine->newRecoveryUnit()), + WriteUnitOfWork::RecoveryUnitState::kNotInUnitOfWork); + opCtx->swapLockState(std::make_unique<LockerNoop>(), WithLock::withoutLock()); + + opCtxs.emplace_back(std::move(client), std::move(opCtx)); + } + + return opCtxs; + } }; const std::unique_ptr<ClockSource> clock = std::make_unique<ClockSourceMock>(); -TEST(KVEngineTestHarness, SimpleRS1) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, SimpleRS1) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); ASSERT(engine); std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } RecordId loc; { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - StatusWith<RecordId> res = rs->insertRecord(&opCtx, "abc", 4, Timestamp()); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + StatusWith<RecordId> res = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp()); ASSERT_OK(res.getStatus()); loc = res.getValue(); uow.commit(); } { - MyOperationContext opCtx(engine); - ASSERT_EQUALS(std::string("abc"), rs->dataFor(&opCtx, loc).data()); + auto opCtx = _makeOperationContext(engine); + ASSERT_EQUALS(std::string("abc"), rs->dataFor(opCtx.get(), loc).data()); } { - MyOperationContext opCtx(engine); - std::vector<std::string> all = engine->getAllIdents(&opCtx); + auto opCtx = _makeOperationContext(engine); + std::vector<std::string> all = engine->getAllIdents(opCtx.get()); ASSERT_EQUALS(1U, all.size()); ASSERT_EQUALS(ns, all[0]); } } -TEST(KVEngineTestHarness, Restart1) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, Restart1) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); ASSERT(engine); @@ -175,24 +202,24 @@ TEST(KVEngineTestHarness, Restart1) { { std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - StatusWith<RecordId> res = rs->insertRecord(&opCtx, "abc", 4, Timestamp()); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + StatusWith<RecordId> res = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp()); ASSERT_OK(res.getStatus()); loc = res.getValue(); uow.commit(); } { - MyOperationContext opCtx(engine); - ASSERT_EQUALS(std::string("abc"), rs->dataFor(&opCtx, loc).data()); + auto opCtx = _makeOperationContext(engine); + ASSERT_EQUALS(std::string("abc"), rs->dataFor(opCtx.get(), loc).data()); } } @@ -200,15 +227,15 @@ TEST(KVEngineTestHarness, Restart1) { { std::unique_ptr<RecordStore> rs; - MyOperationContext opCtx(engine); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); - ASSERT_EQUALS(std::string("abc"), rs->dataFor(&opCtx, loc).data()); + auto opCtx = _makeOperationContext(engine); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); + ASSERT_EQUALS(std::string("abc"), rs->dataFor(opCtx.get(), loc).data()); } } -TEST(KVEngineTestHarness, SimpleSorted1) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, SimpleSorted1) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); ASSERT(engine); @@ -217,20 +244,21 @@ TEST(KVEngineTestHarness, SimpleSorted1) { std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - ASSERT_OK(engine->createRecordStore(&opCtx, "catalog", "catalog", CollectionOptions())); - rs = engine->getRecordStore(&opCtx, "catalog", "catalog", CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + ASSERT_OK( + engine->createRecordStore(opCtx.get(), "catalog", "catalog", CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), "catalog", "catalog", CollectionOptions()); uow.commit(); } std::unique_ptr<Collection> collection; { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - collection = - std::make_unique<CollectionImpl>(&opCtx, ns, RecordId(0), UUID::gen(), std::move(rs)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + collection = std::make_unique<CollectionImpl>( + opCtx.get(), ns, RecordId(0), UUID::gen(), std::move(rs)); uow.commit(); } @@ -239,86 +267,89 @@ TEST(KVEngineTestHarness, SimpleSorted1) { << BSON("a" << 1))); std::unique_ptr<SortedDataInterface> sorted; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createSortedDataInterface(&opCtx, CollectionOptions(), ident, &desc)); - sorted = engine->getSortedDataInterface(&opCtx, CollectionOptions(), ident, &desc); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK( + engine->createSortedDataInterface(opCtx.get(), CollectionOptions(), ident, &desc)); + sorted = engine->getSortedDataInterface(opCtx.get(), CollectionOptions(), ident, &desc); ASSERT(sorted); } { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); const RecordId recordId(6, 4); const KeyString::Value keyString = KeyString::HeapBuilder( sorted->getKeyStringVersion(), BSON("" << 5), sorted->getOrdering(), recordId) .release(); - ASSERT_OK(sorted->insert(&opCtx, keyString, true)); + ASSERT_OK(sorted->insert(opCtx.get(), keyString, true)); uow.commit(); } { - MyOperationContext opCtx(engine); - ASSERT_EQUALS(1, sorted->numEntries(&opCtx)); + auto opCtx = _makeOperationContext(engine); + ASSERT_EQUALS(1, sorted->numEntries(opCtx.get())); } } -TEST(KVEngineTestHarness, TemporaryRecordStoreSimple) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, TemporaryRecordStoreSimple) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); ASSERT(engine); std::string ident = "temptemp"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - rs = engine->makeTemporaryRecordStore(&opCtx, ident); + auto opCtx = _makeOperationContext(engine); + rs = engine->makeTemporaryRecordStore(opCtx.get(), ident); ASSERT(rs); } RecordId loc; { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - StatusWith<RecordId> res = rs->insertRecord(&opCtx, "abc", 4, Timestamp()); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + StatusWith<RecordId> res = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp()); ASSERT_OK(res.getStatus()); loc = res.getValue(); uow.commit(); } { - MyOperationContext opCtx(engine); - ASSERT_EQUALS(std::string("abc"), rs->dataFor(&opCtx, loc).data()); + auto opCtx = _makeOperationContext(engine); + ASSERT_EQUALS(std::string("abc"), rs->dataFor(opCtx.get(), loc).data()); - std::vector<std::string> all = engine->getAllIdents(&opCtx); + std::vector<std::string> all = engine->getAllIdents(opCtx.get()); ASSERT_EQUALS(1U, all.size()); ASSERT_EQUALS(ident, all[0]); - WriteUnitOfWork wuow(&opCtx); - ASSERT_OK(engine->dropIdent(opCtx.recoveryUnit(), ident)); + WriteUnitOfWork wuow(opCtx.get()); + ASSERT_OK(engine->dropIdent(opCtx->recoveryUnit(), ident)); wuow.commit(); } } -TEST(KVEngineTestHarness, AllDurableTimestamp) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, AllDurableTimestamp) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); CollectionOptions options; options.capped = true; options.cappedSize = 10240; options.cappedMaxDocs = -1; NamespaceString oplogNss("local.oplog.rs"); - ASSERT_OK(engine->createRecordStore(&opCtx, oplogNss.ns(), "ident", options)); - rs = engine->getRecordStore(&opCtx, oplogNss.ns(), "ident", options); + ASSERT_OK(engine->createRecordStore(opCtx.get(), oplogNss.ns(), "ident", options)); + rs = engine->getRecordStore(opCtx.get(), oplogNss.ns(), "ident", options); ASSERT(rs); } { + auto opCtxs = _makeOperationContexts(engine, 2); + Timestamp t11(1, 1); Timestamp t12(1, 2); Timestamp t21(2, 1); @@ -328,10 +359,10 @@ TEST(KVEngineTestHarness, AllDurableTimestamp) { auto t21Doc = BSON("ts" << t21); Timestamp allDurable = engine->getAllDurableTimestamp(); - MyOperationContext opCtx1(engine); - WriteUnitOfWork uow1(&opCtx1); + auto opCtx1 = opCtxs[0].second.get(); + WriteUnitOfWork uow1(opCtx1); ASSERT_EQ(invariant(rs->insertRecord( - &opCtx1, t11Doc.objdata(), t11Doc.objsize(), Timestamp::min())), + opCtx1, t11Doc.objdata(), t11Doc.objsize(), Timestamp::min())), RecordId(1, 1)); Timestamp lastAllDurable = allDurable; @@ -339,10 +370,10 @@ TEST(KVEngineTestHarness, AllDurableTimestamp) { ASSERT_GTE(allDurable, lastAllDurable); ASSERT_LT(allDurable, t11); - MyOperationContext opCtx2(engine); - WriteUnitOfWork uow2(&opCtx2); + auto opCtx2 = opCtxs[1].second.get(); + WriteUnitOfWork uow2(opCtx2); ASSERT_EQ(invariant(rs->insertRecord( - &opCtx2, t21Doc.objdata(), t21Doc.objsize(), Timestamp::min())), + opCtx2, t21Doc.objdata(), t21Doc.objsize(), Timestamp::min())), RecordId(2, 1)); uow2.commit(); @@ -352,7 +383,7 @@ TEST(KVEngineTestHarness, AllDurableTimestamp) { ASSERT_LT(allDurable, t11); ASSERT_EQ(invariant(rs->insertRecord( - &opCtx1, t12Doc.objdata(), t12Doc.objsize(), Timestamp::min())), + opCtx1, t12Doc.objdata(), t12Doc.objsize(), Timestamp::min())), RecordId(1, 2)); lastAllDurable = allDurable; @@ -387,8 +418,8 @@ TEST(KVEngineTestHarness, AllDurableTimestamp) { * | Rollback | | * | | Rollback | */ -TEST(KVEngineTestHarness, PinningOldestWithAnotherSession) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, PinningOldestWithAnotherSession) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -397,42 +428,44 @@ TEST(KVEngineTestHarness, PinningOldestWithAnotherSession) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } - MyOperationContext opCtx1(engine); - WriteUnitOfWork uow1(&opCtx1); - StatusWith<RecordId> res = rs->insertRecord(&opCtx1, "abc", 4, Timestamp(10, 10)); + auto opCtxs = _makeOperationContexts(engine, 2); + + auto opCtx1 = opCtxs[0].second.get(); + WriteUnitOfWork uow1(opCtx1); + StatusWith<RecordId> res = rs->insertRecord(opCtx1, "abc", 4, Timestamp(10, 10)); RecordId rid = res.getValue(); uow1.commit(); RecordData rd; - opCtx1.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - Timestamp(15, 15)); + opCtx1->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + Timestamp(15, 15)); - MyOperationContext opCtx2(engine); - WriteUnitOfWork uow2(&opCtx2); + auto opCtx2 = opCtxs[1].second.get(); + WriteUnitOfWork uow2(opCtx2); - ASSERT(rs->findRecord(&opCtx1, rid, &rd)); - ASSERT_OK(opCtx2.recoveryUnit()->setTimestamp(Timestamp(20, 20))); - ASSERT_OK(rs->updateRecord(&opCtx2, rid, "updated", 8)); + ASSERT(rs->findRecord(opCtx1, rid, &rd)); + ASSERT_OK(opCtx2->recoveryUnit()->setTimestamp(Timestamp(20, 20))); + ASSERT_OK(rs->updateRecord(opCtx2, rid, "updated", 8)); - ASSERT(rs->findRecord(&opCtx1, rid, &rd)); + ASSERT(rs->findRecord(opCtx1, rid, &rd)); ASSERT_EQUALS(std::string("abc"), rd.data()); uow2.commit(); - opCtx1.recoveryUnit()->abandonSnapshot(); - ASSERT(rs->findRecord(&opCtx1, rid, &rd)); + opCtx1->recoveryUnit()->abandonSnapshot(); + ASSERT(rs->findRecord(opCtx1, rid, &rd)); ASSERT_EQUALS(std::string("abc"), rd.data()); - opCtx2.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - Timestamp(15, 15)); - ASSERT(rs->findRecord(&opCtx2, rid, &rd)); + opCtx2->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + Timestamp(15, 15)); + ASSERT(rs->findRecord(opCtx2, rid, &rd)); ASSERT_EQUALS(std::string("abc"), rd.data()); } @@ -456,29 +489,31 @@ TEST(KVEngineTestHarness, PinningOldestWithAnotherSession) { * | Timestamp :commit 25 | | | * | | | QueryTimestamp :all_durable (30) | */ -TEST(KVEngineTestHarness, AllDurable) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, AllDurable) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } { + auto opCtxs = _makeOperationContexts(engine, 4); + const Timestamp kInsertTimestamp1 = Timestamp(10, 10); const Timestamp kInsertTimestamp2 = Timestamp(20, 20); const Timestamp kInsertTimestamp3 = Timestamp(30, 30); const Timestamp kInsertTimestamp4 = Timestamp(25, 25); Timestamp allDurable = engine->getAllDurableTimestamp(); - MyOperationContext opCtx1(engine); - WriteUnitOfWork uow1(&opCtx1); - auto swRid = rs->insertRecord(&opCtx1, "abc", 4, kInsertTimestamp1); + auto opCtx1 = opCtxs[0].second.get(); + WriteUnitOfWork uow1(opCtx1); + auto swRid = rs->insertRecord(opCtx1, "abc", 4, kInsertTimestamp1); ASSERT_OK(swRid); uow1.commit(); @@ -487,9 +522,9 @@ TEST(KVEngineTestHarness, AllDurable) { ASSERT_GTE(allDurable, lastAllDurable); ASSERT_LTE(allDurable, kInsertTimestamp1); - MyOperationContext opCtx2(engine); - WriteUnitOfWork uow2(&opCtx2); - swRid = rs->insertRecord(&opCtx2, "abc", 4, kInsertTimestamp2); + auto opCtx2 = opCtxs[1].second.get(); + WriteUnitOfWork uow2(opCtx2); + swRid = rs->insertRecord(opCtx2, "abc", 4, kInsertTimestamp2); ASSERT_OK(swRid); lastAllDurable = allDurable; @@ -497,9 +532,9 @@ TEST(KVEngineTestHarness, AllDurable) { ASSERT_GTE(allDurable, lastAllDurable); ASSERT_LT(allDurable, kInsertTimestamp2); - MyOperationContext opCtx3(engine); - WriteUnitOfWork uow3(&opCtx3); - swRid = rs->insertRecord(&opCtx3, "abc", 4, kInsertTimestamp3); + auto opCtx3 = opCtxs[2].second.get(); + WriteUnitOfWork uow3(opCtx3); + swRid = rs->insertRecord(opCtx3, "abc", 4, kInsertTimestamp3); ASSERT_OK(swRid); uow3.commit(); @@ -515,9 +550,9 @@ TEST(KVEngineTestHarness, AllDurable) { ASSERT_GTE(allDurable, lastAllDurable); ASSERT_LTE(allDurable, kInsertTimestamp3); - MyOperationContext opCtx4(engine); - WriteUnitOfWork uow4(&opCtx4); - swRid = rs->insertRecord(&opCtx4, "abc", 4, kInsertTimestamp4); + auto opCtx4 = opCtxs[3].second.get(); + WriteUnitOfWork uow4(opCtx4); + swRid = rs->insertRecord(opCtx4, "abc", 4, kInsertTimestamp4); ASSERT_OK(swRid); lastAllDurable = allDurable; @@ -543,8 +578,8 @@ TEST(KVEngineTestHarness, AllDurable) { * | Begin :readAt 10 | * | Read A (1) | */ -TEST(KVEngineTestHarness, BasicTimestampSingle) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, BasicTimestampSingle) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -553,28 +588,30 @@ TEST(KVEngineTestHarness, BasicTimestampSingle) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } const Timestamp kReadTimestamp = Timestamp(9, 9); const Timestamp kInsertTimestamp = Timestamp(10, 10); + auto opCtxs = _makeOperationContexts(engine, 2); + // Start a read transaction. - MyOperationContext opCtx1(engine); + auto opCtx1 = opCtxs[0].second.get(); - opCtx1.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - kReadTimestamp); - ASSERT(!rs->findRecord(&opCtx1, RecordId::minLong(), nullptr)); + opCtx1->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + kReadTimestamp); + ASSERT(!rs->findRecord(opCtx1, RecordId::minLong(), nullptr)); // Insert a record at a later time. RecordId rid; { - MyOperationContext opCtx2(engine); - WriteUnitOfWork wuow(&opCtx2); - auto swRid = rs->insertRecord(&opCtx2, "abc", 4, kInsertTimestamp); + auto opCtx2 = opCtxs[1].second.get(); + WriteUnitOfWork wuow(opCtx2); + auto swRid = rs->insertRecord(opCtx2, "abc", 4, kInsertTimestamp); ASSERT_OK(swRid); rid = swRid.getValue(); wuow.commit(); @@ -582,16 +619,16 @@ TEST(KVEngineTestHarness, BasicTimestampSingle) { // Should not see the record, even if we abandon the snapshot as the read timestamp is still // earlier than the insert timestamp. - ASSERT(!rs->findRecord(&opCtx1, rid, nullptr)); - opCtx1.recoveryUnit()->abandonSnapshot(); - ASSERT(!rs->findRecord(&opCtx1, rid, nullptr)); + ASSERT(!rs->findRecord(opCtx1, rid, nullptr)); + opCtx1->recoveryUnit()->abandonSnapshot(); + ASSERT(!rs->findRecord(opCtx1, rid, nullptr)); - opCtx1.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - kInsertTimestamp); - opCtx1.recoveryUnit()->abandonSnapshot(); + opCtx1->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + kInsertTimestamp); + opCtx1->recoveryUnit()->abandonSnapshot(); RecordData rd; - ASSERT(rs->findRecord(&opCtx1, rid, &rd)); + ASSERT(rs->findRecord(opCtx1, rid, &rd)); ASSERT_EQ(std::string("abc"), rd.data()); } @@ -613,8 +650,8 @@ TEST(KVEngineTestHarness, BasicTimestampSingle) { * | Begin :readAt 20 | * | Read A (2) | */ -TEST(KVEngineTestHarness, BasicTimestampMultiple) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, BasicTimestampMultiple) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -623,9 +660,9 @@ TEST(KVEngineTestHarness, BasicTimestampMultiple) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } @@ -635,28 +672,28 @@ TEST(KVEngineTestHarness, BasicTimestampMultiple) { RecordId rid; { // Initial insert of record. - MyOperationContext opCtx(engine); - WriteUnitOfWork wuow(&opCtx); - auto swRid = rs->insertRecord(&opCtx, "abc", 4, t10); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork wuow(opCtx.get()); + auto swRid = rs->insertRecord(opCtx.get(), "abc", 4, t10); ASSERT_OK(swRid); rid = swRid.getValue(); // Update a record at a later time. - ASSERT_OK(opCtx.recoveryUnit()->setTimestamp(t20)); - auto res = rs->updateRecord(&opCtx, rid, "updated", 8); + ASSERT_OK(opCtx->recoveryUnit()->setTimestamp(t20)); + auto res = rs->updateRecord(opCtx.get(), rid, "updated", 8); ASSERT_OK(res); wuow.commit(); } RecordData rd; - MyOperationContext opCtx(engine); - opCtx.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t10); - ASSERT(rs->findRecord(&opCtx, rid, &rd)); + auto opCtx = _makeOperationContext(engine); + opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t10); + ASSERT(rs->findRecord(opCtx.get(), rid, &rd)); ASSERT_EQUALS(std::string("abc"), rd.data()); - opCtx.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t20); - opCtx.recoveryUnit()->abandonSnapshot(); - ASSERT(rs->findRecord(&opCtx, rid, &rd)); + opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t20); + opCtx->recoveryUnit()->abandonSnapshot(); + ASSERT(rs->findRecord(opCtx.get(), rid, &rd)); ASSERT_EQUALS(std::string("updated"), rd.data()); } @@ -672,8 +709,8 @@ TEST(KVEngineTestHarness, BasicTimestampMultiple) { * | | Abandon Snapshot | * | | Read A (1) | */ -TEST(KVEngineTestHarness, SingleReadWithConflict) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, SingleReadWithConflict) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -682,35 +719,37 @@ TEST(KVEngineTestHarness, SingleReadWithConflict) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } - MyOperationContext opCtx2(engine); - opCtx2.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - Timestamp(20, 20)); + auto opCtxs = _makeOperationContexts(engine, 2); + + auto opCtx2 = opCtxs[1].second.get(); + opCtx2->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + Timestamp(20, 20)); - MyOperationContext opCtx1(engine); - WriteUnitOfWork uow1(&opCtx1); - StatusWith<RecordId> res = rs->insertRecord(&opCtx1, "abc", 4, Timestamp(10, 10)); + auto opCtx1 = opCtxs[0].second.get(); + WriteUnitOfWork uow1(opCtx1); + StatusWith<RecordId> res = rs->insertRecord(opCtx1, "abc", 4, Timestamp(10, 10)); ASSERT_OK(res); RecordId loc = res.getValue(); // Cannot find record before commit. RecordData rd; - ASSERT(!rs->findRecord(&opCtx2, loc, &rd)); + ASSERT(!rs->findRecord(opCtx2, loc, &rd)); // Cannot find record after commit due to snapshot isolation. uow1.commit(); - ASSERT(!rs->findRecord(&opCtx2, loc, &rd)); + ASSERT(!rs->findRecord(opCtx2, loc, &rd)); // Abandon snapshot for visibility. - opCtx2.recoveryUnit()->abandonSnapshot(); + opCtx2->recoveryUnit()->abandonSnapshot(); - ASSERT(rs->findRecord(&opCtx2, loc, &rd)); - ASSERT_EQUALS(std::string("abc"), rs->dataFor(&opCtx2, loc).data()); + ASSERT(rs->findRecord(opCtx2, loc, &rd)); + ASSERT_EQUALS(std::string("abc"), rs->dataFor(opCtx2, loc).data()); } /* @@ -725,8 +764,8 @@ TEST(KVEngineTestHarness, SingleReadWithConflict) { * | Read A (NOT_FOUND) | * | Write A 1 (NOT_FOUND)| */ -DEATH_TEST_REGEX(KVEngineTestHarness, SnapshotHidesVisibility, ".*item not found.*") { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +DEATH_TEST_REGEX_F(KVEngineTestHarness, SnapshotHidesVisibility, ".*item not found.*") { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -735,29 +774,31 @@ DEATH_TEST_REGEX(KVEngineTestHarness, SnapshotHidesVisibility, ".*item not found std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } - MyOperationContext opCtx1(engine); - WriteUnitOfWork uow1(&opCtx1); - StatusWith<RecordId> res = rs->insertRecord(&opCtx1, "abc", 4, Timestamp(10, 10)); + auto opCtxs = _makeOperationContexts(engine, 2); + + auto opCtx1 = opCtxs[0].second.get(); + WriteUnitOfWork uow1(opCtx1); + StatusWith<RecordId> res = rs->insertRecord(opCtx1, "abc", 4, Timestamp(10, 10)); ASSERT_OK(res); RecordId loc = res.getValue(); uow1.commit(); // Snapshot was taken before the insert and will not find the record even after the commit. RecordData rd; - MyOperationContext opCtx2(engine); - opCtx2.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - Timestamp(9, 9)); - ASSERT(!rs->findRecord(&opCtx2, loc, &rd)); + auto opCtx2 = opCtxs[1].second.get(); + opCtx2->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + Timestamp(9, 9)); + ASSERT(!rs->findRecord(opCtx2, loc, &rd)); // Trying to write in an outdated snapshot will cause item not found. - WriteUnitOfWork uow2(&opCtx2); - auto swRid = rs->updateRecord(&opCtx2, loc, "updated", 8); + WriteUnitOfWork uow2(opCtx2); + auto swRid = rs->updateRecord(opCtx2, loc, "updated", 8); uow2.commit(); } @@ -780,8 +821,8 @@ DEATH_TEST_REGEX(KVEngineTestHarness, SnapshotHidesVisibility, ".*item not found * | Read A (1) | * | Read Oplog (FOUND) | */ -TEST(KVEngineTestHarness, SingleReadWithConflictWithOplog) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, SingleReadWithConflictWithOplog) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -791,9 +832,9 @@ TEST(KVEngineTestHarness, SingleReadWithConflictWithOplog) { std::unique_ptr<RecordStore> collectionRs; std::unique_ptr<RecordStore> oplogRs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - collectionRs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + collectionRs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(collectionRs); CollectionOptions options; @@ -802,8 +843,8 @@ TEST(KVEngineTestHarness, SingleReadWithConflictWithOplog) { options.cappedMaxDocs = -1; NamespaceString oplogNss("local.oplog.rs"); - ASSERT_OK(engine->createRecordStore(&opCtx, oplogNss.ns(), "ident", options)); - oplogRs = engine->getRecordStore(&opCtx, oplogNss.ns(), "ident", options); + ASSERT_OK(engine->createRecordStore(opCtx.get(), oplogNss.ns(), "ident", options)); + oplogRs = engine->getRecordStore(opCtx.get(), oplogNss.ns(), "ident", options); ASSERT(oplogRs); } @@ -813,11 +854,11 @@ TEST(KVEngineTestHarness, SingleReadWithConflictWithOplog) { const Timestamp t9(9, 9); const Timestamp t10(10, 10); { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); // Insert into collectionRs. - StatusWith<RecordId> res = collectionRs->insertRecord(&opCtx, "abc", 4, t10); + StatusWith<RecordId> res = collectionRs->insertRecord(opCtx.get(), "abc", 4, t10); ASSERT_OK(res); locCollection = res.getValue(); @@ -825,21 +866,21 @@ TEST(KVEngineTestHarness, SingleReadWithConflictWithOplog) { auto t11Doc = BSON("ts" << t10); ASSERT_EQ(invariant(oplogRs->insertRecord( - &opCtx, t11Doc.objdata(), t11Doc.objsize(), Timestamp::min())), + opCtx.get(), t11Doc.objdata(), t11Doc.objsize(), Timestamp::min())), RecordId(10, 10)); locOplog = RecordId(10, 10); uow.commit(); } - MyOperationContext opCtx(engine); - opCtx.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t9); - ASSERT(!collectionRs->findRecord(&opCtx, locCollection, &rd)); - ASSERT(!oplogRs->findRecord(&opCtx, locOplog, &rd)); + auto opCtx = _makeOperationContext(engine); + opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t9); + ASSERT(!collectionRs->findRecord(opCtx.get(), locCollection, &rd)); + ASSERT(!oplogRs->findRecord(opCtx.get(), locOplog, &rd)); - opCtx.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t10); - opCtx.recoveryUnit()->abandonSnapshot(); - ASSERT(collectionRs->findRecord(&opCtx, locCollection, &rd)); - ASSERT(oplogRs->findRecord(&opCtx, locOplog, &rd)); + opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, t10); + opCtx->recoveryUnit()->abandonSnapshot(); + ASSERT(collectionRs->findRecord(opCtx.get(), locCollection, &rd)); + ASSERT(oplogRs->findRecord(opCtx.get(), locOplog, &rd)); } /* @@ -857,8 +898,8 @@ TEST(KVEngineTestHarness, SingleReadWithConflictWithOplog) { * | Begin :readAt 15 | | * | Read A (DB exception) | | */ -TEST(KVEngineTestHarness, PinningOldestTimestampWithReadConflict) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, PinningOldestTimestampWithReadConflict) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -867,27 +908,28 @@ TEST(KVEngineTestHarness, PinningOldestTimestampWithReadConflict) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - StatusWith<RecordId> res = rs->insertRecord(&opCtx, "abc", 4, Timestamp(10, 10)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + StatusWith<RecordId> res = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp(10, 10)); RecordId rid = res.getValue(); uow.commit(); RecordData rd; - opCtx.recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, - Timestamp(15, 15)); - ASSERT(rs->findRecord(&opCtx, rid, &rd)); + opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, + Timestamp(15, 15)); + ASSERT(rs->findRecord(opCtx.get(), rid, &rd)); engine->setOldestTimestamp(Timestamp(20, 20), false); - opCtx.recoveryUnit()->abandonSnapshot(); - ASSERT_THROWS_CODE(rs->findRecord(&opCtx, rid, &rd), DBException, ErrorCodes::SnapshotTooOld); + opCtx->recoveryUnit()->abandonSnapshot(); + ASSERT_THROWS_CODE( + rs->findRecord(opCtx.get(), rid, &rd), DBException, ErrorCodes::SnapshotTooOld); } @@ -900,10 +942,10 @@ TEST(KVEngineTestHarness, PinningOldestTimestampWithReadConflict) { * | Write A 1 | | * | Commit :commit 2 (WCE) | | */ -DEATH_TEST_REGEX(KVEngineTestHarness, - PinningOldestTimestampWithWriteConflict, - ".*commit timestamp.*is less than the oldest timestamp.*") { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +DEATH_TEST_REGEX_F(KVEngineTestHarness, + PinningOldestTimestampWithWriteConflict, + ".*commit timestamp.*is less than the oldest timestamp.*") { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -912,18 +954,18 @@ DEATH_TEST_REGEX(KVEngineTestHarness, std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } { // A write transaction cannot insert records before the oldest timestamp. engine->setOldestTimestamp(Timestamp(2, 2), false); - MyOperationContext opCtx2(engine); - WriteUnitOfWork uow2(&opCtx2); - StatusWith<RecordId> res = rs->insertRecord(&opCtx2, "abc", 4, Timestamp(1, 1)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow2(opCtx.get()); + StatusWith<RecordId> res = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp(1, 1)); uow2.commit(); } } @@ -943,8 +985,8 @@ DEATH_TEST_REGEX(KVEngineTestHarness, * | Read A (1) | | * | Read B (NOT_FOUND) | | */ -TEST(KVEngineTestHarness, RollingBackToLastStable) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, RollingBackToLastStable) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -955,21 +997,21 @@ TEST(KVEngineTestHarness, RollingBackToLastStable) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } RecordId ridA; { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - auto res = rs->insertRecord(&opCtx, "abc", 4, Timestamp(1, 1)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + auto res = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp(1, 1)); ASSERT_OK(res); ridA = res.getValue(); uow.commit(); - ASSERT_EQUALS(1, rs->numRecords(&opCtx)); + ASSERT_EQUALS(1, rs->numRecords(opCtx.get())); } { @@ -981,38 +1023,38 @@ TEST(KVEngineTestHarness, RollingBackToLastStable) { ASSERT(!engine->getLastStableRecoveryTimestamp()); // Force a checkpoint to be taken. This should advance the last stable timestamp. - MyOperationContext opCtx(engine); - engine->flushAllFiles(&opCtx, false); + auto opCtx = _makeOperationContext(engine); + engine->flushAllFiles(opCtx.get(), false); ASSERT_EQ(engine->getLastStableRecoveryTimestamp(), Timestamp(1, 1)); } RecordId ridB; { // Insert a record after the stable timestamp. - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - StatusWith<RecordId> swRid = rs->insertRecord(&opCtx, "def", 4, Timestamp(3, 3)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + StatusWith<RecordId> swRid = rs->insertRecord(opCtx.get(), "def", 4, Timestamp(3, 3)); ASSERT_OK(swRid); ridB = swRid.getValue(); - ASSERT_EQUALS(2, rs->numRecords(&opCtx)); + ASSERT_EQUALS(2, rs->numRecords(opCtx.get())); uow.commit(); } { // Rollback to the last stable timestamp. - MyOperationContext opCtx(engine); - StatusWith<Timestamp> swTimestamp = engine->recoverToStableTimestamp(&opCtx); + auto opCtx = _makeOperationContext(engine); + StatusWith<Timestamp> swTimestamp = engine->recoverToStableTimestamp(opCtx.get()); ASSERT_EQ(swTimestamp.getValue(), Timestamp(1, 1)); // Verify that we can find record A and can't find the record B inserted at Timestamp(3, 3) // in the collection any longer. 'numRecords' will still show two as it's the fast count and // doesn't get reflected during the rollback. RecordData rd; - opCtx.recoveryUnit()->abandonSnapshot(); - ASSERT(rs->findRecord(&opCtx, ridA, &rd)); + opCtx->recoveryUnit()->abandonSnapshot(); + ASSERT(rs->findRecord(opCtx.get(), ridA, &rd)); ASSERT_EQ(std::string("abc"), rd.data()); - ASSERT_FALSE(rs->findRecord(&opCtx, ridB, nullptr)); - ASSERT_EQUALS(2, rs->numRecords(&opCtx)); + ASSERT_FALSE(rs->findRecord(opCtx.get(), ridB, nullptr)); + ASSERT_EQUALS(2, rs->numRecords(opCtx.get())); } } @@ -1025,10 +1067,10 @@ TEST(KVEngineTestHarness, RollingBackToLastStable) { * | Write A 1 | | * | Timestamp :commit 1 (ROLLBACK) | | */ -DEATH_TEST_REGEX(KVEngineTestHarness, - CommitBehindStable, - ".*commit timestamp.*is less than the stable timestamp.*") { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +DEATH_TEST_REGEX_F(KVEngineTestHarness, + CommitBehindStable, + ".*commit timestamp.*is less than the stable timestamp.*") { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -1039,9 +1081,9 @@ DEATH_TEST_REGEX(KVEngineTestHarness, std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } @@ -1052,16 +1094,16 @@ DEATH_TEST_REGEX(KVEngineTestHarness, ASSERT(!engine->getLastStableRecoveryTimestamp()); // Force a checkpoint to be taken. This should advance the last stable timestamp. - MyOperationContext opCtx(engine); - engine->flushAllFiles(&opCtx, false); + auto opCtx = _makeOperationContext(engine); + engine->flushAllFiles(opCtx.get(), false); ASSERT_EQ(engine->getLastStableRecoveryTimestamp(), Timestamp(2, 2)); } { // Committing a behind the stable timestamp is not allowed. - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - auto swRid = rs->insertRecord(&opCtx, "abc", 4, Timestamp(1, 1)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + auto swRid = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp(1, 1)); uow.commit(); } } @@ -1075,8 +1117,8 @@ DEATH_TEST_REGEX(KVEngineTestHarness, * | Write A 1 | | * | Timestamp :commit 2 | | */ -TEST(KVEngineTestHarness, CommitAtStable) { - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); +TEST_F(KVEngineTestHarness, CommitAtStable) { + std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create(getServiceContext())); KVEngine* engine = helper->getEngine(); // TODO SERVER-48314: Remove after implementing correct behavior on biggie. if (engine->isEphemeral()) @@ -1087,9 +1129,9 @@ TEST(KVEngineTestHarness, CommitAtStable) { std::string ns = "a.b"; std::unique_ptr<RecordStore> rs; { - MyOperationContext opCtx(engine); - ASSERT_OK(engine->createRecordStore(&opCtx, ns, ns, CollectionOptions())); - rs = engine->getRecordStore(&opCtx, ns, ns, CollectionOptions()); + auto opCtx = _makeOperationContext(engine); + ASSERT_OK(engine->createRecordStore(opCtx.get(), ns, ns, CollectionOptions())); + rs = engine->getRecordStore(opCtx.get(), ns, ns, CollectionOptions()); ASSERT(rs); } @@ -1100,8 +1142,8 @@ TEST(KVEngineTestHarness, CommitAtStable) { ASSERT(!engine->getLastStableRecoveryTimestamp()); // Force a checkpoint to be taken. This should advance the last stable timestamp. - MyOperationContext opCtx(engine); - engine->flushAllFiles(&opCtx, false); + auto opCtx = _makeOperationContext(engine); + engine->flushAllFiles(opCtx.get(), false); ASSERT_EQ(engine->getLastStableRecoveryTimestamp(), Timestamp(2, 2)); } @@ -1109,9 +1151,9 @@ TEST(KVEngineTestHarness, CommitAtStable) { { // For a non-prepared transaction, the commit timestamp can be equal to the stable // timestamp. - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - auto swRid = rs->insertRecord(&opCtx, "abc", 4, Timestamp(2, 2)); + auto opCtx = _makeOperationContext(engine); + WriteUnitOfWork uow(opCtx.get()); + auto swRid = rs->insertRecord(opCtx.get(), "abc", 4, Timestamp(2, 2)); ASSERT_OK(swRid); rid = swRid.getValue(); uow.commit(); @@ -1119,15 +1161,15 @@ TEST(KVEngineTestHarness, CommitAtStable) { { // Rollback to the last stable timestamp. - MyOperationContext opCtx(engine); - StatusWith<Timestamp> swTimestamp = engine->recoverToStableTimestamp(&opCtx); + auto opCtx = _makeOperationContext(engine); + StatusWith<Timestamp> swTimestamp = engine->recoverToStableTimestamp(opCtx.get()); ASSERT_EQ(swTimestamp.getValue(), Timestamp(2, 2)); // Transaction with timestamps equal to lastStable will not be rolled back. - opCtx.recoveryUnit()->abandonSnapshot(); + opCtx->recoveryUnit()->abandonSnapshot(); RecordData data; - ASSERT_TRUE(rs->findRecord(&opCtx, rid, &data)); - ASSERT_EQUALS(1, rs->numRecords(&opCtx)); + ASSERT_TRUE(rs->findRecord(opCtx.get(), rid, &data)); + ASSERT_EQUALS(1, rs->numRecords(opCtx.get())); } } @@ -1478,11 +1520,12 @@ DEATH_TEST_REGEX_F(DurableCatalogImplTest, } // namespace -std::unique_ptr<KVHarnessHelper> KVHarnessHelper::create() { - return basicFactory(); +std::unique_ptr<KVHarnessHelper> KVHarnessHelper::create(ServiceContext* svcCtx) { + return basicFactory(svcCtx); }; -void KVHarnessHelper::registerFactory(std::function<std::unique_ptr<KVHarnessHelper>()> factory) { +void KVHarnessHelper::registerFactory( + std::function<std::unique_ptr<KVHarnessHelper>(ServiceContext*)> factory) { basicFactory = std::move(factory); }; diff --git a/src/mongo/db/storage/kv/kv_engine_test_harness.h b/src/mongo/db/storage/kv/kv_engine_test_harness.h index ed2f5d66d14..234c1462a6d 100644 --- a/src/mongo/db/storage/kv/kv_engine_test_harness.h +++ b/src/mongo/db/storage/kv/kv_engine_test_harness.h @@ -55,8 +55,9 @@ public: virtual KVEngine* restartEngine() = 0; - static std::unique_ptr<KVHarnessHelper> create(); - static void registerFactory(std::function<std::unique_ptr<KVHarnessHelper>()> factory); + static std::unique_ptr<KVHarnessHelper> create(ServiceContext* svcCtx); + static void registerFactory( + std::function<std::unique_ptr<KVHarnessHelper>(ServiceContext*)> factory); }; } // namespace mongo diff --git a/src/mongo/db/storage/kv/kv_engine_timestamps_test.cpp b/src/mongo/db/storage/kv/kv_engine_timestamps_test.cpp index 034bd0e0318..0fc5665be32 100644 --- a/src/mongo/db/storage/kv/kv_engine_timestamps_test.cpp +++ b/src/mongo/db/storage/kv/kv_engine_timestamps_test.cpp @@ -197,7 +197,7 @@ public: } void setUp() override { - helper = KVHarnessHelper::create(); + helper = KVHarnessHelper::create(getGlobalServiceContext()); engine = helper->getEngine(); snapshotManager = helper->getEngine()->getSnapshotManager(); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine_test.cpp index 49619f6cee8..ce2b7c15a13 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine_test.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine_test.cpp @@ -55,14 +55,13 @@ namespace mongo { namespace { -class WiredTigerKVHarnessHelper : public KVHarnessHelper, public ScopedGlobalServiceContextForTest { +class WiredTigerKVHarnessHelper : public KVHarnessHelper { public: - WiredTigerKVHarnessHelper(bool forRepair = false) + WiredTigerKVHarnessHelper(ServiceContext* svcCtx, bool forRepair = false) : _dbpath("wt-kv-harness"), _forRepair(forRepair), _engine(makeEngine()) { - auto context = getGlobalServiceContext(); repl::ReplicationCoordinator::set( - context, - std::make_unique<repl::ReplicationCoordinatorMock>(context, repl::ReplSettings())); + svcCtx, + std::make_unique<repl::ReplicationCoordinatorMock>(svcCtx, repl::ReplSettings())); _engine->notifyStartupComplete(); } @@ -100,16 +99,21 @@ private: std::unique_ptr<WiredTigerKVEngine> _engine; }; -class WiredTigerKVEngineTest : public unittest::Test, public ScopedGlobalServiceContextForTest { +class WiredTigerKVEngineTest : public ServiceContextTest { public: WiredTigerKVEngineTest(bool repair = false) - : _helper(repair), _engine(_helper.getWiredTigerKVEngine()) {} + : _helper(getServiceContext(), repair), _engine(_helper.getWiredTigerKVEngine()) {} - std::unique_ptr<OperationContext> makeOperationContext() { - return std::make_unique<OperationContextNoop>(_engine->newRecoveryUnit()); +protected: + ServiceContext::UniqueOperationContext _makeOperationContext() { + auto opCtx = makeOperationContext(); + opCtx->setRecoveryUnit( + std::unique_ptr<RecoveryUnit>(_helper.getEngine()->newRecoveryUnit()), + WriteUnitOfWork::RecoveryUnitState::kNotInUnitOfWork); + opCtx->swapLockState(std::make_unique<LockerNoop>(), WithLock::withoutLock()); + return opCtx; } -protected: WiredTigerKVHarnessHelper _helper; WiredTigerKVEngine* _engine; }; @@ -120,7 +124,7 @@ public: }; TEST_F(WiredTigerKVEngineRepairTest, OrphanedDataFilesCanBeRecovered) { - auto opCtxPtr = makeOperationContext(); + auto opCtxPtr = _makeOperationContext(); NamespaceString nss("a.b"); std::string ident = "collection-1234"; @@ -178,7 +182,7 @@ TEST_F(WiredTigerKVEngineRepairTest, OrphanedDataFilesCanBeRecovered) { } TEST_F(WiredTigerKVEngineRepairTest, UnrecoverableOrphanedDataFilesAreRebuilt) { - auto opCtxPtr = makeOperationContext(); + auto opCtxPtr = _makeOperationContext(); NamespaceString nss("a.b"); std::string ident = "collection-1234"; @@ -246,7 +250,7 @@ TEST_F(WiredTigerKVEngineTest, TestOplogTruncation) { std::unique_ptr<Checkpointer> checkpointer = std::make_unique<Checkpointer>(_engine); checkpointer->go(); - auto opCtxPtr = makeOperationContext(); + auto opCtxPtr = _makeOperationContext(); // The initial data timestamp has to be set to take stable checkpoints. The first stable // timestamp greater than this will also trigger a checkpoint. The following loop of the // CheckpointThread will observe the new `checkpointDelaySecs` value. @@ -351,7 +355,7 @@ TEST_F(WiredTigerKVEngineTest, IdentDrop) { return; #endif - auto opCtxPtr = makeOperationContext(); + auto opCtxPtr = _makeOperationContext(); NamespaceString nss("a.b"); std::string ident = "collection-1234"; @@ -392,7 +396,7 @@ TEST_F(WiredTigerKVEngineTest, IdentDrop) { } TEST_F(WiredTigerKVEngineTest, TestBasicPinOldestTimestamp) { - auto opCtxRaii = makeOperationContext(); + auto opCtxRaii = _makeOperationContext(); const Timestamp initTs = Timestamp(1, 0); // Initialize the oldest timestamp. @@ -433,7 +437,7 @@ TEST_F(WiredTigerKVEngineTest, TestBasicPinOldestTimestamp) { * of all active requests will be obeyed. */ TEST_F(WiredTigerKVEngineTest, TestMultiPinOldestTimestamp) { - auto opCtxRaii = makeOperationContext(); + auto opCtxRaii = _makeOperationContext(); const Timestamp initTs = Timestamp(1, 0); _engine->setOldestTimestamp(initTs, false); @@ -474,7 +478,7 @@ TEST_F(WiredTigerKVEngineTest, TestMultiPinOldestTimestamp) { * relative to the current oldest timestamp. */ TEST_F(WiredTigerKVEngineTest, TestPinOldestTimestampErrors) { - auto opCtxRaii = makeOperationContext(); + auto opCtxRaii = _makeOperationContext(); const Timestamp initTs = Timestamp(10, 0); _engine->setOldestTimestamp(initTs, false); @@ -497,8 +501,8 @@ TEST_F(WiredTigerKVEngineTest, TestPinOldestTimestampErrors) { } -std::unique_ptr<KVHarnessHelper> makeHelper() { - return std::make_unique<WiredTigerKVHarnessHelper>(); +std::unique_ptr<KVHarnessHelper> makeHelper(ServiceContext* svcCtx) { + return std::make_unique<WiredTigerKVHarnessHelper>(svcCtx); } MONGO_INITIALIZER(RegisterKVHarnessFactory)(InitializerContext*) { diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp index 001d26dab60..1a8814c009d 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp @@ -2073,6 +2073,15 @@ void WiredTigerRecordStore::_initNextIdIfNeeded(OperationContext* opCtx) { return; } + // During startup recovery, the collectionAlwaysNeedsSizeAdjustment flag is not set by default + // for the sake of efficiency. However, if we reach this point, we may need to set it in order + // to ensure that capped deletes can occur on documents inserted earlier in startup recovery. + if (inReplicationRecovery(opCtx->getServiceContext()) && + !sizeRecoveryState(opCtx->getServiceContext()) + .collectionAlwaysNeedsSizeAdjustment(getIdent())) { + checkSize(opCtx); + } + // Need to start at 1 so we are always higher than RecordId::minLong() int64_t nextId = 1; |