Compare commits

...

23 Commits

Author SHA1 Message Date
Jawwad Asghar
31895f53cd SERVER-73998 Fixing expansions issue with sys-perf microbenchmark tests
(cherry picked from commit c0c1e7dff1)
2023-02-15 14:05:47 +00:00
Benety Goh
8b06b20e74 SERVER-73858 Oplog batch application index builds on an empty collection should ignore same errors as non-empty collection case
(cherry picked from commit 0b0048e3ec)
2023-02-14 22:06:33 +00:00
Benety Goh
f876854381 SERVER-73858 add IndexBuildsCoordinator::isCreateIndexesErrorSafeToIgnore()
(cherry picked from commit 944b024917)
2023-02-14 20:37:06 +00:00
Benety Goh
d3b2ad3244 SERVER-73858 add js test for geo 2d index options conflict during initial sync
(cherry picked from commit 3d7dfa8ad0)
2023-02-14 18:05:49 +00:00
Jack Mulrow
ae13a0375b SERVER-73949 Join created executor in transaction API unit tests
(cherry picked from commit 393506ef23)
2023-02-14 17:15:34 +00:00
Anton Korshunov
a748104759 SERVER-71159 Include apiStrict flag into SBE plan cache key
(cherry picked from commit 1b27b42504)
2023-02-14 15:59:30 +00:00
dalyd
37f6d07553 SERVER-73719 Comment out legacy sys-perf buildvariants v6.3 2023-02-13 21:23:44 +00:00
Pierlauro Sciarelli
09cb75d4c6 SERVER-73385 Releasing unheld critical section upon sharded rename error must result in a no-op 2023-02-13 15:41:41 +00:00
Kevin Cherkauer
f4b99751fb SERVER-73822 Time-series $group rewrite ignores certain accumulators
(cherry picked from commit f9fd648140)
2023-02-13 12:43:18 +00:00
Antonio Fuschetto
b5f7f35d46 SERVER-73890 Only run the resilient movePrimary in random_DDL_operations.js FSM 2023-02-13 08:46:33 +00:00
Dan Larkin-York
96399bf635 SERVER-73636 Fix poor allocation pattern in validation reporting
(cherry picked from commit 2d90115a22)
2023-02-10 22:47:41 +00:00
Gregory Wlodarek
ced7b06862 SERVER-73745 Zero initialize IndexKeyBucket struct
(cherry picked from commit ceb331a747)
2023-02-10 20:45:47 +00:00
james-hippler
619ab6338d SERVER-72825 [v6.3] Remove Outdated/Duplicate Entries for Multiversion Tests 2023-02-10 17:56:30 +00:00
dylrich
6a050da034 SERVER-73722: run amazon 2022 publish on rhel 8
(cherry picked from commit f7afadd90f)
2023-02-09 16:43:21 +00:00
Mikhail Shchatko
5927f2e811 SERVER-72821 Add more required variants to etc/evergreen_nightly.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
239040917d SERVER-72821 Change references to "v6.3" in etc/perf.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
de755012e0 SERVER-72821 Remove all feature flags variants from etc/system_perf.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
e72d191a30 SERVER-72821 Remove renew_ssl_cert from etc/system_perf.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
2b1a5b3ccc SERVER-72821 Change references to "v6.3" in etc/system_perf.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
180639fd33 SERVER-72821 Update suffixes in generate_version_expansions.py 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
2e15f33879 SERVER-72821 Moved required variants to etc/evergreen_nightly.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
4d1c6a2b36 SERVER-72821 Remove wtdevelop variants from etc/evergreen.yml 2023-02-07 20:00:41 +00:00
Mikhail Shchatko
3419f8de5e SERVER-72821 Change references to "v6.3" in etc/evergreen_yml_components/definitions.yml 2023-02-07 20:00:41 +00:00
39 changed files with 2098 additions and 1819 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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,
* ]
*/

View File

@ -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);
})();

View 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);
}());

View 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);
})();

View File

@ -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);
}

View File

@ -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;

View File

@ -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}",

View File

@ -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

View File

@ -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 {};
}
}

View File

@ -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', "

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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}}]}"));

View File

@ -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();

View File

@ -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 {

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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==

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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