diff options
author | Justin Seyster <justin.seyster@mongodb.com> | 2022-08-11 20:37:34 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-08-11 21:18:11 +0000 |
commit | 850596a5f30f7c18ac5fde21270db302951adcfd (patch) | |
tree | 69353d9e8f94a1e4bf86e85de1f863b8c0e65f01 /src/mongo/db/index | |
parent | b9b5671845d2d91a7713b7d630749621e221ec12 (diff) | |
download | mongo-850596a5f30f7c18ac5fde21270db302951adcfd.tar.gz |
SERVER-68658 Unit test fixture for IndexBuildInterceptor
Diffstat (limited to 'src/mongo/db/index')
-rw-r--r-- | src/mongo/db/index/SConscript | 4 | ||||
-rw-r--r-- | src/mongo/db/index/index_build_interceptor.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/index/index_build_interceptor.h | 6 | ||||
-rw-r--r-- | src/mongo/db/index/index_build_interceptor_test.cpp | 122 | ||||
-rw-r--r-- | src/mongo/db/index/skipped_record_tracker.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/index/skipped_record_tracker.h | 6 |
6 files changed, 137 insertions, 10 deletions
diff --git a/src/mongo/db/index/SConscript b/src/mongo/db/index/SConscript index 56ddcb682c1..484b9e4dec6 100644 --- a/src/mongo/db/index/SConscript +++ b/src/mongo/db/index/SConscript @@ -177,14 +177,18 @@ indexTestEnv.CppUnitTest( 'column_key_generator_test.cpp', 'column_store_sorter_test.cpp', 'hash_key_generator_test.cpp', + 'index_build_interceptor_test.cpp', 's2_key_generator_test.cpp', 's2_bucket_key_generator_test.cpp', 'sort_key_generator_test.cpp', 'wildcard_key_generator_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/catalog/catalog_test_fixture', + '$BUILD_DIR/mongo/db/catalog_raii', '$BUILD_DIR/mongo/db/exec/document_value/document_value_test_util', '$BUILD_DIR/mongo/db/exec/working_set', + '$BUILD_DIR/mongo/db/index/index_access_method', '$BUILD_DIR/mongo/db/matcher/expressions', '$BUILD_DIR/mongo/db/mongohasher', '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', diff --git a/src/mongo/db/index/index_build_interceptor.cpp b/src/mongo/db/index/index_build_interceptor.cpp index 59f8c7d1d6f..36072c25bf5 100644 --- a/src/mongo/db/index/index_build_interceptor.cpp +++ b/src/mongo/db/index/index_build_interceptor.cpp @@ -59,7 +59,8 @@ MONGO_FAIL_POINT_DEFINE(hangDuringIndexBuildDrainYieldSecond); MONGO_FAIL_POINT_DEFINE(hangIndexBuildDuringDrainWritesPhase); MONGO_FAIL_POINT_DEFINE(hangIndexBuildDuringDrainWritesPhaseSecond); -IndexBuildInterceptor::IndexBuildInterceptor(OperationContext* opCtx, IndexCatalogEntry* entry) +IndexBuildInterceptor::IndexBuildInterceptor(OperationContext* opCtx, + const IndexCatalogEntry* entry) : _indexCatalogEntry(entry), _sideWritesTable(opCtx->getServiceContext()->getStorageEngine()->makeTemporaryRecordStore( opCtx, KeyFormat::Long)), @@ -71,7 +72,7 @@ IndexBuildInterceptor::IndexBuildInterceptor(OperationContext* opCtx, IndexCatal } IndexBuildInterceptor::IndexBuildInterceptor(OperationContext* opCtx, - IndexCatalogEntry* entry, + const IndexCatalogEntry* entry, StringData sideWritesIdent, boost::optional<StringData> duplicateKeyTrackerIdent, boost::optional<StringData> skippedRecordTrackerIdent) diff --git a/src/mongo/db/index/index_build_interceptor.h b/src/mongo/db/index/index_build_interceptor.h index 07eb25cdba3..46c4f5e6e8b 100644 --- a/src/mongo/db/index/index_build_interceptor.h +++ b/src/mongo/db/index/index_build_interceptor.h @@ -67,7 +67,7 @@ public: * table to store any duplicate key constraint violations found during the build, if the index * being built has uniqueness constraints. */ - IndexBuildInterceptor(OperationContext* opCtx, IndexCatalogEntry* entry); + IndexBuildInterceptor(OperationContext* opCtx, const IndexCatalogEntry* entry); /** * Finds the temporary table associated with storing writes during this index build. Only used @@ -76,7 +76,7 @@ public: * violations found during the build, if the index being built has uniqueness constraints. */ IndexBuildInterceptor(OperationContext* opCtx, - IndexCatalogEntry* entry, + const IndexCatalogEntry* entry, StringData sideWritesIdent, boost::optional<StringData> duplicateKeyTrackerIdent, boost::optional<StringData> skippedRecordTrackerIdent); @@ -194,7 +194,7 @@ private: long long iteration) const; // The entry for the index that is being built. - IndexCatalogEntry* _indexCatalogEntry; + const IndexCatalogEntry* _indexCatalogEntry; // This temporary record store records intercepted keys that will be written into the index by // calling drainWritesIntoIndex(). It is owned by the interceptor and dropped along with it. diff --git a/src/mongo/db/index/index_build_interceptor_test.cpp b/src/mongo/db/index/index_build_interceptor_test.cpp new file mode 100644 index 00000000000..30f996d69d2 --- /dev/null +++ b/src/mongo/db/index/index_build_interceptor_test.cpp @@ -0,0 +1,122 @@ +/** + * Copyright (C) 2022-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/db/catalog/catalog_test_fixture.h" +#include "mongo/db/catalog_raii.h" +#include "mongo/db/index/index_build_interceptor.h" + +namespace mongo { +namespace { +class IndexBuilderInterceptorTest : public CatalogTestFixture { +protected: + const IndexCatalogEntry* createIndex(BSONObj spec) { + WriteUnitOfWork wuow(operationContext()); + auto* indexCatalog = _coll->getWritableCollection(operationContext())->getIndexCatalog(); + uassertStatusOK(indexCatalog->createIndexOnEmptyCollection( + operationContext(), _coll->getWritableCollection(operationContext()), spec)); + wuow.commit(); + + return indexCatalog->getEntry(indexCatalog->findIndexByName( + operationContext(), spec.getStringField(IndexDescriptor::kIndexNameFieldName))); + } + + std::unique_ptr<IndexBuildInterceptor> createIndexBuildInterceptor(BSONObj spec) { + return std::make_unique<IndexBuildInterceptor>(operationContext(), + createIndex(std::move(spec))); + } + + std::unique_ptr<TemporaryRecordStore> getSideWritesTable( + std::unique_ptr<IndexBuildInterceptor> interceptor) { + // In order to get access to the interceptor's side writes table, we have to mark the table + // as permanent and then destroy the interceptor. + interceptor->keepTemporaryTables(); + auto sideWritesIdent = interceptor->getSideWritesTableIdent(); + interceptor.reset(); + + return operationContext() + ->getServiceContext() + ->getStorageEngine() + ->makeTemporaryRecordStoreFromExistingIdent(operationContext(), sideWritesIdent); + } + + std::vector<BSONObj> getSideWritesTableContents( + std::unique_ptr<IndexBuildInterceptor> interceptor) { + auto table = getSideWritesTable(std::move(interceptor)); + + std::vector<BSONObj> contents; + auto cursor = table->rs()->getCursor(operationContext()); + while (auto record = cursor->next()) { + contents.push_back(record->data.toBson().getOwned()); + } + return contents; + } + + void setUp() override { + CatalogTestFixture::setUp(); + ASSERT_OK(storageInterface()->createCollection(operationContext(), _nss, {})); + _coll.emplace(operationContext(), _nss, MODE_X); + } + + void tearDown() override { + _coll.reset(); + CatalogTestFixture::tearDown(); + } + +private: + NamespaceString _nss{"testDB.interceptor"}; + boost::optional<AutoGetCollection> _coll; +}; + +TEST_F(IndexBuilderInterceptorTest, SingleInsertIsSavedToSideWritesTable) { + auto interceptor = createIndexBuildInterceptor(fromjson("{v: 2, name: 'a_1', key: {a: 1}}")); + + KeyString::HeapBuilder ksBuilder(KeyString::Version::kLatestVersion); + ksBuilder.appendNumberLong(10); + KeyString::Value keyString(ksBuilder.release()); + + WriteUnitOfWork wuow(operationContext()); + int64_t numKeys = 0; + ASSERT_OK(interceptor->sideWrite( + operationContext(), {keyString}, {}, {}, IndexBuildInterceptor::Op::kInsert, &numKeys)); + ASSERT_EQ(1, numKeys); + wuow.commit(); + + BufBuilder bufBuilder; + keyString.serialize(bufBuilder); + BSONBinData serializedKeyString(bufBuilder.buf(), bufBuilder.len(), BinDataGeneral); + + auto sideWrites = getSideWritesTableContents(std::move(interceptor)); + ASSERT_EQ(1, sideWrites.size()); + ASSERT_BSONOBJ_EQ(BSON("op" + << "i" + << "key" << serializedKeyString), + sideWrites[0]); +} +} // namespace +} // namespace mongo diff --git a/src/mongo/db/index/skipped_record_tracker.cpp b/src/mongo/db/index/skipped_record_tracker.cpp index f5cf3e44e79..7e21c6202cd 100644 --- a/src/mongo/db/index/skipped_record_tracker.cpp +++ b/src/mongo/db/index/skipped_record_tracker.cpp @@ -46,11 +46,11 @@ namespace { static constexpr StringData kRecordIdField = "recordId"_sd; } -SkippedRecordTracker::SkippedRecordTracker(IndexCatalogEntry* indexCatalogEntry) +SkippedRecordTracker::SkippedRecordTracker(const IndexCatalogEntry* indexCatalogEntry) : SkippedRecordTracker(nullptr, indexCatalogEntry, boost::none) {} SkippedRecordTracker::SkippedRecordTracker(OperationContext* opCtx, - IndexCatalogEntry* indexCatalogEntry, + const IndexCatalogEntry* indexCatalogEntry, boost::optional<StringData> ident) : _indexCatalogEntry(indexCatalogEntry) { if (!ident) { diff --git a/src/mongo/db/index/skipped_record_tracker.h b/src/mongo/db/index/skipped_record_tracker.h index fecdf868ded..61cda65a47f 100644 --- a/src/mongo/db/index/skipped_record_tracker.h +++ b/src/mongo/db/index/skipped_record_tracker.h @@ -46,9 +46,9 @@ class SkippedRecordTracker { SkippedRecordTracker(const SkippedRecordTracker&) = delete; public: - explicit SkippedRecordTracker(IndexCatalogEntry* indexCatalogEntry); + explicit SkippedRecordTracker(const IndexCatalogEntry* indexCatalogEntry); SkippedRecordTracker(OperationContext* opCtx, - IndexCatalogEntry* indexCatalogEntry, + const IndexCatalogEntry* indexCatalogEntry, boost::optional<StringData> ident); /** @@ -85,7 +85,7 @@ public: } private: - IndexCatalogEntry* _indexCatalogEntry; + const IndexCatalogEntry* _indexCatalogEntry; // This temporary record store is owned by the duplicate key tracker. std::unique_ptr<TemporaryRecordStore> _skippedRecordsTable; |