summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2023-01-30 16:35:56 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-01-31 02:23:21 +0000
commit8aca0afe03fd7f9c3041463a470c7758e3c2a73e (patch)
tree956dab3499b3968fa24bbb8fa6925eea24f7098b
parent1b0c8231c24f550fc24453c3ce220eb58ba83663 (diff)
downloadmongo-8aca0afe03fd7f9c3041463a470c7758e3c2a73e.tar.gz
SERVER-73238 Move some shard_key_pattern query methods out of 'grid'
-rw-r--r--src/mongo/db/SConscript10
-rw-r--r--src/mongo/db/commands/SConscript3
-rw-r--r--src/mongo/db/index/SConscript9
-rw-r--r--src/mongo/db/pipeline/SConscript3
-rw-r--r--src/mongo/db/pipeline/document_source_change_stream_handle_topology_change.cpp1
-rw-r--r--src/mongo/db/query/SConscript17
-rw-r--r--src/mongo/db/s/analyze_shard_key_read_write_distribution.cpp7
-rw-r--r--src/mongo/db/s/session_catalog_migration_source.cpp19
-rw-r--r--src/mongo/db/s/session_catalog_migration_source.h23
-rw-r--r--src/mongo/db/s/session_catalog_migration_source_test.cpp105
-rw-r--r--src/mongo/db/session/SConscript1
-rw-r--r--src/mongo/db/update/SConscript1
-rw-r--r--src/mongo/s/SConscript33
-rw-r--r--src/mongo/s/collection_routing_info_targeter.cpp20
-rw-r--r--src/mongo/s/commands/SConscript3
-rw-r--r--src/mongo/s/commands/cluster_clear_jumbo_flag_cmd.cpp8
-rw-r--r--src/mongo/s/commands/cluster_find_and_modify_cmd.cpp8
-rw-r--r--src/mongo/s/commands/cluster_move_chunk_cmd.cpp9
-rw-r--r--src/mongo/s/commands/cluster_split_cmd.cpp9
-rw-r--r--src/mongo/s/query/SConscript40
-rw-r--r--src/mongo/s/shard_key_pattern.cpp63
-rw-r--r--src/mongo/s/shard_key_pattern.h62
-rw-r--r--src/mongo/s/shard_key_pattern_query_util.cpp80
-rw-r--r--src/mongo/s/shard_key_pattern_query_util.h75
-rw-r--r--src/mongo/s/shard_key_pattern_test.cpp109
-rw-r--r--src/mongo/s/write_ops/SConscript34
-rw-r--r--src/mongo/s/write_ops/write_without_shard_key_util.cpp4
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()) {