diff options
Diffstat (limited to 'src/mongo/dbtests')
38 files changed, 407 insertions, 763 deletions
diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript index 033d83b139b..9aea0a64976 100644 --- a/src/mongo/dbtests/SConscript +++ b/src/mongo/dbtests/SConscript @@ -32,7 +32,8 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/db/catalog/catalog_impl', '$BUILD_DIR/mongo/db/dbdirectclient', - '$BUILD_DIR/mongo/db/index/index_access_method', + '$BUILD_DIR/mongo/db/index/index_access_method_factory', + '$BUILD_DIR/mongo/db/index/index_access_methods', '$BUILD_DIR/mongo/db/index_builds_coordinator_mongod', '$BUILD_DIR/mongo/db/op_observer', '$BUILD_DIR/mongo/db/service_context_d', @@ -95,6 +96,7 @@ env.Program( 'mock_dbclient_conn_test.cpp', 'mock_replica_set_test.cpp', 'multikey_paths_test.cpp', + 'shared_buffer_test.cpp', 'pdfiletests.cpp', 'plan_executor_invalidation_test.cpp', 'plan_ranking.cpp', @@ -133,7 +135,6 @@ env.Program( ], LIBDEPS=[ "$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils", - '$BUILD_DIR/mongo/bson/util/bson_column', "$BUILD_DIR/mongo/client/clientdriver_network", "$BUILD_DIR/mongo/client/replica_set_monitor_protocol_test_util", "$BUILD_DIR/mongo/db/auth/authmongod", @@ -148,7 +149,7 @@ env.Program( "$BUILD_DIR/mongo/db/commands/test_commands_enabled", "$BUILD_DIR/mongo/db/concurrency/deferred_writer", "$BUILD_DIR/mongo/db/exec/document_value/document_value_test_util", - "$BUILD_DIR/mongo/db/index/index_access_method", + "$BUILD_DIR/mongo/db/index/index_access_methods", "$BUILD_DIR/mongo/db/logical_time_metadata_hook", "$BUILD_DIR/mongo/db/mongohasher", "$BUILD_DIR/mongo/db/multitenancy", diff --git a/src/mongo/dbtests/cursor_manager_test.cpp b/src/mongo/dbtests/cursor_manager_test.cpp index 52d543e9157..1cc8ee1f535 100644 --- a/src/mongo/dbtests/cursor_manager_test.cpp +++ b/src/mongo/dbtests/cursor_manager_test.cpp @@ -708,33 +708,6 @@ TEST_F(CursorManagerTestCustomOpCtx, MultipleCursorsMultipleOperationKeys) { ASSERT(cursors.find(cursor2) != cursors.end()); } -TEST_F(CursorManagerTestCustomOpCtx, MultipleCursorsSameOperationKey) { - auto opKey = UUID::gen(); - - auto opCtx = _queryServiceContext->makeOperationContext(); - opCtx->setOperationKey(opKey); - auto cursor1 = makeCursor(opCtx.get()).getCursor()->cursorid(); - auto cursor2 = makeCursor(opCtx.get()).getCursor()->cursorid(); - - // Retrieve cursors for operation key - should be both cursors. - auto cursors = useCursorManager()->getCursorsForOpKeys({opKey}); - ASSERT_EQ(cursors.size(), size_t(2)); - ASSERT(cursors.find(cursor1) != cursors.end()); - ASSERT(cursors.find(cursor2) != cursors.end()); - - // Now delete first one. The other should remain. - ASSERT_OK(useCursorManager()->killCursor(opCtx.get(), cursor1)); - cursors = useCursorManager()->getCursorsForOpKeys({opKey}); - ASSERT_EQ(cursors.size(), size_t(1)); - ASSERT(cursors.find(cursor1) == cursors.end()); - ASSERT(cursors.find(cursor2) != cursors.end()); - - // Now delete the other. None should remain. - ASSERT_OK(useCursorManager()->killCursor(opCtx.get(), cursor2)); - cursors = useCursorManager()->getCursorsForOpKeys({opKey}); - ASSERT_EQ(cursors.size(), size_t(0)); -} - TEST_F(CursorManagerTestCustomOpCtx, TimedOutCursorShouldNotBeReturnedForOpKeyLookup) { auto opKey = UUID::gen(); auto opCtx = _queryServiceContext->makeOperationContext(); @@ -780,44 +753,5 @@ TEST_F(CursorManagerTestCustomOpCtx, CursorsMarkedAsKilledAreReturnedForOpKeyLoo auto cursors = useCursorManager()->getCursorsForOpKeys({opKey}); ASSERT_EQ(cursors.size(), size_t(1)); } - -TEST_F(CursorManagerTestCustomOpCtx, - GetCursorIdsForNamespaceReturnsSingleEntryForMatchingNamespace) { - auto opCtx = _queryServiceContext->makeOperationContext(); - auto pinned = makeCursor(opCtx.get()); - auto cursorId = pinned.getCursor()->cursorid(); - auto cursorsForNamespace = useCursorManager()->getCursorIdsForNamespace(kTestNss); - ASSERT_EQUALS(cursorsForNamespace.size(), 1ull); - ASSERT_EQUALS(cursorsForNamespace[0], cursorId); -} - -TEST_F(CursorManagerTestCustomOpCtx, - GetCursorIdsForNamespaceReturnsMultipleEntriesForMatchingNamespace) { - auto opCtx = _queryServiceContext->makeOperationContext(); - auto pinned1 = makeCursor(opCtx.get()); - auto pinned2 = makeCursor(opCtx.get()); - auto cursorId1 = pinned1.getCursor()->cursorid(); - auto cursorId2 = pinned2.getCursor()->cursorid(); - auto cursorsForNamespace = useCursorManager()->getCursorIdsForNamespace(kTestNss); - ASSERT_EQUALS(cursorsForNamespace.size(), 2ull); - // The results for cursorsForNamespace won't necessarily be the same as the order of insertion. - std::set<CursorId> cursorsForNamespaceSet(cursorsForNamespace.begin(), - cursorsForNamespace.end()); - - ASSERT_EQUALS(cursorsForNamespaceSet.count(cursorId1), 1ull); - ASSERT_EQUALS(cursorsForNamespaceSet.count(cursorId2), 1ull); -} - -TEST_F(CursorManagerTestCustomOpCtx, - GetCursorIdsForNamespaceDoesNotReturnEntriesForNonMatchingNamespace) { - auto opCtx = _queryServiceContext->makeOperationContext(); - // Add a cursor for kTestNss. - auto pinned = makeCursor(opCtx.get()); - // Get cursors for a different NamespaceString. - auto cursorsForNamespace = - useCursorManager()->getCursorIdsForNamespace(NamespaceString("somerandom.nss")); - ASSERT_EQUALS(cursorsForNamespace.size(), 0ull); -} - } // namespace } // namespace mongo diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp index 08349d40c15..ca5d8b519d1 100644 --- a/src/mongo/dbtests/documentsourcetests.cpp +++ b/src/mongo/dbtests/documentsourcetests.cpp @@ -240,7 +240,7 @@ TEST_F(DocumentSourceCursorTest, SerializationQueryPlannerExplainLevel) { ctx()->explain = verb; createSource(); - auto explainResult = source()->serialize(SerializationOptions{boost::make_optional(verb)}); + auto explainResult = source()->serialize(verb); ASSERT_FALSE(explainResult["$cursor"]["queryPlanner"].missing()); ASSERT_TRUE(explainResult["$cursor"]["executionStats"].missing()); @@ -255,7 +255,7 @@ TEST_F(DocumentSourceCursorTest, SerializationExecStatsExplainLevel) { // Execute the plan so that the source populates its internal execution stats. exhaustCursor(); - auto explainResult = source()->serialize(SerializationOptions{boost::make_optional(verb)}); + auto explainResult = source()->serialize(verb); ASSERT_FALSE(explainResult["$cursor"]["queryPlanner"].missing()); ASSERT_FALSE(explainResult["$cursor"]["executionStats"].missing()); ASSERT_TRUE(explainResult["$cursor"]["executionStats"]["allPlansExecution"].missing()); @@ -271,8 +271,7 @@ TEST_F(DocumentSourceCursorTest, SerializationExecAllPlansExplainLevel) { // Execute the plan so that the source populates its internal executionStats. exhaustCursor(); - auto explainResult = - source()->serialize(SerializationOptions{boost::make_optional(verb)}).getDocument(); + auto explainResult = source()->serialize(verb).getDocument(); ASSERT_FALSE(explainResult["$cursor"]["queryPlanner"].missing()); ASSERT_FALSE(explainResult["$cursor"]["executionStats"].missing()); ASSERT_FALSE(explainResult["$cursor"]["executionStats"]["allPlansExecution"].missing()); @@ -289,8 +288,7 @@ TEST_F(DocumentSourceCursorTest, ExpressionContextAndSerializeVerbosityMismatch) // Execute the plan so that the source populates its internal executionStats. exhaustCursor(); - ASSERT_THROWS_CODE( - source()->serialize(SerializationOptions{boost::make_optional(verb2)}), DBException, 50660); + ASSERT_THROWS_CODE(source()->serialize(verb2), DBException, 50660); } TEST_F(DocumentSourceCursorTest, TailableAwaitDataCursorShouldErrorAfterTimeout) { diff --git a/src/mongo/dbtests/extensions_callback_real_test.cpp b/src/mongo/dbtests/extensions_callback_real_test.cpp index 9475d0e2779..a2d88117969 100644 --- a/src/mongo/dbtests/extensions_callback_real_test.cpp +++ b/src/mongo/dbtests/extensions_callback_real_test.cpp @@ -255,10 +255,13 @@ TEST_F(ExtensionsCallbackRealTest, WhereExpressionDesugarsToExprAndInternalJs) { auto expr1 = unittest::assertGet( ExtensionsCallbackReal(&_opCtx, &_nss).parseWhere(expCtx, query1.firstElement())); + BSONObjBuilder gotMatch; + expr1->serialize(&gotMatch); + auto expectedMatch = fromjson( "{$expr: {$function: {'body': 'function() { return this.x == 10; }', 'args': " "['$$CURRENT'], 'lang': 'js', '_internalSetObjToThis': true}}}"); - ASSERT_BSONOBJ_EQ(expr1->serialize(), expectedMatch); + ASSERT_BSONOBJ_EQ(gotMatch.obj(), expectedMatch); } } diff --git a/src/mongo/dbtests/framework.cpp b/src/mongo/dbtests/framework.cpp index 27068cc571e..330d796e9f3 100644 --- a/src/mongo/dbtests/framework.cpp +++ b/src/mongo/dbtests/framework.cpp @@ -43,6 +43,7 @@ #include "mongo/db/client.h" #include "mongo/db/concurrency/lock_state.h" #include "mongo/db/dbdirectclient.h" +#include "mongo/db/index/index_access_method_factory_impl.h" #include "mongo/db/index_builds_coordinator_mongod.h" #include "mongo/db/op_observer_registry.h" #include "mongo/db/s/collection_sharding_state_factory_shard.h" @@ -117,6 +118,8 @@ int runDbTests(int argc, char** argv) { StorageControl::startStorageControls(globalServiceContext, true /*forTestOnly*/); DatabaseHolder::set(globalServiceContext, std::make_unique<DatabaseHolderImpl>()); + IndexAccessMethodFactory::set(globalServiceContext, + std::make_unique<IndexAccessMethodFactoryImpl>()); Collection::Factory::set(globalServiceContext, std::make_unique<CollectionImpl::FactoryImpl>()); IndexBuildsCoordinator::set(globalServiceContext, std::make_unique<IndexBuildsCoordinatorMongod>()); diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index d80fd3a471d..6e6da7e8c7a 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -90,8 +90,8 @@ public: ASSERT_TRUE(indexCatalog(&opCtx)->numIndexesReady(&opCtx) == numFinishedIndexesStart + 2); - auto ii = - indexCatalog(&opCtx)->getIndexIterator(&opCtx, IndexCatalog::InclusionPolicy::kReady); + std::unique_ptr<IndexCatalog::IndexIterator> ii = + indexCatalog(&opCtx)->getIndexIterator(&opCtx, false); int indexesIterated = 0; bool foundIndex = false; while (ii->more()) { @@ -229,129 +229,6 @@ public: } }; -class PrepareUniqueIndexRecords : IndexCatalogTestBase { -public: - ~PrepareUniqueIndexRecords() { - auto opCtx = cc().makeOperationContext(); - AutoGetDb db{opCtx.get(), _nss.db(), LockMode::MODE_X}; - WriteUnitOfWork wuow{opCtx.get()}; - ASSERT_OK(db.getDb()->dropCollection(opCtx.get(), _nss)); - wuow.commit(); - } - - void run() { - auto opCtx = cc().makeOperationContext(); - dbtests::WriteContextForTests ctx{opCtx.get(), _nss.ns()}; - - ASSERT_OK(dbtests::createIndexFromSpec( - opCtx.get(), - _nss.ns(), - BSON(IndexDescriptor::kIndexVersionFieldName - << static_cast<int>(kIndexVersion) << IndexDescriptor::kIndexNameFieldName << "a_1" - << IndexDescriptor::kKeyPatternFieldName << BSON("a" << 1) - << IndexDescriptor::kPrepareUniqueFieldName << true))); - - AutoGetCollection coll{opCtx.get(), _nss, LockMode::MODE_X}; - auto doc1 = BSON("_id" << 1 << "a" << 1); - auto doc2 = BSON("_id" << 2 << "a" << 1); - - { - WriteUnitOfWork wuow{opCtx.get()}; - ASSERT_OK(indexCatalog(opCtx.get()) - ->indexRecords(opCtx.get(), *coll, {{RecordId{1}, {}, &doc1}}, nullptr)); - wuow.commit(); - } - - { - WriteUnitOfWork wuow{opCtx.get()}; - ASSERT_NOT_OK( - indexCatalog(opCtx.get()) - ->indexRecords(opCtx.get(), *coll, {{RecordId{2}, {}, &doc2}}, nullptr)); - } - - opCtx->setEnforceConstraints(false); - - { - WriteUnitOfWork wuow{opCtx.get()}; - ASSERT_OK(indexCatalog(opCtx.get()) - ->indexRecords(opCtx.get(), *coll, {{RecordId{2}, {}, &doc2}}, nullptr)); - wuow.commit(); - } - } -}; - -class PrepareUniqueUpdateRecord : IndexCatalogTestBase { -public: - ~PrepareUniqueUpdateRecord() { - auto opCtx = cc().makeOperationContext(); - AutoGetDb db{opCtx.get(), _nss.db(), LockMode::MODE_X}; - WriteUnitOfWork wuow{opCtx.get()}; - ASSERT_OK(db.getDb()->dropCollection(opCtx.get(), _nss)); - wuow.commit(); - } - - void run() { - auto opCtx = cc().makeOperationContext(); - dbtests::WriteContextForTests ctx{opCtx.get(), _nss.ns()}; - - ASSERT_OK(dbtests::createIndexFromSpec( - opCtx.get(), - _nss.ns(), - BSON(IndexDescriptor::kIndexVersionFieldName - << static_cast<int>(kIndexVersion) << IndexDescriptor::kIndexNameFieldName << "a_1" - << IndexDescriptor::kKeyPatternFieldName << BSON("a" << 1) - << IndexDescriptor::kPrepareUniqueFieldName << true))); - - AutoGetCollection coll{opCtx.get(), _nss, LockMode::MODE_X}; - auto doc1 = BSON("_id" << 1 << "a" << 1); - auto doc2 = BSON("_id" << 2 << "a" << 2); - auto updatedDoc2 = BSON("_id" << 2 << "a" << 1); - - { - WriteUnitOfWork wuow{opCtx.get()}; - ASSERT_OK(indexCatalog(opCtx.get()) - ->indexRecords(opCtx.get(), - *coll, - {{RecordId{1}, {}, &doc1}, {RecordId{2}, {}, &doc2}}, - nullptr)); - wuow.commit(); - } - - { - WriteUnitOfWork wuow{opCtx.get()}; - int64_t keysInsertedOut, keysDeletedOut; - ASSERT_NOT_OK(indexCatalog(opCtx.get()) - ->updateRecord(opCtx.get(), - *coll, - doc2, - updatedDoc2, - RecordId{2}, - &keysInsertedOut, - &keysDeletedOut)); - ASSERT_EQ(keysInsertedOut, 0); - ASSERT_EQ(keysDeletedOut, 0); - } - - opCtx->setEnforceConstraints(false); - - { - WriteUnitOfWork wuow{opCtx.get()}; - int64_t keysInsertedOut, keysDeletedOut; - ASSERT_OK(indexCatalog(opCtx.get()) - ->updateRecord(opCtx.get(), - *coll, - doc2, - updatedDoc2, - RecordId{2}, - &keysInsertedOut, - &keysDeletedOut)); - ASSERT_EQ(keysInsertedOut, 1); - ASSERT_EQ(keysDeletedOut, 1); - wuow.commit(); - } - } -}; - class IndexCatalogTests : public OldStyleSuiteSpecification { public: IndexCatalogTests() : OldStyleSuiteSpecification("indexcatalogtests") {} @@ -359,8 +236,6 @@ public: add<IndexIteratorTests>(); add<IndexCatalogEntryDroppedTest>(); add<RefreshEntry>(); - add<PrepareUniqueIndexRecords>(); - add<PrepareUniqueUpdateRecord>(); } }; diff --git a/src/mongo/dbtests/indexupdatetests.cpp b/src/mongo/dbtests/indexupdatetests.cpp index 2988f9f658a..e38d3663bc2 100644 --- a/src/mongo/dbtests/indexupdatetests.cpp +++ b/src/mongo/dbtests/indexupdatetests.cpp @@ -222,10 +222,8 @@ public: .getStatus()); auto& coll = collection(); - auto desc = coll->getIndexCatalog()->findIndexByName( - _opCtx, - "a", - IndexCatalog::InclusionPolicy::kReady | IndexCatalog::InclusionPolicy::kUnfinished); + auto desc = + coll->getIndexCatalog()->findIndexByName(_opCtx, "a", true /* includeUnfinished */); ASSERT(desc); // Hybrid index builds check duplicates explicitly. diff --git a/src/mongo/dbtests/jsobjtests.cpp b/src/mongo/dbtests/jsobjtests.cpp index 04a95679903..0c20c6f0f9b 100644 --- a/src/mongo/dbtests/jsobjtests.cpp +++ b/src/mongo/dbtests/jsobjtests.cpp @@ -505,7 +505,7 @@ public: bb << "a" << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + 4) + 1); - ASSERT_OK(mongo::validateBSON(tmp)); + ASSERT(tmp.valid()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT_BSONOBJ_EQ(tmp, BSON("a" << 1)); @@ -513,7 +513,7 @@ public: bb << "b" << 2; BSONObj obj = bb.obj(); ASSERT_EQUALS(obj.objsize(), 4 + (1 + 2 + 4) + (1 + 2 + 4) + 1); - ASSERT_OK(mongo::validateBSON(obj)); + ASSERT(obj.valid()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 2)); @@ -523,7 +523,7 @@ public: bb << "a" << GT << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + 1); - ASSERT_OK(mongo::validateBSON(tmp)); + ASSERT(tmp.valid()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT_BSONOBJ_EQ(tmp, BSON("a" << BSON("$gt" << 1))); @@ -532,7 +532,7 @@ public: BSONObj obj = bb.obj(); ASSERT(obj.objsize() == 4 + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + 1); - ASSERT_OK(mongo::validateBSON(obj)); + ASSERT(obj.valid()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); ASSERT_BSONOBJ_EQ(obj, BSON("a" << BSON("$gt" << 1) << "b" << BSON("$lt" << 2))); @@ -542,7 +542,7 @@ public: bb << "a" << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + 4) + 1); - ASSERT_OK(mongo::validateBSON(tmp)); + ASSERT(tmp.valid()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT_BSONOBJ_EQ(tmp, BSON("a" << 1)); @@ -554,7 +554,7 @@ public: } bb << "b" << arr.arr(); BSONObj obj = bb.obj(); - ASSERT_OK(mongo::validateBSON(obj)); + ASSERT(obj.valid()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); } @@ -756,8 +756,8 @@ class Base { public: virtual ~Base() {} void run() { - ASSERT_OK(mongo::validateBSON(valid())); - ASSERT(!mongo::validateBSON(invalid()).isOK()); + ASSERT(valid().valid()); + ASSERT(!invalid().valid()); } protected: @@ -806,7 +806,7 @@ public: b.appendNull("a"); BSONObj o = b.done(); set(o, 4, mongo::Undefined); - ASSERT_OK(mongo::validateBSON(o)); + ASSERT(o.valid()); } }; @@ -990,7 +990,7 @@ public: void run() { const char data[] = {0x07, 0x00, 0x00, 0x00, char(type_), 'a', 0x00}; BSONObj o(data); - ASSERT(!mongo::validateBSON(o).isOK()); + ASSERT(!o.valid()); } private: @@ -1329,7 +1329,7 @@ public: b2.done(); b1.append("f", 10.0); BSONObj ret = b1.done(); - ASSERT_OK(mongo::validateBSON(ret)); + ASSERT(ret.valid()); ASSERT(ret.woCompare(fromjson("{a:'bcd',foo:{ggg:44},f:10}")) == 0); } }; @@ -1350,7 +1350,7 @@ public: BSONObj o = BSON("now" << DATENOW); Date_t after = jsTime(); - ASSERT_OK(mongo::validateBSON(o)); + ASSERT(o.valid()); BSONElement e = o["now"]; ASSERT(e.type() == Date); @@ -1368,7 +1368,7 @@ public: b.appendTimeT("now", aTime); BSONObj o = b.obj(); - ASSERT_OK(mongo::validateBSON(o)); + ASSERT(o.valid()); BSONElement e = o["now"]; ASSERT_EQUALS(Date, e.type()); @@ -1382,8 +1382,8 @@ public: BSONObj min = BSON("a" << MINKEY); BSONObj max = BSON("b" << MAXKEY); - ASSERT_OK(mongo::validateBSON(min)); - ASSERT_OK(mongo::validateBSON(max)); + ASSERT(min.valid()); + ASSERT(max.valid()); BSONElement minElement = min["a"]; BSONElement maxElement = max["b"]; diff --git a/src/mongo/dbtests/jsontests.cpp b/src/mongo/dbtests/jsontests.cpp index c4410a8c45e..cb16219f51d 100644 --- a/src/mongo/dbtests/jsontests.cpp +++ b/src/mongo/dbtests/jsontests.cpp @@ -42,7 +42,6 @@ #include <limits> #include <sstream> -#include "mongo/bson/util/bsoncolumnbuilder.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/dbtests/dbtests.h" @@ -625,7 +624,7 @@ void assertEquals(const std::string& json, } void checkEquivalence(const std::string& json, const BSONObj& bson) { - ASSERT_OK(mongo::validateBSON(fromjson(json))); + ASSERT(fromjson(json).valid()); assertEquals(json, bson, fromjson(json), "mode: json-to-bson"); assertEquals(json, bson, fromjson(tojson(bson)), "mode: <default>"); assertEquals(json, bson, fromjson(tojson(bson, LegacyStrict)), "mode: strict"); @@ -836,27 +835,12 @@ TEST(FromJsonTest, BinDataTypes) { {0x05, MD5Type}, {0x06, Encrypt}, {0x07, Column}, - {0x08, Sensitive}, {0x80, bdtCustom}, }; for (const auto& ts : specs) { - if (ts.bdt == Column) { - BSONColumnBuilder cb(""); - cb.append(BSON("a" - << "abc") - .getField("a")); - BSONBinData columnData = cb.finalize(); - checkEquivalence(fmt::sprintf(R"({ "a" : { "$binary" : "%s", "$type" : "%02x" } })", - base64::encode(columnData.data, columnData.length), - ts.code), - BSONObjBuilder() - .appendBinData("a", columnData.length, ts.bdt, columnData.data) - .obj()); - } else { - checkEquivalence( - fmt::sprintf(R"({ "a" : { "$binary" : "YWJj", "$type" : "%02x" } })", ts.code), - BSONObjBuilder().appendBinData("a", 3, ts.bdt, "abc").obj()); - } + checkEquivalence( + fmt::sprintf(R"({ "a" : { "$binary" : "YWJj", "$type" : "%02x" } })", ts.code), + BSONObjBuilder().appendBinData("a", 3, ts.bdt, "abc").obj()); } } diff --git a/src/mongo/dbtests/mock/mock_replica_set.cpp b/src/mongo/dbtests/mock/mock_replica_set.cpp index 3871e1ef191..b03ffd477ed 100644 --- a/src/mongo/dbtests/mock/mock_replica_set.cpp +++ b/src/mongo/dbtests/mock/mock_replica_set.cpp @@ -149,7 +149,7 @@ void MockReplicaSet::setPrimary(const string& hostAndPort) { _primaryHost = hostAndPort; - mockHelloCmd(); + mockIsMasterCmd(); mockReplSetGetStatusCmd(); } @@ -183,7 +183,7 @@ repl::ReplSetConfig MockReplicaSet::getReplConfig() const { void MockReplicaSet::setConfig(const repl::ReplSetConfig& newConfig) { _replConfig = newConfig; - mockHelloCmd(); + mockIsMasterCmd(); mockReplSetGetStatusCmd(); } @@ -211,14 +211,14 @@ BSONObj MockReplicaSet::mockHelloResponseFor(const MockRemoteDBServer& server) c const MemberConfig* member = _replConfig.findMemberByHostAndPort(hostAndPort); if (!member) { - builder.append("isWritablePrimary", false); + builder.append("ismaster", false); builder.append("secondary", false); vector<string> hostList; builder.append("hosts", hostList); } else { const bool isPrimary = hostAndPort.toString() == getPrimary(); - builder.append("isWritablePrimary", isPrimary); + builder.append("ismaster", isPrimary); builder.append("secondary", !isPrimary); { @@ -285,12 +285,14 @@ BSONObj MockReplicaSet::mockHelloResponseFor(const MockRemoteDBServer& server) c return builder.obj(); } -void MockReplicaSet::mockHelloCmd() { +void MockReplicaSet::mockIsMasterCmd() { for (ReplNodeMap::iterator nodeIter = _nodeMap.begin(); nodeIter != _nodeMap.end(); ++nodeIter) { - auto helloReply = mockHelloResponseFor(*nodeIter->second); + auto isMaster = mockHelloResponseFor(*nodeIter->second); - nodeIter->second->setCommandReply("hello", helloReply); + // DBClientBase::isMaster() sends "ismaster", but ReplicaSetMonitor sends "isMaster". + nodeIter->second->setCommandReply("ismaster", isMaster); + nodeIter->second->setCommandReply("isMaster", isMaster); } } diff --git a/src/mongo/dbtests/mock/mock_replica_set.h b/src/mongo/dbtests/mock/mock_replica_set.h index d93ba956ee8..677d0b822a1 100644 --- a/src/mongo/dbtests/mock/mock_replica_set.h +++ b/src/mongo/dbtests/mock/mock_replica_set.h @@ -57,7 +57,7 @@ class ClockSource; class MockReplicaSet { public: /** - * Creates a mock replica set and automatically mocks the hello and replSetGetStatus commands + * Creates a mock replica set and automatically mocks the isMaster and replSetGetStatus commands * based on the default replica set configuration. Either the first node is primary and the * others are secondaries, or all are secondaries. By default, hostnames begin with "$", which * signals to ReplicaSetMonitor and to ConnectionString::connect that these are mocked hosts. @@ -87,11 +87,12 @@ public: std::vector<std::string> getSecondaries() const; /** - * Sets the configuration for this replica sets. This also has a side effect of mocking the - * hello and replSetGetStatus command responses based on the new config. + * Sets the configuration for this replica sets. This also has a side effect + * of mocking the ismaster and replSetGetStatus command responses based on + * the new config. * - * Note: does not automatically select a new primary. Can be done manually by calling - * setPrimary. + * Note: does not automatically select a new primary. Can be done manually by + * calling setPrimary. */ void setConfig(const repl::ReplSetConfig& newConfig); @@ -137,9 +138,10 @@ private: typedef std::map<std::string, MockRemoteDBServer*> ReplNodeMap; /** - * Mocks the "hello" command based on the information on the current replica set configuration. + * Mocks the ismaster command based on the information on the current + * replica set configuration. */ - void mockHelloCmd(); + void mockIsMasterCmd(); /** * Mock the hello response for the given server. diff --git a/src/mongo/dbtests/mock_dbclient_conn_test.cpp b/src/mongo/dbtests/mock_dbclient_conn_test.cpp index 19ca674c84c..a0da2e717ea 100644 --- a/src/mongo/dbtests/mock_dbclient_conn_test.cpp +++ b/src/mongo/dbtests/mock_dbclient_conn_test.cpp @@ -507,23 +507,23 @@ TEST(MockDBClientConnTest, CyclingCmd) { MockRemoteDBServer server("test"); { - vector<mongo::StatusWith<BSONObj>> helloReplySequence; - helloReplySequence.push_back(BSON("set" - << "a" - << "isWritablePrimary" << true << "ok" << 1)); - helloReplySequence.push_back(BSON("set" - << "a" - << "isWritablePrimary" << false << "ok" << 1)); - server.setCommandReply("hello", helloReplySequence); + vector<mongo::StatusWith<BSONObj>> isMasterSequence; + isMasterSequence.push_back(BSON("set" + << "a" + << "isMaster" << true << "ok" << 1)); + isMasterSequence.push_back(BSON("set" + << "a" + << "isMaster" << false << "ok" << 1)); + server.setCommandReply("isMaster", isMasterSequence); } { MockDBClientConnection conn(&server); BSONObj response; - ASSERT(conn.runCommand("foo.baz", BSON("hello" << 1), response)); + ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("a", response["set"].str()); - ASSERT(response["isWritablePrimary"].trueValue()); + ASSERT(response["isMaster"].trueValue()); ASSERT_EQUALS(1U, server.getCmdCount()); } @@ -531,10 +531,10 @@ TEST(MockDBClientConnTest, CyclingCmd) { { MockDBClientConnection conn(&server); BSONObj response; - ASSERT(conn.runCommand("foo.baz", BSON("hello" << 1), response)); + ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("a", response["set"].str()); - ASSERT(!response["isWritablePrimary"].trueValue()); + ASSERT(!response["isMaster"].trueValue()); ASSERT_EQUALS(2U, server.getCmdCount()); } @@ -542,10 +542,10 @@ TEST(MockDBClientConnTest, CyclingCmd) { { MockDBClientConnection conn(&server); BSONObj response; - ASSERT(conn.runCommand("foo.baz", BSON("hello" << 1), response)); + ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("a", response["set"].str()); - ASSERT(response["isWritablePrimary"].trueValue()); + ASSERT(response["isMaster"].trueValue()); ASSERT_EQUALS(3U, server.getCmdCount()); } @@ -554,13 +554,13 @@ TEST(MockDBClientConnTest, CyclingCmd) { TEST(MockDBClientConnTest, MultipleStoredResponse) { MockRemoteDBServer server("test"); server.setCommandReply("serverStatus", BSON("ok" << 0)); - server.setCommandReply("hello", BSON("ok" << 1 << "secondary" << false)); + server.setCommandReply("isMaster", BSON("ok" << 1 << "secondary" << false)); MockDBClientConnection conn(&server); { BSONObj response; ASSERT(conn.runCommand("foo.baz", - BSON("hello" + BSON("isMaster" << "abc"), response)); ASSERT(!response["secondary"].trueValue()); diff --git a/src/mongo/dbtests/mock_replica_set_test.cpp b/src/mongo/dbtests/mock_replica_set_test.cpp index 3b87b3b20e5..e3461193747 100644 --- a/src/mongo/dbtests/mock_replica_set_test.cpp +++ b/src/mongo/dbtests/mock_replica_set_test.cpp @@ -71,7 +71,7 @@ TEST(MockReplicaSetTest, GetNode) { ASSERT(replSet.getNode("$n3:27017") == nullptr); } -TEST(MockReplicaSetTest, HelloNode0) { +TEST(MockReplicaSetTest, IsMasterNode0) { MockReplicaSet replSet("n", 3); set<string> expectedHosts; expectedHosts.insert("$n0:27017"); @@ -80,10 +80,11 @@ TEST(MockReplicaSetTest, HelloNode0) { BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n0:27017"); - bool ok = MockDBClientConnection(node).runCommand("foo.bar", BSON("hello" << 1), cmdResponse); + bool ok = + MockDBClientConnection(node).runCommand("foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); - ASSERT(cmdResponse["isWritablePrimary"].trueValue()); + ASSERT(cmdResponse["ismaster"].trueValue()); ASSERT(!cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n0:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); @@ -98,7 +99,7 @@ TEST(MockReplicaSetTest, HelloNode0) { ASSERT(expectedHosts == hostList); } -TEST(MockReplicaSetTest, HelloNode1) { +TEST(MockReplicaSetTest, IsMasterNode1) { MockReplicaSet replSet("n", 3); set<string> expectedHosts; expectedHosts.insert("$n0:27017"); @@ -107,10 +108,11 @@ TEST(MockReplicaSetTest, HelloNode1) { BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n1:27017"); - bool ok = MockDBClientConnection(node).runCommand("foo.bar", BSON("hello" << 1), cmdResponse); + bool ok = + MockDBClientConnection(node).runCommand("foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); - ASSERT(!cmdResponse["isWritablePrimary"].trueValue()); + ASSERT(!cmdResponse["ismaster"].trueValue()); ASSERT(cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n1:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); @@ -125,7 +127,7 @@ TEST(MockReplicaSetTest, HelloNode1) { ASSERT(expectedHosts == hostList); } -TEST(MockReplicaSetTest, HelloNode2) { +TEST(MockReplicaSetTest, IsMasterNode2) { MockReplicaSet replSet("n", 3); set<string> expectedHosts; expectedHosts.insert("$n0:27017"); @@ -134,10 +136,11 @@ TEST(MockReplicaSetTest, HelloNode2) { BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n2:27017"); - bool ok = MockDBClientConnection(node).runCommand("foo.bar", BSON("hello" << 1), cmdResponse); + bool ok = + MockDBClientConnection(node).runCommand("foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); - ASSERT(!cmdResponse["isWritablePrimary"].trueValue()); + ASSERT(!cmdResponse["ismaster"].trueValue()); ASSERT(cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n2:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); @@ -287,7 +290,7 @@ ReplSetConfig _getConfigWithMemberRemoved(const ReplSetConfig& oldConfig, } } // namespace -TEST(MockReplicaSetTest, HelloReconfigNodeRemoved) { +TEST(MockReplicaSetTest, IsMasterReconfigNodeRemoved) { MockReplicaSet replSet("n", 3); ReplSetConfig oldConfig = replSet.getReplConfig(); @@ -296,14 +299,14 @@ TEST(MockReplicaSetTest, HelloReconfigNodeRemoved) { replSet.setConfig(newConfig); { - // Check that node is still a writable primary. + // Check isMaster for node still in set BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n0:27017"); bool ok = - MockDBClientConnection(node).runCommand("foo.bar", BSON("hello" << 1), cmdResponse); + MockDBClientConnection(node).runCommand("foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); - ASSERT(cmdResponse["isWritablePrimary"].trueValue()); + ASSERT(cmdResponse["ismaster"].trueValue()); ASSERT(!cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n0:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); @@ -324,14 +327,14 @@ TEST(MockReplicaSetTest, HelloReconfigNodeRemoved) { } { - // Check node is no longer a writable primary. + // Check isMaster for node still not in set anymore BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode(hostToRemove); bool ok = - MockDBClientConnection(node).runCommand("foo.bar", BSON("hello" << 1), cmdResponse); + MockDBClientConnection(node).runCommand("foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); - ASSERT(!cmdResponse["isWritablePrimary"].trueValue()); + ASSERT(!cmdResponse["ismaster"].trueValue()); ASSERT(!cmdResponse["secondary"].trueValue()); ASSERT_EQUALS(hostToRemove, cmdResponse["me"].str()); ASSERT_EQUALS("n", cmdResponse["setName"].str()); diff --git a/src/mongo/dbtests/multikey_paths_test.cpp b/src/mongo/dbtests/multikey_paths_test.cpp index 34afd00fa0e..c7d8e1acb28 100644 --- a/src/mongo/dbtests/multikey_paths_test.cpp +++ b/src/mongo/dbtests/multikey_paths_test.cpp @@ -95,8 +95,7 @@ public: const MultikeyPaths& expectedMultikeyPaths) { const IndexCatalog* indexCatalog = collection->getIndexCatalog(); std::vector<const IndexDescriptor*> indexes; - indexCatalog->findIndexesByKeyPattern( - _opCtx.get(), keyPattern, IndexCatalog::InclusionPolicy::kReady, &indexes); + indexCatalog->findIndexesByKeyPattern(_opCtx.get(), keyPattern, false, &indexes); ASSERT_EQ(indexes.size(), 1U); auto desc = indexes[0]; const IndexCatalogEntry* ice = indexCatalog->getEntry(desc); diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index e6600bfb05b..a503185daf2 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -136,7 +136,7 @@ public: _mps->addPlan(std::move(solutions[i]), std::move(root), ws.get()); } // This is what sets a backup plan, should we test for it. - NoopYieldPolicy yieldPolicy(&_opCtx, _opCtx.getServiceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(_opCtx.getServiceContext()->getFastClockSource()); _mps->pickBestPlan(&yieldPolicy).transitional_ignore(); ASSERT(_mps->bestPlanChosen()); diff --git a/src/mongo/dbtests/query_plan_executor.cpp b/src/mongo/dbtests/query_plan_executor.cpp index 7b3249b313d..b97dae14aa5 100644 --- a/src/mongo/dbtests/query_plan_executor.cpp +++ b/src/mongo/dbtests/query_plan_executor.cpp @@ -188,8 +188,7 @@ private: CollectionPtr collection = CollectionCatalog::get(&_opCtx)->lookupCollectionByNamespace(&_opCtx, nss); std::vector<const IndexDescriptor*> indexes; - collection->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, obj, IndexCatalog::InclusionPolicy::kReady, &indexes); + collection->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, obj, false, &indexes); ASSERT_LTE(indexes.size(), 1U); return indexes.size() == 0 ? nullptr : indexes[0]; } diff --git a/src/mongo/dbtests/query_stage_and.cpp b/src/mongo/dbtests/query_stage_and.cpp index 8773f170ca3..269682199c2 100644 --- a/src/mongo/dbtests/query_stage_and.cpp +++ b/src/mongo/dbtests/query_stage_and.cpp @@ -75,8 +75,7 @@ public: const IndexDescriptor* getIndex(const BSONObj& obj, const CollectionPtr& coll) { std::vector<const IndexDescriptor*> indexes; - coll->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, obj, IndexCatalog::InclusionPolicy::kReady, &indexes); + coll->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, obj, false, &indexes); if (indexes.empty()) { FAIL(str::stream() << "Unable to find index with key pattern " << obj); } diff --git a/src/mongo/dbtests/query_stage_batched_delete.cpp b/src/mongo/dbtests/query_stage_batched_delete.cpp index ec68fa04093..fdf55709d99 100644 --- a/src/mongo/dbtests/query_stage_batched_delete.cpp +++ b/src/mongo/dbtests/query_stage_batched_delete.cpp @@ -32,6 +32,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/exec/batched_delete_stage.h" @@ -41,7 +42,6 @@ #include "mongo/db/op_observer_noop.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/service_context.h" -#include "mongo/db/storage/checkpointer.h" #include "mongo/dbtests/dbtests.h" #include "mongo/util/tick_source_mock.h" @@ -84,31 +84,15 @@ public: class QueryStageBatchedDeleteTest : public unittest::Test { public: QueryStageBatchedDeleteTest() : _client(&_opCtx) { - // Since this test overrides the tick source on the global service context, it may - // conflict with the checkpoint thread, which needs to create an operation context. - // Since this test suite is run in isolation, it should be safe to disable the - // background job before installing a new tick source. - auto service = _opCtx.getServiceContext(); - if (!_tickSource) { - if (auto checkpointer = Checkpointer::get(service)) { - // BackgrounJob::cancel() keeps the checkpoint thread from starting. - // However, if it is already running, we use Checkpoint::shutdown() - // to wait for it to stop. - if (!checkpointer->cancel().isOK()) { - checkpointer->shutdown({ErrorCodes::ShutdownInProgress, ""}); - } - } - - auto tickSource = std::make_unique<TickSourceMock<Milliseconds>>(); - _tickSource = tickSource.get(); - service->setTickSource(std::move(tickSource)); - } - _tickSource->reset(1); + auto tickSource = std::make_unique<TickSourceMock<Milliseconds>>(); + tickSource->reset(1); + _tickSource = tickSource.get(); + _opCtx.getServiceContext()->setTickSource(std::move(tickSource)); std::unique_ptr<ClockAdvancingOpObserver> opObserverUniquePtr = std::make_unique<ClockAdvancingOpObserver>(); opObserverUniquePtr->tickSource = _tickSource; _opObserver = opObserverUniquePtr.get(); - service->setOpObserver(std::move(opObserverUniquePtr)); + _opCtx.getServiceContext()->setOpObserver(std::move(opObserverUniquePtr)); } virtual ~QueryStageBatchedDeleteTest() { @@ -226,15 +210,12 @@ protected: boost::intrusive_ptr<ExpressionContext> _expCtx = make_intrusive<ExpressionContext>(&_opCtx, nullptr, nss); ClockAdvancingOpObserver* _opObserver; - static TickSourceMock<Milliseconds>* _tickSource; + TickSourceMock<Milliseconds>* _tickSource; private: DBDirectClient _client; }; -// static -TickSourceMock<Milliseconds>* QueryStageBatchedDeleteTest::_tickSource = nullptr; - // Confirms batched deletes wait until a batch meets the targetBatchDocs before deleting documents. TEST_F(QueryStageBatchedDeleteTest, BatchedDeleteTargetBatchDocsBasic) { dbtests::WriteContextForTests ctx(&_opCtx, nss.ns()); @@ -255,9 +236,9 @@ TEST_F(QueryStageBatchedDeleteTest, BatchedDeleteTargetBatchDocsBasic) { ASSERT_EQUALS(state, PlanStage::NEED_TIME); // Only delete documents once the current batch reaches targetBatchDocs. - nIterations++; int batch = nIterations / (int)targetBatchDocs; ASSERT_EQUALS(stats->docsDeleted, targetBatchDocs * batch); + nIterations++; } // There should be 2 more docs deleted by the time the command returns EOF. @@ -544,7 +525,7 @@ TEST_F(QueryStageBatchedDeleteTest, BatchedDeleteTargetBatchTimeMSBasic) { // targetBatchDocs. { ASSERT_LTE(nDocs, targetBatchDocs); - for (auto i = 0; i < nDocs; i++) { + for (auto i = 0; i <= nDocs; i++) { state = deleteStage->work(&id); ASSERT_EQ(stats->docsDeleted, 0); ASSERT_EQ(state, PlanStage::NEED_TIME); @@ -626,7 +607,7 @@ TEST_F(QueryStageBatchedDeleteTest, BatchedDeleteTargetBatchTimeMSWithTargetBatc // Stages up to targetBatchDocs - 1 documents in the buffer. { - for (auto i = 0; i < targetBatchDocs - 1; i++) { + for (auto i = 0; i < targetBatchDocs; i++) { state = deleteStage->work(&id); ASSERT_EQ(stats->docsDeleted, 0); ASSERT_EQ(state, PlanStage::NEED_TIME); diff --git a/src/mongo/dbtests/query_stage_cached_plan.cpp b/src/mongo/dbtests/query_stage_cached_plan.cpp index 57c58e58489..0c7f88009f3 100644 --- a/src/mongo/dbtests/query_stage_cached_plan.cpp +++ b/src/mongo/dbtests/query_stage_cached_plan.cpp @@ -166,7 +166,7 @@ public: std::move(mockChild)); // This should succeed after triggering a replan. - NoopYieldPolicy yieldPolicy(&_opCtx, _opCtx.getServiceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(_opCtx.getServiceContext()->getFastClockSource()); ASSERT_OK(cachedPlanStage.pickBestPlan(&yieldPolicy)); } @@ -221,7 +221,7 @@ TEST_F(QueryStageCachedPlan, QueryStageCachedPlanFailureMemoryLimitExceeded) { std::move(mockChild)); // This should succeed after triggering a replan. - NoopYieldPolicy yieldPolicy(&_opCtx, _opCtx.getServiceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(_opCtx.getServiceContext()->getFastClockSource()); ASSERT_OK(cachedPlanStage.pickBestPlan(&yieldPolicy)); ASSERT_EQ(getNumResultsForStage(_ws, &cachedPlanStage, cq.get()), 2U); @@ -275,7 +275,7 @@ TEST_F(QueryStageCachedPlan, QueryStageCachedPlanHitMaxWorks) { std::move(mockChild)); // This should succeed after triggering a replan. - NoopYieldPolicy yieldPolicy(&_opCtx, _opCtx.getServiceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(_opCtx.getServiceContext()->getFastClockSource()); ASSERT_OK(cachedPlanStage.pickBestPlan(&yieldPolicy)); ASSERT_EQ(getNumResultsForStage(_ws, &cachedPlanStage, cq.get()), 2U); @@ -538,7 +538,7 @@ TEST_F(QueryStageCachedPlan, DoesNotThrowOnYieldRecoveryWhenIndexIsDroppedAferPl decisionWorks, std::make_unique<MockStage>(_expCtx.get(), &_ws)); - NoopYieldPolicy yieldPolicy(&_opCtx, _opCtx.getServiceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(_opCtx.getServiceContext()->getFastClockSource()); ASSERT_OK(cachedPlanStage.pickBestPlan(&yieldPolicy)); // Drop an index while the CachedPlanStage is in a saved state. We should be able to restore diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index 6f21a6437b8..fafbd58c0ef 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -339,38 +339,6 @@ TEST_F(QueryStageCollectionScanTest, QueryStageCollscanBasicBackwardWithMatch) { ASSERT_EQUALS(25, countResults(CollectionScanParams::BACKWARD, obj)); } -TEST_F(QueryStageCollectionScanTest, - QueryTestCollscanStopsScanningOnFilterFailureInClusteredCollectionIfSpecified) { - auto ns = NamespaceString("a.b"); - auto collDeleter = createClusteredCollection(ns, false /* prePopulate */); - for (int i = 1; i <= numObj(); ++i) { - insertDocument(ns, BSON("_id" << i << "foo" << i)); - } - - AutoGetCollectionForRead autoColl(&_opCtx, ns); - const CollectionPtr& coll = autoColl.getCollection(); - ASSERT(coll->isClustered()); - - // Configure the threshold and the expected number of scanned documents. - const int threshold = numObj() / 2; - const int expectedNumberOfScannedDocuments = threshold + 1; - - // Configure the scan. - CollectionScanParams params; - params.shouldReturnEofOnFilterMismatch = true; - WorkingSet ws; - LTEMatchExpression filter{"foo"_sd, Value(threshold)}; - auto scan = std::make_unique<CollectionScan>(_expCtx.get(), coll, params, &ws, &filter); - - // Scan all matching documents. - WorkingSetID id = WorkingSet::INVALID_ID; - while (!scan->isEOF()) { - scan->work(&id); - } - auto collScanStats = static_cast<const CollectionScanStats*>(scan->getSpecificStats()); - ASSERT_EQUALS(expectedNumberOfScannedDocuments, collScanStats->docsTested); -} - // Get objects in the order we inserted them. TEST_F(QueryStageCollectionScanTest, QueryStageCollscanObjectsInOrderForward) { AutoGetCollectionForReadCommand collection(&_opCtx, nss); @@ -569,6 +537,11 @@ TEST_F(QueryStageCollectionScanTest, QueryTestCollscanResumeAfterRecordIdSeekSuc unique_ptr<PlanStage> ps = std::make_unique<CollectionScan>( _expCtx.get(), collection.getCollection(), params, ws.get(), nullptr); + WorkingSetID id = WorkingSet::INVALID_ID; + + // Check that the resume succeeds in making the cursor. + ASSERT_EQUALS(PlanStage::NEED_TIME, ps->work(&id)); + // Run the rest of the scan and verify the results. auto statusWithPlanExecutor = plan_executor_factory::make(_expCtx, diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index 89487c2bca7..956c1f463b7 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -203,8 +203,7 @@ public: IndexScan* createIndexScan(MatchExpression* expr, WorkingSet* ws) { const IndexCatalog* catalog = _coll->getIndexCatalog(); std::vector<const IndexDescriptor*> indexes; - catalog->findIndexesByKeyPattern( - &_opCtx, BSON("x" << 1), IndexCatalog::InclusionPolicy::kReady, &indexes); + catalog->findIndexesByKeyPattern(&_opCtx, BSON("x" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); auto descriptor = indexes[0]; @@ -327,15 +326,12 @@ public: class QueryStageCountUpdateDuringYield : public CountStageTest { public: void run() { + // expected count would be kDocuments-2 but we update the first and second records + // after doing the first unit of work so they wind up getting counted later on CountCommandRequest request((NamespaceString(ns()))); request.setQuery(BSON("x" << GTE << 2)); - // We call 'interject' after first unit of work that skips the first document, so it is - // not counted. - testCount(request, kDocuments - 1); - - // We call 'interject' after first unit of work and even if some documents are skipped, - // they are added to the end of the index on x so they are counted later. + testCount(request, kDocuments); testCount(request, kDocuments, true); } diff --git a/src/mongo/dbtests/query_stage_count_scan.cpp b/src/mongo/dbtests/query_stage_count_scan.cpp index b03ed4a49a9..7485a938c01 100644 --- a/src/mongo/dbtests/query_stage_count_scan.cpp +++ b/src/mongo/dbtests/query_stage_count_scan.cpp @@ -95,8 +95,7 @@ public: const IndexDescriptor* getIndex(Database* db, const BSONObj& obj) { std::vector<const IndexDescriptor*> indexes; - getCollection()->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, obj, IndexCatalog::InclusionPolicy::kReady, &indexes); + getCollection()->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, obj, false, &indexes); return indexes.empty() ? nullptr : indexes[0]; } diff --git a/src/mongo/dbtests/query_stage_delete.cpp b/src/mongo/dbtests/query_stage_delete.cpp index d8725ddbc24..5c07aab93cf 100644 --- a/src/mongo/dbtests/query_stage_delete.cpp +++ b/src/mongo/dbtests/query_stage_delete.cpp @@ -32,6 +32,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/exec/collection_scan.h" diff --git a/src/mongo/dbtests/query_stage_distinct.cpp b/src/mongo/dbtests/query_stage_distinct.cpp index bea39ab55f1..57552d1f18e 100644 --- a/src/mongo/dbtests/query_stage_distinct.cpp +++ b/src/mongo/dbtests/query_stage_distinct.cpp @@ -130,8 +130,7 @@ public: // Set up the distinct stage. std::vector<const IndexDescriptor*> indexes; - coll->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, BSON("a" << 1), IndexCatalog::InclusionPolicy::kReady, &indexes); + coll->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, BSON("a" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); DistinctParams params{&_opCtx, coll, indexes[0]}; @@ -197,8 +196,7 @@ public: // Set up the distinct stage. std::vector<const IndexDescriptor*> indexes; - coll->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, BSON("a" << 1), IndexCatalog::InclusionPolicy::kReady, &indexes); + coll->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, BSON("a" << 1), false, &indexes); verify(indexes.size() == 1); DistinctParams params{&_opCtx, coll, indexes[0]}; @@ -265,7 +263,7 @@ public: std::vector<const IndexDescriptor*> indices; coll->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, BSON("a" << 1 << "b" << 1), IndexCatalog::InclusionPolicy::kReady, &indices); + &_opCtx, BSON("a" << 1 << "b" << 1), false, &indices); ASSERT_EQ(1U, indices.size()); DistinctParams params{&_opCtx, coll, indices[0]}; diff --git a/src/mongo/dbtests/query_stage_ixscan.cpp b/src/mongo/dbtests/query_stage_ixscan.cpp index d8a2454b259..30ebc65e983 100644 --- a/src/mongo/dbtests/query_stage_ixscan.cpp +++ b/src/mongo/dbtests/query_stage_ixscan.cpp @@ -97,8 +97,7 @@ public: IndexScan* createIndexScanSimpleRange(BSONObj startKey, BSONObj endKey) { IndexCatalog* catalog = _coll->getIndexCatalog(); std::vector<const IndexDescriptor*> indexes; - catalog->findIndexesByKeyPattern( - &_opCtx, BSON("x" << 1), IndexCatalog::InclusionPolicy::kReady, &indexes); + catalog->findIndexesByKeyPattern(&_opCtx, BSON("x" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); // We are not testing indexing here so use maximal bounds @@ -121,8 +120,7 @@ public: int direction = 1) { IndexCatalog* catalog = _coll->getIndexCatalog(); std::vector<const IndexDescriptor*> indexes; - catalog->findIndexesByKeyPattern( - &_opCtx, BSON("x" << 1), IndexCatalog::InclusionPolicy::kReady, &indexes); + catalog->findIndexesByKeyPattern(&_opCtx, BSON("x" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); IndexScanParams params(&_opCtx, _collPtr, indexes[0]); diff --git a/src/mongo/dbtests/query_stage_merge_sort.cpp b/src/mongo/dbtests/query_stage_merge_sort.cpp index 4b25e270647..f3f9f48139d 100644 --- a/src/mongo/dbtests/query_stage_merge_sort.cpp +++ b/src/mongo/dbtests/query_stage_merge_sort.cpp @@ -75,8 +75,7 @@ public: const IndexDescriptor* getIndex(const BSONObj& obj, const CollectionPtr& coll) { std::vector<const IndexDescriptor*> indexes; - coll->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, obj, IndexCatalog::InclusionPolicy::kReady, &indexes); + coll->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, obj, false, &indexes); return indexes.empty() ? nullptr : indexes[0]; } diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp index b4420113077..3552cf095fd 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -146,7 +146,7 @@ unique_ptr<PlanStage> getIxScanPlan(ExpressionContext* expCtx, int desiredFooValue) { std::vector<const IndexDescriptor*> indexes; coll->getIndexCatalog()->findIndexesByKeyPattern( - expCtx->opCtx, BSON("foo" << 1), IndexCatalog::InclusionPolicy::kReady, &indexes); + expCtx->opCtx, BSON("foo" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); IndexScanParams ixparams(expCtx->opCtx, coll, indexes[0]); @@ -182,11 +182,6 @@ unique_ptr<PlanStage> getCollScanPlan(ExpressionContext* expCtx, return root; } -const PlanStage* getBestPlanRoot(const MultiPlanStage* mps) { - auto bestPlanIdx = mps->bestPlanIdx(); - return bestPlanIdx ? mps->getChildren()[bestPlanIdx.get()].get() : nullptr; -} - std::unique_ptr<MultiPlanStage> runMultiPlanner(ExpressionContext* expCtx, const NamespaceString& nss, const CollectionPtr& coll, @@ -196,7 +191,6 @@ std::unique_ptr<MultiPlanStage> runMultiPlanner(ExpressionContext* expCtx, // at least). unique_ptr<WorkingSet> sharedWs(new WorkingSet()); unique_ptr<PlanStage> ixScanRoot = getIxScanPlan(expCtx, coll, sharedWs.get(), desiredFooValue); - const auto* ixScanRootPtr = ixScanRoot.get(); // Plan 1: CollScan. BSONObj filterObj = BSON("foo" << desiredFooValue); @@ -212,11 +206,10 @@ std::unique_ptr<MultiPlanStage> runMultiPlanner(ExpressionContext* expCtx, mps->addPlan(createQuerySolution(), std::move(collScanRoot), sharedWs.get()); // Plan 0 aka the first plan aka the index scan should be the best. - NoopYieldPolicy yieldPolicy(expCtx->opCtx, - expCtx->opCtx->getServiceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(expCtx->opCtx->getServiceContext()->getFastClockSource()); ASSERT_OK(mps->pickBestPlan(&yieldPolicy)); ASSERT(mps->bestPlanChosen()); - ASSERT_EQUALS(getBestPlanRoot(mps.get()), ixScanRootPtr); + ASSERT_EQUALS(0, *mps->bestPlanIdx()); return mps; } @@ -249,8 +242,6 @@ TEST_F(QueryStageMultiPlanTest, MPSCollectionScanVsHighlySelectiveIXScan) { unique_ptr<WorkingSet> sharedWs(new WorkingSet()); unique_ptr<PlanStage> ixScanRoot = getIxScanPlan(_expCtx.get(), coll, sharedWs.get(), 7); - const auto* ixScanRootPtr = ixScanRoot.get(); - // Plan 1: CollScan with matcher. BSONObj filterObj = BSON("foo" << 7); unique_ptr<MatchExpression> filter = makeMatchExpressionFromFilter(_expCtx.get(), filterObj); @@ -265,7 +256,11 @@ TEST_F(QueryStageMultiPlanTest, MPSCollectionScanVsHighlySelectiveIXScan) { mps->addPlan(createQuerySolution(), std::move(ixScanRoot), sharedWs.get()); mps->addPlan(createQuerySolution(), std::move(collScanRoot), sharedWs.get()); - const auto* mpsPtr = mps.get(); + // Plan 0 aka the first plan aka the index scan should be the best. + NoopYieldPolicy yieldPolicy(_clock); + ASSERT_OK(mps->pickBestPlan(&yieldPolicy)); + ASSERT(mps->bestPlanChosen()); + ASSERT_EQUALS(0, *mps->bestPlanIdx()); // Takes ownership of arguments other than 'collection'. auto statusWithPlanExecutor = @@ -278,9 +273,6 @@ TEST_F(QueryStageMultiPlanTest, MPSCollectionScanVsHighlySelectiveIXScan) { ASSERT_OK(statusWithPlanExecutor.getStatus()); auto exec = std::move(statusWithPlanExecutor.getValue()); - ASSERT_TRUE(mpsPtr->bestPlanChosen()); - ASSERT_EQUALS(mpsPtr->getChildren()[mpsPtr->bestPlanIdx().get()].get(), ixScanRootPtr); - // Get all our results out. int results = 0; BSONObj obj; @@ -429,7 +421,7 @@ TEST_F(QueryStageMultiPlanTest, MPSBackupPlan) { } // This sets a backup plan. - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, _clock); + NoopYieldPolicy yieldPolicy(_clock); ASSERT_OK(mps->pickBestPlan(&yieldPolicy)); ASSERT(mps->bestPlanChosen()); ASSERT(mps->hasBackupPlan()); @@ -492,8 +484,6 @@ TEST_F(QueryStageMultiPlanTest, MPSExplainAllPlans) { auto ws = std::make_unique<WorkingSet>(); auto firstPlan = std::make_unique<MockStage>(_expCtx.get(), ws.get()); - const auto* firstPlanPtr = firstPlan.get(); - auto secondPlan = std::make_unique<MockStage>(_expCtx.get(), ws.get()); for (int i = 0; i < nDocs; ++i) { @@ -529,7 +519,7 @@ TEST_F(QueryStageMultiPlanTest, MPSExplainAllPlans) { auto root = static_cast<MultiPlanStage*>(execImpl->getRootStage()); ASSERT_TRUE(root->bestPlanChosen()); // The first candidate plan should have won. - ASSERT_EQ(getBestPlanRoot(root), firstPlanPtr); + ASSERT_EQ(*root->bestPlanIdx(), 0); BSONObjBuilder bob; Explain::explainStages(exec.get(), @@ -642,8 +632,7 @@ TEST_F(QueryStageMultiPlanTest, ShouldReportErrorIfExceedsTimeLimitDuringPlannin multiPlanStage.addPlan(createQuerySolution(), std::move(ixScanRoot), sharedWs.get()); multiPlanStage.addPlan(createQuerySolution(), std::move(collScanRoot), sharedWs.get()); - AlwaysTimeOutYieldPolicy alwaysTimeOutPolicy(_expCtx->opCtx, - serviceContext()->getFastClockSource()); + AlwaysTimeOutYieldPolicy alwaysTimeOutPolicy(serviceContext()->getFastClockSource()); const auto status = multiPlanStage.pickBestPlan(&alwaysTimeOutPolicy); ASSERT_EQ(ErrorCodes::ExceededTimeLimit, status); ASSERT_STRING_CONTAINS(status.reason(), "error while multiplanner was selecting best plan"); @@ -683,8 +672,7 @@ TEST_F(QueryStageMultiPlanTest, ShouldReportErrorIfKilledDuringPlanning) { multiPlanStage.addPlan(createQuerySolution(), std::move(ixScanRoot), sharedWs.get()); multiPlanStage.addPlan(createQuerySolution(), std::move(collScanRoot), sharedWs.get()); - AlwaysPlanKilledYieldPolicy alwaysPlanKilledYieldPolicy(_expCtx->opCtx, - serviceContext()->getFastClockSource()); + AlwaysPlanKilledYieldPolicy alwaysPlanKilledYieldPolicy(serviceContext()->getFastClockSource()); ASSERT_EQ(ErrorCodes::QueryPlanKilled, multiPlanStage.pickBestPlan(&alwaysPlanKilledYieldPolicy)); } @@ -731,7 +719,7 @@ TEST_F(QueryStageMultiPlanTest, AddsContextDuringException) { multiPlanStage.addPlan( createQuerySolution(), std::make_unique<ThrowyPlanStage>(_expCtx.get()), sharedWs.get()); - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, _clock); + NoopYieldPolicy yieldPolicy(_clock); auto status = multiPlanStage.pickBestPlan(&yieldPolicy); ASSERT_EQ(ErrorCodes::InternalError, status); ASSERT_STRING_CONTAINS(status.reason(), "error while multiplanner was selecting best plan"); diff --git a/src/mongo/dbtests/query_stage_subplan.cpp b/src/mongo/dbtests/query_stage_subplan.cpp index 632aa91f9f8..5f8807bfc4d 100644 --- a/src/mongo/dbtests/query_stage_subplan.cpp +++ b/src/mongo/dbtests/query_stage_subplan.cpp @@ -67,16 +67,6 @@ public: ASSERT_OK(dbtests::createIndex(opCtx(), nss.ns(), obj)); } - void addIndexWithWildcardProjection(BSONObj keys, BSONObj wildcardProjection) { - auto indexSpec = BSON( - IndexDescriptor::kIndexNameFieldName - << DBClientBase::genIndexName(keys) << IndexDescriptor::kKeyPatternFieldName << keys - << IndexDescriptor::kUniqueFieldName << false << IndexDescriptor::kIndexVersionFieldName - << static_cast<int>(IndexDescriptor::IndexVersion::kV2) - << IndexDescriptor::kPathProjectionFieldName << wildcardProjection); - ASSERT_OK(dbtests::createIndexFromSpec(opCtx(), nss.ns(), indexSpec)); - } - void dropIndex(BSONObj keyPattern) { _client.dropIndex(nss.ns(), std::move(keyPattern)); } @@ -164,7 +154,7 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanGeo2dOr) { new SubplanStage(_expCtx.get(), collection, &ws, plannerParams, cq.get())); // Plan selection should succeed due to falling back on regular planning. - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, _clock); + NoopYieldPolicy yieldPolicy(_clock); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); } @@ -202,7 +192,7 @@ void assertSubplanFromCache(QueryStageSubplanTest* test, const dbtests::WriteCon std::unique_ptr<SubplanStage> subplan( new SubplanStage(test->expCtx(), collection, &ws, plannerParams, cq.get())); - NoopYieldPolicy yieldPolicy(test->opCtx(), test->serviceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(test->serviceContext()->getFastClockSource()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Nothing is in the cache yet, so neither branch should have been planned from @@ -255,10 +245,7 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanDontCacheZeroResults) { addIndex(BSON("a" << 1 << "b" << 1)); addIndex(BSON("a" << 1)); addIndex(BSON("c" << 1)); - // Exclude field 'c' from the wildcard index to make sure that the field has only one relevant - // index. - addIndexWithWildcardProjection(BSON("$**" << 1), BSON("c" << 0)); - + addIndex(BSON("$**" << 1)); for (int i = 0; i < 10; i++) { insert(BSON("a" << 1 << "b" << i << "c" << i)); @@ -285,7 +272,7 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanDontCacheZeroResults) { std::unique_ptr<SubplanStage> subplan( new SubplanStage(_expCtx.get(), collection, &ws, plannerParams, cq.get())); - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, _clock); + NoopYieldPolicy yieldPolicy(_clock); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Nothing is in the cache yet, so neither branch should have been planned from @@ -314,9 +301,7 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanDontCacheTies) { addIndex(BSON("a" << 1 << "b" << 1)); addIndex(BSON("a" << 1 << "c" << 1)); addIndex(BSON("d" << 1)); - // Exclude field 'd' from the wildcard index to make sure that the field has only one relevant - // index. - addIndexWithWildcardProjection(BSON("$**" << 1), BSON("d" << 0)); + addIndex(BSON("$**" << 1)); for (int i = 0; i < 10; i++) { insert(BSON("a" << 1 << "e" << 1 << "d" << 1)); @@ -343,7 +328,7 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanDontCacheTies) { std::unique_ptr<SubplanStage> subplan( new SubplanStage(_expCtx.get(), collection, &ws, plannerParams, cq.get())); - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, _clock); + NoopYieldPolicy yieldPolicy(_clock); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Nothing is in the cache yet, so neither branch should have been planned from @@ -515,7 +500,7 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanPlanRootedOrNE) { std::unique_ptr<SubplanStage> subplan( new SubplanStage(_expCtx.get(), collection, &ws, plannerParams, cq.get())); - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, _clock); + NoopYieldPolicy yieldPolicy(_clock); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); size_t numResults = 0; @@ -560,8 +545,7 @@ TEST_F(QueryStageSubplanTest, ShouldReportErrorIfExceedsTimeLimitDuringPlanning) auto coll = ctx.getCollection(); SubplanStage subplanStage(_expCtx.get(), coll, &workingSet, params, canonicalQuery.get()); - AlwaysTimeOutYieldPolicy alwaysTimeOutPolicy(_expCtx->opCtx, - serviceContext()->getFastClockSource()); + AlwaysTimeOutYieldPolicy alwaysTimeOutPolicy(serviceContext()->getFastClockSource()); ASSERT_EQ(ErrorCodes::ExceededTimeLimit, subplanStage.pickBestPlan(&alwaysTimeOutPolicy)); } @@ -586,8 +570,7 @@ TEST_F(QueryStageSubplanTest, ShouldReportErrorIfKilledDuringPlanning) { auto coll = ctx.getCollection(); SubplanStage subplanStage(_expCtx.get(), coll, &workingSet, params, canonicalQuery.get()); - AlwaysPlanKilledYieldPolicy alwaysPlanKilledYieldPolicy(_expCtx->opCtx, - serviceContext()->getFastClockSource()); + AlwaysPlanKilledYieldPolicy alwaysPlanKilledYieldPolicy(serviceContext()->getFastClockSource()); ASSERT_EQ(ErrorCodes::QueryPlanKilled, subplanStage.pickBestPlan(&alwaysPlanKilledYieldPolicy)); } @@ -670,7 +653,7 @@ TEST_F(QueryStageSubplanTest, ShouldNotThrowOnRestoreIfIndexDroppedAfterPlanSele WorkingSet workingSet; SubplanStage subplanStage(_expCtx.get(), collection, &workingSet, params, canonicalQuery.get()); - NoopYieldPolicy yieldPolicy(_expCtx->opCtx, serviceContext()->getFastClockSource()); + NoopYieldPolicy yieldPolicy(serviceContext()->getFastClockSource()); ASSERT_OK(subplanStage.pickBestPlan(&yieldPolicy)); // Mimic a yield by saving the state of the subplan stage and dropping our lock. Then drop an diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index a3a46a047cd..e5aa014b78c 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -127,8 +127,7 @@ public: const IndexDescriptor* getIndex(const BSONObj& obj) { AutoGetCollectionForReadCommand collection(&_opCtx, NamespaceString(ns())); std::vector<const IndexDescriptor*> indexes; - collection->getIndexCatalog()->findIndexesByKeyPattern( - &_opCtx, obj, IndexCatalog::InclusionPolicy::kReady, &indexes); + collection->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, obj, false, &indexes); return indexes.empty() ? nullptr : indexes[0]; } diff --git a/src/mongo/dbtests/query_stage_trial.cpp b/src/mongo/dbtests/query_stage_trial.cpp index 8b40e446f55..00f7bdbcfa9 100644 --- a/src/mongo/dbtests/query_stage_trial.cpp +++ b/src/mongo/dbtests/query_stage_trial.cpp @@ -88,7 +88,7 @@ protected: std::unique_ptr<PlanYieldPolicy> yieldPolicy() { return std::make_unique<NoopYieldPolicy>( - opCtx(), opCtx()->getServiceContext()->getFastClockSource()); + opCtx()->getServiceContext()->getFastClockSource()); } OperationContext* opCtx() { diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp index 1c6d2302260..64db23ea494 100644 --- a/src/mongo/dbtests/query_stage_update.cpp +++ b/src/mongo/dbtests/query_stage_update.cpp @@ -38,6 +38,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/exec/collection_scan.h" @@ -55,6 +56,15 @@ #include "mongo/db/update/update_driver.h" #include "mongo/dbtests/dbtests.h" +#define ASSERT_DOES_NOT_THROW(EXPRESSION) \ + try { \ + EXPRESSION; \ + } catch (const AssertionException& e) { \ + ::str::stream err; \ + err << "Threw an exception incorrectly: " << e.toString(); \ + ::mongo::unittest::TestAssertionFailure(__FILE__, __LINE__, err).stream(); \ + } + namespace QueryStageUpdate { using std::make_unique; diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index 2fe9e828355..f7aefecaf55 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -1205,7 +1205,7 @@ public: std::unique_ptr<DBClientCursor> cursor = _client.find(std::move(findRequest)); while (cursor->more()) { BSONObj o = cursor->next(); - verify(validateBSON(o).isOK()); + verify(o.valid()); } } void run() { diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp index da3611735e8..dde6c946431 100644 --- a/src/mongo/dbtests/repltests.cpp +++ b/src/mongo/dbtests/repltests.cpp @@ -36,7 +36,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/client.h" -#include "mongo/db/concurrency/exception_util.h" +#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/json.h" @@ -73,7 +73,6 @@ repl::OplogEntry makeOplogEntry(repl::OpTime opTime, nss, // namespace boost::none, // uuid boost::none, // fromMigrate - boost::none, // checkExistenceForDiffInsert OplogEntry::kOplogVersion, // version object, // o object2, // o2 @@ -375,12 +374,12 @@ protected: virtual void reset() const = 0; }; -// Some operations are only idempotent when in RECOVERING from unstable checkpoint, not in -// SECONDARY. This includes duplicate inserts and deletes. +// Some operations are only idempotent when in RECOVERING, not in SECONDARY. This includes +// duplicate inserts and deletes. class Recovering : public Base { protected: virtual OplogApplication::Mode getOplogApplicationMode() { - return OplogApplication::Mode::kUnstableRecovering; + return OplogApplication::Mode::kRecovering; } }; diff --git a/src/mongo/dbtests/rollbacktests.cpp b/src/mongo/dbtests/rollbacktests.cpp index 2f9c12a0577..75ce5b01d6e 100644 --- a/src/mongo/dbtests/rollbacktests.cpp +++ b/src/mongo/dbtests/rollbacktests.cpp @@ -110,16 +110,11 @@ void assertEmpty(OperationContext* opCtx, const NamespaceString& nss) { } bool indexExists(OperationContext* opCtx, const NamespaceString& nss, const string& idxName) { auto coll = CollectionCatalog::get(opCtx)->lookupCollectionByNamespace(opCtx, nss); - return coll->getIndexCatalog()->findIndexByName( - opCtx, - idxName, - IndexCatalog::InclusionPolicy::kReady | - IndexCatalog::InclusionPolicy::kUnfinished) != nullptr; + return coll->getIndexCatalog()->findIndexByName(opCtx, idxName, true) != nullptr; } bool indexReady(OperationContext* opCtx, const NamespaceString& nss, const string& idxName) { auto coll = CollectionCatalog::get(opCtx)->lookupCollectionByNamespace(opCtx, nss); - return coll->getIndexCatalog()->findIndexByName( - opCtx, idxName, IndexCatalog::InclusionPolicy::kReady) != nullptr; + return coll->getIndexCatalog()->findIndexByName(opCtx, idxName, false) != nullptr; } size_t getNumIndexEntries(OperationContext* opCtx, const NamespaceString& nss, @@ -128,7 +123,7 @@ size_t getNumIndexEntries(OperationContext* opCtx, auto coll = CollectionCatalog::get(opCtx)->lookupCollectionByNamespace(opCtx, nss); const IndexCatalog* catalog = coll->getIndexCatalog(); - auto desc = catalog->findIndexByName(opCtx, idxName, IndexCatalog::InclusionPolicy::kReady); + auto desc = catalog->findIndexByName(opCtx, idxName, false); if (desc) { auto iam = catalog->getEntry(desc)->accessMethod()->asSortedData(); diff --git a/src/mongo/dbtests/shared_buffer_test.cpp b/src/mongo/dbtests/shared_buffer_test.cpp new file mode 100644 index 00000000000..a1c62eef885 --- /dev/null +++ b/src/mongo/dbtests/shared_buffer_test.cpp @@ -0,0 +1,191 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/base/string_data.h" +#include "mongo/util/shared_buffer.h" +#include "mongo/util/shared_buffer_fragment.h" + +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace { + +using SharedBufferTest = unittest::Test; + +TEST_F(SharedBufferTest, ReallocOrCopyNull) { + SharedBuffer buf; + ASSERT_EQ(buf.capacity(), 0u); + ASSERT(!buf); + ASSERT(!buf.isShared()); + buf.reallocOrCopy(10); + ASSERT(buf); + ASSERT(!buf.isShared()); + ASSERT_EQ(buf.capacity(), 10u); +} + +TEST_F(SharedBufferTest, ReallocOrCopyNullShared) { + // null SharedBuffers are never considered "shared", even when copied. + SharedBuffer buf; + const SharedBuffer sharer = buf; + ASSERT_EQ(buf.capacity(), 0u); + ASSERT(!buf); + ASSERT(!buf.isShared()); + buf.reallocOrCopy(10); + ASSERT(buf); + ASSERT(!buf.isShared()); + ASSERT_EQ(buf.capacity(), 10u); + ASSERT_EQ(sharer.capacity(), 0u); +} + +SharedBuffer makeBuffer() { + SharedBuffer buf = SharedBuffer::allocate(4); + memcpy(buf.get(), "foo", 4); + return buf; +} + +TEST_F(SharedBufferTest, ReallocOrCopyGrow) { + SharedBuffer buf = makeBuffer(); + ASSERT_EQ(buf.capacity(), 4u); + ASSERT(buf); + ASSERT(!buf.isShared()); + buf.reallocOrCopy(10); + ASSERT(buf); + ASSERT(!buf.isShared()); + ASSERT_EQ(buf.capacity(), 10u); + ASSERT_EQ("foo"_sd, buf.get()); +} + +TEST_F(SharedBufferTest, ReallocOrCopyGrowShared) { + SharedBuffer buf = makeBuffer(); + const SharedBuffer sharer = buf; + ASSERT_EQ(buf.capacity(), 4u); + ASSERT(buf); + ASSERT(buf.isShared()); + buf.reallocOrCopy(10); + ASSERT(buf); + ASSERT(!buf.isShared()); + ASSERT_EQ(buf.capacity(), 10u); + ASSERT_EQ(sharer.capacity(), 4u); + ASSERT_EQ("foo"_sd, buf.get()); + ASSERT_EQ("foo"_sd, sharer.get()); + ASSERT_NE(buf.get(), sharer.get()); +} + +TEST_F(SharedBufferTest, ReallocOrCopyShrink) { + SharedBuffer buf = makeBuffer(); + ASSERT_EQ(buf.capacity(), 4u); + ASSERT(buf); + ASSERT(!buf.isShared()); + // The buffer is already at least 1 byte. + buf.reallocOrCopy(1); + ASSERT(buf); + // We copy it anyway. + ASSERT(!buf.isShared()); + ASSERT_EQ(buf.capacity(), 1u); + ASSERT_EQ('f', buf.get()[0]); +} + +TEST_F(SharedBufferTest, ReallocOrCopyShrinkShared) { + SharedBuffer buf = makeBuffer(); + const SharedBuffer sharer = buf; + ASSERT_EQ(buf.capacity(), 4u); + ASSERT(buf); + ASSERT(buf.isShared()); + // The buffer is already at least 1 byte. + buf.reallocOrCopy(1); + ASSERT(buf); + // We copy it anyway. + ASSERT(!buf.isShared()); + ASSERT_EQ(buf.capacity(), 1u); + ASSERT_EQ(sharer.capacity(), 4u); + ASSERT_EQ('f', buf.get()[0]); + ASSERT_EQ("foo"_sd, sharer.get()); + ASSERT_NE(buf.get(), sharer.get()); +} + +TEST_F(SharedBufferTest, SharedBufferFragmentBuilder) { + constexpr size_t kBlockSize = 16; + SharedBufferFragmentBuilder builder(kBlockSize); + + auto verifyFragment = [](const SharedBufferFragment& fragment, uint8_t expected) { + for (size_t i = 0; i < fragment.size(); ++i) + ASSERT(memcmp(fragment.get() + i, &expected, 1) == 0); + }; + + builder.start(kBlockSize / 2); + ASSERT_EQ(builder.capacity(), kBlockSize); + uint8_t one = 1; + memset(builder.get(), one, kBlockSize / 2); + auto fragment1 = builder.finish(kBlockSize / 2); + ASSERT_EQ(fragment1.size(), kBlockSize / 2); + verifyFragment(fragment1, one); + + builder.start(kBlockSize / 2); + ASSERT_EQ(builder.capacity(), kBlockSize / 2); + // We can use less than we ask for + uint8_t two = 2; + memset(builder.get(), two, kBlockSize / 4); + auto fragment2 = builder.finish(kBlockSize / 4); + ASSERT_EQ(fragment2.size(), kBlockSize / 4); + // Buffers should not overlap and be next to each other + ASSERT_EQ(fragment1.get() + fragment1.size(), fragment2.get()); + verifyFragment(fragment2, two); + + // Verify that anything written is transfered when we grow + builder.start(builder.capacity()); + ASSERT_EQ(builder.capacity(), kBlockSize / 4); + uint8_t three = 3; + size_t written = kBlockSize / 4; + // Write current capacity + memset(builder.get(), three, written); + builder.grow(kBlockSize); + // Write the rest + memset(builder.get() + written, three, builder.capacity() - written); + auto fragment3 = builder.finish(kBlockSize); + for (size_t i = 0; i < (kBlockSize / 4); ++i) + ASSERT(memcmp(fragment3.get() + i, &three, 1) == 0); + ASSERT_GTE(builder.capacity(), kBlockSize); + verifyFragment(fragment3, three); + + builder.start(builder.capacity()); + auto ptr = builder.get(); + builder.discard(); + builder.start(builder.capacity()); + ASSERT_EQ(builder.get(), ptr); + + // No buffers should have been overwritten by others + verifyFragment(fragment1, one); + verifyFragment(fragment2, two); + verifyFragment(fragment3, three); +} + +} // namespace +} // namespace mongo diff --git a/src/mongo/dbtests/storage_debug_util.cpp b/src/mongo/dbtests/storage_debug_util.cpp index 408a9c76b6c..29266bc6ddd 100644 --- a/src/mongo/dbtests/storage_debug_util.cpp +++ b/src/mongo/dbtests/storage_debug_util.cpp @@ -64,7 +64,7 @@ void printCollectionAndIndexTableEntries(OperationContext* opCtx, const Namespac // Iterate and print each index's table of documents. const auto indexCatalog = coll->getIndexCatalog(); - const auto it = indexCatalog->getIndexIterator(opCtx, IndexCatalog::InclusionPolicy::kReady); + const auto it = indexCatalog->getIndexIterator(opCtx, /*includeUnfinished*/ false); while (it->more()) { const auto indexCatalogEntry = it->next(); const auto indexDescriptor = indexCatalogEntry->descriptor(); diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp index f85755ac87e..031057cb7cf 100644 --- a/src/mongo/dbtests/validate_tests.cpp +++ b/src/mongo/dbtests/validate_tests.cpp @@ -54,7 +54,7 @@ using std::unique_ptr; namespace { const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; -const bool kLogDiagnostics = true; +const bool kTurnOnExtraLoggingForTest = true; std::size_t omitTransientWarningsFromCount(const ValidateResults& results) { return std::count_if( @@ -146,14 +146,8 @@ protected: ValidateResults results; BSONObjBuilder output; - ASSERT_OK(CollectionValidation::validate(&_opCtx, - _nss, - mode, - repairMode, - /*additionalOptions=*/{}, - &results, - &output, - kLogDiagnostics)); + ASSERT_OK(CollectionValidation::validate( + &_opCtx, _nss, mode, repairMode, &results, &output, kTurnOnExtraLoggingForTest)); // Check if errors are reported if and only if valid is set to false. ASSERT_EQ(results.valid, results.errors.empty()); @@ -184,23 +178,6 @@ protected: dumpOnErrorGuard.dismiss(); } - void ensureValidateWarned() { - ValidateResults results = runValidate(); - - ScopeGuard dumpOnErrorGuard([&] { - StorageDebugUtil::printValidateResults(results); - StorageDebugUtil::printCollectionAndIndexTableEntries(&_opCtx, _nss); - }); - - ASSERT_TRUE(results.valid) << "Validation failed when it should've worked."; - ASSERT_TRUE(results.errors.empty()) - << "Validation reported errors when it should not have."; - ASSERT_FALSE(results.warnings.empty()) - << "Validation did not report a warning when it should have."; - - dumpOnErrorGuard.dismiss(); - } - void ensureValidateFailed() { ValidateResults results = runValidate(); @@ -1218,10 +1195,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1337,10 +1313,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1427,10 +1402,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1540,10 +1514,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1570,10 +1543,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1607,10 +1579,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1727,10 +1698,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1759,10 +1729,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1792,10 +1761,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1883,10 +1851,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1915,10 +1882,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -1947,10 +1913,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2100,10 +2065,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2131,10 +2095,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2167,10 +2130,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2339,10 +2301,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2370,10 +2331,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2407,10 +2367,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2668,10 +2627,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2702,10 +2660,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2739,10 +2696,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2865,10 +2821,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2897,10 +2852,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -2930,10 +2884,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3331,10 +3284,9 @@ public: _nss, mode, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3400,10 +3352,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3432,10 +3383,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3468,10 +3418,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3500,10 +3449,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3667,10 +3615,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3697,10 +3644,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3728,10 +3674,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3876,10 +3821,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3906,10 +3850,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -3936,10 +3879,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4043,10 +3985,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kAdjustMultikey, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4077,10 +4018,9 @@ public: _nss, CollectionValidation::ValidateMode::kForeground, CollectionValidation::RepairMode::kAdjustMultikey, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4140,10 +4080,9 @@ public: _nss, mode, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4239,10 +4178,9 @@ public: _nss, mode, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4260,205 +4198,6 @@ public: } }; -/** - * Validate detects duplicate keys in a secondary unique index {a: 1} when the index is - * on a clustered collection. - * Two cases are tested: - * 1. The false negative case: when validate says there isn't a uniqueness - * violation even though there is one. - * 2. The false positive case: when validate says there is a uniqueness - * violation even though there isn't one. - * - * False negative case: - * Suppose we have two documents {_id: "1000000000", a: 1} and {_id: "1000000000", a: 1} - * that live in a collection. Since they have the same value for field 'a', they violate - * the uniqueness constraint of the index. - * The key strings for index {a: 1} for the two docs look something like this. - * They map from the value of 'a' in the document to the recordId. - * Buffer for keystring1: 1,1000000000 - * Buffer for keystring2: 1,2000000000 - * - * When we compareWithoutRecordIdLong(), we chop off only the number of - * bytes used in a long before making the comparison in the buffer. Since a long - * is 8 bytes, we cut 8 characters off. - * Truncated buffer 1: 1,10 - * Truncated buffer 2: 1,20 - * - * And we can see that the two truncated buffers above still aren't equal. But instead, - * if we used compareWithoutRecordIdStr(), we first figure out how many bytes we need - * to chop to exclude the recordId, and that way only the index entry value is compared. - * Now the unique index violation can be detected, as both the truncated buffers are - * equal. - * Truncated buffer 1: 1 - * Truncated buffer 2: 1 - * - * False positive case: - * Suppose we have two documents {_id: "1", a: 10000001} and {_id: "2", a: 10000002}. - * Clearly they don't violate any constraints. However it is possible, if we truncate - * more bytes than necessary, that we will end up truncating some of the bytes of the - * field 'a'. For example, - * Pre-truncation: - * Buffer for keystring1: 10000001,1 - * Buffer for keystring2: 10000002,2 - * Post-truncation: - * Buffer for keystring1: 10000 - * Buffer for keystring2: 10000 - * This can lead to a false positive uniqueness violation. - */ -template <bool falsePositiveCase> -class ValidateDuplicateKeyOnClusteredCollection : public ValidateBase { -public: - ValidateDuplicateKeyOnClusteredCollection() - : ValidateBase(/*full=*/true, /*background=*/false, /*clustered=*/true) {} - - void run() { - // Cannot run validate with {background:true} if the storage engine does not support - // checkpoints. - if (_background && !_supportsBackgroundValidation) { - return; - } - - SharedBufferFragmentBuilder pooledBuilder( - KeyString::HeapBuilder::kHeapAllocatorDefaultBytes); - - lockDb(MODE_X); - ASSERT(coll()); - - // Create a unique index on {a: 1} - const auto indexName = "a"; - const auto indexKey = BSON("a" << 1); - auto status = dbtests::createIndexFromSpec( - &_opCtx, - coll()->ns().ns(), - BSON("name" << indexName << "key" << indexKey << "v" << static_cast<int>(kIndexVersion) - << "unique" << true)); - ASSERT_OK(status); - - - // Insert documents. - auto firstDoc = BSON("_id" - << "1000000000000" - << "a" << 1); - auto secondDoc = BSON("_id" - << "2000000000000" - << "a" << 1); - if (falsePositiveCase) { - firstDoc = BSON("_id" - << "1" - << "a" << 10000001); - secondDoc = BSON("_id" - << "2" - << "a" << 10000002); - } - OpDebug* const nullOpDebug = nullptr; - lockDb(MODE_X); - { - WriteUnitOfWork wunit(&_opCtx); - ASSERT_OK( - coll()->insertDocument(&_opCtx, InsertStatement(firstDoc), nullOpDebug, true)); - if (falsePositiveCase) { - ASSERT_OK( - coll()->insertDocument(&_opCtx, InsertStatement(secondDoc), nullOpDebug, true)); - } - wunit.commit(); - } - releaseDb(); - ensureValidateWorked(); - - // Insert a document with a duplicate key for "a". - if (!falsePositiveCase) { - lockDb(MODE_X); - - const IndexCatalog* indexCatalog = coll()->getIndexCatalog(); - - InsertDeleteOptions options; - options.dupsAllowed = true; - - WriteUnitOfWork wunit(&_opCtx); - - // Insert a record and its keys separately. We do this to bypass duplicate constraint - // checking. Inserting a record and all of its keys ensures that validation fails - // because there are duplicate keys, and not just because there are keys without - // corresponding records. - auto swRecordId = - coll()->getRecordStore()->insertRecord(&_opCtx, - record_id_helpers::keyForObj(secondDoc), - secondDoc.objdata(), - secondDoc.objsize(), - Timestamp()); - ASSERT_OK(swRecordId); - wunit.commit(); - - // Insert the key on "a". - { - auto descriptor = indexCatalog->findIndexByName(&_opCtx, indexName); - auto entry = const_cast<IndexCatalogEntry*>(indexCatalog->getEntry(descriptor)); - auto iam = entry->accessMethod()->asSortedData(); - auto interceptor = std::make_unique<IndexBuildInterceptor>(&_opCtx, entry); - - KeyStringSet keys; - iam->getKeys(&_opCtx, - coll(), - pooledBuilder, - secondDoc, - InsertDeleteOptions::ConstraintEnforcementMode::kRelaxConstraints, - SortedDataIndexAccessMethod::GetKeysContext::kAddingKeys, - &keys, - nullptr, - nullptr, - swRecordId.getValue()); - ASSERT_EQ(1, keys.size()); - - { - WriteUnitOfWork wunit(&_opCtx); - - int64_t numInserted; - auto insertStatus = iam->insertKeysAndUpdateMultikeyPaths( - &_opCtx, - coll(), - {keys.begin(), keys.end()}, - {}, - MultikeyPaths{}, - options, - [this, &interceptor](const KeyString::Value& duplicateKey) { - return interceptor->recordDuplicateKey(&_opCtx, duplicateKey); - }, - &numInserted); - - ASSERT_EQUALS(numInserted, 1); - ASSERT_OK(insertStatus); - - wunit.commit(); - } - - ASSERT_NOT_OK(interceptor->checkDuplicateKeyConstraints(&_opCtx)); - } - - releaseDb(); - } - - ValidateResults results = runValidate(); - - ScopeGuard dumpOnErrorGuard([&] { - StorageDebugUtil::printValidateResults(results); - StorageDebugUtil::printCollectionAndIndexTableEntries(&_opCtx, coll()->ns()); - }); - - if (falsePositiveCase) { - ASSERT(results.valid) << "Validation failed when it should have worked."; - ASSERT_EQ(static_cast<size_t>(0), results.errors.size()); - } else { - ASSERT_FALSE(results.valid) << "Validation worked when it should have failed."; - ASSERT_EQ(static_cast<size_t>(1), results.errors.size()); - } - ASSERT_EQ(static_cast<size_t>(0), omitTransientWarningsFromCount(results)); - ASSERT_EQ(static_cast<size_t>(0), results.extraIndexEntries.size()); - ASSERT_EQ(static_cast<size_t>(0), results.missingIndexEntries.size()); - - dumpOnErrorGuard.dismiss(); - } -}; - class ValidateRepairOnClusteredCollection : public ValidateBase { public: ValidateRepairOnClusteredCollection() @@ -4534,10 +4273,9 @@ public: _nss, mode, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4566,10 +4304,9 @@ public: _nss, mode, CollectionValidation::RepairMode::kFixErrors, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4687,10 +4424,9 @@ public: _nss, CollectionValidation::ValidateMode::kForegroundFull, CollectionValidation::RepairMode::kNone, - /*additionalOptions=*/{}, &results, &output, - kLogDiagnostics)); + kTurnOnExtraLoggingForTest)); ScopeGuard dumpOnErrorGuard([&] { StorageDebugUtil::printValidateResults(results); @@ -4784,8 +4520,6 @@ public: add<ValidateInvalidBSONOnClusteredCollection<true>>(); add<ValidateReportInfoOnClusteredCollection<false>>(); add<ValidateReportInfoOnClusteredCollection<true>>(); - add<ValidateDuplicateKeyOnClusteredCollection<true /*falsePositiveCase*/>>(); - add<ValidateDuplicateKeyOnClusteredCollection<false /*falsePositiveCase*/>>(); add<ValidateRepairOnClusteredCollection>(); add<ValidateInvalidRecordIdOnClusteredCollection<false>>(false /*withSecondaryIndex*/); diff --git a/src/mongo/dbtests/wildcard_multikey_persistence_test.cpp b/src/mongo/dbtests/wildcard_multikey_persistence_test.cpp index cc4fd043dd2..c57eb9ac4b8 100644 --- a/src/mongo/dbtests/wildcard_multikey_persistence_test.cpp +++ b/src/mongo/dbtests/wildcard_multikey_persistence_test.cpp @@ -137,7 +137,7 @@ protected: * Verifes that the index access method associated with 'indexName' in the collection identified * by 'nss' reports 'expectedPaths' as the set of multikey paths. */ - void assertMultikeyPathSetEquals(const OrderedPathSet& expectedPaths, + void assertMultikeyPathSetEquals(const std::set<std::string>& expectedPaths, const NamespaceString& nss = kDefaultNSS, const std::string& indexName = kDefaultIndexName) { // Convert the set of std::string to a set of FieldRef. |
