Compare commits
23 Commits
master
...
BACKPORT-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31895f53cd | ||
|
|
8b06b20e74 | ||
|
|
f876854381 | ||
|
|
d3b2ad3244 | ||
|
|
ae13a0375b | ||
|
|
a748104759 | ||
|
|
37f6d07553 | ||
|
|
09cb75d4c6 | ||
|
|
f4b99751fb | ||
|
|
b5f7f35d46 | ||
|
|
96399bf635 | ||
|
|
ced7b06862 | ||
|
|
619ab6338d | ||
|
|
6a050da034 | ||
|
|
5927f2e811 | ||
|
|
239040917d | ||
|
|
de755012e0 | ||
|
|
e72d191a30 | ||
|
|
2b1a5b3ccc | ||
|
|
180639fd33 | ||
|
|
2e15f33879 | ||
|
|
4d1c6a2b36 | ||
|
|
3419f8de5e |
@ -61,8 +61,8 @@ def generate_version_expansions():
|
||||
raise ValueError("Unable to parse version from stdin and no version.json provided")
|
||||
|
||||
if version_parts[0]:
|
||||
expansions["suffix"] = "latest"
|
||||
expansions["src_suffix"] = "latest"
|
||||
expansions["suffix"] = "v6.3-latest"
|
||||
expansions["src_suffix"] = "v6.3-latest"
|
||||
expansions["is_release"] = "false"
|
||||
else:
|
||||
expansions["suffix"] = version_line
|
||||
|
||||
@ -30,6 +30,8 @@ last-continuous:
|
||||
ticket: SERVER-53335
|
||||
- test_file: jstests/replsets/replSetGetStatus_member_wall_times.js
|
||||
ticket: SERVER-54909
|
||||
- test_file: jstests/sharding/migration_server_status.js
|
||||
ticket: SERVER-56186
|
||||
- test_file: jstests/sharding/cwwc_conflict_add_shard.js
|
||||
ticket: SERVER-56800
|
||||
- test_file: jstests/sharding/reconfig_fails_no_cwwc_set_sharding.js
|
||||
@ -254,12 +256,16 @@ last-continuous:
|
||||
ticket: SERVER-67723
|
||||
- test_file: jstests/sharding/collection_uuid_shard_capped_collection.js
|
||||
ticket: SERVER-67885
|
||||
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
|
||||
ticket: SERVER-68361
|
||||
- test_file: jstests/core/txns/txn_ops_allowed_on_buckets_coll.js
|
||||
ticket: SERVER-68556
|
||||
- test_file: jstests/core/txns/no_writes_to_system_collections_in_txn.js
|
||||
ticket: SERVER-68556
|
||||
- test_file: jstests/sharding/resharding_temp_ns_routing_info_unsharded.js
|
||||
ticket: SERVER-68628
|
||||
- test_file: jstests/sharding/move_chunk_concurrent_cloning.js
|
||||
ticket: SERVER-68648
|
||||
- test_file: jstests/sharding/move_chunk_interrupt_postimage.js
|
||||
ticket: SERVER-68728
|
||||
- test_file: jstests/sharding/resharding_critical_section_metrics.js
|
||||
@ -272,26 +278,22 @@ last-continuous:
|
||||
ticket: SERVER-69861
|
||||
- test_file: jstests/aggregation/expressions/switch_errors.js
|
||||
ticket: SERVER-70190
|
||||
- test_file: jstests/core/cover_null_queries.js
|
||||
ticket: SERVER-70436
|
||||
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
|
||||
ticket: SERVER-68361
|
||||
- test_file: jstests/sharding/migration_server_status.js
|
||||
ticket: SERVER-56186
|
||||
- test_file: jstests/replsets/apply_ops_strips_hash.js
|
||||
ticket: SERVER-70841
|
||||
- test_file: jstests/replsets/wtimeout_too_large.js
|
||||
ticket: SERVER-70360
|
||||
- test_file: jstests/sharding/all_collection_stats.js
|
||||
ticket: SERVER-71477
|
||||
- test_file: jstests/core/cover_null_queries.js
|
||||
ticket: SERVER-70436
|
||||
- test_file: jstests/sharding/timeseries_sharding_admin_commands.js
|
||||
ticket: SERVER-70790
|
||||
- test_file: jstests/replsets/apply_ops_strips_hash.js
|
||||
ticket: SERVER-70841
|
||||
- test_file: jstests/sharding/all_collection_stats.js
|
||||
ticket: SERVER-71477
|
||||
- test_file: jstests/sharding/hidden_index.js
|
||||
ticket: SERVER-71638
|
||||
- test_file: jstests/sharding/invalid_system_views_sharded_collection.js
|
||||
ticket: SERVER-71667
|
||||
- test_file: jstests/sharding/drop_collection.js
|
||||
ticket: SERVER-71689
|
||||
- test_file: jstests/sharding/hidden_index.js
|
||||
ticket: SERVER-71638
|
||||
- test_file: jstests/core/query/project/project_with_collation.js
|
||||
ticket: SERVER-72416
|
||||
- test_file: jstests/core/collation.js
|
||||
@ -300,12 +302,12 @@ last-continuous:
|
||||
ticket: SERVER-72416
|
||||
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/oplog_rollover.js
|
||||
ticket: SERVER-72422
|
||||
- test_file: jstests/sharding/move_chunk_concurrent_cloning.js
|
||||
ticket: SERVER-68648
|
||||
- test_file: jstests/sharding/timeseries_cluster_indexstats.js
|
||||
ticket: SERVER-72620
|
||||
- test_file: jstests/core/timeseries/bucket_unpacking_with_sort_extended_range.js
|
||||
ticket: SERVER-73110
|
||||
- test_file: jstests/core/timeseries/timeseries_groupby_reorder.js
|
||||
ticket: SERVER-73822
|
||||
suites: null
|
||||
last-lts:
|
||||
all:
|
||||
@ -405,6 +407,8 @@ last-lts:
|
||||
ticket: SERVER-55305
|
||||
- test_file: jstests/replsets/rollback_with_coalesced_txn_table_updates_from_vectored_inserts.js
|
||||
ticket: SERVER-55305
|
||||
- test_file: jstests/sharding/migration_server_status.js
|
||||
ticket: SERVER-56186
|
||||
- test_file: jstests/sharding/time_zone_info_mongos.js
|
||||
ticket: SERVER-56371
|
||||
- test_file: jstests/concurrency/fsm_workloads/findAndModify_flip_location.js
|
||||
@ -637,12 +641,16 @@ last-lts:
|
||||
ticket: SERVER-67723
|
||||
- test_file: jstests/sharding/collection_uuid_shard_capped_collection.js
|
||||
ticket: SERVER-67885
|
||||
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
|
||||
ticket: SERVER-68361
|
||||
- test_file: jstests/core/txns/txn_ops_allowed_on_buckets_coll.js
|
||||
ticket: SERVER-68556
|
||||
- test_file: jstests/core/txns/no_writes_to_system_collections_in_txn.js
|
||||
ticket: SERVER-68556
|
||||
- test_file: jstests/sharding/resharding_temp_ns_routing_info_unsharded.js
|
||||
ticket: SERVER-68628
|
||||
- test_file: jstests/sharding/move_chunk_concurrent_cloning.js
|
||||
ticket: SERVER-68648
|
||||
- test_file: jstests/sharding/move_chunk_interrupt_postimage.js
|
||||
ticket: SERVER-68728
|
||||
- test_file: jstests/replsets/tenant_migration_recipient_forget_migration.js
|
||||
@ -653,26 +661,22 @@ last-lts:
|
||||
ticket: SERVER-69861
|
||||
- test_file: jstests/aggregation/expressions/switch_errors.js
|
||||
ticket: SERVER-70190
|
||||
- test_file: jstests/core/cover_null_queries.js
|
||||
ticket: SERVER-70436
|
||||
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
|
||||
ticket: SERVER-68361
|
||||
- test_file: jstests/sharding/migration_server_status.js
|
||||
ticket: SERVER-56186
|
||||
- test_file: jstests/replsets/apply_ops_strips_hash.js
|
||||
ticket: SERVER-70841
|
||||
- test_file: jstests/replsets/wtimeout_too_large.js
|
||||
ticket: SERVER-70360
|
||||
- test_file: jstests/sharding/all_collection_stats.js
|
||||
ticket: SERVER-71477
|
||||
- test_file: jstests/core/cover_null_queries.js
|
||||
ticket: SERVER-70436
|
||||
- test_file: jstests/sharding/timeseries_sharding_admin_commands.js
|
||||
ticket: SERVER-70790
|
||||
- test_file: jstests/replsets/apply_ops_strips_hash.js
|
||||
ticket: SERVER-70841
|
||||
- test_file: jstests/sharding/all_collection_stats.js
|
||||
ticket: SERVER-71477
|
||||
- test_file: jstests/sharding/hidden_index.js
|
||||
ticket: SERVER-71638
|
||||
- test_file: jstests/sharding/invalid_system_views_sharded_collection.js
|
||||
ticket: SERVER-71667
|
||||
- test_file: jstests/sharding/drop_collection.js
|
||||
ticket: SERVER-71689
|
||||
- test_file: jstests/sharding/hidden_index.js
|
||||
ticket: SERVER-71638
|
||||
- test_file: jstests/core/query/project/project_with_collation.js
|
||||
ticket: SERVER-72416
|
||||
- test_file: jstests/core/collation.js
|
||||
@ -681,10 +685,10 @@ last-lts:
|
||||
ticket: SERVER-72416
|
||||
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/oplog_rollover.js
|
||||
ticket: SERVER-72422
|
||||
- test_file: jstests/sharding/move_chunk_concurrent_cloning.js
|
||||
ticket: SERVER-68648
|
||||
- test_file: jstests/sharding/timeseries_cluster_indexstats.js
|
||||
ticket: SERVER-72620
|
||||
- test_file: jstests/core/timeseries/bucket_unpacking_with_sort_extended_range.js
|
||||
ticket: SERVER-73110
|
||||
- test_file: jstests/core/timeseries/timeseries_groupby_reorder.js
|
||||
ticket: SERVER-73822
|
||||
suites: null
|
||||
|
||||
@ -346,40 +346,6 @@ buildvariants:
|
||||
- name: sharding_gen
|
||||
- name: sharding_opportunistic_secondary_targeting_gen
|
||||
|
||||
- <<: *linux-64-debug-required-template
|
||||
name: &linux-64-debug-wtdevelop linux-64-debug-wtdevelop
|
||||
display_name: "~ Linux DEBUG WiredTiger develop"
|
||||
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
|
||||
modules:
|
||||
- wtdevelop
|
||||
depends_on:
|
||||
- name: archive_dist_test_debug
|
||||
variant: &linux_x86_dynamic_debug_wtdevelop_compile_variant_name linux-x86-dynamic-debug-wtdevelop-compile
|
||||
- name: version_gen
|
||||
variant: generate-tasks-for-version
|
||||
# This is added because of EVG-18211.
|
||||
# Without this we are adding extra dependencies on evergreen and it is causing strain
|
||||
omit_generated_tasks: true
|
||||
expansions:
|
||||
use_wt_develop: true
|
||||
resmoke_jobs_factor: 0.5 # Avoid starting too many mongod's
|
||||
large_distro_name: rhel80-medium
|
||||
max_sub_suites: "5"
|
||||
target_resmoke_time: "15"
|
||||
compile_flags: >-
|
||||
--dbg=on
|
||||
--opt=on
|
||||
-j$(grep -c ^processor /proc/cpuinfo)
|
||||
--variables-files=etc/scons/mongodbtoolchain_stable_gcc.vars
|
||||
--enable-free-mon=on
|
||||
--enable-http-client=on
|
||||
--link-model=dynamic
|
||||
scons_cache_mode: all
|
||||
scons_cache_scope: shared
|
||||
num_scons_link_jobs_available: 0.99
|
||||
test_flags: --excludeWithAnyTags=requires_http_client
|
||||
compile_variant: *linux_x86_dynamic_debug_wtdevelop_compile_variant_name
|
||||
|
||||
- name: &tla-plus tla-plus
|
||||
display_name: "TLA+"
|
||||
run_on:
|
||||
@ -3439,18 +3405,6 @@ buildvariants:
|
||||
- windows-vsCurrent-large
|
||||
- name: .benchmarks !benchmarks_orphaned
|
||||
|
||||
- <<: *enterprise-windows-nopush-template
|
||||
name: &enterprise-windows-wtdevelop enterprise-windows-wtdevelop
|
||||
display_name: "~ Enterprise Windows WiredTiger develop"
|
||||
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
|
||||
modules:
|
||||
- enterprise
|
||||
- wtdevelop
|
||||
expansions:
|
||||
<<: *enterprise-windows-nopush-expansions-template
|
||||
use_wt_develop: true
|
||||
compile_variant: *enterprise-windows-wtdevelop
|
||||
|
||||
### QO & QE Patch-Specific Build Variants ###
|
||||
- <<: *enterprise-windows-nopush-template
|
||||
name: &windows-compile-query-patch-only windows-compile-query-patch-only
|
||||
|
||||
@ -6,16 +6,358 @@ include:
|
||||
- filename: etc/evergreen_yml_components/variants/atlas.yml
|
||||
- filename: etc/evergreen_yml_components/variants/misc_release.yml
|
||||
### Comment out when using this file for a LTS or Rapid release branch. ###
|
||||
- filename: etc/evergreen_yml_components/variants/ibm.yml
|
||||
# - filename: etc/evergreen_yml_components/variants/ibm.yml
|
||||
### Uncomment when using this file for a LTS release branch. ###
|
||||
# - filename: etc/evergreen_yml_components/variants/in_memory.yml
|
||||
### Uncomment when using this file for a LTS or Rapid release branch. ###
|
||||
# - filename: etc/evergreen_yml_components/variants/sanitizer.yml
|
||||
- filename: etc/evergreen_yml_components/variants/sanitizer.yml
|
||||
### Uncomment when using this file for a LTS or Rapid release branch. ###
|
||||
# - filename: etc/evergreen_yml_components/variants/ninja.yml
|
||||
- filename: etc/evergreen_yml_components/variants/ninja.yml
|
||||
- filename: etc/evergreen_yml_components/variants/compile_static_analysis.yml
|
||||
|
||||
|
||||
parameters:
|
||||
- key: evergreen_config_file_path
|
||||
value: "etc/evergreen_nightly.yml"
|
||||
description: "path to this file"
|
||||
|
||||
|
||||
variables:
|
||||
|
||||
# Common compile variant dependency specifications.
|
||||
- &linux_x86_dynamic_compile_variant_dependency
|
||||
depends_on:
|
||||
- name: archive_dist_test_debug
|
||||
variant: &linux_x86_dynamic_compile_variant_name linux-x86-dynamic-compile-required
|
||||
- name: version_gen
|
||||
variant: generate-tasks-for-version
|
||||
# This is added because of EVG-18211.
|
||||
# Without this we are adding extra dependencies on evergreen and it is causing strain
|
||||
omit_generated_tasks: true
|
||||
|
||||
- &linux_x86_dynamic_debug_compile_variant_dependency
|
||||
depends_on:
|
||||
- name: archive_dist_test_debug
|
||||
variant: &linux_x86_dynamic_debug_compile_variant_name linux-x86-dynamic-debug-compile-required
|
||||
- name: version_gen
|
||||
variant: generate-tasks-for-version
|
||||
# This is added because of EVG-18211.
|
||||
# Without this we are adding extra dependencies on evergreen and it is causing strain
|
||||
omit_generated_tasks: true
|
||||
|
||||
- &linux_debug_aubsan_compile_variant_dependency
|
||||
depends_on:
|
||||
- name: archive_dist_test_debug
|
||||
variant: &linux_debug_aubsan_compile_variant_name linux-debug-aubsan-compile-required
|
||||
- name: version_gen
|
||||
variant: generate-tasks-for-version
|
||||
# This is added because of EVG-18211.
|
||||
# Without this we are adding extra dependencies on evergreen and it is causing strain
|
||||
omit_generated_tasks: true
|
||||
|
||||
- &windows_compile_variant_dependency
|
||||
depends_on:
|
||||
- name: archive_dist_test_debug
|
||||
variant: &windows_compile_variant_name windows-compile-required
|
||||
- name: version_gen
|
||||
variant: generate-tasks-for-version
|
||||
# This is added because of EVG-18211.
|
||||
# Without this we are adding extra dependencies on evergreen and it is causing strain
|
||||
omit_generated_tasks: true
|
||||
- name: version_burn_in_gen
|
||||
variant: generate-tasks-for-version
|
||||
|
||||
- &linux_x86_generic_expansions
|
||||
multiversion_platform: rhel80
|
||||
multiversion_edition: enterprise
|
||||
repo_edition: enterprise
|
||||
large_distro_name: rhel80-medium
|
||||
num_scons_link_jobs_available: 0.99
|
||||
compile_variant: *linux_x86_dynamic_compile_variant_name
|
||||
|
||||
# If you add anything to san_options, make sure the appropriate changes are
|
||||
# also made to SConstruct.
|
||||
# and also to the san_options in compile_static_analysis.yml
|
||||
- aubsan_options: &aubsan_options
|
||||
>-
|
||||
UBSAN_OPTIONS="print_stacktrace=1:external_symbolizer_path=/opt/mongodbtoolchain/v4/bin/llvm-symbolizer"
|
||||
LSAN_OPTIONS="suppressions=etc/lsan.suppressions:report_objects=1"
|
||||
ASAN_OPTIONS="detect_leaks=1:check_initialization_order=true:strict_init_order=true:abort_on_error=1:disable_coredump=0:handle_abort=1:strict_string_checks=true:detect_invalid_pointer_pairs=1:external_symbolizer_path=/opt/mongodbtoolchain/v4/bin/llvm-symbolizer"
|
||||
|
||||
|
||||
buildvariants:
|
||||
|
||||
- &linux-64-debug-required-template
|
||||
<<: *linux_x86_dynamic_debug_compile_variant_dependency
|
||||
name: &linux-64-debug-required linux-64-debug-required
|
||||
display_name: "! Linux x86 Shared Library DEBUG"
|
||||
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
|
||||
run_on:
|
||||
- rhel80-medium
|
||||
expansions:
|
||||
resmoke_jobs_factor: 0.5 # Avoid starting too many mongod's
|
||||
test_flags: --excludeWithAnyTags=requires_http_client
|
||||
target_resmoke_time: 15
|
||||
max_sub_suites: 5
|
||||
large_distro_name: rhel80-medium
|
||||
compile_variant: *linux_x86_dynamic_debug_compile_variant_name
|
||||
tasks:
|
||||
- name: .aggregation !.encrypt
|
||||
- name: .auth !.audit !.multiversion
|
||||
- name: .causally_consistent !.wo_snapshot
|
||||
- name: .change_streams !.secondary_reads
|
||||
- name: .clustered_collections
|
||||
- name: .misc_js
|
||||
- name: disk_wiredtiger
|
||||
- name: free_monitoring
|
||||
- name: .jscore .common
|
||||
- name: jsCore_txns_large_txns_format
|
||||
- name: json_schema
|
||||
- name: query_golden_classic
|
||||
- name: libunwind_tests
|
||||
- name: .multi_shard
|
||||
- name: multi_stmt_txn_jscore_passthrough_with_migration_gen
|
||||
- name: .ocsp
|
||||
- name: .read_write_concern
|
||||
- name: .replica_sets !.encrypt !.ignore_non_generated_replica_sets_jscore_passthrough !.fcbis
|
||||
- name: replica_sets_jscore_passthrough_gen
|
||||
- name: replica_sets_reconfig_jscore_passthrough_gen
|
||||
- name: replica_sets_reconfig_jscore_stepdown_passthrough_gen
|
||||
- name: replica_sets_max_mirroring_large_txns_format_gen
|
||||
- name: .retry
|
||||
- name: .read_only
|
||||
- name: session_jscore_passthrough
|
||||
- name: sharded_multi_stmt_txn_jscore_passthrough
|
||||
- name: .sharding .jscore !.wo_snapshot
|
||||
- name: sharding_gen
|
||||
- name: sharding_opportunistic_secondary_targeting_gen
|
||||
|
||||
- &enterprise-windows-template
|
||||
<<: *windows_compile_variant_dependency
|
||||
name: &enterprise-windows-required enterprise-windows-required
|
||||
display_name: "! Enterprise Windows"
|
||||
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
|
||||
modules:
|
||||
- enterprise
|
||||
run_on:
|
||||
- windows-vsCurrent-small
|
||||
expansions: &windows_required_expansions
|
||||
compile_variant: *windows_compile_variant_name
|
||||
exe: ".exe"
|
||||
content_type: application/zip
|
||||
python: '/cygdrive/c/python/python37/python.exe'
|
||||
ext: zip
|
||||
multiversion_platform: windows
|
||||
multiversion_edition: enterprise
|
||||
jstestfuzz_num_generated_files: 35
|
||||
target_resmoke_time: 20
|
||||
max_sub_suites: 5
|
||||
large_distro_name: windows-vsCurrent-large
|
||||
push_path: windows
|
||||
push_bucket: downloads.10gen.com
|
||||
push_name: windows
|
||||
push_arch: x86_64-enterprise
|
||||
test_flags: &windows_common_test_excludes --excludeWithAnyTags=incompatible_with_windows_tls
|
||||
external_auth_jobs_max: 1
|
||||
tasks:
|
||||
#- name: burn_in_tests_gen
|
||||
- name: audit
|
||||
- name: auth_audit_gen
|
||||
- name: causally_consistent_jscore_txns_passthrough
|
||||
distros:
|
||||
- windows-vsCurrent-large
|
||||
- name: .encrypt !.aggregation !.replica_sets !.sharding !.jscore
|
||||
- name: external_auth
|
||||
- name: external_auth_aws
|
||||
- name: external_auth_windows
|
||||
distros:
|
||||
- windows-2016-dc
|
||||
- name: .jscore .common !.sharding
|
||||
- name: jsCore_auth
|
||||
- name: jsCore_ese
|
||||
- name: jsCore_txns_large_txns_format
|
||||
- name: .jstestfuzz .common
|
||||
- name: mqlrun
|
||||
- name: noPassthrough_gen
|
||||
- name: noPassthroughWithMongod_gen
|
||||
- name: .replica_sets .common !.ignore_non_generated_replica_sets_jscore_passthrough
|
||||
- name: .replica_sets .multi_oplog !.ignore_non_generated_replica_sets_jscore_passthrough !.gcm
|
||||
- name: replica_sets_jscore_passthrough_gen
|
||||
distros:
|
||||
- windows-vsCurrent-large
|
||||
- name: sasl
|
||||
- name: .sharding .txns
|
||||
- name: sharding_auth_gen
|
||||
- name: sharding_auth_audit_gen
|
||||
- name: sharding_ese_gen
|
||||
|
||||
- &enterprise-rhel-80-64-bit-dynamic-template
|
||||
<<: *linux_x86_dynamic_compile_variant_dependency
|
||||
name: &enterprise-rhel-80-64-bit-dynamic-required enterprise-rhel-80-64-bit-dynamic-required
|
||||
display_name: "! Shared Library Enterprise RHEL 8.0"
|
||||
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
|
||||
modules:
|
||||
- enterprise
|
||||
run_on:
|
||||
- rhel80-small
|
||||
expansions: &enterprise-rhel-80-64-bit-dynamic-expansions
|
||||
<<: *linux_x86_generic_expansions
|
||||
scons_cache_scope: shared
|
||||
scons_cache_mode: all
|
||||
has_packages: false
|
||||
jstestfuzz_num_generated_files: 40
|
||||
jstestfuzz_concurrent_num_files: 10
|
||||
target_resmoke_time: 10
|
||||
max_sub_suites: 5
|
||||
idle_timeout_factor: 1.5
|
||||
exec_timeout_factor: 1.5
|
||||
large_distro_name: rhel80-medium
|
||||
depends_on:
|
||||
- name: archive_dist_test_debug
|
||||
variant: *linux_x86_dynamic_compile_variant_name
|
||||
- name: version_gen
|
||||
variant: generate-tasks-for-version
|
||||
# This is added because of EVG-18211.
|
||||
# Without this we are adding extra dependencies on evergreen and it is causing strain
|
||||
omit_generated_tasks: true
|
||||
- name: version_burn_in_gen
|
||||
variant: generate-tasks-for-version
|
||||
tasks:
|
||||
#- name: burn_in_tests_gen
|
||||
- name: .aggfuzzer
|
||||
- name: .aggregation
|
||||
- name: audit
|
||||
- name: .auth
|
||||
- name: unittest_shell_hang_analyzer_gen
|
||||
- name: .causally_consistent !.sharding
|
||||
- name: .change_streams
|
||||
- name: .change_stream_fuzzer
|
||||
- name: .misc_js
|
||||
- name: .concurrency !.large !.ubsan !.no_txns !.debug_only
|
||||
- name: .concurrency .large !.ubsan !.no_txns !.debug_only
|
||||
distros:
|
||||
- rhel80-medium
|
||||
- name: .config_fuzzer !.large
|
||||
- name: .config_fuzzer .large
|
||||
distros:
|
||||
- rhel80-medium
|
||||
- name: disk_wiredtiger
|
||||
- name: .encrypt
|
||||
- name: idl_tests
|
||||
- name: initial_sync_fuzzer_gen
|
||||
- name: jsCore
|
||||
distros:
|
||||
- rhel80-xlarge
|
||||
- name: .jscore .common !jsCore
|
||||
- name: jsCore_min_batch_repeat_queries_ese_gsm
|
||||
- name: jsCore_txns_large_txns_format
|
||||
- name: json_schema
|
||||
- name: .jstestfuzz !.flow_control # Flow control jstestfuzz take longer.
|
||||
- name: libunwind_tests
|
||||
- name: mqlrun
|
||||
- name: .multi_shard
|
||||
- name: multi_stmt_txn_jscore_passthrough_with_migration_gen
|
||||
- name: multiversion_gen
|
||||
- name: .query_fuzzer
|
||||
- name: .random_multiversion_ds
|
||||
- name: .read_write_concern .large
|
||||
distros:
|
||||
- rhel80-medium
|
||||
- name: .read_write_concern !.large
|
||||
- name: .replica_sets !.encrypt !.auth
|
||||
distros:
|
||||
- rhel80-xlarge
|
||||
- name: replica_sets_api_version_jscore_passthrough_gen
|
||||
- name: replica_sets_reconfig_jscore_passthrough_gen
|
||||
- name: replica_sets_reconfig_jscore_stepdown_passthrough_gen
|
||||
distros:
|
||||
- rhel80-xlarge
|
||||
- name: replica_sets_reconfig_kill_primary_jscore_passthrough_gen
|
||||
distros:
|
||||
- rhel80-xlarge
|
||||
- name: retryable_writes_jscore_passthrough_gen
|
||||
- name: retryable_writes_jscore_stepdown_passthrough_gen
|
||||
distros:
|
||||
- rhel80-medium
|
||||
- name: .read_only
|
||||
- name: .rollbackfuzzer
|
||||
- name: sasl
|
||||
- name: search
|
||||
- name: search_auth
|
||||
- name: search_ssl
|
||||
- name: session_jscore_passthrough
|
||||
- name: .sharding .jscore !.wo_snapshot !.multi_stmt
|
||||
- name: sharding_api_version_jscore_passthrough_gen
|
||||
- name: .sharding .txns
|
||||
- name: .sharding .common
|
||||
- name: .updatefuzzer
|
||||
- name: secondary_reads_passthrough_gen
|
||||
- name: .serverless
|
||||
distros:
|
||||
- rhel80-xlarge
|
||||
|
||||
- &rhel80-debug-aubsan-lite-template
|
||||
<<: *linux_debug_aubsan_compile_variant_dependency
|
||||
name: &rhel80-debug-aubsan-lite-required rhel80-debug-aubsan-lite-required
|
||||
display_name: "! Shared Library {A,UB}SAN Enterprise RHEL 8.0 DEBUG"
|
||||
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
|
||||
modules:
|
||||
- enterprise
|
||||
run_on:
|
||||
- rhel80-build
|
||||
expansions: &aubsan-lite-required-expansions
|
||||
compile_variant: *linux_debug_aubsan_compile_variant_name
|
||||
lang_environment: LANG=C
|
||||
san_options: *aubsan_options
|
||||
test_flags: --excludeWithAnyTags=requires_ocsp_stapling
|
||||
resmoke_jobs_factor: 0.3 # Avoid starting too many mongod's under {A,UB}SAN build.
|
||||
hang_analyzer_dump_core: false
|
||||
max_sub_suites: 3
|
||||
num_scons_link_jobs_available: 0.99
|
||||
large_distro_name: rhel80-build
|
||||
tasks:
|
||||
- name: jsCore
|
||||
- name: jsCore_txns
|
||||
|
||||
- <<: *enterprise-rhel-80-64-bit-dynamic-template
|
||||
name: &commit-queue commit-queue
|
||||
display_name: "~ Commit Queue"
|
||||
cron: "0 4 * * 0" # From the ${project_weekly_cron} parameter
|
||||
stepback: false
|
||||
expansions:
|
||||
<<: *linux_x86_generic_expansions
|
||||
scons_cache_scope: shared
|
||||
scons_cache_mode: all
|
||||
has_packages: false
|
||||
compile_flags: >-
|
||||
--ssl
|
||||
MONGO_DISTMOD=rhel80
|
||||
-j$(grep -c ^processor /proc/cpuinfo)
|
||||
--variables-files=etc/scons/mongodbtoolchain_stable_gcc.vars
|
||||
--link-model=dynamic
|
||||
crypt_task_compile_flags: >-
|
||||
SHLINKFLAGS_EXTRA="-Wl,-Bsymbolic
|
||||
-Wl,--no-gnu-unique"
|
||||
CCFLAGS="-fno-gnu-unique"
|
||||
clang_tidy_toolchain: v4
|
||||
num_scons_unit_cc_jobs_available: 0.2
|
||||
compile_variant: *commit-queue
|
||||
depends_on: []
|
||||
tasks:
|
||||
- name: compile_test_and_package_parallel_core_stream_TG
|
||||
distros:
|
||||
- rhel80-xlarge-commitqueue
|
||||
- name: compile_test_and_package_parallel_unittest_stream_TG
|
||||
distros:
|
||||
- rhel80-xlarge-commitqueue
|
||||
- name: compile_test_and_package_parallel_dbtest_stream_TG
|
||||
distros:
|
||||
- rhel80-xlarge-commitqueue
|
||||
- name: jsCore
|
||||
distros:
|
||||
- rhel80-xlarge-commitqueue
|
||||
- name: .lint
|
||||
- name: test_api_version_compatibility
|
||||
- name: validate_commit_message
|
||||
- name: check_feature_flag_tags
|
||||
- name: compile_venv_deps_check
|
||||
|
||||
@ -66,7 +66,7 @@ modules:
|
||||
- name: enterprise
|
||||
repo: git@github.com:10gen/mongo-enterprise-modules.git
|
||||
prefix: src/mongo/db/modules
|
||||
branch: master
|
||||
branch: v6.3
|
||||
|
||||
- name: wtdevelop
|
||||
repo: git@github.com:wiredtiger/wiredtiger.git
|
||||
@ -616,7 +616,7 @@ functions:
|
||||
"get buildnumber": &get_buildnumber
|
||||
command: keyval.inc
|
||||
params:
|
||||
key: "${build_variant}_master"
|
||||
key: "${build_variant}_v6.3"
|
||||
destination: "builder_num"
|
||||
|
||||
"run diskstats": &run_diskstats
|
||||
|
||||
@ -448,8 +448,6 @@ buildvariants:
|
||||
distros:
|
||||
- amazon2022-large
|
||||
- name: .publish_crypt
|
||||
distros:
|
||||
- amazon2022-large
|
||||
- name: secondary_reads_passthrough_gen
|
||||
- name: server_discovery_and_monitoring_json_test_TG
|
||||
- name: .serverless
|
||||
@ -1434,8 +1432,6 @@ buildvariants:
|
||||
distros:
|
||||
- ubuntu2204-arm64-small
|
||||
- name: .publish
|
||||
distros:
|
||||
- rhel80-small
|
||||
- name: generate_buildid_to_debug_symbols_mapping
|
||||
|
||||
- name: enterprise-rhel90-arm64
|
||||
@ -1505,8 +1501,6 @@ buildvariants:
|
||||
distros:
|
||||
- ubuntu2204-arm64-small
|
||||
- name: .publish
|
||||
distros:
|
||||
- rhel80-small
|
||||
- name: generate_buildid_to_debug_symbols_mapping
|
||||
|
||||
- name: suse12
|
||||
|
||||
@ -99,7 +99,7 @@ modules:
|
||||
- name: enterprise
|
||||
repo: git@github.com:10gen/mongo-enterprise-modules.git
|
||||
prefix: src/mongo/db/modules
|
||||
branch: master
|
||||
branch: v6.3
|
||||
- name: mongo-tools
|
||||
repo: git@github.com:mongodb/mongo-tools.git
|
||||
prefix: mongo-tools/src/github.com/mongodb
|
||||
|
||||
2139
etc/system_perf.yml
2139
etc/system_perf.yml
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,8 @@
|
||||
* ]
|
||||
*/
|
||||
|
||||
load('jstests/libs/feature_flag_util.js');
|
||||
|
||||
const dbPrefix = jsTestName() + '_DB_';
|
||||
const dbCount = 2;
|
||||
const collPrefix = 'sharded_coll_';
|
||||
@ -62,6 +64,10 @@ var $config = (function() {
|
||||
]);
|
||||
},
|
||||
movePrimary: function(db, collName, connCache) {
|
||||
if (this.skipMovePrimary) {
|
||||
return;
|
||||
}
|
||||
|
||||
db = getRandomDb(db);
|
||||
const shardId = getRandomShard(connCache);
|
||||
|
||||
@ -91,6 +97,10 @@ var $config = (function() {
|
||||
};
|
||||
|
||||
let setup = function(db, collName, connCache) {
|
||||
// TODO (SERVER-71309): Remove once 7.0 becomes last LTS. Prevent non-resilient movePrimary
|
||||
// operations from being executed in multiversion suites.
|
||||
this.skipMovePrimary = !FeatureFlagUtil.isEnabled(db.getMongo(), 'ResilientMovePrimary');
|
||||
|
||||
for (var i = 0; i < dbCount; i++) {
|
||||
const dbName = dbPrefix + i;
|
||||
const newDb = db.getSiblingDB(dbName);
|
||||
@ -116,7 +126,7 @@ var $config = (function() {
|
||||
startState: 'create',
|
||||
states: states,
|
||||
transitions: transitions,
|
||||
data: {},
|
||||
data: {skipMovePrimary: false},
|
||||
setup: setup,
|
||||
teardown: teardown,
|
||||
passConnectionCache: true
|
||||
|
||||
@ -16,10 +16,6 @@
|
||||
* does_not_support_add_remove_shards,
|
||||
* # This test just performs rename operations that can't be executed in transactions
|
||||
* does_not_support_transactions,
|
||||
* # Can be removed once PM-1965-Milestone-1 is completed.
|
||||
*
|
||||
* # TODO SERVER-73385 reenable when fixed.
|
||||
* assumes_balancer_off,
|
||||
* ]
|
||||
*/
|
||||
|
||||
|
||||
@ -38,7 +38,18 @@ if (!isMongos(db)) {
|
||||
res.stages[1]);
|
||||
}
|
||||
|
||||
const res = coll.aggregate([{$group: {_id: '$meta', accmin: {$min: '$b'}, accmax: {$max: '$c'}}}])
|
||||
.toArray();
|
||||
let res = coll.aggregate([{$group: {_id: '$meta', accmin: {$min: '$b'}, accmax: {$max: '$c'}}}])
|
||||
.toArray();
|
||||
assert.docEq([{"_id": null, "accmin": 1, "accmax": 3}], res);
|
||||
|
||||
// Test SERVER-73822 fix: complex $min and $max (i.e. not just straight field refs) work correctly.
|
||||
res = coll.aggregate([{
|
||||
$group: {
|
||||
_id: '$meta',
|
||||
accmin: {$min: {$add: ["$b", "$c"]}},
|
||||
accmax: {$max: {$add: ["$b", "$c"]}}
|
||||
}
|
||||
}])
|
||||
.toArray();
|
||||
assert.docEq([{"_id": null, "accmin": 2, "accmax": 6}], res);
|
||||
})();
|
||||
|
||||
145
jstests/noPassthrough/sbe_plan_cache_api_version.js
Normal file
145
jstests/noPassthrough/sbe_plan_cache_api_version.js
Normal file
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Validates the behaviour of the the SBE plan cache when the API version was provided to the
|
||||
* aggregate command.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
load("jstests/libs/analyze_plan.js");
|
||||
load("jstests/libs/sbe_util.js");
|
||||
|
||||
const conn = MongoRunner.runMongod({});
|
||||
assert.neq(conn, null, "mongod failed to start");
|
||||
const db = conn.getDB("plan_cache_api_version");
|
||||
const coll = db.coll;
|
||||
coll.drop();
|
||||
|
||||
const isSBEEnabled = checkSBEEnabled(db);
|
||||
|
||||
assert.commandWorked(coll.insert([{a: 1, b: 1}, {a: 2, b: 2}]));
|
||||
|
||||
// Runs the given pipeline with the specified options and returns its plan cache key.
|
||||
function runPipeline(pipeline, options, explainOptions = {}) {
|
||||
const command = Object.assign({aggregate: coll.getName(), pipeline, cursor: {}}, options);
|
||||
const result = coll.runCommand(command);
|
||||
assert.commandWorked(result);
|
||||
assert.eq(result.cursor.firstBatch.length, 1, result.cursor.firstBatch);
|
||||
|
||||
const explain = coll.runCommand(Object.assign({explain: command}, explainOptions));
|
||||
assert.commandWorked(explain);
|
||||
assert.neq(explain, null);
|
||||
assert.eq(explain.explainVersion, isSBEEnabled ? "2" : "1", explain);
|
||||
assert.neq(explain.queryPlanner.planCacheKey, null, explain);
|
||||
return explain.queryPlanner.planCacheKey;
|
||||
}
|
||||
|
||||
// Runs the given 'pipeline' with the API version and returns its plan cache key.
|
||||
function runPipelineWithApiVersion(pipeline) {
|
||||
const options = {apiVersion: '1'};
|
||||
return runPipeline(pipeline, options, options);
|
||||
}
|
||||
|
||||
// Runs the given 'pipeline' with the API version and 'apiStrict: true' and returns its plan cache
|
||||
// key.
|
||||
function runPipelineWithApiStrict(pipeline) {
|
||||
const options = {apiVersion: '1', apiStrict: true};
|
||||
return runPipeline(pipeline, options, options);
|
||||
}
|
||||
|
||||
// Asserts that a plan cache entry for the given 'cacheKey' exists in the plan cache and has
|
||||
// certain properties set as per provided 'properties' argument.
|
||||
function assertPlanCacheEntryExists(cacheKey, properties = {}) {
|
||||
const entries =
|
||||
coll.aggregate([{$planCacheStats: {}}, {$match: {planCacheKey: cacheKey}}]).toArray();
|
||||
assert.eq(entries.length, 1, entries);
|
||||
const entry = entries[0];
|
||||
|
||||
if (isSBEEnabled) {
|
||||
// The version:"2" field indicates that this is an SBE plan cache entry.
|
||||
assert.eq(entry.version, "2", entry);
|
||||
assert.eq(entry.isActive, properties.isActive, entry);
|
||||
assert.eq(entry.isPinned, properties.isPinned, entry);
|
||||
} else {
|
||||
// The version:"1" field indicates that this is an classic plan cache entry.
|
||||
assert.eq(entry.version, "1", entry);
|
||||
assert.eq(entry.isActive, properties.isActive, entry);
|
||||
}
|
||||
}
|
||||
|
||||
const pipeline = [{$match: {a: 1, b: 1}}];
|
||||
|
||||
// Run a set of testcases where each testcase defines a set of indexes on the collection and
|
||||
// executes the above pipeline with and without the API strict flag. Assert that the plan cache
|
||||
// keys for each of the two queries are different and two different plan cache entries have been
|
||||
// created.
|
||||
|
||||
const sbeEngineTestcases = [
|
||||
{
|
||||
withApiVersion: {isActive: true, isPinned: true},
|
||||
withApiStrict: {isActive: true, isPinned: true},
|
||||
indexSpecs: []
|
||||
},
|
||||
{
|
||||
withApiVersion: {isActive: true, isPinned: true},
|
||||
withApiStrict: {isActive: true, isPinned: true},
|
||||
indexSpecs: [{keyPattern: {a: 1}, options: {name: "a_1"}}]
|
||||
},
|
||||
{
|
||||
withApiVersion: {isActive: false, isPinned: false},
|
||||
withApiStrict: {isActive: true, isPinned: true},
|
||||
indexSpecs: [
|
||||
{keyPattern: {a: 1}, options: {name: "a_1"}},
|
||||
{keyPattern: {a: 1}, options: {name: "a_1_sparse", sparse: true}}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const classicEngineTestcases = [
|
||||
{
|
||||
withApiVersion: {isActive: false},
|
||||
withApiStrict: {isActive: false},
|
||||
indexSpecs: [
|
||||
{keyPattern: {a: 1}, options: {name: "a_1"}},
|
||||
{keyPattern: {b: 1}, options: {name: "b_1"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
withApiVersion: {isActive: false},
|
||||
withApiStrict: {isActive: false},
|
||||
indexSpecs: [
|
||||
{keyPattern: {a: 1}, options: {name: "a_1"}},
|
||||
{keyPattern: {a: 1}, options: {name: "a_1_sparse", sparse: true}},
|
||||
{keyPattern: {b: 1}, options: {name: "b_1"}}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const testcases = isSBEEnabled ? sbeEngineTestcases : classicEngineTestcases;
|
||||
for (const testcase of testcases) {
|
||||
[true, false].forEach((runWithApiStrictFirst) => {
|
||||
assert.commandWorked(coll.dropIndexes());
|
||||
|
||||
for (const indexSpec of testcase.indexSpecs) {
|
||||
assert.commandWorked(coll.createIndex(indexSpec.keyPattern, indexSpec.options));
|
||||
}
|
||||
|
||||
let planCacheKeyWithApiVersion;
|
||||
let planCacheKeyWithApiStrict;
|
||||
|
||||
if (runWithApiStrictFirst) {
|
||||
planCacheKeyWithApiStrict = runPipelineWithApiStrict(pipeline);
|
||||
planCacheKeyWithApiVersion = runPipelineWithApiVersion(pipeline);
|
||||
} else {
|
||||
planCacheKeyWithApiVersion = runPipelineWithApiVersion(pipeline);
|
||||
planCacheKeyWithApiStrict = runPipelineWithApiStrict(pipeline);
|
||||
}
|
||||
|
||||
assert.neq(planCacheKeyWithApiVersion, planCacheKeyWithApiStrict);
|
||||
assertPlanCacheEntryExists(planCacheKeyWithApiVersion, testcase.withApiVersion);
|
||||
assertPlanCacheEntryExists(planCacheKeyWithApiStrict, testcase.withApiStrict);
|
||||
});
|
||||
}
|
||||
|
||||
MongoRunner.stopMongod(conn);
|
||||
}());
|
||||
89
jstests/replsets/initial_sync_geo_index_conflict.js
Normal file
89
jstests/replsets/initial_sync_geo_index_conflict.js
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Asserts that applying a single-phase createIndexes oplog entry for a 2d geo index with a
|
||||
* floating point bits field doesn't cause initial-sync to fail if there is an existing index
|
||||
* spec with a rounded bits value.
|
||||
* This may happen if the index was first created on the primary when the collection was empty.
|
||||
* The initial sync node would have to clone the index with the rounded value provided by
|
||||
* listIndexes and subsequently re-apply the single-phase index build entry.
|
||||
*
|
||||
* @tags: [
|
||||
* requires_fcv_70,
|
||||
* ]
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
load('jstests/libs/fail_point_util.js');
|
||||
load('jstests/noPassthrough/libs/index_build.js');
|
||||
|
||||
function runTest(numDocs) {
|
||||
const dbName = 'test';
|
||||
const collectionName = 'coll-' + numDocs;
|
||||
|
||||
// Start one-node repl-set.
|
||||
const rst = new ReplSetTest({nodes: 1});
|
||||
rst.startSet();
|
||||
rst.initiate();
|
||||
const primary = rst.getPrimary();
|
||||
const primaryDB = primary.getDB(dbName);
|
||||
const primaryColl = primaryDB.getCollection(collectionName);
|
||||
|
||||
// Add a secondary.
|
||||
const secondary = rst.add({
|
||||
rsConfig: {votes: 0, priority: 0},
|
||||
setParameter: {
|
||||
numInitialSyncAttempts: 1,
|
||||
// Increase log level to see debug messages for "Ignoring indexing error".
|
||||
logComponentVerbosity: tojsononeline({replication: 1, storage: 1}),
|
||||
},
|
||||
});
|
||||
|
||||
// While the secondary is hung, we create the same index multiple times to
|
||||
// reproduce the interaction between single and two phase index builds on the
|
||||
// same index.
|
||||
const failPoint = configureFailPoint(secondary, 'initialSyncHangBeforeCopyingDatabases');
|
||||
rst.reInitiate();
|
||||
failPoint.wait();
|
||||
|
||||
try {
|
||||
// Create the index using the empty collection fast path. The index build should be
|
||||
// replicated in a single createIndexes oplog entry. A floating point 'bits' option would be
|
||||
// converted to a whole number (12 in this case) when initial sync recreates the indexes on
|
||||
// the collection during the cloning phase. However, the oplog entry generated would still
|
||||
// contain the floating point value 12.345.
|
||||
assert.commandWorked(primaryColl.createIndex({a: '2d'}, {bits: 12.345}));
|
||||
|
||||
for (let i = 0; i < numDocs; i++) {
|
||||
assert.commandWorked(primaryColl.insert({_id: i, a: i}));
|
||||
}
|
||||
} finally {
|
||||
// Resume initial sync. The createIndexes oplog entry will be applied.
|
||||
failPoint.off();
|
||||
}
|
||||
|
||||
// Wait for initial sync to finish.
|
||||
rst.awaitSecondaryNodes();
|
||||
|
||||
// We handle single phase indexing errors in different parts of the oplog application logic
|
||||
// depending on whether the collection is empty at the time. Hence, the different log message
|
||||
// IDs.
|
||||
const expectedLogMsgId = (numDocs === 0 ? 7261800 : 4718200);
|
||||
checkLog.containsJson(secondary, expectedLogMsgId, {
|
||||
namespace: primaryColl.getFullName(),
|
||||
spec: (spec) => {
|
||||
jsTestLog('Checking index spec in oplog application log message: ' + tojson(spec));
|
||||
return spec.name === 'a_2d';
|
||||
}
|
||||
});
|
||||
|
||||
// We rely on the replica set test fixture shutdown to compare the collection contents
|
||||
// (including index specs) between the two nodes in the cluster.
|
||||
rst.stopSet();
|
||||
}
|
||||
|
||||
// We test both empty and non-empty collections because these are handled slightly differently
|
||||
// in the oplog application code.
|
||||
runTest(0);
|
||||
runTest(1);
|
||||
})();
|
||||
@ -280,9 +280,21 @@ void KeyStringIndexConsistency::addIndexEntryErrors(OperationContext* opCtx,
|
||||
// many as possible within memory limits.
|
||||
using ExtraIt = SimpleBSONObjSet::const_iterator;
|
||||
std::vector<ExtraIt> extraIndexEntriesBySize;
|
||||
// Since the extra entries are stored in a map of sets, we have to iterate the entries in the
|
||||
// map and sum the size of the sets in order to get the total number. Given that we can have at
|
||||
// most 64 indexes per collection, and the total number of entries could potentially be in the
|
||||
// millions, we expect that iterating the map will be much less costly than the additional
|
||||
// allocations and copies that could result from not calling 'reserve' on the vector.
|
||||
size_t totalExtraIndexEntriesCount =
|
||||
std::accumulate(_extraIndexEntries.begin(),
|
||||
_extraIndexEntries.end(),
|
||||
0,
|
||||
[](size_t total, const std::pair<IndexKey, SimpleBSONObjSet>& set) {
|
||||
return total + set.second.size();
|
||||
});
|
||||
extraIndexEntriesBySize.reserve(totalExtraIndexEntriesCount);
|
||||
for (const auto& extraIndexEntry : _extraIndexEntries) {
|
||||
const SimpleBSONObjSet& entries = extraIndexEntry.second;
|
||||
extraIndexEntriesBySize.reserve(extraIndexEntriesBySize.size() + entries.size());
|
||||
for (auto it = entries.begin(); it != entries.end(); ++it) {
|
||||
extraIndexEntriesBySize.push_back(it);
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ public:
|
||||
|
||||
protected:
|
||||
struct IndexKeyBucket {
|
||||
uint32_t indexKeyCount;
|
||||
uint32_t bucketSizeBytes;
|
||||
uint32_t indexKeyCount = 0;
|
||||
uint32_t bucketSizeBytes = 0;
|
||||
};
|
||||
|
||||
CollectionValidation::ValidateState* _validateState;
|
||||
|
||||
@ -516,6 +516,14 @@ std::vector<std::string> IndexBuildsCoordinator::extractIndexNames(
|
||||
return indexNames;
|
||||
}
|
||||
|
||||
bool IndexBuildsCoordinator::isCreateIndexesErrorSafeToIgnore(
|
||||
const Status& status, IndexBuildsManager::IndexConstraints indexConstraints) {
|
||||
return (status == ErrorCodes::IndexAlreadyExists ||
|
||||
((status == ErrorCodes::IndexOptionsConflict ||
|
||||
status == ErrorCodes::IndexKeySpecsConflict) &&
|
||||
IndexBuildsManager::IndexConstraints::kRelax == indexConstraints));
|
||||
}
|
||||
|
||||
StatusWith<std::pair<long long, long long>> IndexBuildsCoordinator::rebuildIndexesForRecovery(
|
||||
OperationContext* opCtx,
|
||||
const NamespaceString& nss,
|
||||
@ -1804,10 +1812,7 @@ void IndexBuildsCoordinator::createIndex(OperationContext* opCtx,
|
||||
opCtx, collection, {spec}, buildUUID, onInitFn, options));
|
||||
} catch (DBException& ex) {
|
||||
const auto& status = ex.toStatus();
|
||||
if (status == ErrorCodes::IndexAlreadyExists ||
|
||||
((status == ErrorCodes::IndexOptionsConflict ||
|
||||
status == ErrorCodes::IndexKeySpecsConflict) &&
|
||||
IndexBuildsManager::IndexConstraints::kRelax == indexConstraints)) {
|
||||
if (IndexBuildsCoordinator::isCreateIndexesErrorSafeToIgnore(status, indexConstraints)) {
|
||||
LOGV2_DEBUG(4718200,
|
||||
1,
|
||||
"Ignoring indexing error",
|
||||
@ -2171,10 +2176,8 @@ IndexBuildsCoordinator::PostSetupAction IndexBuildsCoordinator::_setUpIndexBuild
|
||||
opCtx, collection, replState->buildUUID, MultiIndexBlock::kNoopOnCleanUpFn);
|
||||
|
||||
const auto& status = ex.toStatus();
|
||||
if (status == ErrorCodes::IndexAlreadyExists ||
|
||||
((status == ErrorCodes::IndexOptionsConflict ||
|
||||
status == ErrorCodes::IndexKeySpecsConflict) &&
|
||||
options.indexConstraints == IndexBuildsManager::IndexConstraints::kRelax)) {
|
||||
if (IndexBuildsCoordinator::isCreateIndexesErrorSafeToIgnore(status,
|
||||
options.indexConstraints)) {
|
||||
LOGV2_DEBUG(20662,
|
||||
1,
|
||||
"Ignoring indexing error: {error}",
|
||||
|
||||
@ -124,6 +124,16 @@ public:
|
||||
*/
|
||||
static std::vector<std::string> extractIndexNames(const std::vector<BSONObj>& specs);
|
||||
|
||||
/**
|
||||
* Returns true if an index creation error is safe to ignore.
|
||||
* Consolidates the checking for the multiple scenarios where we may create indexes.
|
||||
* - createIndexes command on the primary;
|
||||
* - during oplog application (both empty and non-empty collection cases); and
|
||||
* - single-phase index creation for internal collections.
|
||||
*/
|
||||
static bool isCreateIndexesErrorSafeToIgnore(
|
||||
const Status& status, IndexBuildsManager::IndexConstraints indexConstraints);
|
||||
|
||||
/**
|
||||
* Sets up the in-memory and durable state of the index build. When successful, returns after
|
||||
* the index build has started and the first catalog write has been made, and if called on a
|
||||
|
||||
@ -815,6 +815,8 @@ DocumentSourceInternalUnpackBucket::rewriteGroupByMinMax(Pipeline::SourceContain
|
||||
AccumulationExpression accExpr = stmt.expr;
|
||||
accExpr.argument = newExpr;
|
||||
accumulationStatements.emplace_back(stmt.fieldName, std::move(accExpr));
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -94,6 +94,25 @@ TEST_F(InternalUnpackBucketGroupReorder, MinMaxGroupOnMetadata) {
|
||||
ASSERT_BSONOBJ_EQ(optimized, serialized[0]);
|
||||
}
|
||||
|
||||
// Test SERVER-73822 fix: complex $min and $max (i.e. not just straight field refs) work correctly.
|
||||
TEST_F(InternalUnpackBucketGroupReorder, MinMaxComplexGroupOnMetadata) {
|
||||
auto unpackSpecObj = fromjson(
|
||||
"{$_internalUnpackBucket: { include: ['a', 'b', 'c'], metaField: 'meta1', timeField: 't', "
|
||||
"bucketMaxSpanSeconds: 3600}}");
|
||||
auto groupSpecObj = fromjson(
|
||||
"{$group: {_id: '$meta1.a.b', accmin: {$min: {$add: ['$b', {$const: 0}]}}, accmax: {$max: "
|
||||
"{$add: [{$const: 0}, '$c']}}}}");
|
||||
|
||||
auto pipeline = Pipeline::parse(makeVector(unpackSpecObj, groupSpecObj), getExpCtx());
|
||||
pipeline->optimizePipeline();
|
||||
|
||||
auto serialized = pipeline->serializeToBson();
|
||||
ASSERT_EQ(2, serialized.size());
|
||||
// Order of fields may be different between original 'unpackSpecObj' and 'serialized[0]'.
|
||||
// ASSERT_BSONOBJ_EQ(unpackSpecObj, serialized[0]);
|
||||
ASSERT_BSONOBJ_EQ(groupSpecObj, serialized[1]);
|
||||
}
|
||||
|
||||
TEST_F(InternalUnpackBucketGroupReorder, MinMaxGroupOnMetafield) {
|
||||
auto unpackSpecObj = fromjson(
|
||||
"{$_internalUnpackBucket: { include: ['a', 'b', 'c'], metaField: 'meta1', timeField: 't', "
|
||||
|
||||
@ -86,7 +86,7 @@ const char kEncodeProjectionSection = '|';
|
||||
const char kEncodeProjectionRequirementSeparator = '-';
|
||||
const char kEncodeRegexFlagsSeparator = '/';
|
||||
const char kEncodeSortSection = '~';
|
||||
const char kEncodeEngineSection = '@';
|
||||
const char kEncodeFlagsSection = '@';
|
||||
const char kEncodePipelineSection = '^';
|
||||
|
||||
// These special bytes are used in the encoding of auto-parameterized match expressions in the SBE
|
||||
@ -134,7 +134,7 @@ void encodeUserString(StringData s, BuilderType* builder) {
|
||||
case kEncodeProjectionRequirementSeparator:
|
||||
case kEncodeRegexFlagsSeparator:
|
||||
case kEncodeSortSection:
|
||||
case kEncodeEngineSection:
|
||||
case kEncodeFlagsSection:
|
||||
case kEncodeParamMarker:
|
||||
case kEncodeConstantLiteralMarker:
|
||||
case kEncodePipelineSection:
|
||||
@ -701,7 +701,13 @@ CanonicalQuery::QueryShapeString encode(const CanonicalQuery& cq) {
|
||||
|
||||
// This encoding can be removed once the classic query engine reaches EOL and SBE is used
|
||||
// exclusively for all query execution.
|
||||
keyBuilder << kEncodeEngineSection << (cq.getForceClassicEngine() ? "f" : "t");
|
||||
keyBuilder << kEncodeFlagsSection << (cq.getForceClassicEngine() ? "f" : "t");
|
||||
|
||||
// The apiStrict flag can cause the query to see different set of indexes. For example, all
|
||||
// sparse indexes will be ignored with apiStrict is used.
|
||||
const bool apiStrict =
|
||||
cq.getOpCtx() && APIParameters::get(cq.getOpCtx()).getAPIStrict().value_or(false);
|
||||
keyBuilder << (apiStrict ? "t" : "f");
|
||||
|
||||
return keyBuilder.str();
|
||||
}
|
||||
@ -1114,6 +1120,11 @@ std::string encodeSBE(const CanonicalQuery& cq) {
|
||||
bufBuilder.appendStr(strBuilderEncoded, false /* includeEndingNull */);
|
||||
bufBuilder.appendChar(cq.getForceGenerateRecordId() ? 1 : 0);
|
||||
bufBuilder.appendChar(cq.isCountLike() ? 1 : 0);
|
||||
// The apiStrict flag can cause the query to see different set of indexes. For example, all
|
||||
// sparse indexes will be ignored with apiStrict is used.
|
||||
const bool apiStrict =
|
||||
cq.getOpCtx() && APIParameters::get(cq.getOpCtx()).getAPIStrict().value_or(false);
|
||||
bufBuilder.appendChar(apiStrict ? 1 : 0);
|
||||
|
||||
encodeFindCommandRequest(cq.getFindCommandRequest(), &bufBuilder);
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
#include "mongo/db/pipeline/expression_context_for_test.h"
|
||||
#include "mongo/db/pipeline/inner_pipeline_stage_impl.h"
|
||||
#include "mongo/db/query/canonical_query.h"
|
||||
#include "mongo/db/query/canonical_query_test_util.h"
|
||||
#include "mongo/db/query/plan_cache_key_factory.h"
|
||||
#include "mongo/db/query/query_test_service_context.h"
|
||||
#include "mongo/idl/server_parameter_test_util.h"
|
||||
@ -47,7 +48,6 @@ namespace {
|
||||
|
||||
using std::unique_ptr;
|
||||
|
||||
static const NamespaceString nss("testdb.testcoll");
|
||||
static const NamespaceString foreignNss("testdb.foreigncoll");
|
||||
|
||||
unittest::GoldenTestConfig goldenTestConfig{"src/mongo/db/test_output/query"};
|
||||
@ -63,117 +63,119 @@ std::vector<std::unique_ptr<InnerPipelineStageInterface>> parsePipeline(
|
||||
return stages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility functions to create a CanonicalQuery
|
||||
*/
|
||||
unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj,
|
||||
BSONObj collation,
|
||||
std::unique_ptr<FindCommandRequest> findCommand = nullptr,
|
||||
std::vector<BSONObj> pipelineObj = {},
|
||||
bool isCountLike = false) {
|
||||
QueryTestServiceContext serviceContext;
|
||||
auto opCtx = serviceContext.makeOperationContext();
|
||||
class CanonicalQueryEncoderTest : public CanonicalQueryTest {
|
||||
protected:
|
||||
unique_ptr<CanonicalQuery> canonicalize(
|
||||
OperationContext* opCtx,
|
||||
BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj,
|
||||
BSONObj collation,
|
||||
std::unique_ptr<FindCommandRequest> findCommand = nullptr,
|
||||
std::vector<BSONObj> pipelineObj = {},
|
||||
bool isCountLike = false) {
|
||||
if (!findCommand) {
|
||||
findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
}
|
||||
findCommand->setFilter(query.getOwned());
|
||||
findCommand->setSort(sort.getOwned());
|
||||
findCommand->setProjection(proj.getOwned());
|
||||
findCommand->setCollation(collation.getOwned());
|
||||
|
||||
if (!findCommand) {
|
||||
findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
const auto expCtx = make_intrusive<ExpressionContextForTest>(opCtx, nss);
|
||||
expCtx->addResolvedNamespaces({foreignNss});
|
||||
if (!findCommand->getCollation().isEmpty()) {
|
||||
auto statusWithCollator = CollatorFactoryInterface::get(opCtx->getServiceContext())
|
||||
->makeFromBSON(findCommand->getCollation());
|
||||
ASSERT_OK(statusWithCollator.getStatus());
|
||||
expCtx->setCollator(std::move(statusWithCollator.getValue()));
|
||||
}
|
||||
auto pipeline = parsePipeline(expCtx, pipelineObj);
|
||||
|
||||
auto statusWithCQ =
|
||||
CanonicalQuery::canonicalize(opCtx,
|
||||
std::move(findCommand),
|
||||
false,
|
||||
expCtx,
|
||||
ExtensionsCallbackNoop(),
|
||||
MatchExpressionParser::kAllowAllSpecialFeatures,
|
||||
ProjectionPolicies::findProjectionPolicies(),
|
||||
std::move(pipeline),
|
||||
isCountLike);
|
||||
ASSERT_OK(statusWithCQ.getStatus());
|
||||
return std::move(statusWithCQ.getValue());
|
||||
}
|
||||
findCommand->setFilter(query.getOwned());
|
||||
findCommand->setSort(sort.getOwned());
|
||||
findCommand->setProjection(proj.getOwned());
|
||||
findCommand->setCollation(collation.getOwned());
|
||||
|
||||
const auto expCtx = make_intrusive<ExpressionContextForTest>(opCtx.get(), nss);
|
||||
expCtx->addResolvedNamespaces({foreignNss});
|
||||
if (!findCommand->getCollation().isEmpty()) {
|
||||
auto statusWithCollator = CollatorFactoryInterface::get(opCtx->getServiceContext())
|
||||
->makeFromBSON(findCommand->getCollation());
|
||||
ASSERT_OK(statusWithCollator.getStatus());
|
||||
expCtx->setCollator(std::move(statusWithCollator.getValue()));
|
||||
unique_ptr<CanonicalQuery> canonicalize(OperationContext* opCtx, const char* queryStr) {
|
||||
BSONObj queryObj = fromjson(queryStr);
|
||||
return canonicalize(opCtx, queryObj, {}, {}, {});
|
||||
}
|
||||
auto pipeline = parsePipeline(expCtx, pipelineObj);
|
||||
|
||||
auto statusWithCQ =
|
||||
CanonicalQuery::canonicalize(opCtx.get(),
|
||||
std::move(findCommand),
|
||||
false,
|
||||
expCtx,
|
||||
ExtensionsCallbackNoop(),
|
||||
MatchExpressionParser::kAllowAllSpecialFeatures,
|
||||
ProjectionPolicies::findProjectionPolicies(),
|
||||
std::move(pipeline),
|
||||
isCountLike);
|
||||
ASSERT_OK(statusWithCQ.getStatus());
|
||||
return std::move(statusWithCQ.getValue());
|
||||
}
|
||||
|
||||
unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) {
|
||||
BSONObj queryObj = fromjson(queryStr);
|
||||
return canonicalize(queryObj, {}, {}, {});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test functions for computeKey, when no indexes are present. Cache keys are intentionally
|
||||
* obfuscated and are meaningful only within the current lifetime of the server process. Users
|
||||
* should treat plan cache keys as opaque.
|
||||
*/
|
||||
void testComputeKey(unittest::GoldenTestContext& gctx, const CanonicalQuery& cq) {
|
||||
gctx.outStream() << "==== VARIATION: cq=" << cq.toString() << std::endl;
|
||||
const auto key = cq.encodeKey();
|
||||
gctx.outStream() << key << std::endl;
|
||||
}
|
||||
|
||||
void testComputeKey(unittest::GoldenTestContext& gctx, BSONObj query, BSONObj sort, BSONObj proj) {
|
||||
BSONObj collation;
|
||||
gctx.outStream() << "==== VARIATION: query=" << query << ", sort=" << sort << ", proj=" << proj
|
||||
<< std::endl;
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(query, sort, proj, collation));
|
||||
const auto key = cq->encodeKey();
|
||||
gctx.outStream() << key << std::endl;
|
||||
}
|
||||
|
||||
void testComputeKey(unittest::GoldenTestContext& gctx,
|
||||
const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr) {
|
||||
testComputeKey(gctx, fromjson(queryStr), fromjson(sortStr), fromjson(projStr));
|
||||
}
|
||||
|
||||
void testComputeSBEKey(unittest::GoldenTestContext& gctx,
|
||||
const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
std::unique_ptr<FindCommandRequest> findCommand = nullptr,
|
||||
std::vector<BSONObj> pipelineObj = {},
|
||||
bool isCountLike = false) {
|
||||
auto& stream = gctx.outStream();
|
||||
stream << "==== VARIATION: sbe, query=" << queryStr << ", sort=" << sortStr
|
||||
<< ", proj=" << projStr;
|
||||
if (findCommand) {
|
||||
stream << ", allowDiskUse=" << findCommand->getAllowDiskUse()
|
||||
<< ", returnKey=" << findCommand->getReturnKey()
|
||||
<< ", requestResumeToken=" << findCommand->getRequestResumeToken();
|
||||
/**
|
||||
* Test functions for computeKey, when no indexes are present. Cache keys are intentionally
|
||||
* obfuscated and are meaningful only within the current lifetime of the server process. Users
|
||||
* should treat plan cache keys as opaque.
|
||||
*/
|
||||
void testComputeKey(unittest::GoldenTestContext& gctx, const CanonicalQuery& cq) {
|
||||
gctx.outStream() << "==== VARIATION: cq=" << cq.toString() << std::endl;
|
||||
const auto key = cq.encodeKey();
|
||||
gctx.outStream() << key << std::endl;
|
||||
}
|
||||
if (isCountLike) {
|
||||
stream << ", isCountLike=true";
|
||||
}
|
||||
stream << std::endl;
|
||||
BSONObj collation;
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(fromjson(queryStr),
|
||||
fromjson(sortStr),
|
||||
fromjson(projStr),
|
||||
collation,
|
||||
std::move(findCommand),
|
||||
std::move(pipelineObj),
|
||||
isCountLike));
|
||||
cq->setSbeCompatible(true);
|
||||
const auto key = canonical_query_encoder::encodeSBE(*cq);
|
||||
gctx.outStream() << key << std::endl;
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKey) {
|
||||
void testComputeKey(unittest::GoldenTestContext& gctx,
|
||||
BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj) {
|
||||
BSONObj collation;
|
||||
gctx.outStream() << "==== VARIATION: query=" << query << ", sort=" << sort
|
||||
<< ", proj=" << proj << std::endl;
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(opCtx(), query, sort, proj, collation));
|
||||
const auto key = cq->encodeKey();
|
||||
gctx.outStream() << key << std::endl;
|
||||
}
|
||||
|
||||
void testComputeKey(unittest::GoldenTestContext& gctx,
|
||||
const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr) {
|
||||
testComputeKey(gctx, fromjson(queryStr), fromjson(sortStr), fromjson(projStr));
|
||||
}
|
||||
|
||||
void testComputeSBEKey(unittest::GoldenTestContext& gctx,
|
||||
const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
std::unique_ptr<FindCommandRequest> findCommand = nullptr,
|
||||
std::vector<BSONObj> pipelineObj = {},
|
||||
bool isCountLike = false) {
|
||||
auto& stream = gctx.outStream();
|
||||
stream << "==== VARIATION: sbe, query=" << queryStr << ", sort=" << sortStr
|
||||
<< ", proj=" << projStr;
|
||||
if (findCommand) {
|
||||
stream << ", allowDiskUse=" << findCommand->getAllowDiskUse()
|
||||
<< ", returnKey=" << findCommand->getReturnKey()
|
||||
<< ", requestResumeToken=" << findCommand->getRequestResumeToken();
|
||||
}
|
||||
if (isCountLike) {
|
||||
stream << ", isCountLike=true";
|
||||
}
|
||||
stream << std::endl;
|
||||
BSONObj collation;
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(opCtx(),
|
||||
fromjson(queryStr),
|
||||
fromjson(sortStr),
|
||||
fromjson(projStr),
|
||||
collation,
|
||||
std::move(findCommand),
|
||||
std::move(pipelineObj),
|
||||
isCountLike));
|
||||
cq->setSbeCompatible(true);
|
||||
const auto key = canonical_query_encoder::encodeSBE(*cq);
|
||||
gctx.outStream() << key << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKey) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// Generated cache keys should be treated as opaque to the user.
|
||||
|
||||
@ -250,7 +252,7 @@ TEST(CanonicalQueryEncoderTest, ComputeKey) {
|
||||
testComputeKey(gctx, "{$or: [{a: 1}]}", "{}", "{'a.$': 1}");
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, EncodeNotEqualNullPredicates) {
|
||||
TEST_F(CanonicalQueryEncoderTest, EncodeNotEqualNullPredicates) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// The computed key depends on which execution engine is enabled. As such, we disable SBE for
|
||||
// this test so that the test doesn't break should the default value of
|
||||
@ -270,7 +272,7 @@ TEST(CanonicalQueryEncoderTest, EncodeNotEqualNullPredicates) {
|
||||
|
||||
// Delimiters found in user field names or non-standard projection field values
|
||||
// must be escaped.
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeyEscaped) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeyEscaped) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// The computed key depends on which execution engine is enabled. As such, we disable SBE for
|
||||
// this test so that the test doesn't break should the default value of
|
||||
@ -292,23 +294,23 @@ TEST(CanonicalQueryEncoderTest, ComputeKeyEscaped) {
|
||||
|
||||
// Cache keys for $geoWithin queries with legacy and GeoJSON coordinates should
|
||||
// not be the same.
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeyGeoWithin) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeyGeoWithin) {
|
||||
// Legacy coordinates.
|
||||
unique_ptr<CanonicalQuery> cqLegacy(
|
||||
canonicalize("{a: {$geoWithin: "
|
||||
"{$box: [[-180, -90], [180, 90]]}}}"));
|
||||
unique_ptr<CanonicalQuery> cqLegacy(canonicalize(opCtx(),
|
||||
"{a: {$geoWithin: "
|
||||
"{$box: [[-180, -90], [180, 90]]}}}"));
|
||||
// GeoJSON coordinates.
|
||||
unique_ptr<CanonicalQuery> cqNew(
|
||||
canonicalize("{a: {$geoWithin: "
|
||||
"{$geometry: {type: 'Polygon', coordinates: "
|
||||
"[[[0, 0], [0, 90], [90, 0], [0, 0]]]}}}}"));
|
||||
unique_ptr<CanonicalQuery> cqNew(canonicalize(opCtx(),
|
||||
"{a: {$geoWithin: "
|
||||
"{$geometry: {type: 'Polygon', coordinates: "
|
||||
"[[[0, 0], [0, 90], [90, 0], [0, 0]]]}}}}"));
|
||||
ASSERT_NOT_EQUALS(canonical_query_encoder::encode(*cqLegacy),
|
||||
canonical_query_encoder::encode(*cqNew));
|
||||
}
|
||||
|
||||
// GEO_NEAR cache keys should include information on geometry and CRS in addition
|
||||
// to the match type and field name.
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeyGeoNear) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeyGeoNear) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// The computed key depends on which execution engine is enabled. As such, we disable SBE for
|
||||
// this test so that the test doesn't break should the default value of
|
||||
@ -325,7 +327,7 @@ TEST(CanonicalQueryEncoderTest, ComputeKeyGeoNear) {
|
||||
"{}");
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeyRegexDependsOnFlags) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeyRegexDependsOnFlags) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// The computed key depends on which execution engine is enabled. As such, we enable SBE for
|
||||
// this test in order to ensure that we have coverage for both SBE and the classic engine.
|
||||
@ -360,7 +362,7 @@ TEST(CanonicalQueryEncoderTest, ComputeKeyRegexDependsOnFlags) {
|
||||
testComputeKey(gctx, "{a: /abc/im}", "{}", "{}");
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeyMatchInDependsOnPresenceOfRegexAndFlags) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeyMatchInDependsOnPresenceOfRegexAndFlags) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// The computed key depends on which execution engine is enabled. As such, we disable SBE for
|
||||
// this test so that the test doesn't break should the default value of
|
||||
@ -406,7 +408,7 @@ TEST(CanonicalQueryEncoderTest, ComputeKeyMatchInDependsOnPresenceOfRegexAndFlag
|
||||
testComputeKey(gctx, "{a: {$not: {$in: [/foo/i]}}}", "{}", "{}");
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, CheckCollationIsEncoded) {
|
||||
TEST_F(CanonicalQueryEncoderTest, CheckCollationIsEncoded) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// The computed key depends on which execution engine is enabled. As such, we disable SBE for
|
||||
// this test so that the test doesn't break should the default value of
|
||||
@ -415,12 +417,12 @@ TEST(CanonicalQueryEncoderTest, CheckCollationIsEncoded) {
|
||||
"forceClassicEngine");
|
||||
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(
|
||||
fromjson("{a: 1, b: 1}"), {}, {}, fromjson("{locale: 'mock_reverse_string'}")));
|
||||
opCtx(), fromjson("{a: 1, b: 1}"), {}, {}, fromjson("{locale: 'mock_reverse_string'}")));
|
||||
|
||||
testComputeKey(gctx, *cq);
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeySBE) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeySBE) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// Generated cache keys should be treated as opaque to the user.
|
||||
|
||||
@ -493,7 +495,7 @@ TEST(CanonicalQueryEncoderTest, ComputeKeySBE) {
|
||||
testComputeSBEKey(gctx, "{a: 1}", "{}", "{}", std::move(findCommand));
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeySBEWithPipeline) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeySBEWithPipeline) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// SBE must be enabled in order to generate SBE plan cache keys.
|
||||
RAIIServerParameterControllerForTest controllerSBE("internalQueryFrameworkControl",
|
||||
@ -523,7 +525,7 @@ TEST(CanonicalQueryEncoderTest, ComputeKeySBEWithPipeline) {
|
||||
{getLookupBson("a", "b", "as"), getLookupBson("a1", "b1", "as1")});
|
||||
}
|
||||
|
||||
TEST(CanonicalQueryEncoderTest, ComputeKeySBEWithReadConcern) {
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeySBEWithReadConcern) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
// SBE must be enabled in order to generate SBE plan cache keys.
|
||||
RAIIServerParameterControllerForTest controllerSBE("internalQueryFrameworkControl",
|
||||
@ -546,5 +548,29 @@ TEST(CanonicalQueryEncoderTest, ComputeKeySBEWithReadConcern) {
|
||||
testComputeSBEKey(gctx, "{a: 1}", "{a: 1}", "{}", std::move(findCommand));
|
||||
}
|
||||
|
||||
TEST_F(CanonicalQueryEncoderTest, ComputeKeyWithApiStrict) {
|
||||
unittest::GoldenTestContext gctx(&goldenTestConfig);
|
||||
{
|
||||
RAIIServerParameterControllerForTest controllerSBE("internalQueryFrameworkControl",
|
||||
"forceClassicEngine");
|
||||
APIParameters::get(opCtx()).setAPIStrict(false);
|
||||
testComputeKey(gctx, "{}", "{}", "{}");
|
||||
|
||||
APIParameters::get(opCtx()).setAPIStrict(true);
|
||||
testComputeKey(gctx, "{}", "{}", "{}");
|
||||
}
|
||||
|
||||
{
|
||||
RAIIServerParameterControllerForTest controllerSBE("internalQueryFrameworkControl",
|
||||
"trySbeEngine");
|
||||
|
||||
APIParameters::get(opCtx()).setAPIStrict(false);
|
||||
testComputeSBEKey(gctx, "{}", "{}", "{}");
|
||||
|
||||
APIParameters::get(opCtx()).setAPIStrict(true);
|
||||
testComputeSBEKey(gctx, "{}", "{}", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mongo
|
||||
|
||||
@ -29,22 +29,18 @@
|
||||
|
||||
#include "mongo/db/query/canonical_query_test_util.h"
|
||||
|
||||
#include "mongo/db/query/query_test_service_context.h"
|
||||
#include "mongo/unittest/unittest.h"
|
||||
|
||||
namespace mongo {
|
||||
const NamespaceString CanonicalQueryTest::nss("test.collection");
|
||||
|
||||
/**
|
||||
* Utility functions to create a CanonicalQuery
|
||||
*/
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) {
|
||||
QueryTestServiceContext serviceContext;
|
||||
auto opCtx = serviceContext.makeOperationContext();
|
||||
|
||||
std::unique_ptr<CanonicalQuery> CanonicalQueryTest::canonicalize(const BSONObj& queryObj) {
|
||||
auto findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
findCommand->setFilter(queryObj);
|
||||
const boost::intrusive_ptr<ExpressionContext> expCtx;
|
||||
auto statusWithCQ =
|
||||
CanonicalQuery::canonicalize(opCtx.get(),
|
||||
CanonicalQuery::canonicalize(opCtx(),
|
||||
std::move(findCommand),
|
||||
false,
|
||||
expCtx,
|
||||
@ -54,18 +50,15 @@ std::unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) {
|
||||
return std::move(statusWithCQ.getValue());
|
||||
}
|
||||
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(StringData queryStr) {
|
||||
std::unique_ptr<CanonicalQuery> CanonicalQueryTest::canonicalize(StringData queryStr) {
|
||||
BSONObj queryObj = fromjson(queryStr.toString());
|
||||
return canonicalize(queryObj);
|
||||
}
|
||||
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj,
|
||||
BSONObj collation) {
|
||||
QueryTestServiceContext serviceContext;
|
||||
auto opCtx = serviceContext.makeOperationContext();
|
||||
|
||||
std::unique_ptr<CanonicalQuery> CanonicalQueryTest::canonicalize(BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj,
|
||||
BSONObj collation) {
|
||||
auto findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
findCommand->setFilter(query);
|
||||
findCommand->setSort(sort);
|
||||
@ -73,7 +66,7 @@ std::unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
|
||||
findCommand->setCollation(collation);
|
||||
const boost::intrusive_ptr<ExpressionContext> expCtx;
|
||||
auto statusWithCQ =
|
||||
CanonicalQuery::canonicalize(opCtx.get(),
|
||||
CanonicalQuery::canonicalize(opCtx(),
|
||||
std::move(findCommand),
|
||||
false,
|
||||
expCtx,
|
||||
@ -83,25 +76,22 @@ std::unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
|
||||
return std::move(statusWithCQ.getValue());
|
||||
}
|
||||
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
const char* collationStr) {
|
||||
std::unique_ptr<CanonicalQuery> CanonicalQueryTest::canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
const char* collationStr) {
|
||||
return canonicalize(
|
||||
fromjson(queryStr), fromjson(sortStr), fromjson(projStr), fromjson(collationStr));
|
||||
}
|
||||
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr) {
|
||||
QueryTestServiceContext serviceContext;
|
||||
auto opCtx = serviceContext.makeOperationContext();
|
||||
|
||||
std::unique_ptr<CanonicalQuery> CanonicalQueryTest::canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr) {
|
||||
auto findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
findCommand->setFilter(fromjson(queryStr));
|
||||
findCommand->setSort(fromjson(sortStr));
|
||||
@ -117,7 +107,7 @@ std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
findCommand->setMax(fromjson(maxStr));
|
||||
const boost::intrusive_ptr<ExpressionContext> expCtx;
|
||||
auto statusWithCQ =
|
||||
CanonicalQuery::canonicalize(opCtx.get(),
|
||||
CanonicalQuery::canonicalize(opCtx(),
|
||||
std::move(findCommand),
|
||||
false,
|
||||
expCtx,
|
||||
@ -127,18 +117,15 @@ std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
return std::move(statusWithCQ.getValue());
|
||||
}
|
||||
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr,
|
||||
bool explain) {
|
||||
QueryTestServiceContext serviceContext;
|
||||
auto opCtx = serviceContext.makeOperationContext();
|
||||
|
||||
std::unique_ptr<CanonicalQuery> CanonicalQueryTest::canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr,
|
||||
bool explain) {
|
||||
auto findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
findCommand->setFilter(fromjson(queryStr));
|
||||
findCommand->setSort(fromjson(sortStr));
|
||||
@ -154,7 +141,7 @@ std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
findCommand->setMax(fromjson(maxStr));
|
||||
const boost::intrusive_ptr<ExpressionContext> expCtx;
|
||||
auto statusWithCQ =
|
||||
CanonicalQuery::canonicalize(opCtx.get(),
|
||||
CanonicalQuery::canonicalize(opCtx(),
|
||||
std::move(findCommand),
|
||||
explain,
|
||||
expCtx,
|
||||
|
||||
@ -28,36 +28,51 @@
|
||||
*/
|
||||
|
||||
#include "mongo/db/query/canonical_query.h"
|
||||
#include "mongo/db/query/query_test_service_context.h"
|
||||
#include "mongo/unittest/unittest.h"
|
||||
|
||||
namespace mongo {
|
||||
class CanonicalQueryTest : public unittest::Test {
|
||||
public:
|
||||
CanonicalQueryTest() : _opCtx(_serviceContext.makeOperationContext()) {}
|
||||
|
||||
const NamespaceString nss("test.collection");
|
||||
protected:
|
||||
OperationContext* opCtx() const {
|
||||
return _opCtx.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(StringData queryStr);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj,
|
||||
BSONObj collation);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
const char* collationStr);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr,
|
||||
bool explain);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(StringData queryStr);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
|
||||
BSONObj sort,
|
||||
BSONObj proj,
|
||||
BSONObj collation);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
const char* collationStr);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr);
|
||||
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
|
||||
const char* sortStr,
|
||||
const char* projStr,
|
||||
long long skip,
|
||||
long long limit,
|
||||
const char* hintStr,
|
||||
const char* minStr,
|
||||
const char* maxStr,
|
||||
bool explain);
|
||||
|
||||
static const NamespaceString nss;
|
||||
|
||||
private:
|
||||
QueryTestServiceContext _serviceContext;
|
||||
ServiceContext::UniqueOperationContext _opCtx;
|
||||
};
|
||||
} // namespace mongo
|
||||
|
||||
@ -50,6 +50,8 @@ std::ostream& operator<<(std::ostream& stream, const PlanCacheKeyInfo& key) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
using PlanCacheKeyInfoTest = CanonicalQueryTest;
|
||||
|
||||
PlanCacheKeyInfo makeKey(const CanonicalQuery& cq,
|
||||
const std::vector<CoreIndexInfo>& indexCores = {}) {
|
||||
PlanCacheIndexabilityState indexabilityState;
|
||||
@ -108,20 +110,25 @@ void assertPlanCacheKeysUnequalDueToForceClassicEngineValue(const PlanCacheKeyIn
|
||||
auto bStablePart = b.getQueryShape();
|
||||
|
||||
ASSERT_EQ(aUnstablePart, bUnstablePart);
|
||||
// The last character of the stable part encodes the engine that uses this PlanCacheKey. So the
|
||||
// stable parts except for the last character should be identical.
|
||||
ASSERT_EQ(aStablePart.substr(0, aStablePart.size() - 1),
|
||||
bStablePart.substr(0, bStablePart.size() - 1));
|
||||
// The last 2 characters (plus separator) of the stable part encodes the engine that uses this
|
||||
// PlanCacheKey and if apiStrict was used. So the stable parts except for the last two
|
||||
// characters should be identical.
|
||||
ASSERT_EQ(aStablePart.substr(0, aStablePart.size() - 2),
|
||||
bStablePart.substr(0, bStablePart.size() - 2));
|
||||
|
||||
// Should have at least 1 byte to represent whether we must use the classic engine.
|
||||
ASSERT_GTE(aStablePart.size(), 1);
|
||||
// Should have at least 2 byte to represent whether we must use the classic engine and stable
|
||||
// API.
|
||||
ASSERT_GTE(aStablePart.size(), 2);
|
||||
|
||||
// The indexability discriminators should match.
|
||||
ASSERT_EQ(a.getIndexabilityDiscriminators(), b.getIndexabilityDiscriminators());
|
||||
|
||||
// The stable parts should not match because of the last character.
|
||||
// The stable parts should not match because of the second character from the back, encoding the
|
||||
// engine type.
|
||||
ASSERT_NE(aStablePart, bStablePart);
|
||||
ASSERT_NE(aStablePart.back(), bStablePart.back());
|
||||
ASSERT_NE(aStablePart[aStablePart.size() - 2], bStablePart[bStablePart.size() - 2]);
|
||||
// Ensure that the the apiStrict values are equal.
|
||||
ASSERT_EQ(aStablePart.back(), bStablePart.back());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,7 +148,7 @@ void assertPlanCacheKeysUnequalDueToDiscriminators(const PlanCacheKeyInfo& a,
|
||||
|
||||
// When a sparse index is present, computeKey() should generate different keys depending on
|
||||
// whether or not the predicates in the given query can use the index.
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeySparseIndex) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeySparseIndex) {
|
||||
const auto keyPattern = BSON("a" << 1);
|
||||
const std::vector<CoreIndexInfo> indexCores = {
|
||||
CoreIndexInfo(keyPattern,
|
||||
@ -170,7 +177,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeySparseIndex) {
|
||||
// When a partial index is present, computeKey() should generate different keys depending on
|
||||
// whether or not the predicates in the given query "match" the predicates in the partial index
|
||||
// filter.
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyPartialIndex) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeyPartialIndex) {
|
||||
BSONObj filterObj = BSON("f" << BSON("$gt" << 0));
|
||||
unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj));
|
||||
|
||||
@ -195,7 +202,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyPartialIndex) {
|
||||
}
|
||||
|
||||
// Query shapes should get the same plan cache key if they have the same collation indexability.
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyCollationIndex) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeyCollationIndex) {
|
||||
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
|
||||
|
||||
const auto keyPattern = BSON("a" << 1);
|
||||
@ -262,7 +269,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyCollationIndex) {
|
||||
makeKey(*inContainsStringHasCollation, indexCores).getIndexabilityDiscriminators());
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardIndex) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeyWildcardIndex) {
|
||||
auto entryProjUpdatePair = makeWildcardUpdate(BSON("a.$**" << 1));
|
||||
|
||||
const std::vector<CoreIndexInfo> indexCores = {entryProjUpdatePair.first};
|
||||
@ -322,7 +329,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardIndex) {
|
||||
"<0><0>");
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardIndexDiscriminatesEqualityToEmptyObj) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeyWildcardIndexDiscriminatesEqualityToEmptyObj) {
|
||||
auto entryProjUpdatePair = makeWildcardUpdate(BSON("a.$**" << 1));
|
||||
|
||||
const std::vector<CoreIndexInfo> indexCores = {entryProjUpdatePair.first};
|
||||
@ -344,7 +351,8 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardIndexDiscriminatesEqualityToEmptyOb
|
||||
ASSERT_EQ(makeKey(*inWithEmptyObj, indexCores).getIndexabilityDiscriminators(), "<1>");
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardDiscriminatesCorrectlyBasedOnPartialFilterExpression) {
|
||||
TEST_F(PlanCacheKeyInfoTest,
|
||||
ComputeKeyWildcardDiscriminatesCorrectlyBasedOnPartialFilterExpression) {
|
||||
BSONObj filterObj = BSON("x" << BSON("$gt" << 0));
|
||||
std::unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj));
|
||||
|
||||
@ -412,7 +420,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardDiscriminatesCorrectlyBasedOnPartia
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, DifferentQueryEngines) {
|
||||
TEST_F(PlanCacheKeyInfoTest, DifferentQueryEngines) {
|
||||
const auto keyPattern = BSON("a" << 1);
|
||||
const std::vector<CoreIndexInfo> indexCores = {
|
||||
CoreIndexInfo(keyPattern,
|
||||
@ -438,7 +446,8 @@ TEST(PlanCacheKeyInfoTest, DifferentQueryEngines) {
|
||||
assertPlanCacheKeysUnequalDueToForceClassicEngineValue(classicEngineKey, noClassicEngineKey);
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardDiscriminatesCorrectlyWithPartialFilterAndExpression) {
|
||||
TEST_F(PlanCacheKeyInfoTest,
|
||||
ComputeKeyWildcardDiscriminatesCorrectlyWithPartialFilterAndExpression) {
|
||||
// Partial filter is an AND of multiple conditions.
|
||||
BSONObj filterObj = BSON("x" << BSON("$gt" << 0) << "y" << BSON("$gt" << 0));
|
||||
std::unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj));
|
||||
@ -466,7 +475,8 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardDiscriminatesCorrectlyWithPartialFi
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyDiscriminatesCorrectlyWithPartialFilterAndWildcardProjection) {
|
||||
TEST_F(PlanCacheKeyInfoTest,
|
||||
ComputeKeyDiscriminatesCorrectlyWithPartialFilterAndWildcardProjection) {
|
||||
BSONObj filterObj = BSON("x" << BSON("$gt" << 0));
|
||||
std::unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj));
|
||||
|
||||
@ -498,7 +508,8 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyDiscriminatesCorrectlyWithPartialFilterAndW
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardDiscriminatesCorrectlyWithPartialFilterOnNestedField) {
|
||||
TEST_F(PlanCacheKeyInfoTest,
|
||||
ComputeKeyWildcardDiscriminatesCorrectlyWithPartialFilterOnNestedField) {
|
||||
BSONObj filterObj = BSON("x.y" << BSON("$gt" << 0));
|
||||
std::unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj));
|
||||
|
||||
@ -523,7 +534,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyWildcardDiscriminatesCorrectlyWithPartialFi
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, StableKeyDoesNotChangeAcrossIndexCreation) {
|
||||
TEST_F(PlanCacheKeyInfoTest, StableKeyDoesNotChangeAcrossIndexCreation) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 0}}"));
|
||||
const auto preIndexKey = makeKey(*cq);
|
||||
const auto preIndexStableKey = preIndexKey.getQueryShape();
|
||||
@ -544,7 +555,7 @@ TEST(PlanCacheKeyInfoTest, StableKeyDoesNotChangeAcrossIndexCreation) {
|
||||
ASSERT_EQ(postIndexKey.getIndexabilityDiscriminators(), "<1>");
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyNotEqualsArray) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeyNotEqualsArray) {
|
||||
unique_ptr<CanonicalQuery> cqNeArray(canonicalize("{a: {$ne: [1]}}"));
|
||||
unique_ptr<CanonicalQuery> cqNeScalar(canonicalize("{a: {$ne: 123}}"));
|
||||
|
||||
@ -577,7 +588,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyNotEqualsArray) {
|
||||
ASSERT_EQ(withIndexNeArrayKey.getIndexabilityDiscriminators(), "<0><1>");
|
||||
}
|
||||
|
||||
TEST(PlanCacheKeyInfoTest, ComputeKeyNinArray) {
|
||||
TEST_F(PlanCacheKeyInfoTest, ComputeKeyNinArray) {
|
||||
unique_ptr<CanonicalQuery> cqNinArray(canonicalize("{a: {$nin: [123, [1]]}}"));
|
||||
unique_ptr<CanonicalQuery> cqNinScalar(canonicalize("{a: {$nin: [123, 456]}}"));
|
||||
|
||||
@ -618,7 +629,7 @@ TEST(PlanCacheKeyInfoTest, ComputeKeyNinArray) {
|
||||
// Whether the discriminator referred to the first not-eq node or the second would be
|
||||
// ambiguous. This would make it possible for two queries with different shapes (and different
|
||||
// plans) to get the same plan cache key. We test that this does not happen for a simple example.
|
||||
TEST(PlanCacheKeyInfoTest, PlanCacheKeyCollision) {
|
||||
TEST_F(PlanCacheKeyInfoTest, PlanCacheKeyCollision) {
|
||||
unique_ptr<CanonicalQuery> cqNeA(canonicalize("{$or: [{a: {$ne: 5}}, {a: {$ne: [12]}}]}"));
|
||||
unique_ptr<CanonicalQuery> cqNeB(canonicalize("{$or: [{a: {$ne: [12]}}, {a: {$ne: 5}}]}"));
|
||||
|
||||
|
||||
@ -74,6 +74,43 @@ using std::string;
|
||||
using std::unique_ptr;
|
||||
using std::vector;
|
||||
|
||||
class PlanCacheTest : public CanonicalQueryTest {
|
||||
protected:
|
||||
/**
|
||||
* Test functions for shouldCacheQuery.
|
||||
*
|
||||
* Use these functions to assert which categories of canonicalized queries are suitable for
|
||||
* inclusion in the plan cache.
|
||||
*/
|
||||
void assertShouldCacheQuery(const CanonicalQuery& query) {
|
||||
if (shouldCacheQuery(query)) {
|
||||
return;
|
||||
}
|
||||
str::stream ss;
|
||||
ss << "Canonical query should be cacheable: " << query.toString();
|
||||
FAIL(ss);
|
||||
}
|
||||
|
||||
void assertShouldNotCacheQuery(const CanonicalQuery& query) {
|
||||
if (!shouldCacheQuery(query)) {
|
||||
return;
|
||||
}
|
||||
str::stream ss;
|
||||
ss << "Canonical query should not be cacheable: " << query.toString();
|
||||
FAIL(ss);
|
||||
}
|
||||
|
||||
void assertShouldNotCacheQuery(const BSONObj& query) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(query));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
void assertShouldNotCacheQuery(const char* queryStr) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(queryStr));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
};
|
||||
|
||||
PlanCacheKey makeKey(const CanonicalQuery& cq, const std::vector<CoreIndexInfo>& indexCores = {}) {
|
||||
PlanCacheIndexabilityState indexabilityState;
|
||||
indexabilityState.updateDiscriminators(indexCores);
|
||||
@ -84,10 +121,12 @@ PlanCacheKey makeKey(const CanonicalQuery& cq, const std::vector<CoreIndexInfo>&
|
||||
return {PlanCacheKeyInfo{cq.encodeKey(), indexabilityKeyBuilder.str()}};
|
||||
}
|
||||
|
||||
// Helper which constructs a $** IndexEntry and returns it along with an owned ProjectionExecutor.
|
||||
// The latter simulates the ProjectionExecutor which, during normal operation, is owned and
|
||||
// maintained by the $** index's IndexAccessMethod, and is required because the plan cache will
|
||||
// obtain unowned pointers to it.
|
||||
/**
|
||||
* Helper which constructs a $** IndexEntry and returns it along with an owned ProjectionExecutor.
|
||||
* The latter simulates the ProjectionExecutor which, during normal operation, is owned and
|
||||
* maintained by the $** index's IndexAccessMethod, and is required because the plan cache will
|
||||
* obtain unowned pointers to it.
|
||||
*/
|
||||
std::pair<IndexEntry, std::unique_ptr<WildcardProjection>> makeWildcardEntry(BSONObj keyPattern) {
|
||||
auto wcProj = std::make_unique<WildcardProjection>(
|
||||
WildcardKeyGenerator::createProjectionExecutor(keyPattern, {}));
|
||||
@ -108,11 +147,11 @@ std::pair<IndexEntry, std::unique_ptr<WildcardProjection>> makeWildcardEntry(BSO
|
||||
}
|
||||
|
||||
//
|
||||
// Tests for CachedSolution
|
||||
// Tests for CachedSolution.
|
||||
//
|
||||
|
||||
/**
|
||||
* Utility function to create a PlanRankingDecision
|
||||
* Utility function to create a PlanRankingDecision.
|
||||
*/
|
||||
std::unique_ptr<plan_ranker::PlanRankingDecision> createDecision(size_t numPlans,
|
||||
size_t works = 0) {
|
||||
@ -131,40 +170,6 @@ std::unique_ptr<plan_ranker::PlanRankingDecision> createDecision(size_t numPlans
|
||||
return why;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test functions for shouldCacheQuery
|
||||
* Use these functions to assert which categories
|
||||
* of canonicalized queries are suitable for inclusion
|
||||
* in the planner cache.
|
||||
*/
|
||||
void assertShouldCacheQuery(const CanonicalQuery& query) {
|
||||
if (shouldCacheQuery(query)) {
|
||||
return;
|
||||
}
|
||||
str::stream ss;
|
||||
ss << "Canonical query should be cacheable: " << query.toString();
|
||||
FAIL(ss);
|
||||
}
|
||||
|
||||
void assertShouldNotCacheQuery(const CanonicalQuery& query) {
|
||||
if (!shouldCacheQuery(query)) {
|
||||
return;
|
||||
}
|
||||
str::stream ss;
|
||||
ss << "Canonical query should not be cacheable: " << query.toString();
|
||||
FAIL(ss);
|
||||
}
|
||||
|
||||
void assertShouldNotCacheQuery(const BSONObj& query) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(query));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
void assertShouldNotCacheQuery(const char* queryStr) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize(queryStr));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
std::unique_ptr<QuerySolution> getQuerySolutionForCaching() {
|
||||
std::unique_ptr<QuerySolution> qs = std::make_unique<QuerySolution>();
|
||||
qs->cacheData = std::make_unique<SolutionCacheData>();
|
||||
@ -173,69 +178,73 @@ std::unique_ptr<QuerySolution> getQuerySolutionForCaching() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cacheable queries
|
||||
* These queries will be added to the cache with run-time statistics
|
||||
* and can be managed with the cache DB commands.
|
||||
* Cacheable queries.
|
||||
*
|
||||
* These queries will be added to the cache with run-time statistics and can be managed with the
|
||||
* cache DB commands.
|
||||
*/
|
||||
|
||||
TEST(PlanCacheTest, ShouldCacheQueryBasic) {
|
||||
TEST_F(PlanCacheTest, ShouldCacheQueryBasic) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
assertShouldCacheQuery(*cq);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, ShouldCacheQuerySort) {
|
||||
TEST_F(PlanCacheTest, ShouldCacheQuerySort) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{}", "{a: -1}", "{_id: 0, a: 1}", "{}"));
|
||||
assertShouldCacheQuery(*cq);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Non-cacheable queries.
|
||||
*
|
||||
* These queries will be sent through the planning process everytime.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Collection scan
|
||||
* Collection scan.
|
||||
*
|
||||
* This should normally be handled by the IDHack runner.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldNotCacheQueryCollectionScan) {
|
||||
TEST_F(PlanCacheTest, ShouldNotCacheQueryCollectionScan) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{}"));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hint
|
||||
* Hint.
|
||||
*
|
||||
* A hinted query implies strong user preference for a particular index.
|
||||
* Therefore, not much point in caching.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldNotCacheQueryWithHint) {
|
||||
TEST_F(PlanCacheTest, ShouldNotCacheQueryWithHint) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: 1}", "{}", "{}", 0, 0, "{a: 1, b: 1}", "{}", "{}"));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Min queries are a specialized case of hinted queries
|
||||
* Min queries are a specialized case of hinted queries.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldNotCacheQueryWithMin) {
|
||||
TEST_F(PlanCacheTest, ShouldNotCacheQueryWithMin) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: 1}", "{}", "{}", 0, 0, "{a: 1}", "{a: 100}", "{}"));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Max queries are non-cacheable for the same reasons as min queries.
|
||||
* Max queries are non-cacheable for the same reasons as min queries.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldNotCacheQueryWithMax) {
|
||||
TEST_F(PlanCacheTest, ShouldNotCacheQueryWithMax) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: 1}", "{}", "{}", 0, 0, "{a: 1}", "{}", "{a: 100}"));
|
||||
assertShouldNotCacheQuery(*cq);
|
||||
}
|
||||
|
||||
/**
|
||||
* $geoWithin queries with legacy coordinates are cacheable as long as
|
||||
* the planner is able to come up with a cacheable solution.
|
||||
* $geoWithin queries with legacy coordinates are cacheable as long as the planner is able to come
|
||||
* up with a cacheable solution.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldCacheQueryWithGeoWithinLegacyCoordinates) {
|
||||
TEST_F(PlanCacheTest, ShouldCacheQueryWithGeoWithinLegacyCoordinates) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: {$geoWithin: "
|
||||
"{$box: [[-180, -90], [180, 90]]}}}"));
|
||||
@ -245,7 +254,7 @@ TEST(PlanCacheTest, ShouldCacheQueryWithGeoWithinLegacyCoordinates) {
|
||||
/**
|
||||
* $geoWithin queries with GeoJSON coordinates are supported by the index bounds builder.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldCacheQueryWithGeoWithinJSONCoordinates) {
|
||||
TEST_F(PlanCacheTest, ShouldCacheQueryWithGeoWithinJSONCoordinates) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: {$geoWithin: "
|
||||
"{$geometry: {type: 'Polygon', coordinates: "
|
||||
@ -256,7 +265,7 @@ TEST(PlanCacheTest, ShouldCacheQueryWithGeoWithinJSONCoordinates) {
|
||||
/**
|
||||
* $geoWithin queries with both legacy and GeoJSON coordinates are cacheable.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldCacheQueryWithGeoWithinLegacyAndJSONCoordinates) {
|
||||
TEST_F(PlanCacheTest, ShouldCacheQueryWithGeoWithinLegacyAndJSONCoordinates) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{$or: [{a: {$geoWithin: {$geometry: {type: 'Polygon', "
|
||||
"coordinates: [[[0, 0], [0, 90], "
|
||||
@ -268,7 +277,7 @@ TEST(PlanCacheTest, ShouldCacheQueryWithGeoWithinLegacyAndJSONCoordinates) {
|
||||
/**
|
||||
* $geoIntersects queries are always cacheable because they support GeoJSON coordinates only.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldCacheQueryWithGeoIntersects) {
|
||||
TEST_F(PlanCacheTest, ShouldCacheQueryWithGeoIntersects) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: {$geoIntersects: "
|
||||
"{$geometry: {type: 'Point', coordinates: "
|
||||
@ -277,10 +286,10 @@ TEST(PlanCacheTest, ShouldCacheQueryWithGeoIntersects) {
|
||||
}
|
||||
|
||||
/**
|
||||
* $geoNear queries are cacheable because we are able to distinguish
|
||||
* between flat and spherical queries.
|
||||
* $geoNear queries are cacheable because we are able to distinguish between flat and spherical
|
||||
* queries.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldNotCacheQueryWithGeoNear) {
|
||||
TEST_F(PlanCacheTest, ShouldNotCacheQueryWithGeoNear) {
|
||||
unique_ptr<CanonicalQuery> cq(
|
||||
canonicalize("{a: {$geoNear: {$geometry: {type: 'Point',"
|
||||
"coordinates: [0,0]}, $maxDistance:100}}}"));
|
||||
@ -288,11 +297,10 @@ TEST(PlanCacheTest, ShouldNotCacheQueryWithGeoNear) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Explain queries are not-cacheable because of allPlans cannot
|
||||
* be accurately generated from stale cached stats in the plan cache for
|
||||
* non-winning plans.
|
||||
* Explain queries are not-cacheable because of allPlans cannot be accurately generated from stale
|
||||
* cached stats in the plan cache for non-winning plans.
|
||||
*/
|
||||
TEST(PlanCacheTest, ShouldNotCacheQueryExplain) {
|
||||
TEST_F(PlanCacheTest, ShouldNotCacheQueryExplain) {
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}",
|
||||
"{}",
|
||||
"{}",
|
||||
@ -324,7 +332,7 @@ void addCacheEntryForShape(const CanonicalQuery& cq, PlanCache* planCache) {
|
||||
ASSERT_OK(planCache->set(makeKey(cq), qs->cacheData->clone(), *decision, Date_t{}, &callbacks));
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, InactiveEntriesDisabled) {
|
||||
TEST_F(PlanCacheTest, InactiveEntriesDisabled) {
|
||||
// Set the global flag for disabling active entries.
|
||||
internalQueryCacheDisableInactiveEntries.store(true);
|
||||
ON_BLOCK_EXIT([] { internalQueryCacheDisableInactiveEntries.store(false); });
|
||||
@ -355,7 +363,7 @@ TEST(PlanCacheTest, InactiveEntriesDisabled) {
|
||||
ASSERT_EQ(planCache.get(key).state, PlanCache::CacheEntryState::kNotPresent);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheLRUPolicyRemovesInactiveEntries) {
|
||||
TEST_F(PlanCacheTest, PlanCacheLRUPolicyRemovesInactiveEntries) {
|
||||
// Use a tiny cache size.
|
||||
const size_t kCacheSize = 2;
|
||||
PlanCache planCache(kCacheSize);
|
||||
@ -391,7 +399,7 @@ TEST(PlanCacheTest, PlanCacheLRUPolicyRemovesInactiveEntries) {
|
||||
ASSERT_EQ(planCache.get(keyC).state, PlanCache::CacheEntryState::kPresentInactive);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheRemoveDeletesInactiveEntries) {
|
||||
TEST_F(PlanCacheTest, PlanCacheRemoveDeletesInactiveEntries) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -412,7 +420,7 @@ TEST(PlanCacheTest, PlanCacheRemoveDeletesInactiveEntries) {
|
||||
ASSERT_EQ(planCache.get(key).state, PlanCache::CacheEntryState::kNotPresent);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheFlushDeletesInactiveEntries) {
|
||||
TEST_F(PlanCacheTest, PlanCacheFlushDeletesInactiveEntries) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -433,7 +441,7 @@ TEST(PlanCacheTest, PlanCacheFlushDeletesInactiveEntries) {
|
||||
ASSERT_EQ(planCache.get(key).state, PlanCache::CacheEntryState::kNotPresent);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, AddActiveCacheEntry) {
|
||||
TEST_F(PlanCacheTest, AddActiveCacheEntry) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -464,7 +472,7 @@ TEST(PlanCacheTest, AddActiveCacheEntry) {
|
||||
ASSERT_EQ(planCache.get(key).state, PlanCache::CacheEntryState::kNotPresent);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, WorksValueIncreases) {
|
||||
TEST_F(PlanCacheTest, WorksValueIncreases) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -538,7 +546,7 @@ TEST(PlanCacheTest, WorksValueIncreases) {
|
||||
ASSERT_EQ(planCache.get(key).state, PlanCache::CacheEntryState::kNotPresent);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, WorksValueIncreasesByAtLeastOne) {
|
||||
TEST_F(PlanCacheTest, WorksValueIncreasesByAtLeastOne) {
|
||||
// Will use a very small growth coefficient.
|
||||
const double kWorksCoeff = 1.10;
|
||||
|
||||
@ -582,7 +590,7 @@ TEST(PlanCacheTest, WorksValueIncreasesByAtLeastOne) {
|
||||
ASSERT_EQ(planCache.get(key).state, PlanCache::CacheEntryState::kNotPresent);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, SetIsNoopWhenNewEntryIsWorse) {
|
||||
TEST_F(PlanCacheTest, SetIsNoopWhenNewEntryIsWorse) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -626,7 +634,7 @@ TEST(PlanCacheTest, SetIsNoopWhenNewEntryIsWorse) {
|
||||
ASSERT_EQ(entry->works.value(), 20U);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, SetOverwritesWhenNewEntryIsBetter) {
|
||||
TEST_F(PlanCacheTest, SetOverwritesWhenNewEntryIsBetter) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -669,7 +677,7 @@ TEST(PlanCacheTest, SetOverwritesWhenNewEntryIsBetter) {
|
||||
ASSERT_EQ(entry->works.value(), 10U);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, DeactivateCacheEntry) {
|
||||
TEST_F(PlanCacheTest, DeactivateCacheEntry) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -709,7 +717,7 @@ TEST(PlanCacheTest, DeactivateCacheEntry) {
|
||||
ASSERT_EQ(entry->works.value(), 20U);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, GetMatchingStatsMatchesAndSerializesCorrectly) {
|
||||
TEST_F(PlanCacheTest, GetMatchingStatsMatchesAndSerializesCorrectly) {
|
||||
PlanCache planCache(5000);
|
||||
|
||||
// Create a cache entry with 5 works.
|
||||
@ -897,6 +905,7 @@ protected:
|
||||
// Clean up any previous state from a call to runQueryFull or runQueryAsCommand.
|
||||
solns.clear();
|
||||
|
||||
NamespaceString nss("test.collection");
|
||||
auto findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
findCommand->setFilter(query);
|
||||
findCommand->setSort(sort);
|
||||
@ -1011,6 +1020,7 @@ protected:
|
||||
QueryTestServiceContext serviceContext;
|
||||
auto opCtx = serviceContext.makeOperationContext();
|
||||
|
||||
NamespaceString nss("test.collection");
|
||||
auto findCommand = std::make_unique<FindCommandRequest>(nss);
|
||||
findCommand->setFilter(query);
|
||||
findCommand->setSort(sort);
|
||||
@ -1715,7 +1725,7 @@ TEST_F(CachePlanSelectionTest, ContainedOrAndIntersection) {
|
||||
"]}}}}");
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) {
|
||||
TEST_F(PlanCacheTest, PlanCacheSizeWithCRUDOperations) {
|
||||
PlanCache planCache(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1, b: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
@ -1789,7 +1799,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) {
|
||||
ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), originalSize);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheSizeWithEviction) {
|
||||
TEST_F(PlanCacheTest, PlanCacheSizeWithEviction) {
|
||||
const size_t kCacheSize = 5;
|
||||
PlanCache planCache(kCacheSize);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1, b: 1}"));
|
||||
@ -1867,7 +1877,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheSizeWithMultiplePlanCaches) {
|
||||
TEST_F(PlanCacheTest, PlanCacheSizeWithMultiplePlanCaches) {
|
||||
PlanCache planCache1(5000);
|
||||
PlanCache planCache2(5000);
|
||||
unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1, b: 1}"));
|
||||
@ -1930,7 +1940,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithMultiplePlanCaches) {
|
||||
ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), originalSize);
|
||||
}
|
||||
|
||||
TEST(PlanCacheTest, PlanCacheMaxSizeParameterCanBeZero) {
|
||||
TEST_F(PlanCacheTest, PlanCacheMaxSizeParameterCanBeZero) {
|
||||
PlanCache planCache{0U};
|
||||
unique_ptr<CanonicalQuery> query(canonicalize("{a: 1, c: 1}"));
|
||||
auto qs = getQuerySolutionForCaching();
|
||||
|
||||
@ -289,15 +289,20 @@ void createIndexForApplyOps(OperationContext* opCtx,
|
||||
try {
|
||||
indexBuildsCoordinator->createIndexesOnEmptyCollection(
|
||||
opCtx, coll, {indexSpec}, fromMigrate);
|
||||
} catch (const ExceptionFor<ErrorCodes::IndexAlreadyExists>& e) {
|
||||
// Ignore the "IndexAlreadyExists" error during oplog application.
|
||||
LOGV2_DEBUG(7261800,
|
||||
1,
|
||||
"Ignoring indexing error",
|
||||
"error"_attr = redact(e.toStatus()),
|
||||
logAttrs(indexCollection->ns()),
|
||||
logAttrs(indexCollection->uuid()),
|
||||
"spec"_attr = indexSpec);
|
||||
} catch (DBException& ex) {
|
||||
// Some indexing errors can be ignored during oplog application.
|
||||
const auto& status = ex.toStatus();
|
||||
if (IndexBuildsCoordinator::isCreateIndexesErrorSafeToIgnore(status, constraints)) {
|
||||
LOGV2_DEBUG(7261800,
|
||||
1,
|
||||
"Ignoring indexing error",
|
||||
"error"_attr = redact(status),
|
||||
logAttrs(indexCollection->ns()),
|
||||
logAttrs(indexCollection->uuid()),
|
||||
"spec"_attr = indexSpec);
|
||||
return;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
wuow.commit();
|
||||
} else {
|
||||
|
||||
@ -203,7 +203,6 @@ ExecutorFuture<void> RenameCollectionCoordinator::_runImpl(
|
||||
checkCollectionUUIDMismatch(
|
||||
opCtx, fromNss, *coll, _doc.getExpectedSourceUUID());
|
||||
|
||||
|
||||
uassert(ErrorCodes::NamespaceNotFound,
|
||||
str::stream() << "Collection " << fromNss << " doesn't exist.",
|
||||
coll.getCollection());
|
||||
@ -236,10 +235,13 @@ ExecutorFuture<void> RenameCollectionCoordinator::_runImpl(
|
||||
_doc.setTargetUUID(getCollectionUUID(
|
||||
opCtx, toNss, optTargetCollType, /*throwNotFound*/ false));
|
||||
|
||||
auto criticalSection = ShardingRecoveryService::get(opCtx);
|
||||
if (!targetIsSharded) {
|
||||
// (SERVER-67325) Acquire critical section on the target collection in order
|
||||
// to disallow concurrent `createCollection`
|
||||
// to disallow concurrent `createCollection`. In case the collection does
|
||||
// not exist, it will be later released by the rename participant. In case
|
||||
// the collection exists and is unsharded, the critical section can be
|
||||
// released right away as the participant will re-acquire it when needed.
|
||||
auto criticalSection = ShardingRecoveryService::get(opCtx);
|
||||
criticalSection->acquireRecoverableCriticalSectionBlockWrites(
|
||||
opCtx,
|
||||
toNss,
|
||||
@ -255,23 +257,17 @@ ExecutorFuture<void> RenameCollectionCoordinator::_runImpl(
|
||||
uassert(ErrorCodes::NamespaceExists,
|
||||
str::stream() << "a view already exists with that name: " << toNss,
|
||||
!CollectionCatalog::get(opCtx)->lookupView(opCtx, toNss));
|
||||
}
|
||||
|
||||
const bool targetExists = [&]() {
|
||||
if (targetIsSharded) {
|
||||
return true;
|
||||
if (CollectionCatalog::get(opCtx)->lookupCollectionByNamespace(opCtx,
|
||||
toNss)) {
|
||||
// Release the critical section because the unsharded target collection
|
||||
// already exists, hence no risk of concurrent `createCollection`
|
||||
criticalSection->releaseRecoverableCriticalSection(
|
||||
opCtx,
|
||||
toNss,
|
||||
criticalSectionReason,
|
||||
WriteConcerns::kLocalWriteConcern);
|
||||
}
|
||||
auto collectionCatalog = CollectionCatalog::get(opCtx);
|
||||
auto targetColl =
|
||||
collectionCatalog->lookupCollectionByNamespace(opCtx, toNss);
|
||||
return (bool)targetColl; // true if exists and is unsharded
|
||||
}();
|
||||
|
||||
if (targetExists) {
|
||||
// Release the critical section because the target collection
|
||||
// already exists, hence no risk of concurrent `createCollection`
|
||||
criticalSection->releaseRecoverableCriticalSection(
|
||||
opCtx, toNss, criticalSectionReason, WriteConcerns::kLocalWriteConcern);
|
||||
}
|
||||
|
||||
sharding_ddl_util::checkRenamePreconditions(
|
||||
@ -295,7 +291,11 @@ ExecutorFuture<void> RenameCollectionCoordinator::_runImpl(
|
||||
} catch (const DBException&) {
|
||||
auto criticalSection = ShardingRecoveryService::get(opCtx);
|
||||
criticalSection->releaseRecoverableCriticalSection(
|
||||
opCtx, toNss, criticalSectionReason, WriteConcerns::kLocalWriteConcern);
|
||||
opCtx,
|
||||
toNss,
|
||||
criticalSectionReason,
|
||||
WriteConcerns::kLocalWriteConcern,
|
||||
false /* throwIfReasonDiffers */);
|
||||
_completeOnError = true;
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
==== VARIATION: cq=ns=testdb.testcollTree: $and
|
||||
==== VARIATION: cq=ns=test.collectionTree: $and
|
||||
a $eq 1
|
||||
b $eq 1
|
||||
Sort: {}
|
||||
Proj: {}
|
||||
Collation: { locale: "mock_reverse_string" }
|
||||
|
||||
an[eqa,eqb]#mock_reverse_string02300000@f
|
||||
an[eqa,eqb]#mock_reverse_string02300000@ff
|
||||
|
||||
@ -1,80 +1,80 @@
|
||||
==== VARIATION: query={}, sort={}, proj={}
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={ $or: [ { a: 1 }, { b: 2 } ] }, sort={}, proj={}
|
||||
or[eqa,eqb]@f
|
||||
or[eqa,eqb]@ff
|
||||
==== VARIATION: query={ $or: [ { a: 1 }, { b: 1 }, { c: 1 } ], d: 1 }, sort={}, proj={}
|
||||
an[or[eqa,eqb,eqc],eqd]@f
|
||||
an[or[eqa,eqb,eqc],eqd]@ff
|
||||
==== VARIATION: query={ $or: [ { a: 1 }, { b: 1 } ], c: 1, d: 1 }, sort={}, proj={}
|
||||
an[or[eqa,eqb],eqc,eqd]@f
|
||||
an[or[eqa,eqb],eqc,eqd]@ff
|
||||
==== VARIATION: query={ a: 1, b: 1, c: 1 }, sort={}, proj={}
|
||||
an[eqa,eqb,eqc]@f
|
||||
an[eqa,eqb,eqc]@ff
|
||||
==== VARIATION: query={ a: 1, beqc: 1 }, sort={}, proj={}
|
||||
an[eqa,eqbeqc]@f
|
||||
an[eqa,eqbeqc]@ff
|
||||
==== VARIATION: query={ ap1a: 1 }, sort={}, proj={}
|
||||
eqap1a@f
|
||||
eqap1a@ff
|
||||
==== VARIATION: query={ aab: 1 }, sort={}, proj={}
|
||||
eqaab@f
|
||||
eqaab@ff
|
||||
==== VARIATION: query={}, sort={ a: 1 }, proj={}
|
||||
an~aa@f
|
||||
an~aa@ff
|
||||
==== VARIATION: query={}, sort={ a: -1 }, proj={}
|
||||
an~da@f
|
||||
an~da@ff
|
||||
==== VARIATION: query={ $text: { $search: "search keywords" } }, sort={ a: { $meta: "textScore" } }, proj={ a: { $meta: "textScore" } }
|
||||
te_fts~ta@f
|
||||
te_fts~ta@ff
|
||||
==== VARIATION: query={ a: 1 }, sort={ b: 1 }, proj={}
|
||||
eqa~ab@f
|
||||
eqa~ab@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: 1 }
|
||||
an|_id-a@f
|
||||
an|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: -1 }
|
||||
an|_id-a@f
|
||||
an|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: -1.0 }
|
||||
an|_id-a@f
|
||||
an|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: true }
|
||||
an|_id-a@f
|
||||
an|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: 0 }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: false }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: 99 }
|
||||
an|_id-a@f
|
||||
an|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: "foo" }
|
||||
an|_id@f
|
||||
an|_id@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $slice: [ 3, 5 ] } }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $slice: [ 3, 5 ] }, b: 0 }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $slice: [ 3, 5 ] }, b: 1 }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $elemMatch: { x: 2 } } }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $elemMatch: { x: 2 } }, b: 0 }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $elemMatch: { x: 2 } }, b: 1 }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: { $slice: [ 3, 5 ] }, b: { $elemMatch: { x: 2 } } }
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: ObjectId('507f191e810c19729de860ea') }
|
||||
an|_id@f
|
||||
an|_id@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ _id: 0, a: ObjectId('507f191e810c19729de860ea'), b: "foo" }
|
||||
an|@f
|
||||
an|@ff
|
||||
==== VARIATION: query={ a: 1 }, sort={}, proj={ a.$: 1 }
|
||||
eqa@f
|
||||
eqa@ff
|
||||
==== VARIATION: query={ a: 1 }, sort={}, proj={ a: 1 }
|
||||
eqa|_id-a@f
|
||||
eqa|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: 1, b: 1 }
|
||||
an|_id-a-b@f
|
||||
an|_id-a-b@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ b: 1, a: 1 }
|
||||
an|_id-a-b@f
|
||||
an|_id-a-b@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ b-1: 1, a-2: 1 }
|
||||
an|_id-a\-2-b\-1@f
|
||||
an|_id-a\-2-b\-1@ff
|
||||
==== VARIATION: query={}, sort={ x: 1 }, proj={ $sortKey: { $meta: "sortKey" } }
|
||||
an~ax@f
|
||||
an~ax@ff
|
||||
==== VARIATION: query={}, sort={}, proj={}
|
||||
an@f
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={ x: 1 }, proj={ a: 1, $sortKey: { $meta: "sortKey" } }
|
||||
an~ax|_id-a@f
|
||||
an~ax|_id-a@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: 1 }
|
||||
an|_id-a@f
|
||||
an|_id-a@ff
|
||||
==== VARIATION: query={ $or: [ { a: 1 } ] }, sort={}, proj={ _id: 0, a: 1 }
|
||||
eqa|a@f
|
||||
eqa|a@ff
|
||||
==== VARIATION: query={ $or: [ { a: 1 } ] }, sort={}, proj={ a.$: 1 }
|
||||
eqa@f
|
||||
eqa@ff
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
==== VARIATION: query={ a,[]~|-<>: 1 }, sort={}, proj={}
|
||||
eqa\,\[\]\~\|\-<>@f
|
||||
eqa\,\[\]\~\|\-<>@ff
|
||||
==== VARIATION: query={}, sort={ a,[]~|-<>: 1 }, proj={}
|
||||
an~aa\,\[\]\~\|\-<>@f
|
||||
an~aa\,\[\]\~\|\-<>@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a,[]~|-<>: 1 }
|
||||
an|_id-a\,\[\]\~\|\-<>@f
|
||||
an|_id-a\,\[\]\~\|\-<>@ff
|
||||
==== VARIATION: query={}, sort={}, proj={ a: "foo,[]~|-<>" }
|
||||
an|_id@f
|
||||
an|_id@ff
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
==== VARIATION: query={ a: { $near: [ 0, 0 ], $maxDistance: 0.3 } }, sort={}, proj={}
|
||||
gnanrfl@f
|
||||
gnanrfl@ff
|
||||
==== VARIATION: query={ a: { $nearSphere: [ 0, 0 ], $maxDistance: 0.31 } }, sort={}, proj={}
|
||||
gnanssp@f
|
||||
gnanssp@ff
|
||||
==== VARIATION: query={ a: { $geoNear: { $geometry: { type: "Point", coordinates: [ 0, 0 ] }, $maxDistance: 100 } } }, sort={}, proj={}
|
||||
gnanrsp@f
|
||||
gnanrsp@ff
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
==== VARIATION: query={ a: { $in: [ /foo/ ] } }, sort={}, proj={}
|
||||
rea@f
|
||||
rea@ff
|
||||
==== VARIATION: query={ a: { $in: [ /foo/i ] } }, sort={}, proj={}
|
||||
rea/i/@f
|
||||
rea/i/@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, "foo" ] } }, sort={}, proj={}
|
||||
ina@f
|
||||
ina@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/ ] } }, sort={}, proj={}
|
||||
ina_re@f
|
||||
ina_re@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/is ] } }, sort={}, proj={}
|
||||
ina_re/is/@f
|
||||
ina_re/is/@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/si ] } }, sort={}, proj={}
|
||||
ina_re/is/@f
|
||||
ina_re/is/@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/i, /bar/m, /baz/s ] } }, sort={}, proj={}
|
||||
ina_re/ims/@f
|
||||
ina_re/ims/@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/i, /bar/m, /baz/s, /qux/i, /quux/s ] } }, sort={}, proj={}
|
||||
ina_re/ims/@f
|
||||
ina_re/ims/@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/ism, /bar/msi, /baz/im, /qux/si, /quux/im ] } }, sort={}, proj={}
|
||||
ina_re/ims/@f
|
||||
ina_re/ims/@ff
|
||||
==== VARIATION: query={ a: { $in: [ 1, /foo/msi, /bar/ism, /baz/is, /qux/mi, /quux/im ] } }, sort={}, proj={}
|
||||
ina_re/ims/@f
|
||||
ina_re/ims/@ff
|
||||
==== VARIATION: query={ a: { $not: { $in: [ 1, "foo" ] } } }, sort={}, proj={}
|
||||
nt[ina]@f
|
||||
nt[ina]@ff
|
||||
==== VARIATION: query={ a: { $not: { $in: [ 1, /foo/ ] } } }, sort={}, proj={}
|
||||
nt[ina_re]@f
|
||||
nt[ina_re]@ff
|
||||
==== VARIATION: query={ a: { $not: { $in: [ 1, /foo/i, /bar/i, /baz/msi ] } } }, sort={}, proj={}
|
||||
nt[ina_re/ims/]@f
|
||||
nt[ina_re/ims/]@ff
|
||||
==== VARIATION: query={ a: { $not: { $in: [ /foo/ ] } } }, sort={}, proj={}
|
||||
nt[rea]@f
|
||||
nt[rea]@ff
|
||||
==== VARIATION: query={ a: { $not: { $in: [ /foo/i ] } } }, sort={}, proj={}
|
||||
nt[rea/i/]@f
|
||||
nt[rea/i/]@ff
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
==== VARIATION: query={ a: /sometext/ }, sort={}, proj={}
|
||||
rea@t
|
||||
rea@tf
|
||||
==== VARIATION: query={ a: /sometext/ }, sort={}, proj={}
|
||||
rea@t
|
||||
rea@tf
|
||||
==== VARIATION: query={ a: /sometext/s }, sort={}, proj={}
|
||||
rea/s/@t
|
||||
rea/s/@tf
|
||||
==== VARIATION: query={ a: /sometext/ms }, sort={}, proj={}
|
||||
rea/ms/@t
|
||||
rea/ms/@tf
|
||||
==== VARIATION: query={ a: /sometext/im }, sort={}, proj={}
|
||||
rea/im/@t
|
||||
rea/im/@tf
|
||||
==== VARIATION: query={ a: /sometext/mi }, sort={}, proj={}
|
||||
rea/im/@t
|
||||
rea/im/@tf
|
||||
==== VARIATION: query={ a: /abc/mi }, sort={}, proj={}
|
||||
rea/im/@t
|
||||
rea/im/@tf
|
||||
==== VARIATION: query={ a: /efg/mi }, sort={}, proj={}
|
||||
rea/im/@t
|
||||
rea/im/@tf
|
||||
==== VARIATION: query={ a: //ms }, sort={}, proj={}
|
||||
rea/ms/@t
|
||||
rea/ms/@tf
|
||||
==== VARIATION: query={ a: /___/ms }, sort={}, proj={}
|
||||
rea/ms/@t
|
||||
rea/ms/@tf
|
||||
==== VARIATION: query={ a: { $regex: "abc", $options: "imxsu" } }, sort={}, proj={}
|
||||
rea/imsx/@t
|
||||
rea/imsx/@tf
|
||||
==== VARIATION: query={ a: /abc/im }, sort={}, proj={}
|
||||
rea/im/@t
|
||||
rea/im/@tf
|
||||
|
||||
@ -1,50 +1,50 @@
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={}
|
||||
YW4ABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
YW4ABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={$or: [{a: 1}, {b: 2}]}, sort={}, proj={}
|
||||
b3IAW2VxAGE/AAAAACxlcQBiPwEAAABdBQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
b3IAW2VxAGE/AAAAACxlcQBiPwEAAABdBQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={b: 1}, sort={}, proj={}
|
||||
ZXEAYj8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYj8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1, b: 1, c: 1}, sort={}, proj={}
|
||||
YW4AW2VxAGE/AAAAACxlcQBiPwEAAAAsZXEAYz8CAAAAXQUAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
YW4AW2VxAGE/AAAAACxlcQBiPwEAAAAsZXEAYz8CAAAAXQUAAAAAAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={a: 1}, proj={}
|
||||
YW4ABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
YW4ABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={}, sort={a: -1}, proj={}
|
||||
YW4ABQAAAAB+ZGEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
YW4ABQAAAAB+ZGEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={a: 1}
|
||||
ZXEAYT8AAAAADAAAABBhAAEAAAAAfmFhAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
ZXEAYT8AAAAADAAAABBhAAEAAAAAfmFhAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={a: 1}, proj={a: 1}
|
||||
YW4ADAAAABBhAAEAAAAAfmFhAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
YW4ADAAAABBhAAEAAAAAfmFhAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={a: 1}, proj={a: 1}
|
||||
YW4ADAAAABBhAAEAAAAAfmFhAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
YW4ADAAAABBhAAEAAAAAfmFhAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={a: 1}
|
||||
YW4ADAAAABBhAAEAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
YW4ADAAAABBhAAEAAAAAAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={a: true}
|
||||
YW4ACQAAAAhhAAEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
YW4ACQAAAAhhAAEAAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={a: false}
|
||||
YW4ACQAAAAhhAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
YW4ACQAAAAhhAAAAAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={}, isCountLike=true
|
||||
YW4ABQAAAAAAAQAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
YW4ABQAAAAAAAQAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=1, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAdG5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAHRubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAZm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAGZubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=1, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbnRubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG50bm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5mbgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5uZm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAoAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAKAAAAAAAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAKAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAACgAAAAAAAABubm5uBQAAAABmXg==
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=1
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm50bhgAAAASJHJlY29yZElkAAEAAAAAAAAAAGZe
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5udG4YAAAAEiRyZWNvcmRJZAABAAAAAAAAAABmXg==
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl5aAAAAAyRsb29rdXAATAAAAAJmcm9tAAwAAABmb3JlaWduY29sbAACYXMAAwAAAGFzAAJsb2NhbEZpZWxkAAIAAABhAAJmb3JlaWduRmllbGQAAgAAAGIAAAA=
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZeWgAAAAMkbG9va3VwAEwAAAACZnJvbQAMAAAAZm9yZWlnbmNvbGwAAmFzAAMAAABhcwACbG9jYWxGaWVsZAACAAAAYQACZm9yZWlnbkZpZWxkAAIAAABiAAAA
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl5bAAAAAyRsb29rdXAATQAAAAJmcm9tAAwAAABmb3JlaWduY29sbAACYXMAAwAAAGFzAAJsb2NhbEZpZWxkAAMAAABhMQACZm9yZWlnbkZpZWxkAAIAAABiAAAA
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZeWwAAAAMkbG9va3VwAE0AAAACZnJvbQAMAAAAZm9yZWlnbmNvbGwAAmFzAAMAAABhcwACbG9jYWxGaWVsZAADAAAAYTEAAmZvcmVpZ25GaWVsZAACAAAAYgAAAA==
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl5bAAAAAyRsb29rdXAATQAAAAJmcm9tAAwAAABmb3JlaWduY29sbAACYXMAAwAAAGFzAAJsb2NhbEZpZWxkAAIAAABhAAJmb3JlaWduRmllbGQAAwAAAGIxAAAA
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZeWwAAAAMkbG9va3VwAE0AAAACZnJvbQAMAAAAZm9yZWlnbmNvbGwAAmFzAAMAAABhcwACbG9jYWxGaWVsZAACAAAAYQACZm9yZWlnbkZpZWxkAAMAAABiMQAAAA==
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl5bAAAAAyRsb29rdXAATQAAAAJmcm9tAAwAAABmb3JlaWduY29sbAACYXMABAAAAGFzMQACbG9jYWxGaWVsZAACAAAAYQACZm9yZWlnbkZpZWxkAAIAAABiAAAA
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZeWwAAAAMkbG9va3VwAE0AAAACZnJvbQAMAAAAZm9yZWlnbmNvbGwAAmFzAAQAAABhczEAAmxvY2FsRmllbGQAAgAAAGEAAmZvcmVpZ25GaWVsZAACAAAAYgAAAA==
|
||||
==== VARIATION: sbe, query={a: 1}, sort={}, proj={}
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAbm5ubgUAAAAAZl5aAAAAAyRsb29rdXAATAAAAAJmcm9tAAwAAABmb3JlaWduY29sbAACYXMAAwAAAGFzAAJsb2NhbEZpZWxkAAIAAABhAAJmb3JlaWduRmllbGQAAgAAAGIAAABdAAAAAyRsb29rdXAATwAAAAJmcm9tAAwAAABmb3JlaWduY29sbAACYXMABAAAAGFzMQACbG9jYWxGaWVsZAADAAAAYTEAAmZvcmVpZ25GaWVsZAADAAAAYjEAAAA=
|
||||
ZXEAYT8AAAAABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZeWgAAAAMkbG9va3VwAEwAAAACZnJvbQAMAAAAZm9yZWlnbmNvbGwAAmFzAAMAAABhcwACbG9jYWxGaWVsZAACAAAAYQACZm9yZWlnbkZpZWxkAAIAAABiAAAAXQAAAAMkbG9va3VwAE8AAAACZnJvbQAMAAAAZm9yZWlnbmNvbGwAAmFzAAQAAABhczEAAmxvY2FsRmllbGQAAwAAAGExAAJmb3JlaWduRmllbGQAAwAAAGIxAAAA
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAZl4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={a: 1}, sort={a: 1}, proj={}, allowDiskUse=0, returnKey=0, requestResumeToken=0
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAbm5ubgUAAAAAdF4=
|
||||
ZXEAYT8AAAAABQAAAAB+YWEAAAAAAAAAAAAAAG5ubm4FAAAAAHRe
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
==== VARIATION: query={}, sort={}, proj={}
|
||||
an@ff
|
||||
==== VARIATION: query={}, sort={}, proj={}
|
||||
an@ft
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={}
|
||||
YW4ABQAAAAAAAAAAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
==== VARIATION: sbe, query={}, sort={}, proj={}
|
||||
YW4ABQAAAAAAAAEAAAAAAAAAAG5ubm4FAAAAAGZe
|
||||
@ -1,10 +1,10 @@
|
||||
==== VARIATION: query={ a: { $not: { $eq: null } } }, sort={}, proj={ _id: 0, a: 1 }
|
||||
ntnot_eq_null[eqa]|a@f
|
||||
ntnot_eq_null[eqa]|a@ff
|
||||
==== VARIATION: query={ a: { $not: { $eq: null } } }, sort={ a: 1 }, proj={ _id: 0, a: 1 }
|
||||
ntnot_eq_null[eqa]~aa|a@f
|
||||
ntnot_eq_null[eqa]~aa|a@ff
|
||||
==== VARIATION: query={ a: { $not: { $gte: null } } }, sort={ a: 1 }, proj={ _id: 0, a: 1 }
|
||||
ntnot_eq_null[gea]~aa|a@f
|
||||
ntnot_eq_null[gea]~aa|a@ff
|
||||
==== VARIATION: query={ a: { $not: { $lte: null } } }, sort={ a: 1 }, proj={ _id: 0, a: 1 }
|
||||
ntnot_eq_null[lea]~aa|a@f
|
||||
ntnot_eq_null[lea]~aa|a@ff
|
||||
==== VARIATION: query={ a: { $not: { $eq: true } } }, sort={ a: 1 }, proj={ _id: 0, a: 1 }
|
||||
nt[eqa]~aa|a@f
|
||||
nt[eqa]~aa|a@ff
|
||||
|
||||
@ -2328,6 +2328,10 @@ TEST_F(TxnAPITest, WaitsForBestEffortAbortOnNonTransientErrorIfNotCancelled) {
|
||||
|
||||
// After the abort finishes, the API should not have retried.
|
||||
expectSentAbort(1 /* txnNumber */, WriteConcernOptions().toBSON());
|
||||
|
||||
// Wait for tasks so destructors run on the main test thread.
|
||||
executor->shutdown();
|
||||
executor->join();
|
||||
}
|
||||
|
||||
TEST_F(TxnAPITest, WaitsForBestEffortAbortOnTransientError) {
|
||||
@ -2395,6 +2399,10 @@ TEST_F(TxnAPITest, WaitsForBestEffortAbortOnTransientError) {
|
||||
boost::none /* readConcern */,
|
||||
WriteConcernOptions().toBSON() /* writeConcern */);
|
||||
ASSERT_EQ(lastRequest.firstElementFieldNameStringData(), "commitTransaction"_sd);
|
||||
|
||||
// Wait for tasks so destructors run on the main test thread.
|
||||
executor->shutdown();
|
||||
executor->join();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Loading…
Reference in New Issue
Block a user