diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2023-01-30 16:35:56 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-01-31 02:23:21 +0000 |
commit | 8aca0afe03fd7f9c3041463a470c7758e3c2a73e (patch) | |
tree | 956dab3499b3968fa24bbb8fa6925eea24f7098b | |
parent | 1b0c8231c24f550fc24453c3ce220eb58ba83663 (diff) | |
download | mongo-8aca0afe03fd7f9c3041463a470c7758e3c2a73e.tar.gz |
SERVER-73238 Move some shard_key_pattern query methods out of 'grid'
27 files changed, 385 insertions, 371 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index eb005debcba..00bcea53987 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1499,6 +1499,7 @@ env.Library( source=[ 'matcher/doc_validation_error.cpp', 'matcher/doc_validation_util.cpp', + 'matcher/expression.cpp', 'matcher/expression_algo.cpp', 'matcher/expression_array.cpp', 'matcher/expression_expr.cpp', @@ -1513,19 +1514,18 @@ env.Library( 'matcher/expression_where_base.cpp', 'matcher/expression_where_noop.cpp', 'matcher/expression_with_placeholder.cpp', - 'matcher/expression.cpp', - 'matcher/extensions_callback_noop.cpp', 'matcher/extensions_callback.cpp', + 'matcher/extensions_callback_noop.cpp', 'matcher/implicit_validator.cpp', 'matcher/match_details.cpp', 'matcher/match_expression_dependencies.cpp', 'matcher/match_expression_util.cpp', 'matcher/matchable.cpp', - 'matcher/matcher_type_set.cpp', 'matcher/matcher.cpp', + 'matcher/matcher_type_set.cpp', 'matcher/rewrite_expr.cpp', - 'matcher/schema/encrypt_schema_types.cpp', 'matcher/schema/encrypt_schema.idl', + 'matcher/schema/encrypt_schema_types.cpp', 'matcher/schema/expression_internal_schema_all_elem_match_from_index.cpp', 'matcher/schema/expression_internal_schema_allowed_properties.cpp', 'matcher/schema/expression_internal_schema_cond.cpp', @@ -1541,6 +1541,7 @@ env.Library( 'matcher/schema/expression_internal_schema_xor.cpp', 'matcher/schema/json_pointer.cpp', 'matcher/schema/json_schema_parser.cpp', + 'pipeline/expression.cpp', 'pipeline/expression_context.cpp', 'pipeline/expression_dependencies.cpp', 'pipeline/expression_function.cpp', @@ -1548,7 +1549,6 @@ env.Library( 'pipeline/expression_parser.idl', 'pipeline/expression_test_api_version.cpp', 'pipeline/expression_trigonometric.cpp', - 'pipeline/expression.cpp', 'pipeline/javascript_execution.cpp', 'pipeline/make_js_function.cpp', 'pipeline/monotonic_expression.cpp', diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index c3ca11d290f..2c1d75c3d9d 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -651,8 +651,7 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/audit', - '$BUILD_DIR/mongo/s/grid', - '$BUILD_DIR/mongo/s/write_ops/cluster_write_ops', + '$BUILD_DIR/mongo/s/sharding_api', 'cluster_server_parameter_cmds_idl', ], ) diff --git a/src/mongo/db/index/SConscript b/src/mongo/db/index/SConscript index ab053edfdcd..c3cba76f3ce 100644 --- a/src/mongo/db/index/SConscript +++ b/src/mongo/db/index/SConscript @@ -15,7 +15,10 @@ env.Benchmark( env.Library( target='expression_params', - source=['expression_params.cpp', 's2_common.cpp'], + source=[ + 'expression_params.cpp', + 's2_common.cpp', + ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/bson/util/bson_extract', @@ -96,10 +99,10 @@ iamEnv.Library( ) iamEnv.Library( - target="column_store_index", + target='column_store_index', source=[ 'column_cell.cpp', - "column_store_sorter.cpp", + 'column_store_sorter.cpp', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index e856ef5fd78..27e709faf15 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -538,12 +538,13 @@ env.Benchmark( 'abt/abt_translate_pipeline_bm.cpp', ], LIBDEPS=[ - "$BUILD_DIR/mongo/db/auth/authmocks", + '$BUILD_DIR/mongo/db/auth/authmocks', '$BUILD_DIR/mongo/db/pipeline/abt_translation', '$BUILD_DIR/mongo/db/pipeline/pipeline', '$BUILD_DIR/mongo/db/query/canonical_query', '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/query_exec', + '$BUILD_DIR/mongo/db/query_expressions', '$BUILD_DIR/mongo/unittest/unittest', '$BUILD_DIR/mongo/util/processinfo', ], diff --git a/src/mongo/db/pipeline/document_source_change_stream_handle_topology_change.cpp b/src/mongo/db/pipeline/document_source_change_stream_handle_topology_change.cpp index e09c35179f4..7aa410dfe35 100644 --- a/src/mongo/db/pipeline/document_source_change_stream_handle_topology_change.cpp +++ b/src/mongo/db/pipeline/document_source_change_stream_handle_topology_change.cpp @@ -39,7 +39,6 @@ #include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" -#include "mongo/s/query/async_results_merger_params_gen.h" #include "mongo/s/query/establish_cursors.h" #include "mongo/util/fail_point.h" diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index 8b35434e51a..78cf04c288c 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -105,16 +105,19 @@ env.Library( ) env.Library( - target="query_plan_cache", + target='query_plan_cache', source=[ - "classic_plan_cache.cpp", - "plan_cache_callbacks.cpp", - "plan_cache_invalidator.cpp", - "sbe_plan_cache.cpp", + 'classic_plan_cache.cpp', + 'plan_cache_callbacks.cpp', + 'plan_cache_invalidator.cpp', + 'sbe_plan_cache.cpp', ], LIBDEPS=[ - "$BUILD_DIR/mongo/base", "$BUILD_DIR/mongo/db/exec/sbe/query_sbe", "canonical_query", - "memory_util" + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/exec/sbe/query_sbe', + '$BUILD_DIR/mongo/db/query_expressions', + 'canonical_query', + 'memory_util', ], ) diff --git a/src/mongo/db/s/analyze_shard_key_read_write_distribution.cpp b/src/mongo/db/s/analyze_shard_key_read_write_distribution.cpp index f767dffc85d..b7dbe4541b5 100644 --- a/src/mongo/db/s/analyze_shard_key_read_write_distribution.cpp +++ b/src/mongo/db/s/analyze_shard_key_read_write_distribution.cpp @@ -27,8 +27,6 @@ * it in the license file. */ -#include "mongo/platform/basic.h" - #include "mongo/db/s/analyze_shard_key_read_write_distribution.h" #include "mongo/db/db_raii.h" @@ -41,6 +39,7 @@ #include "mongo/s/analyze_shard_key_util.h" #include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" +#include "mongo/s/shard_key_pattern_query_util.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding @@ -114,8 +113,8 @@ DistributionMetricsCalculator<DistributionMetricsType, SampleSizeType>::_increme const boost::optional<LegacyRuntimeConstants>& runtimeConstants, const boost::optional<BSONObj>& letParameters) { auto filter = primaryFilter; - auto shardKey = uassertStatusOK( - _getShardKeyPattern().extractShardKeyFromQuery(opCtx, _targeter.getNS(), primaryFilter)); + auto shardKey = uassertStatusOK(extractShardKeyFromBasicQuery( + opCtx, _targeter.getNS(), _getShardKeyPattern(), primaryFilter)); if (shardKey.isEmpty() && !secondaryFilter.isEmpty()) { shardKey = _getShardKeyPattern().extractShardKeyFromDoc(secondaryFilter); filter = shardKey; diff --git a/src/mongo/db/s/session_catalog_migration_source.cpp b/src/mongo/db/s/session_catalog_migration_source.cpp index e8e143e1c41..efcfa3f1bad 100644 --- a/src/mongo/db/s/session_catalog_migration_source.cpp +++ b/src/mongo/db/s/session_catalog_migration_source.cpp @@ -396,7 +396,7 @@ bool SessionCatalogMigrationSource::shouldSkipOplogEntry(const mongo::repl::Oplo const ShardKeyPattern& shardKeyPattern, const ChunkRange& chunkRange) { if (oplogEntry.isCrudOpType()) { - auto shardKey = shardKeyPattern.extractShardKeyFromOplogEntry(oplogEntry); + auto shardKey = extractShardKeyFromOplogEntry(shardKeyPattern, oplogEntry); return !chunkRange.containsKey(shardKey); } @@ -417,7 +417,7 @@ bool SessionCatalogMigrationSource::shouldSkipOplogEntry(const mongo::repl::Oplo // prevent a multi-statement transaction from being retried as a retryable write. return false; } - auto shardKey = shardKeyPattern.extractShardKeyFromOplogEntry(object2.value()); + auto shardKey = extractShardKeyFromOplogEntry(shardKeyPattern, object2.value()); return !chunkRange.containsKey(shardKey); } @@ -432,6 +432,21 @@ long long SessionCatalogMigrationSource::getSessionOplogEntriesSkippedSoFarLower return _sessionOplogEntriesSkippedSoFarLowerBound.load(); } +BSONObj SessionCatalogMigrationSource::extractShardKeyFromOplogEntry( + const ShardKeyPattern& shardKeyPattern, const repl::OplogEntry& entry) { + if (!entry.isCrudOpType()) { + return BSONObj(); + } + + auto objWithDocumentKey = entry.getObjectContainingDocumentKey(); + + if (!entry.isUpdateOrDelete()) { + return shardKeyPattern.extractShardKeyFromDoc(objWithDocumentKey); + } + + return shardKeyPattern.extractShardKeyFromDocumentKey(objWithDocumentKey); +} + void SessionCatalogMigrationSource::_extractOplogEntriesForInternalTransactionForRetryableWrite( WithLock, const repl::OplogEntry& applyOpsOplogEntry, diff --git a/src/mongo/db/s/session_catalog_migration_source.h b/src/mongo/db/s/session_catalog_migration_source.h index d1475a0d727..71e793fa501 100644 --- a/src/mongo/db/s/session_catalog_migration_source.h +++ b/src/mongo/db/s/session_catalog_migration_source.h @@ -30,10 +30,10 @@ #pragma once #include <boost/optional.hpp> -#include <memory> #include "mongo/client/dbclient_cursor.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/repl/oplog_entry.h" #include "mongo/db/repl/optime.h" #include "mongo/db/session/session_txn_record_gen.h" #include "mongo/db/transaction/transaction_history_iterator.h" @@ -181,6 +181,27 @@ public: long long getSessionOplogEntriesToBeMigratedSoFar(); long long getSessionOplogEntriesSkippedSoFarLowerBound(); + /** + * Given an Oplog entry, extracts the shard key corresponding to the key pattern for insert, + * update, and delete op types. If the op type is not a CRUD operation, an empty BSONObj() + * will be returned. + * + * For update and delete operations, the Oplog entry will contain an object with the document + * key. + * + * For insert operations, the Oplog entry will contain the original document from which the + * document key must be extracted + * + * Examples: + * For KeyPattern {'a.b': 1} + * If the oplog entries contains field op='i' + * oplog contains: { a : { b : "1" } } + * If the oplog entries contains field op='u' or op='d' + * oplog contains: { 'a.b': "1" } + */ + static BSONObj extractShardKeyFromOplogEntry(const ShardKeyPattern& shardKeyPattern, + const repl::OplogEntry& entry); + private: /** * An iterator for extracting session write oplogs that need to be cloned during migration. diff --git a/src/mongo/db/s/session_catalog_migration_source_test.cpp b/src/mongo/db/s/session_catalog_migration_source_test.cpp index f3a3e8d5154..040c438c13c 100644 --- a/src/mongo/db/s/session_catalog_migration_source_test.cpp +++ b/src/mongo/db/s/session_catalog_migration_source_test.cpp @@ -27,8 +27,6 @@ * it in the license file. */ -#include "mongo/platform/basic.h" - #include <algorithm> #include <utility> #include <vector> @@ -141,6 +139,31 @@ repl::OplogEntry makeOplogEntry( needsRetryImage); } +repl::OplogEntry makeOplogEntry(repl::OpTime opTime, + repl::OpTypeEnum opType, + BSONObj oField, + boost::optional<BSONObj> o2Field = boost::none) { + return { + repl::DurableOplogEntry(opTime, // optime + opType, // opType + kNs, // namespace + boost::none, // uuid + boost::none, // fromMigrate + repl::OplogEntry::kOplogVersion, // version + oField, // o + o2Field, // o2 + {}, // sessionInfo + boost::none, // upsert + Date_t(), // wall clock time + {}, // statement ids + boost::none, // optime of previous write within same transaction + boost::none, // pre-image optime + boost::none, // post-image optime + boost::none, // ShardId of resharding recipient + boost::none, // _id + boost::none)}; // needsRetryImage +} + repl::OplogEntry makeSentinelOplogEntry(const LogicalSessionId& sessionId, const TxnNumber& txnNumber, Date_t wallClockTime) { @@ -3034,5 +3057,83 @@ TEST_F(SessionCatalogMigrationSourceTest, ShouldSkipOplogEntryWorksWithRewritten rewrittenEntryOne, shardKeyPattern, kNestedChunkRange)); } +TEST_F(SessionCatalogMigrationSourceTest, ExtractShardKeyFromOplogUnnested) { + // + // Unnested ShardKeyPatterns from oplog entries with CRUD operation + // + + ShardKeyPattern pattern(BSON("a" << 1)); + auto deleteOplog = makeOplogEntry(repl::OpTime(Timestamp(50, 10), 1), // optime + repl::OpTypeEnum::kDelete, // op type + BSON("_id" << 1 << "a" << 5)); // o + auto insertOplog = makeOplogEntry(repl::OpTime(Timestamp(60, 10), 1), // optime + repl::OpTypeEnum::kInsert, // op type + BSON("_id" << 2 << "a" << 6)); // o + auto updateOplog = makeOplogEntry(repl::OpTime(Timestamp(70, 10), 1), // optime + repl::OpTypeEnum::kUpdate, // op type + BSON("_id" << 3), // o + BSON("_id" << 3 << "a" << 7)); // o2 + + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, deleteOplog), + fromjson("{a: 5}")); + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, insertOplog), + fromjson("{a: 6}")); + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, updateOplog), + fromjson("{a: 7}")); +} + +TEST_F(SessionCatalogMigrationSourceTest, ExtractShardKeyFromOplogNested) { + // + // Nested ShardKeyPatterns from oplog entries with CRUD operation + // + + ShardKeyPattern pattern(BSON("a.b" << 1)); + auto deleteOplog = makeOplogEntry(repl::OpTime(Timestamp(50, 10), 1), // optime + repl::OpTypeEnum::kDelete, // op type + BSON("_id" << 1 << "a.b" << 5)); // o + auto insertOplog = makeOplogEntry(repl::OpTime(Timestamp(60, 10), 1), // optime + repl::OpTypeEnum::kInsert, // op type + BSON("_id" << 2 << "a" << BSON("b" << 6))); // o + auto updateOplog = makeOplogEntry(repl::OpTime(Timestamp(70, 10), 1), // optime + repl::OpTypeEnum::kUpdate, // op type + BSON("_id" << 3), // o + BSON("_id" << 3 << "a.b" << 7)); // o2 + + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, deleteOplog), + fromjson("{'a.b': 5}")); + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, insertOplog), + fromjson("{'a.b': 6}")); + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, updateOplog), + fromjson("{'a.b': 7}")); +} + +TEST_F(SessionCatalogMigrationSourceTest, ExtractShardKeyFromOplogNonCRUD) { + // + // Oplogs with non-CRUD op types + // + + ShardKeyPattern pattern(BSON("a.b" << 1)); + auto noopOplog = makeOplogEntry(repl::OpTime(Timestamp(50, 10), 1), // optime + repl::OpTypeEnum::kNoop, // op type + BSON("_id" << 1 << "a.b" << 5)); // o + auto commandOplog = makeOplogEntry(repl::OpTime(Timestamp(60, 10), 1), // optime + repl::OpTypeEnum::kCommand, // op type + BSON("create" + << "c")); // o + + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, noopOplog), + BSONObj()); + ASSERT_BSONOBJ_EQ( + SessionCatalogMigrationSource::extractShardKeyFromOplogEntry(pattern, commandOplog), + BSONObj()); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/session/SConscript b/src/mongo/db/session/SConscript index 0e779787bff..32ea42a2691 100644 --- a/src/mongo/db/session/SConscript +++ b/src/mongo/db/session/SConscript @@ -54,7 +54,6 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/client/clientdriver_minimal', - '$BUILD_DIR/mongo/s/write_ops/batch_write_types', 'logical_session_id', 'logical_session_id_helpers', ], diff --git a/src/mongo/db/update/SConscript b/src/mongo/db/update/SConscript index ad3a18f6705..798c490d7fd 100644 --- a/src/mongo/db/update/SConscript +++ b/src/mongo/db/update/SConscript @@ -96,6 +96,7 @@ env.Library( '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/db/ops/write_ops_parsers', '$BUILD_DIR/mongo/db/query/canonical_query', + '$BUILD_DIR/mongo/db/query_expressions', '$BUILD_DIR/mongo/db/server_options_core', 'update', ], diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index ae3e0b0fc72..5528c5128cc 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -32,14 +32,28 @@ env.Library( 'cluster_ddl.cpp', 'cluster_write.cpp', 'collection_routing_info_targeter.cpp', + 'shard_key_pattern_query_util.cpp', + 'write_ops/batch_write_exec.cpp', + 'write_ops/batch_write_op.cpp', + 'write_ops/write_op.cpp', + 'write_ops/write_without_shard_key_util.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/commands/server_status_core', '$BUILD_DIR/mongo/db/fle_crud', '$BUILD_DIR/mongo/db/not_primary_error_tracker', + '$BUILD_DIR/mongo/db/pipeline/pipeline', + '$BUILD_DIR/mongo/db/pipeline/process_interface/mongos_process_interface', '$BUILD_DIR/mongo/db/timeseries/timeseries_conversion_util', '$BUILD_DIR/mongo/db/timeseries/timeseries_options', 'query/cluster_query', - 'write_ops/cluster_write_ops', + 'sharding_router_api', + 'write_ops/batch_write_types', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/catalog/collection_uuid_mismatch_info', + '$BUILD_DIR/mongo/db/internal_transactions_feature_flag', + '$BUILD_DIR/mongo/db/transaction/transaction_api', ], ) @@ -181,8 +195,8 @@ env.Library( 'analyze_shard_key_cmd.idl', 'cannot_implicitly_create_collection_info.cpp', 'catalog/type_changelog.cpp', - 'catalog/type_chunk_base.idl', 'catalog/type_chunk.cpp', + 'catalog/type_chunk_base.idl', 'catalog/type_collection.cpp', 'catalog/type_collection.idl', 'catalog/type_config_version.cpp', @@ -204,7 +218,6 @@ env.Library( 'refresh_query_analyzer_configuration_cmd.idl', 'request_types/abort_reshard_collection.idl', 'request_types/add_shard_request_type.cpp', - 'request_types/get_stats_for_balancing.idl', 'request_types/add_shard_to_zone_request_type.cpp', 'request_types/auto_split_vector.idl', 'request_types/balance_chunk_request_type.cpp', @@ -221,7 +234,7 @@ env.Library( 'request_types/flush_routing_table_cache_updates.idl', 'request_types/get_database_version.idl', 'request_types/get_historical_placement_info.idl', - 'request_types/shardsvr_join_migrations_request.idl', + 'request_types/get_stats_for_balancing.idl', 'request_types/merge_chunk_request.idl', 'request_types/migration_secondary_throttle_options.cpp', 'request_types/move_primary.idl', @@ -231,13 +244,14 @@ env.Library( 'request_types/resharding_operation_time.idl', 'request_types/set_allow_migrations.idl', 'request_types/sharded_ddl_commands.idl', + 'request_types/shardsvr_join_migrations_request.idl', 'request_types/update_zone_key_range_request_type.cpp', 'request_types/wait_for_fail_point.idl', 'resharding/common_types.idl', + 'resharding/resharding_coordinator_service_conflicting_op_in_progress_info.cpp', 'resharding/resharding_feature_flag.idl', 'resharding/resume_token.idl', 'resharding/type_collection_fields.idl', - 'resharding/resharding_coordinator_service_conflicting_op_in_progress_info.cpp', 'shard_cannot_refresh_due_to_locks_held_exception.cpp', 'shard_invalidated_for_targeting_exception.cpp', 'shard_version.cpp', @@ -684,14 +698,11 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/timeseries/timeseries_conversion_util', '$BUILD_DIR/mongo/db/timeseries/timeseries_options', '$BUILD_DIR/mongo/dbtests/mocklib', - '$BUILD_DIR/mongo/s/catalog/sharding_catalog_client_mock', - '$BUILD_DIR/mongo/s/commands/cluster_commands', - '$BUILD_DIR/mongo/s/commands/cluster_commands_common', - '$BUILD_DIR/mongo/s/write_ops/batch_write_types', - '$BUILD_DIR/mongo/s/write_ops/cluster_write_ops', - '$BUILD_DIR/mongo/s/write_ops/write_without_shard_key_util', '$BUILD_DIR/mongo/util/net/network', '$BUILD_DIR/mongo/util/periodic_runner_factory', + 'catalog/sharding_catalog_client_mock', + 'commands/cluster_commands', + 'commands/cluster_commands_common', 'coreshard', 'load_balancer_support', 'mongos_topology_coordinator', diff --git a/src/mongo/s/collection_routing_info_targeter.cpp b/src/mongo/s/collection_routing_info_targeter.cpp index 7ab82e622c8..467f5afac6c 100644 --- a/src/mongo/s/collection_routing_info_targeter.cpp +++ b/src/mongo/s/collection_routing_info_targeter.cpp @@ -27,11 +27,8 @@ * it in the license file. */ - #include "mongo/s/collection_routing_info_targeter.h" -#include <csignal> - #include "mongo/db/commands/server_status_metric.h" #include "mongo/db/curop.h" #include "mongo/db/internal_transactions_feature_flag_gen.h" @@ -53,12 +50,10 @@ #include "mongo/s/cluster_ddl.h" #include "mongo/s/database_version.h" #include "mongo/s/grid.h" -#include "mongo/s/shard_key_pattern.h" +#include "mongo/s/shard_key_pattern_query_util.h" #include "mongo/util/intrusive_counter.h" #include "mongo/util/str.h" -#include "mongo/db/timeseries/timeseries_update_delete_util.h" - #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding @@ -149,8 +144,8 @@ BSONObj getUpdateExprForTargeting(const boost::intrusive_ptr<ExpressionContext> // We are missing _id, so attempt to extract it from an exact match in the update's query spec. // This will guarantee that we can target a single shard, but it is not necessarily fatal if no // exact _id can be found. - const auto idFromQuery = - uassertStatusOK(kVirtualIdShardKey.extractShardKeyFromQuery(expCtx, updateQuery)); + const auto idFromQuery = uassertStatusOK( + extractShardKeyFromBasicQueryWithContext(expCtx, kVirtualIdShardKey, updateQuery)); if (auto idElt = idFromQuery[kIdFieldName]) { updateExpr = updateExpr.addField(idElt); } @@ -472,8 +467,9 @@ std::vector<ShardEndpoint> CollectionRoutingInfoTargeter::targetUpdate( // to target based on the replacement doc, it could result in an insertion even if a document // matching the query exists on another shard. if (isUpsert) { - return targetByShardKey(shardKeyPattern.extractShardKeyFromQuery(expCtx, query), - "Failed to target upsert by query"); + return targetByShardKey( + extractShardKeyFromBasicQueryWithContext(expCtx, shardKeyPattern, query), + "Failed to target upsert by query"); } // We first try to target based on the update's query. It is always valid to forward any update @@ -562,8 +558,8 @@ std::vector<ShardEndpoint> CollectionRoutingInfoTargeter::targetDelete( // Sharded collections have the following further requirements for targeting: // // Limit-1 deletes must be targeted exactly by shard key *or* exact _id - shardKey = uassertStatusOK( - _cri.cm.getShardKeyPattern().extractShardKeyFromQuery(expCtx, deleteQuery)); + shardKey = uassertStatusOK(extractShardKeyFromBasicQueryWithContext( + expCtx, _cri.cm.getShardKeyPattern(), deleteQuery)); } // Target the shard key or delete query diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 4c482b45f4e..9cdf12c20ac 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -157,10 +157,9 @@ env.Library( '$BUILD_DIR/mongo/s/load_balancer_support', '$BUILD_DIR/mongo/s/mongos_topology_coordinator', '$BUILD_DIR/mongo/s/query/cluster_aggregate', - '$BUILD_DIR/mongo/s/query/cluster_client_cursor', + '$BUILD_DIR/mongo/s/query/cluster_query', '$BUILD_DIR/mongo/s/sharding_api', '$BUILD_DIR/mongo/s/sharding_router_api', - '$BUILD_DIR/mongo/s/write_ops/write_without_shard_key_util', '$BUILD_DIR/mongo/transport/message_compressor', '$BUILD_DIR/mongo/transport/transport_layer_common', 'cluster_commands_common', diff --git a/src/mongo/s/commands/cluster_clear_jumbo_flag_cmd.cpp b/src/mongo/s/commands/cluster_clear_jumbo_flag_cmd.cpp index 20d8645fac4..7c5631d646d 100644 --- a/src/mongo/s/commands/cluster_clear_jumbo_flag_cmd.cpp +++ b/src/mongo/s/commands/cluster_clear_jumbo_flag_cmd.cpp @@ -27,9 +27,6 @@ * it in the license file. */ - -#include "mongo/platform/basic.h" - #include <string> #include <vector> @@ -41,6 +38,7 @@ #include "mongo/s/commands/cluster_commands_gen.h" #include "mongo/s/grid.h" #include "mongo/s/request_types/sharded_ddl_commands_gen.h" +#include "mongo/s/shard_key_pattern_query_util.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand @@ -93,8 +91,8 @@ public: boost::optional<Chunk> chunk; if (request().getFind()) { - BSONObj shardKey = uassertStatusOK(cm.getShardKeyPattern().extractShardKeyFromQuery( - opCtx, ns(), *request().getFind())); + BSONObj shardKey = uassertStatusOK(extractShardKeyFromBasicQuery( + opCtx, ns(), cm.getShardKeyPattern(), *request().getFind())); uassert(51260, str::stream() << "no shard key found in chunk query " << *request().getFind(), diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index 90a8323a250..f47f2d5d987 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -27,9 +27,6 @@ * it in the license file. */ - -#include "mongo/platform/basic.h" - #include "mongo/base/status_with.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/db/auth/action_set.h" @@ -61,6 +58,7 @@ #include "mongo/s/query_analysis_sampler_util.h" #include "mongo/s/request_types/cluster_commands_without_shard_key_gen.h" #include "mongo/s/session_catalog_router.h" +#include "mongo/s/shard_key_pattern_query_util.h" #include "mongo/s/stale_exception.h" #include "mongo/s/transaction_router.h" #include "mongo/s/transaction_router_resource_yielder.h" @@ -139,8 +137,8 @@ BSONObj getShardKey(OperationContext* opCtx, auto expCtx = makeExpressionContextWithDefaultsForTargeter( opCtx, nss, collation, verbosity, let, runtimeConstants); - BSONObj shardKey = - uassertStatusOK(chunkMgr.getShardKeyPattern().extractShardKeyFromQuery(expCtx, query)); + BSONObj shardKey = uassertStatusOK( + extractShardKeyFromBasicQueryWithContext(expCtx, chunkMgr.getShardKeyPattern(), query)); uassert(ErrorCodes::ShardKeyNotFound, "Query for sharded findAndModify must contain the shard key", !shardKey.isEmpty()); diff --git a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp index e7f1957011a..0ae1e84d27a 100644 --- a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp +++ b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp @@ -27,9 +27,6 @@ * it in the license file. */ - -#include "mongo/platform/basic.h" - #include "mongo/db/audit.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" @@ -46,11 +43,11 @@ #include "mongo/s/grid.h" #include "mongo/s/request_types/migration_secondary_throttle_options.h" #include "mongo/s/request_types/move_range_request_gen.h" +#include "mongo/s/shard_key_pattern_query_util.h" #include "mongo/util/timer.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand - namespace mongo { namespace { @@ -145,8 +142,8 @@ public: if (find) { // find - BSONObj shardKey = uassertStatusOK( - chunkManager.getShardKeyPattern().extractShardKeyFromQuery(opCtx, ns(), *find)); + BSONObj shardKey = uassertStatusOK(extractShardKeyFromBasicQuery( + opCtx, ns(), chunkManager.getShardKeyPattern(), *find)); uassert(656450, str::stream() << "no shard key found in chunk query " << *find, diff --git a/src/mongo/s/commands/cluster_split_cmd.cpp b/src/mongo/s/commands/cluster_split_cmd.cpp index b5ab273410f..8d5ed3d68e9 100644 --- a/src/mongo/s/commands/cluster_split_cmd.cpp +++ b/src/mongo/s/commands/cluster_split_cmd.cpp @@ -27,9 +27,6 @@ * it in the license file. */ - -#include "mongo/platform/basic.h" - #include <string> #include <vector> @@ -43,11 +40,11 @@ #include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" +#include "mongo/s/shard_key_pattern_query_util.h" #include "mongo/s/shard_util.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand - namespace mongo { namespace { @@ -201,8 +198,8 @@ public: if (!find.isEmpty()) { // find - BSONObj shardKey = - uassertStatusOK(cm.getShardKeyPattern().extractShardKeyFromQuery(opCtx, nss, find)); + BSONObj shardKey = uassertStatusOK( + extractShardKeyFromBasicQuery(opCtx, nss, cm.getShardKeyPattern(), find)); if (shardKey.isEmpty()) { errmsg = str::stream() << "no shard key found in chunk query " << find; return false; diff --git a/src/mongo/s/query/SConscript b/src/mongo/s/query/SConscript index e86fcec4d6a..905c1cbe0f0 100644 --- a/src/mongo/s/query/SConscript +++ b/src/mongo/s/query/SConscript @@ -7,18 +7,22 @@ env = env.Clone() env.Library( target='cluster_query', source=[ + 'cluster_client_cursor_impl.cpp', 'cluster_find.cpp', 'cluster_query_knobs.idl', + 'store_possible_cursor.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/curop_failpoint_helpers', + '$BUILD_DIR/mongo/db/query/command_request_response', '$BUILD_DIR/mongo/db/query/op_metrics', '$BUILD_DIR/mongo/db/query/query_common', '$BUILD_DIR/mongo/s/sharding_router_api', - 'cluster_client_cursor', + 'async_results_merger', 'cluster_cursor_cleanup_job', - 'store_possible_cursor', + 'cluster_cursor_manager', + 'router_exec_stage', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/catalog/collection_uuid_mismatch_info', @@ -37,30 +41,21 @@ env.Library( '$BUILD_DIR/mongo/db/pipeline/pipeline', '$BUILD_DIR/mongo/db/pipeline/process_interface/mongos_process_interface', '$BUILD_DIR/mongo/db/pipeline/sharded_agg_helpers', + '$BUILD_DIR/mongo/db/shared_request_handling', '$BUILD_DIR/mongo/db/views/view_catalog_helpers', '$BUILD_DIR/mongo/db/views/views', - '$BUILD_DIR/mongo/s/query/cluster_client_cursor', 'cluster_query', + 'router_exec_stage', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/catalog/collection_uuid_mismatch_info', '$BUILD_DIR/mongo/db/timeseries/timeseries_options', + 'async_results_merger', 'cqf_utils', ], ) env.Library( - target='cluster_client_cursor', - source=[ - 'cluster_client_cursor_impl.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/db/shared_request_handling', - 'router_exec_stage', - ], -) - -env.Library( target='router_exec_stage', source=[ 'document_source_merge_cursors.cpp', @@ -108,20 +103,6 @@ env.Library( ) env.Library( - target="store_possible_cursor", - source=[ - "store_possible_cursor.cpp", - ], - LIBDEPS=[ - "$BUILD_DIR/mongo/base", - "$BUILD_DIR/mongo/db/query/command_request_response", - "$BUILD_DIR/mongo/db/query/op_metrics", - "cluster_client_cursor", - "cluster_cursor_manager", - ], -) - -env.Library( target="cluster_cursor_manager", source=[ "cluster_cursor_manager.cpp", @@ -180,9 +161,8 @@ env.CppUnitTest( "$BUILD_DIR/mongo/util/clock_source_mock", "async_results_merger", "cluster_aggregate", - "cluster_client_cursor", "cluster_cursor_manager", + "cluster_query", "router_exec_stage", - "store_possible_cursor", ], ) diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index c693528de08..d04632a8aa8 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -27,20 +27,14 @@ * it in the license file. */ -#include "mongo/platform/basic.h" - #include "mongo/s/shard_key_pattern.h" -#include <vector> - #include "mongo/bson/simple_bsonelement_comparator.h" -#include "mongo/db/field_ref.h" #include "mongo/db/field_ref_set.h" #include "mongo/db/hasher.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/matcher/path_internal.h" -#include "mongo/db/query/canonical_query.h" #include "mongo/db/update/path_support.h" #include "mongo/util/str.h" #include "mongo/util/transitional_tools_do_not_use/vector_spooling.h" @@ -430,20 +424,6 @@ BSONObj ShardKeyPattern::extractShardKeyFromDocThrows(const BSONObj& doc) const return shardKey; } -BSONObj ShardKeyPattern::extractShardKeyFromOplogEntry(const repl::OplogEntry& entry) const { - if (!entry.isCrudOpType()) { - return BSONObj(); - } - - auto objWithDocumentKey = entry.getObjectContainingDocumentKey(); - - if (!entry.isUpdateOrDelete()) { - return extractShardKeyFromDoc(objWithDocumentKey); - } - - return extractShardKeyFromDocumentKey(objWithDocumentKey); -} - BSONObj ShardKeyPattern::emplaceMissingShardKeyValuesForDocument(const BSONObj doc) const { BSONObjBuilder fullDocBuilder(doc); for (const auto& skField : _keyPattern.toBSON()) { @@ -460,49 +440,6 @@ BSONObj ShardKeyPattern::emplaceMissingShardKeyValuesForDocument(const BSONObj d return fullDocBuilder.obj(); } -StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(OperationContext* opCtx, - const NamespaceString& nss, - const BSONObj& basicQuery) const { - auto findCommand = std::make_unique<FindCommandRequest>(nss); - findCommand->setFilter(basicQuery.getOwned()); - - const boost::intrusive_ptr<ExpressionContext> expCtx; - auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx, - std::move(findCommand), - false, /* isExplain */ - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); - } - - return extractShardKeyFromQuery(*statusWithCQ.getValue()); -} - -StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery( - boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& basicQuery) const { - auto findCommand = std::make_unique<FindCommandRequest>(expCtx->ns); - findCommand->setFilter(basicQuery.getOwned()); - if (!expCtx->getCollatorBSON().isEmpty()) { - findCommand->setCollation(expCtx->getCollatorBSON().getOwned()); - } - - auto statusWithCQ = - CanonicalQuery::canonicalize(expCtx->opCtx, - std::move(findCommand), - false, /* isExplain */ - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); - } - - return extractShardKeyFromQuery(*statusWithCQ.getValue()); -} - BSONObj ShardKeyPattern::extractShardKeyFromQuery(const CanonicalQuery& query) const { // Extract equalities from query. EqualityMatches equalities; diff --git a/src/mongo/s/shard_key_pattern.h b/src/mongo/s/shard_key_pattern.h index 70f5aff336d..cd19df027e8 100644 --- a/src/mongo/s/shard_key_pattern.h +++ b/src/mongo/s/shard_key_pattern.h @@ -29,23 +29,18 @@ #pragma once -#include <memory> #include <vector> -#include "mongo/base/status.h" #include "mongo/base/status_with.h" #include "mongo/db/exec/filter.h" +#include "mongo/db/field_ref.h" #include "mongo/db/jsobj.h" #include "mongo/db/keypattern.h" +#include "mongo/db/query/canonical_query.h" #include "mongo/db/query/index_bounds.h" -#include "mongo/db/repl/oplog_entry.h" namespace mongo { -class CanonicalQuery; -class FieldRef; -class OperationContext; - /** * Helper struct when generating flattened bounds below * @@ -214,63 +209,10 @@ public: BSONObj extractShardKeyFromDocThrows(const BSONObj& doc) const; /** - * Given an Oplog entry, extracts the shard key corresponding to the key pattern for insert, - * update, and delete op types. If the op type is not a CRUD operation, an empty BSONObj() - * will be returned. - * - * For update and delete operations, the Oplog entry will contain an object with the document - * key. - * - * For insert operations, the Oplog entry will contain the original document from which the - * document key must be extracted - * - * Examples: - * For KeyPattern {'a.b': 1} - * If the oplog entries contains field op='i' - * oplog contains: { a : { b : "1" } } - * If the oplog entries contains field op='u' or op='d' - * oplog contains: { 'a.b': "1" } - */ - BSONObj extractShardKeyFromOplogEntry(const repl::OplogEntry& entry) const; - - /** * Returns the document with missing shard key values set to null. */ BSONObj emplaceMissingShardKeyValuesForDocument(BSONObj doc) const; - /** - * Given a simple BSON query, extracts the shard key corresponding to the key pattern - * from equality matches in the query. The query expression *must not* be a complex query - * with sorts or other attributes. - * - * Logically, the equalities in the BSON query can be serialized into a BSON document and - * then a shard key is extracted from this equality document. - * - * NOTE: BSON queries and BSON documents look similar but are different languages. Use the - * correct shard key extraction function. - * - * Returns !OK status if the query cannot be parsed. Returns an empty BSONObj() if there is - * no shard key found in the query equalities. - * - * Examples: - * If the key pattern is { a : 1 } - * { a : "hi", b : 4 } --> returns { a : "hi" } - * { a : { $eq : "hi" }, b : 4 } --> returns { a : "hi" } - * { $and : [{a : { $eq : "hi" }}, { b : 4 }] } --> returns { a : "hi" } - * If the key pattern is { 'a.b' : 1 } - * { a : { b : "hi" } } --> returns { 'a.b' : "hi" } - * { 'a.b' : "hi" } --> returns { 'a.b' : "hi" } - * { a : { b : { $eq : "hi" } } } --> returns {} because the query language treats this as - * a : { $eq : { b : ... } } - */ - StatusWith<BSONObj> extractShardKeyFromQuery(OperationContext* opCtx, - const NamespaceString& nss, - const BSONObj& basicQuery) const; - - // Used to parse queries that contain let parameters and runtime constants. - StatusWith<BSONObj> extractShardKeyFromQuery(boost::intrusive_ptr<ExpressionContext> expCtx, - const BSONObj& basicQuery) const; - BSONObj extractShardKeyFromQuery(const CanonicalQuery& query) const; /** diff --git a/src/mongo/s/shard_key_pattern_query_util.cpp b/src/mongo/s/shard_key_pattern_query_util.cpp new file mode 100644 index 00000000000..8b8d40c06ad --- /dev/null +++ b/src/mongo/s/shard_key_pattern_query_util.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2018-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/s/shard_key_pattern_query_util.h" + +namespace mongo { + +StatusWith<BSONObj> extractShardKeyFromBasicQuery(OperationContext* opCtx, + const NamespaceString& nss, + const ShardKeyPattern& shardKeyPattern, + const BSONObj& basicQuery) { + auto findCommand = std::make_unique<FindCommandRequest>(nss); + findCommand->setFilter(basicQuery.getOwned()); + + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(findCommand), + false, /* isExplain */ + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + if (!statusWithCQ.isOK()) { + return statusWithCQ.getStatus(); + } + + return shardKeyPattern.extractShardKeyFromQuery(*statusWithCQ.getValue()); +} + +StatusWith<BSONObj> extractShardKeyFromBasicQueryWithContext( + boost::intrusive_ptr<ExpressionContext> expCtx, + const ShardKeyPattern& shardKeyPattern, + const BSONObj& basicQuery) { + auto findCommand = std::make_unique<FindCommandRequest>(expCtx->ns); + findCommand->setFilter(basicQuery.getOwned()); + if (!expCtx->getCollatorBSON().isEmpty()) { + findCommand->setCollation(expCtx->getCollatorBSON().getOwned()); + } + + auto statusWithCQ = + CanonicalQuery::canonicalize(expCtx->opCtx, + std::move(findCommand), + false, /* isExplain */ + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + if (!statusWithCQ.isOK()) { + return statusWithCQ.getStatus(); + } + + return shardKeyPattern.extractShardKeyFromQuery(*statusWithCQ.getValue()); +} + +} // namespace mongo diff --git a/src/mongo/s/shard_key_pattern_query_util.h b/src/mongo/s/shard_key_pattern_query_util.h new file mode 100644 index 00000000000..1872887f96b --- /dev/null +++ b/src/mongo/s/shard_key_pattern_query_util.h @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2018-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/s/shard_key_pattern.h" + +namespace mongo { + +/** + * Given a simple BSON query, extracts the shard key corresponding to the key pattern from equality + * matches in the query. The query expression *must not* be a complex query with sorts or other + * attributes. + * + * Logically, the equalities in the BSON query can be serialized into a BSON document and then a + * shard key is extracted from this equality document. + * + * NOTE: BSON queries and BSON documents look similar but are different languages. Use the correct + * shard key extraction function. + * + * Returns !OK status if the query cannot be parsed. + * Returns an empty BSONObj() if there is no shard key found in the query equalities. + * + * Examples: + * If the key pattern is { a : 1 } + * { a : "hi", b : 4 } --> returns { a : "hi" } + * { a : { $eq : "hi" }, b : 4 } --> returns { a : "hi" } + * { $and : [{a : { $eq : "hi" }}, { b : 4 }] } --> returns { a : "hi" } + * If the key pattern is { 'a.b' : 1 } + * { a : { b : "hi" } } --> returns { 'a.b' : "hi" } + * { 'a.b' : "hi" } --> returns { 'a.b' : "hi" } + * { a : { b : { $eq : "hi" } } } --> returns {} because the query language treats this as + * a : { $eq : { b : ... } } + */ +StatusWith<BSONObj> extractShardKeyFromBasicQuery(OperationContext* opCtx, + const NamespaceString& nss, + const ShardKeyPattern& shardKeyPattern, + const BSONObj& basicQuery); + +/** + * Variant of the above, which is used to parse queries that contain let parameters and runtime + * constants. + */ +StatusWith<BSONObj> extractShardKeyFromBasicQueryWithContext( + boost::intrusive_ptr<ExpressionContext> expCtx, + const ShardKeyPattern& shardKeyPattern, + const BSONObj& basicQuery); + +} // namespace mongo diff --git a/src/mongo/s/shard_key_pattern_test.cpp b/src/mongo/s/shard_key_pattern_test.cpp index 097fa15f014..a59f0494f73 100644 --- a/src/mongo/s/shard_key_pattern_test.cpp +++ b/src/mongo/s/shard_key_pattern_test.cpp @@ -27,14 +27,12 @@ * it in the license file. */ -#include "mongo/platform/basic.h" - #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/hasher.h" #include "mongo/db/json.h" #include "mongo/db/service_context_test_fixture.h" #include "mongo/s/concurrency/locker_mongos_client_observer.h" -#include "mongo/s/shard_key_pattern.h" +#include "mongo/s/shard_key_pattern_query_util.h" #include "mongo/unittest/death_test.h" namespace mongo { @@ -52,7 +50,7 @@ protected: BSONObj queryKey(const ShardKeyPattern& pattern, const BSONObj& query) { const NamespaceString nss("foo"); - StatusWith<BSONObj> status = pattern.extractShardKeyFromQuery(_opCtx, nss, query); + StatusWith<BSONObj> status = extractShardKeyFromBasicQuery(_opCtx, nss, pattern, query); if (!status.isOK()) return BSONObj(); return status.getValue(); @@ -62,35 +60,6 @@ protected: OperationContext* _opCtx; }; -/** - * Creates OplogEntry with given field values. - */ -repl::OplogEntry makeOplogEntry(repl::OpTime opTime, - repl::OpTypeEnum opType, - NamespaceString nss, - BSONObj oField, - boost::optional<BSONObj> o2Field = boost::none) { - return { - repl::DurableOplogEntry(opTime, // optime - opType, // opType - nss, // namespace - boost::none, // uuid - boost::none, // fromMigrate - repl::OplogEntry::kOplogVersion, // version - oField, // o - o2Field, // o2 - {}, // sessionInfo - boost::none, // upsert - Date_t(), // wall clock time - {}, // statement ids - boost::none, // optime of previous write within same transaction - boost::none, // pre-image optime - boost::none, // post-image optime - boost::none, // ShardId of resharding recipient - boost::none, // _id - boost::none)}; // needsRetryImage -} - TEST_F(ShardKeyPatternTest, SingleFieldShardKeyPatternsValidityCheck) { ShardKeyPattern s1(BSON("a" << 1)); ShardKeyPattern s2(BSON("a" << 1.0f)); @@ -174,10 +143,6 @@ static BSONObj docKey(const ShardKeyPattern& pattern, const BSONObj& doc) { return pattern.extractShardKeyFromDoc(doc); } -static BSONObj docKeyFromOplog(const ShardKeyPattern& pattern, const repl::OplogEntry& entry) { - return pattern.extractShardKeyFromOplogEntry(entry); -} - TEST_F(ShardKeyPatternTest, ExtractDocShardKeySingle) { // // Single field ShardKeyPatterns @@ -269,76 +234,6 @@ TEST_F(ShardKeyPatternTest, ExtractDocShardKeyNested) { ASSERT_BSONOBJ_EQ(docKey(pattern, fromjson("{a:{b:[10, 20]}, c:30}")), BSONObj()); } -TEST_F(ShardKeyPatternTest, ExtractShardKeyFromOplogUnnested) { - // - // Unnested ShardKeyPatterns from oplog entries with CRUD operation - // - - ShardKeyPattern pattern(BSON("a" << 1)); - auto deleteOplog = makeOplogEntry(repl::OpTime(Timestamp(50, 10), 1), // optime - repl::OpTypeEnum::kDelete, // op type - NamespaceString("a"), // namespace - BSON("_id" << 1 << "a" << 5)); // o - auto insertOplog = makeOplogEntry(repl::OpTime(Timestamp(60, 10), 1), // optime - repl::OpTypeEnum::kInsert, // op type - NamespaceString("a"), // namespace - BSON("_id" << 2 << "a" << 6)); // o - auto updateOplog = makeOplogEntry(repl::OpTime(Timestamp(70, 10), 1), // optime - repl::OpTypeEnum::kUpdate, // op type - NamespaceString("a"), // namespace - BSON("_id" << 3), // o - BSON("_id" << 3 << "a" << 7)); // o2 - - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, deleteOplog), fromjson("{a: 5}")); - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, insertOplog), fromjson("{a: 6}")); - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, updateOplog), fromjson("{a: 7}")); -} - -TEST_F(ShardKeyPatternTest, ExtractShardKeyFromOplogNested) { - // - // Nested ShardKeyPatterns from oplog entries with CRUD operation - // - - ShardKeyPattern pattern(BSON("a.b" << 1)); - auto deleteOplog = makeOplogEntry(repl::OpTime(Timestamp(50, 10), 1), // optime - repl::OpTypeEnum::kDelete, // op type - NamespaceString("a.b"), // namespace - BSON("_id" << 1 << "a.b" << 5)); // o - auto insertOplog = makeOplogEntry(repl::OpTime(Timestamp(60, 10), 1), // optime - repl::OpTypeEnum::kInsert, // op type - NamespaceString("a.b"), // namespace - BSON("_id" << 2 << "a" << BSON("b" << 6))); // o - auto updateOplog = makeOplogEntry(repl::OpTime(Timestamp(70, 10), 1), // optime - repl::OpTypeEnum::kUpdate, // op type - NamespaceString("a.b"), // namespace - BSON("_id" << 3), // o - BSON("_id" << 3 << "a.b" << 7)); // o2 - - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, deleteOplog), fromjson("{'a.b': 5}")); - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, insertOplog), fromjson("{'a.b': 6}")); - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, updateOplog), fromjson("{'a.b': 7}")); -} - -TEST_F(ShardKeyPatternTest, ExtractShardKeyFromOplogNonCRUD) { - // - // Oplogs with non-CRUD op types - // - - ShardKeyPattern pattern(BSON("a.b" << 1)); - auto noopOplog = makeOplogEntry(repl::OpTime(Timestamp(50, 10), 1), // optime - repl::OpTypeEnum::kNoop, // op type - NamespaceString("a.b"), // namespace - BSON("_id" << 1 << "a.b" << 5)); // o - auto commandOplog = makeOplogEntry(repl::OpTime(Timestamp(60, 10), 1), // optime - repl::OpTypeEnum::kCommand, // op type - NamespaceString("a.b"), // namespace - BSON("create" - << "c")); // o - - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, noopOplog), BSONObj()); - ASSERT_BSONOBJ_EQ(docKeyFromOplog(pattern, commandOplog), BSONObj()); -} - TEST_F(ShardKeyPatternTest, ExtractDocShardKeyDeepNested) { // // Deeply nested ShardKeyPatterns diff --git a/src/mongo/s/write_ops/SConscript b/src/mongo/s/write_ops/SConscript index ec3d5a241e3..f2082063bfa 100644 --- a/src/mongo/s/write_ops/SConscript +++ b/src/mongo/s/write_ops/SConscript @@ -23,37 +23,3 @@ env.Library( '$BUILD_DIR/mongo/s/common_s', ], ) - -env.Library( - target='write_without_shard_key_util', - source=[ - 'write_without_shard_key_util.cpp', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/internal_transactions_feature_flag', - '$BUILD_DIR/mongo/db/transaction/transaction_api', - '$BUILD_DIR/mongo/s/grid', - '$BUILD_DIR/mongo/s/sharding_router_api', - ], -) - -env.Library( - target='cluster_write_ops', - source=[ - 'batch_write_exec.cpp', - 'batch_write_op.cpp', - 'write_op.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/db/commands/server_status_core', - '$BUILD_DIR/mongo/db/internal_transactions_feature_flag', - '$BUILD_DIR/mongo/db/pipeline/pipeline', - '$BUILD_DIR/mongo/db/pipeline/process_interface/mongos_process_interface', - '$BUILD_DIR/mongo/s/sharding_router_api', - 'batch_write_types', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/catalog/collection_uuid_mismatch_info', - 'write_without_shard_key_util', - ], -) diff --git a/src/mongo/s/write_ops/write_without_shard_key_util.cpp b/src/mongo/s/write_ops/write_without_shard_key_util.cpp index 2867ad0b9ac..cb2d2d12884 100644 --- a/src/mongo/s/write_ops/write_without_shard_key_util.cpp +++ b/src/mongo/s/write_ops/write_without_shard_key_util.cpp @@ -26,6 +26,7 @@ * exception statement from all source files in the program, then also delete * it in the license file. */ + #include "mongo/s/write_ops/write_without_shard_key_util.h" #include "mongo/bson/bsonobj.h" @@ -37,6 +38,7 @@ #include "mongo/s/catalog_cache.h" #include "mongo/s/grid.h" #include "mongo/s/request_types/cluster_commands_without_shard_key_gen.h" +#include "mongo/s/shard_key_pattern_query_util.h" #include "mongo/s/transaction_router_resource_yielder.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding @@ -138,7 +140,7 @@ bool useTwoPhaseProtocol(OperationContext* opCtx, } auto shardKey = - uassertStatusOK(cm.getShardKeyPattern().extractShardKeyFromQuery(opCtx, nss, query)); + uassertStatusOK(extractShardKeyFromBasicQuery(opCtx, nss, cm.getShardKeyPattern(), query)); // 'shardKey' will only be populated only if a full equality shard key is extracted. if (shardKey.isEmpty()) { |