diff options
author | Kevin Cherkauer <kevin.cherkauer@mongodb.com> | 2022-12-22 20:08:43 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-01-19 03:13:34 +0000 |
commit | 210f9cbb2a8759db1d9161ee21cf3b596d02d028 (patch) | |
tree | a672761e5f95c340af8fd93b74d3644e3622185f /src/mongo/db/index | |
parent | a2dc5577e42ef8ce6734f4f9a6a46e6972ae873b (diff) | |
download | mongo-210f9cbb2a8759db1d9161ee21cf3b596d02d028.tar.gz |
SERVER-67446 Ensure consistent wildcardProjection specs in catalog
Diffstat (limited to 'src/mongo/db/index')
-rw-r--r-- | src/mongo/db/index/SConscript | 120 | ||||
-rw-r--r-- | src/mongo/db/index/columns_access_method.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/index/index_access_method.cpp | 56 | ||||
-rw-r--r-- | src/mongo/db/index/index_access_method.h | 27 | ||||
-rw-r--r-- | src/mongo/db/index/index_access_method_factory.cpp | 53 | ||||
-rw-r--r-- | src/mongo/db/index/index_access_method_factory_impl.cpp | 91 | ||||
-rw-r--r-- | src/mongo/db/index/index_access_method_factory_impl.h | 50 | ||||
-rw-r--r-- | src/mongo/db/index/index_descriptor.cpp | 43 | ||||
-rw-r--r-- | src/mongo/db/index/index_descriptor.h | 44 | ||||
-rw-r--r-- | src/mongo/db/index/wildcard_access_method.cpp | 10 |
10 files changed, 163 insertions, 341 deletions
diff --git a/src/mongo/db/index/SConscript b/src/mongo/db/index/SConscript index 0795d88a76c..1edde90c0d4 100644 --- a/src/mongo/db/index/SConscript +++ b/src/mongo/db/index/SConscript @@ -4,54 +4,12 @@ Import("env") env = env.Clone() -env.Library( - target='index_descriptor', - source=[ - 'index_descriptor.cpp', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/catalog/index_catalog', - '$BUILD_DIR/mongo/db/query/collation/collator_factory_interface', - '$BUILD_DIR/mongo/db/query_expressions', - '$BUILD_DIR/mongo/db/server_base', - ], -) - -env.Library( - target='key_generator', - source=[ - 'btree_key_generator.cpp', - 'column_key_generator.cpp', - 'expression_keys_private.cpp', - 'sort_key_generator.cpp', - 'wildcard_key_generator.cpp', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/bson/dotted_path_support', - '$BUILD_DIR/mongo/db/exec/projection_executor', - '$BUILD_DIR/mongo/db/exec/working_set', - '$BUILD_DIR/mongo/db/fts/base_fts', - '$BUILD_DIR/mongo/db/geo/geoparser', - '$BUILD_DIR/mongo/db/mongohasher', - '$BUILD_DIR/mongo/db/pipeline/document_path_support', - '$BUILD_DIR/mongo/db/query/collation/collator_interface', - '$BUILD_DIR/mongo/db/query/projection_ast', - '$BUILD_DIR/mongo/db/query/sort_pattern', - '$BUILD_DIR/mongo/db/record_id_helpers', - '$BUILD_DIR/mongo/db/server_base', - '$BUILD_DIR/mongo/db/timeseries/timeseries_conversion_util', - '$BUILD_DIR/third_party/s2/s2', - 'expression_params', - 'index_descriptor', - ], -) - env.Benchmark( target='key_gen_bm', source='key_gen_bm.cpp', LIBDEPS=[ '$BUILD_DIR/mongo/base', - 'key_generator', + 'index_access_method', ], ) @@ -70,33 +28,51 @@ env.Library( ], ) -env.Library( - target='index_access_method_factory', - source=[ - 'index_access_method_factory.cpp', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/server_base', - ], -) - iamEnv = env.Clone() iamEnv.InjectThirdParty(libraries=['snappy']) iamEnv.Library( target="index_access_method", source=[ + '2d_access_method.cpp', + 'btree_access_method.cpp', + 'btree_key_generator.cpp', + 'column_key_generator.cpp', + 'columns_access_method.cpp', 'duplicate_key_tracker.cpp', + 'expression_keys_private.cpp', + 'fts_access_method.cpp', + 'hash_access_method.cpp', 'index_access_method.cpp', 'index_build_interceptor.cpp', 'index_build_interceptor.idl', + 'index_descriptor.cpp', + 's2_access_method.cpp', + 's2_bucket_access_method.cpp', 'skipped_record_tracker.cpp', + 'sort_key_generator.cpp', + 'wildcard_access_method.cpp', + 'wildcard_key_generator.cpp', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/bson/dotted_path_support', '$BUILD_DIR/mongo/db/catalog/collection', + '$BUILD_DIR/mongo/db/catalog/index_catalog', '$BUILD_DIR/mongo/db/catalog/index_catalog_entry', '$BUILD_DIR/mongo/db/concurrency/exception_util', '$BUILD_DIR/mongo/db/curop', + '$BUILD_DIR/mongo/db/exec/projection_executor', + '$BUILD_DIR/mongo/db/exec/working_set', + '$BUILD_DIR/mongo/db/fts/base_fts', + '$BUILD_DIR/mongo/db/geo/geoparser', + '$BUILD_DIR/mongo/db/mongohasher', '$BUILD_DIR/mongo/db/multi_key_path_tracker', + '$BUILD_DIR/mongo/db/pipeline/document_path_support', + '$BUILD_DIR/mongo/db/query/collation/collator_factory_interface', + '$BUILD_DIR/mongo/db/query/collation/collator_interface', + '$BUILD_DIR/mongo/db/query/projection_ast', + '$BUILD_DIR/mongo/db/query/sort_pattern', + '$BUILD_DIR/mongo/db/query_expressions', + '$BUILD_DIR/mongo/db/record_id_helpers', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/db/resumable_index_builds_idl', '$BUILD_DIR/mongo/db/server_base', @@ -109,10 +85,13 @@ iamEnv.Library( '$BUILD_DIR/mongo/db/storage/key_string', '$BUILD_DIR/mongo/db/storage/record_store_base', '$BUILD_DIR/mongo/db/storage/storage_options', + '$BUILD_DIR/mongo/db/timeseries/timeseries_conversion_util', '$BUILD_DIR/mongo/db/vector_clock', '$BUILD_DIR/mongo/util/progress_meter', + '$BUILD_DIR/third_party/s2/s2', '$BUILD_DIR/third_party/shim_snappy', - 'index_descriptor', + 'column_store_index', + 'expression_params', ], ) @@ -133,35 +112,6 @@ iamEnv.Library( ], ) -env.Library( - target='index_access_methods', - source=[ - '2d_access_method.cpp', - 'columns_access_method.cpp', - 'btree_access_method.cpp', - 'fts_access_method.cpp', - 'hash_access_method.cpp', - 'index_access_method_factory_impl.cpp', - 's2_access_method.cpp', - 's2_bucket_access_method.cpp', - 'wildcard_access_method.cpp', - ], - LIBDEPS=[ - 'index_access_method', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/concurrency/exception_util', - '$BUILD_DIR/mongo/db/curop', - '$BUILD_DIR/mongo/db/fts/base_fts', - '$BUILD_DIR/mongo/db/resumable_index_builds_idl', - '$BUILD_DIR/mongo/db/server_base', - '$BUILD_DIR/mongo/db/storage/execution_context', - 'column_store_index', - 'expression_params', - 'key_generator', - ], -) - indexTestEnv = env.Clone() indexTestEnv.InjectThirdParty(libraries=['snappy']) indexTestEnv.CppUnitTest( @@ -184,7 +134,6 @@ indexTestEnv.CppUnitTest( '$BUILD_DIR/mongo/db/catalog/catalog_test_fixture', '$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/mongohasher', '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', '$BUILD_DIR/mongo/db/query/query_test_service_context', @@ -195,7 +144,6 @@ indexTestEnv.CppUnitTest( '$BUILD_DIR/mongo/db/sorter/sorter_stats', 'column_store_index', 'expression_params', - 'index_access_methods', - 'key_generator', + 'index_access_method', ], ) diff --git a/src/mongo/db/index/columns_access_method.cpp b/src/mongo/db/index/columns_access_method.cpp index 52a92c7da73..f894117fb97 100644 --- a/src/mongo/db/index/columns_access_method.cpp +++ b/src/mongo/db/index/columns_access_method.cpp @@ -68,15 +68,7 @@ ColumnStoreAccessMethod::ColumnStoreAccessMethod(IndexCatalogEntry* ice, : _store(std::move(store)), _indexCatalogEntry(ice), _descriptor(ice->descriptor()), - _keyGen(_descriptor->keyPattern(), _descriptor->pathProjection()) { - // Normalize the 'columnstoreProjection' index option to facilitate its comparison as part of - // index signature. - if (!_descriptor->pathProjection().isEmpty()) { - auto* projExec = getColumnstoreProjection()->exec(); - ice->descriptor()->_setNormalizedPathProjection( - projExec->serializeTransformation(boost::none).toBson()); - } -} + _keyGen(_descriptor->keyPattern(), _descriptor->pathProjection()) {} class ColumnStoreAccessMethod::BulkBuilder final : public BulkBuilderCommon<ColumnStoreAccessMethod::BulkBuilder> { diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp index 5d3d226bb23..9ec1d3aec72 100644 --- a/src/mongo/db/index/index_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -27,10 +27,9 @@ * it in the license file. */ - #include "mongo/platform/basic.h" -#include "mongo/db/index/btree_access_method.h" +#include "mongo/db/index/index_access_method.h" #include <utility> #include <vector> @@ -43,15 +42,24 @@ #include "mongo/db/commands/server_status.h" #include "mongo/db/concurrency/exception_util.h" #include "mongo/db/curop.h" +#include "mongo/db/index/2d_access_method.h" +#include "mongo/db/index/btree_access_method.h" #include "mongo/db/index/bulk_builder_common.h" +#include "mongo/db/index/columns_access_method.h" +#include "mongo/db/index/fts_access_method.h" +#include "mongo/db/index/hash_access_method.h" #include "mongo/db/index/index_build_interceptor.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index/s2_access_method.h" +#include "mongo/db/index/s2_bucket_access_method.h" +#include "mongo/db/index/wildcard_access_method.h" #include "mongo/db/jsobj.h" #include "mongo/db/keypattern.h" #include "mongo/db/operation_context.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/repl/timestamp_block.h" #include "mongo/db/storage/execution_context.h" +#include "mongo/db/storage/kv/kv_engine.h" #include "mongo/db/storage/storage_options.h" #include "mongo/logv2/log.h" #include "mongo/platform/atomic_word.h" @@ -72,6 +80,50 @@ MONGO_FAIL_POINT_DEFINE(hangIndexBuildDuringBulkLoadPhaseSecond); MONGO_FAIL_POINT_DEFINE(hangDuringIndexBuildBulkLoadYield); MONGO_FAIL_POINT_DEFINE(hangDuringIndexBuildBulkLoadYieldSecond); +/** + * Static factory method that constructs and returns an appropriate IndexAccessMethod depending on + * the type of the index. + */ +std::unique_ptr<IndexAccessMethod> IndexAccessMethod::make( + OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& collectionOptions, + IndexCatalogEntry* entry, + StringData ident) { + + auto engine = opCtx->getServiceContext()->getStorageEngine()->getEngine(); + auto desc = entry->descriptor(); + auto makeSDI = [&] { + return engine->getSortedDataInterface(opCtx, nss, collectionOptions, ident, desc); + }; + auto makeCS = [&] { + return engine->getColumnStore(opCtx, nss, collectionOptions, ident, desc); + }; + const std::string& type = desc->getAccessMethodName(); + + if ("" == type) + return std::make_unique<BtreeAccessMethod>(entry, makeSDI()); + else if (IndexNames::HASHED == type) + return std::make_unique<HashAccessMethod>(entry, makeSDI()); + else if (IndexNames::GEO_2DSPHERE == type) + return std::make_unique<S2AccessMethod>(entry, makeSDI()); + else if (IndexNames::GEO_2DSPHERE_BUCKET == type) + return std::make_unique<S2BucketAccessMethod>(entry, makeSDI()); + else if (IndexNames::TEXT == type) + return std::make_unique<FTSAccessMethod>(entry, makeSDI()); + else if (IndexNames::GEO_2D == type) + return std::make_unique<TwoDAccessMethod>(entry, makeSDI()); + else if (IndexNames::WILDCARD == type) + return std::make_unique<WildcardAccessMethod>(entry, makeSDI()); + else if (IndexNames::COLUMN == type) + return std::make_unique<ColumnStoreAccessMethod>(entry, makeCS()); + LOGV2(20688, + "Can't find index for keyPattern {keyPattern}", + "Can't find index for keyPattern", + "keyPattern"_attr = desc->keyPattern()); + fassertFailed(31021); +} + namespace { /** diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h index 8e9391f4c29..8819e11912f 100644 --- a/src/mongo/db/index/index_access_method.h +++ b/src/mongo/db/index/index_access_method.h @@ -74,6 +74,12 @@ public: IndexAccessMethod() = default; virtual ~IndexAccessMethod() = default; + static std::unique_ptr<IndexAccessMethod> make(OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& collectionOptions, + IndexCatalogEntry* entry, + StringData ident); + /** * Equivalent to (but shorter and faster than): dynamic_cast<SortedDataIndexAccessMethod*>(this) */ @@ -275,27 +281,6 @@ public: }; /** - * Factory class that constructs an IndexAccessMethod depending on the type of index. - */ -class IndexAccessMethodFactory { -public: - IndexAccessMethodFactory() = default; - virtual ~IndexAccessMethodFactory() = default; - - static IndexAccessMethodFactory* get(ServiceContext* service); - static IndexAccessMethodFactory* get(OperationContext* opCtx); - static void set(ServiceContext* service, - std::unique_ptr<IndexAccessMethodFactory> collectionFactory); - - - virtual std::unique_ptr<IndexAccessMethod> make(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& collectionOptions, - IndexCatalogEntry* entry, - StringData ident) = 0; -}; - -/** * Updates are two steps: verify that it's a valid update, and perform it. * prepareUpdate fills out the UpdateStatus and update actually applies it. */ diff --git a/src/mongo/db/index/index_access_method_factory.cpp b/src/mongo/db/index/index_access_method_factory.cpp deleted file mode 100644 index 986ed2d8967..00000000000 --- a/src/mongo/db/index/index_access_method_factory.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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/db/index/index_access_method.h" - -namespace mongo { -namespace { -const auto getFactory = - ServiceContext::declareDecoration<std::unique_ptr<IndexAccessMethodFactory>>(); -} // namespace - -IndexAccessMethodFactory* IndexAccessMethodFactory::get(ServiceContext* service) { - return getFactory(service).get(); -} - -IndexAccessMethodFactory* IndexAccessMethodFactory::get(OperationContext* opCtx) { - return getFactory(opCtx->getServiceContext()).get(); -} - -void IndexAccessMethodFactory::set(ServiceContext* service, - std::unique_ptr<IndexAccessMethodFactory> newFactory) { - auto& factory = getFactory(service); - factory = std::move(newFactory); -} -} // namespace mongo diff --git a/src/mongo/db/index/index_access_method_factory_impl.cpp b/src/mongo/db/index/index_access_method_factory_impl.cpp deleted file mode 100644 index e027154ba9e..00000000000 --- a/src/mongo/db/index/index_access_method_factory_impl.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 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/db/index/index_access_method_factory_impl.h" - -#include "mongo/db/index/2d_access_method.h" -#include "mongo/db/index/btree_access_method.h" -#include "mongo/db/index/columns_access_method.h" -#include "mongo/db/index/fts_access_method.h" -#include "mongo/db/index/hash_access_method.h" -#include "mongo/db/index/s2_access_method.h" -#include "mongo/db/index/s2_bucket_access_method.h" -#include "mongo/db/index/wildcard_access_method.h" -#include "mongo/db/storage/kv/kv_engine.h" -#include "mongo/logv2/log.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kIndex - - -namespace mongo { - -std::unique_ptr<IndexAccessMethod> IndexAccessMethodFactoryImpl::make( - OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& collectionOptions, - IndexCatalogEntry* entry, - StringData ident) { - - auto engine = opCtx->getServiceContext()->getStorageEngine()->getEngine(); - auto desc = entry->descriptor(); - auto makeSDI = [&] { - return engine->getSortedDataInterface(opCtx, nss, collectionOptions, ident, desc); - }; - auto makeCS = [&] { - return engine->getColumnStore(opCtx, nss, collectionOptions, ident, desc); - }; - const std::string& type = desc->getAccessMethodName(); - - if ("" == type) - return std::make_unique<BtreeAccessMethod>(entry, makeSDI()); - else if (IndexNames::HASHED == type) - return std::make_unique<HashAccessMethod>(entry, makeSDI()); - else if (IndexNames::GEO_2DSPHERE == type) - return std::make_unique<S2AccessMethod>(entry, makeSDI()); - else if (IndexNames::GEO_2DSPHERE_BUCKET == type) - return std::make_unique<S2BucketAccessMethod>(entry, makeSDI()); - else if (IndexNames::TEXT == type) - return std::make_unique<FTSAccessMethod>(entry, makeSDI()); - else if (IndexNames::GEO_2D == type) - return std::make_unique<TwoDAccessMethod>(entry, makeSDI()); - else if (IndexNames::WILDCARD == type) - return std::make_unique<WildcardAccessMethod>(entry, makeSDI()); - else if (IndexNames::COLUMN == type) - return std::make_unique<ColumnStoreAccessMethod>(entry, makeCS()); - LOGV2(20688, - "Can't find index for keyPattern {keyPattern}", - "Can't find index for keyPattern", - "keyPattern"_attr = desc->keyPattern()); - fassertFailed(31021); -} - -} // namespace mongo diff --git a/src/mongo/db/index/index_access_method_factory_impl.h b/src/mongo/db/index/index_access_method_factory_impl.h deleted file mode 100644 index 639ee1c320d..00000000000 --- a/src/mongo/db/index/index_access_method_factory_impl.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * 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. - */ - -#pragma once - -#include "mongo/db/index/index_access_method.h" - -namespace mongo { - -struct CollectionOptions; - -class IndexAccessMethodFactoryImpl : public IndexAccessMethodFactory { -public: - IndexAccessMethodFactoryImpl() = default; - ~IndexAccessMethodFactoryImpl() = default; - - std::unique_ptr<IndexAccessMethod> make(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& collectionOptions, - IndexCatalogEntry* entry, - StringData ident) final; -}; - -} // namespace mongo diff --git a/src/mongo/db/index/index_descriptor.cpp b/src/mongo/db/index/index_descriptor.cpp index a5b4214ee43..e98a2cced88 100644 --- a/src/mongo/db/index/index_descriptor.cpp +++ b/src/mongo/db/index/index_descriptor.cpp @@ -27,7 +27,6 @@ * it in the license file. */ - #include "mongo/platform/basic.h" #include "mongo/db/index/index_descriptor.h" @@ -37,6 +36,9 @@ #include "mongo/bson/simple_bsonelement_comparator.h" #include "mongo/bson/unordered_fields_bsonobj_comparator.h" #include "mongo/db/catalog/index_catalog_entry.h" +#include "mongo/db/exec/index_path_projection.h" +#include "mongo/db/index/column_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/server_options.h" @@ -115,6 +117,11 @@ constexpr StringData IndexDescriptor::kWeightsFieldName; constexpr StringData IndexDescriptor::kPrepareUniqueFieldName; constexpr StringData IndexDescriptor::kColumnStoreCompressorFieldName; +/** + * Constructs an IndexDescriptor object. Arguments: + * accessMethodName - one of the 'IndexNames::XXX' constants from index_names.cpp + * infoObj - options information + */ IndexDescriptor::IndexDescriptor(const std::string& accessMethodName, BSONObj infoObj) : _accessMethodName(accessMethodName), _indexType(IndexNames::nameToType(accessMethodName)), @@ -156,6 +163,27 @@ IndexDescriptor::IndexDescriptor(const std::string& accessMethodName, BSONObj in } else { _compressor = boost::none; } + + // If there is a wildcardProjection or columnstoreProjection, compute and store the normalized + // version in '_normalizedProjection'. + BSONElement wildcardProjection = infoObj[IndexDescriptor::kWildcardProjectionFieldName]; + BSONElement columnStoreProjection = infoObj[IndexDescriptor::kColumnStoreProjectionFieldName]; + tassert(6744600, + "Can't enable both wildcardProjection and columnstoreProjection", + !(wildcardProjection && columnStoreProjection)); + if (wildcardProjection) { + IndexPathProjection indexPathProjection = + static_cast<IndexPathProjection>(WildcardKeyGenerator::createProjectionExecutor( + BSON("$**" << 1), wildcardProjection.Obj())); + _normalizedProjection = + indexPathProjection.exec()->serializeTransformation(boost::none).toBson(); + } else if (columnStoreProjection) { + IndexPathProjection indexPathProjection = static_cast<IndexPathProjection>( + column_keygen::ColumnKeyGenerator::createProjectionExecutor( + BSON("$**" << IndexNames::COLUMN), columnStoreProjection.Obj())); + _normalizedProjection = + indexPathProjection.exec()->serializeTransformation(boost::none).toBson(); + } } bool IndexDescriptor::isIndexVersionSupported(IndexVersion indexVersion) { @@ -175,10 +203,6 @@ IndexDescriptor::Comparison IndexDescriptor::compareIndexOptions( OperationContext* opCtx, const NamespaceString& ns, const IndexCatalogEntry* existingIndex) const { - // The compareIndexOptions method can only be reliably called on a candidate index which is - // being compared against an index that already exists in the catalog. - tassert(4765900, "This object must be a candidate index", !getEntry()); - auto existingIndexDesc = existingIndex->descriptor(); // We first check whether the key pattern is identical for both indexes. @@ -187,8 +211,15 @@ IndexDescriptor::Comparison IndexDescriptor::compareIndexOptions( return Comparison::kDifferent; } + // If the candidate has a wildcardProjection or columnstoreProjection, we must compare the + // normalized versions, not the versions from the catalog which are kept as the user gave them + // and thus may be semantically identical to but syntactically different from the normalized + // form. There are no other types of index projections. Thus, if there is no projection, both + // the original and normalized projections will be empty BSON objects, so we can still do the + // comparison based on the normalized projection. static const UnorderedFieldsBSONObjComparator kUnorderedBSONCmp; - if (kUnorderedBSONCmp.evaluate(_projection != existingIndexDesc->_normalizedProjection)) { + if (kUnorderedBSONCmp.evaluate(_normalizedProjection != + existingIndexDesc->_normalizedProjection)) { return Comparison::kDifferent; } diff --git a/src/mongo/db/index/index_descriptor.h b/src/mongo/db/index/index_descriptor.h index 702b6e3f029..349f79bd9a2 100644 --- a/src/mongo/db/index/index_descriptor.h +++ b/src/mongo/db/index/index_descriptor.h @@ -122,15 +122,40 @@ public: } /** - * Return the path projection spec, if one exists. This is only applicable for '$**' indexes. + * Return the path projection spec, if one exists. This is only applicable for wildcard ('$**') + * and columnstore indexes. It is kept as originally specified by the createIndex() call, not + * normalized. + * + * It contains only the projection object that was contained in one of the fields listed below + * from the original createIndex() parameters object, but it does NOT preserve the field name: + * - "wildcardProjection" (IndexDescriptor::kWildcardProjectionFieldName) + * - "columnstoreProjection" (IndexDescriptor::kColumnStoreProjectionFieldName) + * + * This is set by the IndexDescriptor constructor and never changes after that. + * + * Example: db.a.createIndex({"$**":1}, {"name": "i1", "wildcardProjection": {"a.b": 1}}) + * return (unnormalized) object: {"a.b":{"$numberDouble":"1"}} */ const BSONObj& pathProjection() const { return _projection; } /** - * Returns the normalized path projection spec, if one exists. This is only applicable for '$**' - * indexes. + * Returns the normalized path projection spec, if one exists. This is only applicable for + * wildcard ('$**') and columnstore indexes. It is the normalized version of the path projection + * and is used to determine whether a new index candidate from createIndex() duplicates an + * existing index. + * + * It contains the normalized projection object based on the original object that was contained + * in one of the fields listed below from the original createIndex() parameters object, but it + * does NOT preserve the field name: + * - "wildcardProjection" (IndexDescriptor::kWildcardProjectionFieldName) + * - "columnstoreProjection" (IndexDescriptor::kColumnStoreProjectionFieldName) + * + * This is set by the IndexDescriptor constructor and never changes after that. + * + * Example: db.a.createIndex({"$**":1}, {"name": "i1", "wildcardProjection": {"a.b": 1}}) + * return (normalized) object: {"a":{"b":true},"_id":false} */ const BSONObj& normalizedPathProjection() const { return _normalizedProjection; @@ -271,13 +296,6 @@ public: } private: - // This method should only ever be called by WildcardAccessMethod or ColumnstoreAccessMethod, to - // set the '_normalizedProjection' for descriptors associated with an existing - // IndexCatalogEntry. - void _setNormalizedPathProjection(BSONObj&& proj) { - _normalizedProjection = std::move(proj); - } - /** * Returns wildcardProjection or columnstoreProjection projection */ @@ -305,8 +323,8 @@ private: int64_t _numFields; // How many fields are indexed? BSONObj _keyPattern; - BSONObj _projection; - BSONObj _normalizedProjection; + BSONObj _projection; // for wildcardProjection / columnstoreProjection; never changes + BSONObj _normalizedProjection; // for wildcardProjection / columnstoreProjection; never changes std::string _indexName; bool _isIdIndex; bool _sparse; @@ -326,8 +344,6 @@ private: friend class IndexCatalog; friend class IndexCatalogEntryImpl; friend class IndexCatalogEntryContainer; - friend class WildcardAccessMethod; - friend class ColumnStoreAccessMethod; }; } // namespace mongo diff --git a/src/mongo/db/index/wildcard_access_method.cpp b/src/mongo/db/index/wildcard_access_method.cpp index 0631158e40d..a3b66caa1d2 100644 --- a/src/mongo/db/index/wildcard_access_method.cpp +++ b/src/mongo/db/index/wildcard_access_method.cpp @@ -45,15 +45,7 @@ WildcardAccessMethod::WildcardAccessMethod(IndexCatalogEntry* wildcardState, _indexCatalogEntry->getCollator(), getSortedDataInterface()->getKeyStringVersion(), getSortedDataInterface()->getOrdering(), - getSortedDataInterface()->rsKeyFormat()) { - // Normalize the 'wildcardProjection' index option to facilitate its comparison as part of - // index signature. - if (!_descriptor->pathProjection().isEmpty()) { - auto* projExec = getWildcardProjection()->exec(); - wildcardState->descriptor()->_setNormalizedPathProjection( - projExec->serializeTransformation(boost::none).toBson()); - } -} + getSortedDataInterface()->rsKeyFormat()) {} bool WildcardAccessMethod::shouldMarkIndexAsMultikey(size_t numberOfKeys, const KeyStringSet& multikeyMetadataKeys, |