Compare commits

...

84 Commits

Author SHA1 Message Date
Aaron Morand
6d1f5c5ec4 SERVER-72276 Removing outdated entries for multiversion tests 2022-12-21 19:30:40 -05:00
Paolo Polato
e86b8c099e SERVER-72065 Fix refresh of sessions cache in CSRS secondary nodes 2022-12-19 15:26:18 +00:00
Samy Lanka
f037f034bb SERVER-67213 Wait for all nodes to install config before doing a force reconfig in reconfig.js
(cherry picked from commit e5e5f384e9)
2022-12-16 21:26:37 +00:00
Gregory Noma
4b44c24078 SERVER-72005 Run TSBS on 2022-11 sys-perf variants 2022-12-15 16:08:49 +00:00
Yu Jin Kang Park
5f3ed635a7 SERVER-61909 Fix transaction_too_large_for_cache.js to requires_fcv_62 2022-12-12 18:22:26 +00:00
Trevor Guidry
d4108459eb SERVER-71982 set directConnection=True in standalone.py
this is for multiversion testing with pymongo v4
2022-12-09 20:25:41 +00:00
dalyd
ae174ad93c SERVER-70594 Add updated build variants to sys-perf @dalyd 2022-12-09 17:44:28 +00:00
Jason Chan
d8c83636e6 SERVER-71685 Remove sampling of connAcquisitionToWire metrics
(cherry picked from commit 8cefa36fdd)
2022-12-09 17:14:31 +00:00
Jacob Evans
be31f3772c SERVER-71838 Remove deprecated collStats in ftdc 2022-12-08 21:13:20 +00:00
Jacob Evans
194a588a57 SERVER-71961 Don't expect absent collection ftdc 2022-12-08 20:42:33 +00:00
Allison Easton
84cb06c4db SERVER-71756 Defragmentation policy should issue dataSize commands with estimate true
(cherry picked from commit 49c71b3699)
2022-12-07 21:37:36 +00:00
Suganthi Mani
6b55bbebb1 SERVER-71683 Tenant collection cloner reads the next batch from socket buffer only after writing all the documents in the current batch to storage
(cherry picked from commit 5fee6fff13)
2022-12-07 17:09:48 +00:00
Ryan Egesdahl
135dee6512 SERVER-71902 Remove test_packages_complete task 2022-12-06 20:53:02 +00:00
Tausif Rahman
6f196e05ce SERVER-68500 multiversion tag files are not correctly excluding tests in CI
(cherry picked from commit f4dae67839)
2022-12-06 18:01:19 +00:00
Dan Larkin-York
6161d31622 SERVER-71723 Store WriteBatch measurements using small_vector
(cherry picked from commit 7ca2aafe45)
2022-12-06 17:22:19 +00:00
Tausif Rahman
f2a5b9e9bf Revert "SERVER-68500 multiversion tag files are not correctly excluding tests in CI"
This reverts commit ba23c18841.
2022-12-06 17:18:59 +00:00
Dan Larkin-York
0bb9d60967 SERVER-71721 Avoid extra string copy in NamespaceString constructor
(cherry picked from commit 1bca070739)
2022-12-06 16:50:10 +00:00
Dan Larkin-York
490ac76661 SERVER-71720 Move WriteBatch shared_ptr instead of copying
(cherry picked from commit e2fc105891)
2022-12-06 16:21:42 +00:00
Dan Larkin-York
9b96ed3f33 SERVER-71719 Check if we have bucket to reopen before calling rehydrateBucket
(cherry picked from commit 31be4c3818)
2022-12-06 16:19:41 +00:00
Dan Larkin-York
9d78ef337b SERVER-71718 Refactor extractTimeAndMeta to branch earlier and iterate document once
(cherry picked from commit 88d18f93e8)
2022-12-06 15:47:15 +00:00
Allison Easton
89b2e659a2 SERVER-71788 Defragmentation should handle ChunkTooBig errors
(cherry picked from commit 76d4cb7bd5)
2022-12-05 18:11:12 +00:00
Pierlauro Sciarelli
d3fab9c982 SERVER-71787 Balancer needs to attach forceJumbo to moveRange command 2022-12-05 12:11:43 +00:00
Tommaso Tocci
a7c27ed890 SERVER-71759 dataSize command doesn't yield
(cherry picked from commit 44d81c74e5)
2022-12-03 15:26:48 +00:00
Tausif Rahman
ba23c18841 SERVER-68500 multiversion tag files are not correctly excluding tests in CI
(cherry picked from commit 7a6f90b2bb)
2022-12-03 00:42:57 +00:00
Yu Jin Kang Park
cb651c8d8e SERVER-71750 Revert writeConflictRetry refactor into handleWriteConflictException
(cherry picked from commit 552afb106b)
2022-12-02 14:46:29 +00:00
Yu Jin Kang Park
7e8d18a464 SERVER-71751 Skip core/transaction_too_large_for_cache.js in non-WT storage engines
(cherry picked from commit 761037636e)
2022-12-02 14:46:29 +00:00
Yu Jin Kang Park
9ca8158531 SERVER-61909 Abort operation if it cannot ever fit in WT cache
(cherry picked from commit 9ddbd35120)
2022-12-02 14:46:29 +00:00
Yuhong Zhang
f90b35cf6c SERVER-71360 Avoid signed promotion on the value of the subtype before casting to BinDataType (cherry picked from commit d69c4bd59c) 2022-12-01 20:05:46 +00:00
Jess Balint
7382e1a20f SERVER-65790 create telemetry feature flag 2022-12-01 06:17:59 +00:00
Pierlauro Sciarelli
63d6350c8a SERVER-71666 Reduce number of scanned index entries on chunk migration commit
(cherry picked from commit 591bce5984)
2022-11-30 22:15:28 +00:00
Mindaugas Malinauskas
e62af19b57 SERVER-71568 Fix race condition related to access to ChangeStreamOptions
(cherry picked from commit 92d8c8e3aa)
2022-11-30 13:11:40 +00:00
Tausif Rahman
e7b8e61a29 SERVER-71506 Refactor tooling metrics
(cherry picked from commit b06927da23)
2022-11-29 18:58:50 +00:00
Yu Jin Kang Park
8045c4a777 SERVER-68739 Do not reset WT session stats when fetching op stats 2022-11-29 18:03:30 +00:00
Pol Pinol Castuera
923b5fd65a SERVER-68576 Added number of sharded collections to serverStatus command. 2022-11-29 08:28:01 +00:00
Tausif Rahman
b6ff8ad7ad SERVER-71411 Replace asyncio with explicit timeouts in metrics collection
(cherry picked from commit 93b1775dd9)
2022-11-28 16:34:37 +00:00
Luke Chen
833d66db10 Import wiredtiger: 659bbb26d9e357b714a782755442c78e05ddca7a from branch mongodb-6.2
ref: 9a35c70af8..659bbb26d9
for: 6.2.0-rc2

WT-10192 Fix bug in cursor_prev_skip statistics
2022-11-28 06:24:32 +00:00
Allison Easton
7cc81eb7c8 SERVER-71486 Fix config settings schema modification during fcv upgrade and downgrade
(cherry picked from commit e8d15ab156)
2022-11-24 14:50:18 +00:00
Alya Berciu
67ecf18ff9 SERVER-71445 Update cover_null_queries.js fcv 2022-11-24 12:35:55 +00:00
Pol Pinol Castuera
ad2b7e93f1 SERVER-71477 Check '_internalAllCollectionStatsSpec.getStats()' exists before calling 'makeStatsForNs' 2022-11-24 08:07:57 +00:00
Maddie Zechar
b75695e4e1 SERVER-71529 Add serverStatus metric for classic and SBE plan cache size 2022-11-24 00:10:34 +00:00
Pierlauro Sciarelli
71c42004e0 SERVER-71122 Get rid of the WaitForCleanCorrectEvenAfterClearFollowedBySetFilteringMetadata unit test 2022-11-23 22:26:10 +00:00
Maddie Zechar
141ff826fd SERVER-71386 Telemetry collection fails for queries with non-object fields 2022-11-23 21:36:18 +00:00
Ivan Fefer
bb0c1608a1 SERVER-71270 In timeseries collections prevent match pushdown before project that can affect it 2022-11-23 16:21:46 +00:00
Tommaso Tocci
fa551f7ae3 SERVER-71297 Coverity analysis defect 134120: Fix VersionType::currentVersion parsing
(cherry picked from commit 32bb6bed25)
2022-11-23 13:43:33 +00:00
Milena Ivanova
94323d60eb SERVER-71370 Disable test failing on MacOs
(cherry picked from commit 6e0c9c3b24)
2022-11-23 12:29:33 +00:00
Jeff Zambory
0743b9dbdb SERVER-71473: Begin using the new test stats location
(cherry picked from commit 81b9c1abbc)
2022-11-23 10:08:03 +00:00
Alexander Neben
b57d0f80d3 SERVER-71534 Fixed fuzzer linting scripts
(cherry picked from commit abb9e21146)
2022-11-23 00:21:15 +00:00
Benety Goh
8b1d7be7ab SERVER-71498 QueryStageBatchedDeleteTest initializes TickSourceMock once
(cherry picked from commit a5341aa27e)
2022-11-22 17:35:23 +00:00
Mikhail Shchatko
7726d54b47 SERVER-71518 Use S3 test stats in mongo-task-generator
(cherry picked from commit f590e94413)
2022-11-21 18:54:05 +00:00
Alexander Neben
61620c0d61 SERVER-71471 Fixed deployment process for jstestfuzz
(cherry picked from commit 45400e2540)
2022-11-21 16:44:22 +00:00
Alexander Neben
4f8c870d1e SERVER-71424 Excluded third_party js files from linting
(cherry picked from commit be0adb109b)
2022-11-21 16:44:22 +00:00
Pierlauro Sciarelli
abcdf5a80b SERVER-71435 Increse verbosity level for range-deleter in resmoke 2022-11-21 14:35:37 +00:00
Luke Chen
d21a749138 Import wiredtiger: 9a35c70af8a4e8c67b850d7982a77d5260fb5f08 from branch mongodb-6.2
ref: 2cb2316c04..9a35c70af8
for: 6.2.0-rc2

WT-9773 Fix mirrored table bulk load fail on cache pressure
2022-11-21 03:50:48 +00:00
Luke Chen
eff237c48a Import wiredtiger: 2cb2316c04ed3eb46a983338c3db2dc690e26f32 from branch mongodb-6.2
ref: 185cb65902..2cb2316c04
for: 6.2.0-rc2

WT-9102 Update macOS variant to version 11.00
2022-11-21 03:50:48 +00:00
Luke Chen
80003a2abe Import wiredtiger: 185cb659029fc4e5213783c5d290aa0fab5ab043 from branch mongodb-6.2
ref: 47951efac1..185cb65902
for: 6.2.0-rc2

WT-10164 Split apart the rollback to stable implementation into multiple files
2022-11-21 03:50:48 +00:00
Luke Chen
866c9351be Import wiredtiger: 47951efac16fbf8e5d44230ad18fce1b18858cda from branch mongodb-6.2
ref: 9a23ed36e1..47951efac1
for: 6.2.0-rc2

WT-7492 Ignore the evict drain wait msg in stdout.txt for test_cursor_random
2022-11-21 03:50:48 +00:00
Luke Chen
77dd7f8d28 Import wiredtiger: 9a23ed36e160f47df4068de05795d9c1f4f12e78 from branch mongodb-6.2
ref: de945280b9..9a23ed36e1
for: 6.2.0-rc2

WT-10139 Add record count field for table
2022-11-21 03:50:48 +00:00
Luke Chen
3c16cf3c39 Import wiredtiger: de945280b9fe413f00134ab1f1eeea9c15a05383 from branch mongodb-6.2
ref: b412563e92..de945280b9
for: 6.2.0-rc2

WT-10140 Add a new API to retrieve record count of a table
2022-11-21 03:50:48 +00:00
Luke Chen
5a1c2ba98e Import wiredtiger: b412563e92786caa4e9a36b7430468c2e8d3e649 from branch mongodb-6.2
ref: 147ed016d0..b412563e92
for: 6.2.0-rc2

WT-10159 Disable truncate operation when prepare is enabled in non-stanadlone build
2022-11-21 03:50:48 +00:00
Luke Chen
ac43d305a8 Import wiredtiger: 147ed016d0a3256903b9c9e62453e2bf8f5a3d7f from branch mongodb-6.2
ref: bcbfad0e77..147ed016d0
for: 6.2.0-rc2

WT-10165 Fix wording of 'all committed' in test_timestamp14
2022-11-21 03:50:48 +00:00
Luke Chen
901d618860 Import wiredtiger: bcbfad0e770ce83f9a571ce4115ae76fe0e0817f from branch mongodb-6.2
ref: 6e9fb75859..bcbfad0e77
for: 6.2.0-rc2

WT-10133 Make some non-transactional non-modifying cursor operation retryable.
2022-11-21 03:50:48 +00:00
Luke Chen
14c4127600 Import wiredtiger: 6e9fb75859897ebd99a5db9ce767f27ee5a134d8 from branch mongodb-6.2
ref: 3fdcbdde0e..6e9fb75859
for: 6.2.0-rc2

WT-10152 Add a home directory option to the cppsuite
2022-11-21 03:50:48 +00:00
Luke Chen
dc25f5f142 Import wiredtiger: 3fdcbdde0e500d84b0d4d49c6409274f0d78c74e from branch mongodb-6.2
ref: 35c033d896..3fdcbdde0e
for: 6.2.0-rc2

WT-10131 Upload stack traces to Evergreen for cpp suite tests and fix the executable path
2022-11-21 03:50:48 +00:00
Luke Chen
cc020142b7 Import wiredtiger: 35c033d8964524e2027f3b019ab9d0f657ce0edd from branch mongodb-6.2
ref: 5eee10d1ce..35c033d896
for: 6.2.0-rc2

WT-9834 Wait for a block to be unused before removing it
2022-11-21 03:50:48 +00:00
Luke Chen
1255f157c1 Import wiredtiger: 5eee10d1ceb365e632cdb355612b62eff1ab1b93 from branch mongodb-6.2
ref: 7559c709cc..5eee10d1ce
for: 6.2.0-rc2

WT-10137 Create a feature flag to enable/disable stats in page header
2022-11-21 03:50:47 +00:00
Luke Chen
ddbe563959 Import wiredtiger: 7559c709ccc03ce9c0e6538e421aadd61f650990 from branch mongodb-6.2
ref: 0efbb249a0..7559c709cc
for: 6.2.0-rc2

WT-10155 Move unit-test-long-bucket04 onto a larger Evergreen distro
2022-11-21 03:50:47 +00:00
Luke Chen
168b40f0ff Import wiredtiger: 0efbb249a0a79f504cf3be03129973e2fbb6f428 from branch mongodb-6.2
ref: 5ade1afb83..0efbb249a0
for: 6.2.0-rc2

WT-10062 Fix checkpoint cleanup not to skip internal pages
2022-11-21 03:50:47 +00:00
Steve Tarzia
39881664f2 SERVER-71452 hint _id index and lengthen timeout in allow_partial_results_with_maxTimeMS.js 2022-11-18 19:49:48 +00:00
Yuhong Zhang
fc05e34ea4 Revert "SERVER-65078 Report schema violations as errors when the validation level is 'error' in testing"
This reverts commit d63bf9dfa2.
2022-11-18 15:39:59 +00:00
Yuhong Zhang
efa7a19284 Revert "SERVER-71226 Skip collections with explicitly set conflicting validators in the background validation hook"
This reverts commit 2ef0ee3153.
2022-11-18 15:39:59 +00:00
Trevor Guidry
ee271f84ba SERVER-63104 add resmoke argument for generating all_feature_flags.txt locally
(cherry picked from commit 22f38cf147)
2022-11-16 23:41:36 +00:00
Abdul Qadeer
24ea1d6cd7 SERVER-71383 Add cleanup executor for scoped executor shutdown
(cherry picked from commit 92b2f2d4bf)
2022-11-16 22:35:52 +00:00
Steve Tarzia
29296c1ed9 SERVER-71372 fix getMore of partial results from find on sharded cluster 2022-11-16 17:28:42 +00:00
dylrich
931838789d SERVER-71404: remove .publish_crypt task distro overide for amazon 2022 2022-11-16 16:29:29 +00:00
Mikhail Shchatko
e0c820476e SERVER-70674 Add more required variants to etc/evergreen_nightly.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
ac930ff992 SERVER-70674 Change references to "v6.2" in etc/perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
f1c4d43ce0 SERVER-70674 Remove all feature flags variants from etc/system_perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
0df7825a8b SERVER-70674 Remove renew_ssl_cert from etc/system_perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
3e7effc73a SERVER-70674 Change references to "v6.2" in etc/system_perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
c3cec02457 SERVER-70674 Update suffixes in generate_version_expansions.py 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
dfa1355e07 SERVER-70674 Moved required variants to etc/evergreen_nightly.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
6507c32ebc SERVER-70674 Remove wtdevelop variants from etc/evergreen.yml 2022-11-16 13:55:38 +00:00
Mikhail Shchatko
1840ac24bb SERVER-70674 Change references to "v6.2" in etc/evergreen_yml_components/definitions.yml 2022-11-16 13:55:38 +00:00
Aaron Morand
28d3fe9a1a SERVER-71395 Initial commit into the 6.2 branch 2022-11-15 19:21:00 -05:00
202 changed files with 7057 additions and 5644 deletions

View File

@ -90,3 +90,4 @@ Welcome to MongoDB!
October 16, 2018, including patch fixes for prior versions, are published
under the [Server Side Public License (SSPL) v1](LICENSE-Community.txt).
See individual files for details.

View File

@ -22,6 +22,10 @@ from pkg_resources import parse_version
import SCons
import SCons.Script
from buildscripts.metrics.metrics_datatypes import SConsToolingMetrics
from buildscripts.metrics.tooling_exit_hook import initialize_exit_hook
from buildscripts.metrics.tooling_metrics_utils import register_metrics_collection_atexit
from site_scons.mongo import build_profiles
# This must be first, even before EnsureSConsVersion, if
# we are to avoid bulk loading all tools in the DefaultEnvironment.
@ -52,8 +56,6 @@ SCons.Node.FS.File.release_target_info = release_target_info_noop
from buildscripts import utils
from buildscripts import moduleconfig
from buildscripts.metrics.scons_tooling_metrics import setup_scons_metrics_collection_atexit
import psutil
scons_invocation = '{} {}'.format(sys.executable, ' '.join(sys.argv))
@ -1551,10 +1553,17 @@ env = Environment(variables=env_vars, **envDict)
del envDict
env.AddMethod(lambda env, name, **kwargs: add_option(name, **kwargs), 'AddOption')
# Setup atexit method to store tooling metrics
# The placement of this is intentional. We should only register this function atexit after
# env, env_vars and the parser have been properly initialized.
setup_scons_metrics_collection_atexit(utc_starttime, env_vars, env, _parser, sys.argv)
# The placement of this is intentional. Here we setup an atexit method to store tooling metrics.
# We should only register this function after env, env_vars and the parser have been properly initialized.
register_metrics_collection_atexit(
SConsToolingMetrics.generate_metrics, {
"utc_starttime": datetime.utcnow(),
"env_vars": env_vars,
"env": env,
"parser": _parser,
"args": sys.argv,
"exit_hook": initialize_exit_hook(),
})
if get_option('build-metrics'):
env['BUILD_METRICS_ARTIFACTS_DIR'] = '$BUILD_ROOT/$VARIANT_DIR'

View File

@ -7,7 +7,7 @@ import math
import os
import shlex
import sys
from datetime import datetime, timedelta
from datetime import timedelta
from pathlib import Path
from typing import Dict, List, Optional
@ -19,7 +19,7 @@ from evergreen import EvergreenApi, RetryingEvergreenApi
from buildscripts.ciconfig.evergreen import (EvergreenProjectConfig, parse_evergreen_file)
from buildscripts.resmoke_proxy.resmoke_proxy import ResmokeProxyService
from buildscripts.timeouts.timeout_service import (TimeoutParams, TimeoutService, TimeoutSettings)
from buildscripts.timeouts.timeout_service import (TimeoutParams, TimeoutService)
from buildscripts.util.cmdutils import enable_logging
from buildscripts.util.taskname import determine_task_base_name
@ -372,9 +372,6 @@ def main():
options = parser.parse_args()
end_date = datetime.now()
start_date = end_date - HISTORY_LOOKBACK
timeout_override = timedelta(seconds=options.timeout) if options.timeout else None
exec_timeout_override = timedelta(
seconds=options.exec_timeout) if options.exec_timeout else None
@ -389,7 +386,6 @@ def main():
binder.bind(
EvergreenApi,
RetryingEvergreenApi.get_api(config_file=os.path.expanduser(options.evg_api_config)))
binder.bind(TimeoutSettings, TimeoutSettings(start_date=start_date, end_date=end_date))
binder.bind(TimeoutOverrides, timeout_overrides)
binder.bind(EvergreenProjectConfig,
parse_evergreen_file(os.path.expanduser(options.evg_project_config)))

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.2-latest"
expansions["src_suffix"] = "v6.2-latest"
expansions["is_release"] = "false"
else:
expansions["suffix"] = version_line

View File

@ -30,7 +30,6 @@ Generate a file containing a list of disabled feature flags.
Used by resmoke.py to run only feature flag tests.
"""
import argparse
import os
import sys
@ -43,6 +42,7 @@ sys.path.append(os.path.normpath(os.path.join(os.path.abspath(__file__), '../../
# pylint: disable=wrong-import-position
import buildscripts.idl.lib as lib
from buildscripts.idl.idl import parser
def is_third_party_idl(idl_path: str) -> bool:
@ -56,13 +56,14 @@ def is_third_party_idl(idl_path: str) -> bool:
return False
def gen_all_feature_flags(idl_dir: str, import_dirs: List[str]):
def gen_all_feature_flags(idl_dir: str = os.getcwd()):
"""Generate a list of all feature flags."""
all_flags = []
for idl_path in sorted(lib.list_idls(idl_dir)):
if is_third_party_idl(idl_path):
continue
for feature_flag in lib.parse_idl(idl_path, import_dirs).spec.feature_flags:
doc = parser.parse_file(open(idl_path), idl_path)
for feature_flag in doc.spec.feature_flags:
if feature_flag.default.literal != "true":
all_flags.append(feature_flag.name)
@ -72,18 +73,16 @@ def gen_all_feature_flags(idl_dir: str, import_dirs: List[str]):
return list(set(all_flags) - set(force_disabled_flags))
def gen_all_feature_flags_file(filename: str = lib.ALL_FEATURE_FLAG_FILE):
flags = gen_all_feature_flags()
with open(filename, "w") as output_file:
output_file.write("\n".join(flags))
print("Generated: ", os.path.realpath(output_file.name))
def main():
"""Run the main function."""
arg_parser = argparse.ArgumentParser(description=__doc__)
arg_parser.add_argument("--import-dir", dest="import_dirs", type=str, action="append",
help="Directory to search for IDL import files")
args = arg_parser.parse_args()
flags = gen_all_feature_flags(os.getcwd(), args.import_dirs)
with open(lib.ALL_FEATURE_FLAG_FILE, "w") as output_file:
for flag in flags:
output_file.write("%s\n" % flag)
gen_all_feature_flags_file()
if __name__ == '__main__':

View File

@ -1023,7 +1023,7 @@ def _propagate_globals(spec):
idltype.cpp_type = _prefix_with_namespace(cpp_namespace, idltype.cpp_type)
def _parse(stream, error_file_name):
def parse_file(stream, error_file_name):
# type: (Any, str) -> syntax.IDLParsedSpec
"""
Parse a YAML document into an idl.syntax tree.
@ -1125,7 +1125,7 @@ def parse(stream, input_file_name, resolver):
input_file_name: a file name for error messages to use, and to help resolve imported files.
"""
root_doc = _parse(stream, input_file_name)
root_doc = parse_file(stream, input_file_name)
if root_doc.errors:
return root_doc
@ -1162,7 +1162,7 @@ def parse(stream, input_file_name, resolver):
# Parse imported file
with resolver.open(resolved_file_name) as file_stream:
parsed_doc = _parse(file_stream, resolved_file_name)
parsed_doc = parse_file(file_stream, resolved_file_name)
# Check for errors
if parsed_doc.errors:

View File

@ -5,12 +5,13 @@ import multiprocessing
import os
import socket
import sys
import traceback
from typing import Any, Dict, List, Optional
import distro
import git
from pydantic import BaseModel
from buildscripts.metrics.tooling_exit_hook import _ExitHook
# pylint: disable=bare-except
SCONS_ENV_FILE = "scons_env.env"
@ -20,6 +21,12 @@ SCONS_SECTION_HEADER = "SCONS_ENV"
class BaseMetrics(BaseModel):
"""Base class for an metrics object."""
@classmethod
@abstractmethod
def generate_metrics(cls, **kwargs):
"""Generate metrics."""
raise NotImplementedError
@abstractmethod
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
@ -35,14 +42,14 @@ class BuildInfo(BaseMetrics):
artifact_dir: Optional[str]
@classmethod
def get_scons_build_info(
def generate_metrics(
cls,
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
):
): # pylint: disable=arguments-differ
"""Get SCons build info to the best of our ability."""
artifact_dir = cls._get_scons_artifact_dir(env)
return cls(
@ -59,19 +66,22 @@ class BuildInfo(BaseMetrics):
) -> Optional[Dict[str, Any]]:
"""Get the environment variables options that can be set by users."""
artifact_dir = BuildInfo._get_scons_artifact_dir(env)
artifact_dir = artifact_dir if artifact_dir else '.'
scons_env_filepath = f'{artifact_dir}/{SCONS_ENV_FILE}'
try:
# Use SCons built-in method to save environment variables to a file
env_vars.Save(SCONS_ENV_FILE, env)
env_vars.Save(scons_env_filepath, env)
# Add a section header to the file so we can easily parse with ConfigParser
with open(SCONS_ENV_FILE, 'r') as original:
with open(scons_env_filepath, 'r') as original:
data = original.read()
with open(SCONS_ENV_FILE, 'w') as modified:
with open(scons_env_filepath, 'w') as modified:
modified.write(f"[{SCONS_SECTION_HEADER}]\n" + data)
# Parse file using config parser
config = configparser.ConfigParser()
config.read(SCONS_ENV_FILE)
config.read(scons_env_filepath)
str_dict = dict(config[SCONS_SECTION_HEADER])
return {key: eval(val) for key, val in str_dict.items()} # pylint: disable=eval-used
except:
@ -118,52 +128,27 @@ class BuildInfo(BaseMetrics):
return None in [self.artifact_dir, self.env, self.options, self.build_artifacts]
class ExitInfo(BaseMetrics):
"""Class to store tooling exit information."""
exit_code: Optional[int]
exception: Optional[str]
stacktrace: Optional[str]
@classmethod
def get_resmoke_exit_info(cls):
"""Get the current exit info."""
exc = sys.exc_info()[1]
return cls(
exit_code=0 if not exc else exc.code if exc.__class__ == SystemExit else 1,
exception=exc.__class__.__name__ if exc else None,
stacktrace=traceback.format_exc() if exc else None,
)
@classmethod
def get_scons_exit_info(cls, exit_code):
"""Get the current exit info using the given exit code."""
return cls(
exit_code=exit_code if isinstance(exit_code, int) else None,
exception=None,
stacktrace=None,
)
def is_malformed(self):
"""Return True if this object is missing an exit code."""
return self.exit_code is None
class HostInfo(BaseMetrics):
"""Class to store host information."""
ip_address: Optional[str]
host_os: str
num_cores: int
memory: Optional[float]
@classmethod
def get_host_info(cls):
def generate_metrics(cls): # pylint: disable=arguments-differ
"""Get the host info to the best of our ability."""
try:
ip_address = socket.gethostbyname(socket.gethostname())
except:
ip_address = None
try:
memory = cls._get_memory()
except:
memory = None
return cls(
ip_address=ip_address,
host_os=distro.name(pretty=True),
num_cores=multiprocessing.cpu_count(),
memory=memory,
@ -174,9 +159,9 @@ class HostInfo(BaseMetrics):
"""Get total memory of the host system."""
return os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024.**3)
def is_malformed(self):
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
return self.memory is None
return None in [self.memory, self.ip_address]
class GitInfo(BaseMetrics):
@ -188,7 +173,7 @@ class GitInfo(BaseMetrics):
repo_name: Optional[str]
@classmethod
def get_git_info(cls, filepath: str):
def generate_metrics(cls, filepath: str): # pylint: disable=arguments-differ
"""Get the git info for a repo to the best of our ability."""
try:
commit_hash = git.Repo(filepath).head.commit.hexsha
@ -212,7 +197,7 @@ class GitInfo(BaseMetrics):
repo_name=repo_name,
)
def is_malformed(self):
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
return None in [self.commit_hash, self.branch_name, self.repo_name]
@ -225,7 +210,7 @@ def _get_modules_git_info():
module_git_info = []
try:
module_git_info = [
GitInfo.get_git_info(os.path.join(MODULES_FILEPATH, module))
GitInfo.generate_metrics(os.path.join(MODULES_FILEPATH, module))
for module in os.listdir(MODULES_FILEPATH)
if os.path.isdir(os.path.join(MODULES_FILEPATH, module))
]
@ -234,73 +219,79 @@ def _get_modules_git_info():
return module_git_info
class ToolingMetrics(BaseMetrics):
"""Class to store tooling metrics."""
class ResmokeToolingMetrics(BaseMetrics):
"""Class to store resmoke tooling metrics."""
source: str
utc_starttime: datetime
utc_endtime: datetime
host_info: HostInfo
git_info: GitInfo
exit_info: ExitInfo
build_info: Optional[BuildInfo]
exit_code: Optional[int]
command: List[str]
module_info: List[GitInfo]
ip_address: Optional[str]
@classmethod
def get_resmoke_metrics(
def generate_metrics(
cls,
utc_starttime: datetime,
):
exit_hook: _ExitHook,
): # pylint: disable=arguments-differ
"""Get resmoke metrics to the best of our ability."""
try:
ip_address = socket.gethostbyname(socket.gethostname())
except:
ip_address = None
return cls(
source='resmoke',
utc_starttime=utc_starttime,
utc_endtime=datetime.utcnow(),
host_info=HostInfo.get_host_info(),
git_info=GitInfo.get_git_info('.'),
exit_info=ExitInfo.get_resmoke_exit_info(),
build_info=None,
module_info=_get_modules_git_info(),
host_info=HostInfo.generate_metrics(),
git_info=GitInfo.generate_metrics('.'),
exit_code=exit_hook.exit_code if isinstance(exit_hook.exit_code, int) else None,
command=sys.argv,
ip_address=ip_address,
module_info=_get_modules_git_info(),
)
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
sub_metrics = self.module_info + [self.git_info] + [self.host_info]
return self.exit_code is None or any(metrics.is_malformed() for metrics in sub_metrics)
class SConsToolingMetrics(BaseMetrics):
"""Class to store scons tooling metrics."""
source: str
utc_starttime: datetime
utc_endtime: datetime
host_info: HostInfo
git_info: GitInfo
exit_code: Optional[int]
build_info: BuildInfo
command: List[str]
module_info: List[GitInfo]
@classmethod
def get_scons_metrics(
def generate_metrics(
cls,
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
exit_code: int,
):
exit_hook: _ExitHook,
): # pylint: disable=arguments-differ
"""Get scons metrics to the best of our ability."""
try:
ip_address = socket.gethostbyname(socket.gethostname())
except:
ip_address = None
return cls(
source='scons',
utc_starttime=utc_starttime,
utc_endtime=datetime.utcnow(),
host_info=HostInfo.get_host_info(),
git_info=GitInfo.get_git_info('.'),
exit_info=ExitInfo.get_scons_exit_info(exit_code),
build_info=BuildInfo.get_scons_build_info(utc_starttime, env_vars, env, parser, args),
module_info=_get_modules_git_info(),
host_info=HostInfo.generate_metrics(),
git_info=GitInfo.generate_metrics('.'),
build_info=BuildInfo.generate_metrics(utc_starttime, env_vars, env, parser, args),
exit_code=exit_hook.exit_code if isinstance(exit_hook.exit_code, int) else None,
command=sys.argv,
ip_address=ip_address,
module_info=_get_modules_git_info(),
)
def is_malformed(self):
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
sub_metrics = [self.build_info] if self.source == 'scons' else []
sub_metrics += self.module_info + [self.git_info] + [self.host_info] + [self.exit_info]
return self.ip_address is None or any(metrics.is_malformed() for metrics in sub_metrics)
sub_metrics = self.module_info + [self.git_info] + [self.host_info] + [self.build_info]
return self.exit_code is None or any(metrics.is_malformed() for metrics in sub_metrics)

View File

@ -1,19 +0,0 @@
from datetime import datetime
import logging
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.tooling_metrics_utils import save_tooling_metrics, should_collect_metrics
logger = logging.getLogger('resmoke_tooling_metrics')
def save_resmoke_tooling_metrics(utc_starttime: datetime):
try:
if not should_collect_metrics():
return
tooling_metrics = ToolingMetrics.get_resmoke_metrics(utc_starttime)
save_tooling_metrics(tooling_metrics)
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"%s\nResmoke Metrics Collection Failed -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
exc)

View File

@ -1,71 +0,0 @@
import atexit
import datetime
import logging
import sys
from typing import List
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.tooling_metrics_utils import save_tooling_metrics, should_collect_metrics
logger = logging.getLogger('scons_tooling_metrics')
class SConsExitHook(object):
"""Plumb all sys.exit through this object so that we can access the exit code in atexit."""
def __init__(self):
self.exit_code = None
self._orig_exit = sys.exit
def __del__(self):
sys.exit = self._orig_exit
def initialize(self):
sys.exit = self.exit
def exit(self, code=0):
self.exit_code = code
self._orig_exit(code)
# This method should only be used when registered on atexit
def _save_scons_tooling_metrics(
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
exit_hook: SConsExitHook,
):
"""Save SCons tooling metrics to atlas cluster."""
try:
if not should_collect_metrics():
return
tooling_metrics = ToolingMetrics.get_scons_metrics(utc_starttime, env_vars, env, parser,
args, exit_hook.exit_code)
save_tooling_metrics(tooling_metrics)
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"%sSCons Metrics Collection Failed -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
exc)
def setup_scons_metrics_collection_atexit(
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
) -> None:
"""Register an atexit method for scons metrics collection."""
scons_exit_hook = SConsExitHook()
scons_exit_hook.initialize()
atexit.register(
_save_scons_tooling_metrics,
utc_starttime,
env_vars,
env,
parser,
args,
scons_exit_hook,
)

View File

@ -0,0 +1,36 @@
import sys
# pylint: disable=invalid-name
# pylint: disable=redefined-outer-name
# DO NOT INITIALIZE DIRECTLY -- This is intended to be a singleton.
class _ExitHook(object):
"""Plumb all sys.exit through this object so that we can access the exit code in atexit."""
def __init__(self):
self.exit_code = 0
self._orig_exit = sys.exit
sys.exit = self.exit
def __del__(self):
sys.exit = self._orig_exit
def exit(self, code=0):
self.exit_code = code
self._orig_exit(code)
SINGLETON_TOOLING_METRICS_EXIT_HOOK = None
# Always use this method when initializing _ExitHook -- This guarantees you are using the singleton
# initialize the exit hook as early as possible to ensure we capture the error.
def initialize_exit_hook() -> None:
"""Initialize the exit hook."""
try:
if not SINGLETON_TOOLING_METRICS_EXIT_HOOK:
SINGLETON_TOOLING_METRICS_EXIT_HOOK = _ExitHook()
except UnboundLocalError as _:
SINGLETON_TOOLING_METRICS_EXIT_HOOK = _ExitHook()
return SINGLETON_TOOLING_METRICS_EXIT_HOOK

View File

@ -1,20 +1,17 @@
import atexit
import logging
import os
import asyncio
from typing import Optional
from git import Repo
from typing import Any, Callable, Dict
import pymongo
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
logger = logging.getLogger('tooling_metrics_utils')
logger = logging.getLogger('tooling_metrics')
INTERNAL_TOOLING_METRICS_HOSTNAME = "mongodb+srv://dev-metrics-pl-0.kewhj.mongodb.net"
INTERNAL_TOOLING_METRICS_USERNAME = "internal_tooling_user"
INTERNAL_TOOLING_METRICS_PASSWORD = "internal_tooling_user"
def _get_internal_tooling_metrics_client():
def _get_internal_tooling_metrics_client() -> pymongo.MongoClient:
"""Retrieve client for internal MongoDB tooling metrics cluster."""
return pymongo.MongoClient(
host=INTERNAL_TOOLING_METRICS_HOSTNAME,
@ -24,28 +21,20 @@ def _get_internal_tooling_metrics_client():
serverSelectionTimeoutMS=1000,
connectTimeoutMS=1000,
waitQueueTimeoutMS=1000,
retryWrites=False,
)
EXPECTED_TOOLCHAIN_LOCATION = "/opt/mongodbtoolchain"
def _toolchain_exists() -> bool:
"""Check if the internal MongoDB toolchain exists."""
return os.path.exists(EXPECTED_TOOLCHAIN_LOCATION)
def _git_user_exists() -> Optional[str]:
"""Check if a git user email exists."""
try:
return Repo('.').config_reader().get_value("user", "email", None)
except Exception: # pylint: disable=broad-except
return None
MONGOD_INTENRAL_DISTRO_FILEPATH = '/etc/mongodb-distro-name'
def _is_virtual_workstation() -> bool:
"""Detect whether this is a MongoDB internal virtual workstation."""
return _toolchain_exists() and _git_user_exists()
try:
with open(MONGOD_INTENRAL_DISTRO_FILEPATH, 'r') as file:
return file.read().strip() == 'ubuntu1804-workstation'
except Exception as _: # pylint: disable=broad-except
return False
TOOLING_METRICS_OPT_OUT = "TOOLING_METRICS_OPT_OUT"
@ -56,26 +45,32 @@ def _has_metrics_opt_out() -> bool:
return os.environ.get(TOOLING_METRICS_OPT_OUT, None) == '1'
def should_collect_metrics() -> bool:
def _should_collect_metrics() -> bool:
"""Determine whether to collect tooling metrics."""
return _is_virtual_workstation() and not _has_metrics_opt_out()
async def _save_metrics(metrics: ToolingMetrics) -> None:
"""Save tooling metrics data."""
client = _get_internal_tooling_metrics_client()
client.metrics.tooling_metrics.insert_one(metrics.dict())
def save_tooling_metrics(tooling_metrics: ToolingMetrics) -> None:
"""Persist tooling metrics data to MongoDB Internal Atlas Cluster."""
# DO NOT USE DIRECTLY -- This is only to be used when metrics collection is registered atexit
def _save_metrics(
generate_metrics_function: Callable,
generate_metrics_args: Dict[str, Any],
) -> None:
"""Save metrics to the atlas cluster."""
try:
asyncio.run(asyncio.wait_for(_save_metrics(tooling_metrics), timeout=1.0))
except asyncio.TimeoutError as exc:
logger.warning(
"%s\nTimeout: Tooling metrics collection is not available -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
exc)
client = _get_internal_tooling_metrics_client()
metrics = generate_metrics_function(**generate_metrics_args)
client.metrics.tooling_metrics.insert_one(metrics.dict())
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"%s\nUnexpected: Tooling metrics collection is not available -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
"%s\n\nInternal Metrics Collection Failed -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-dev-platform",
exc)
# This is the only util that should be used externally
def register_metrics_collection_atexit(
generate_metrics_function: Callable,
generate_metrics_args: Dict[str, Any],
) -> None:
"""Register metrics collection on atexit."""
if _should_collect_metrics():
atexit.register(_save_metrics, generate_metrics_function, generate_metrics_args)

View File

@ -3,7 +3,6 @@
import json
import sys
from collections import namedtuple
from datetime import datetime, timedelta
from statistics import mean
from typing import Dict, List
@ -13,7 +12,8 @@ import structlog
from buildscripts.resmokelib.testing.report import TestInfo, TestReport
from buildscripts.resmokelib.utils import get_task_name_without_suffix
from buildscripts.util.cmdutils import enable_logging
from evergreen import RetryingEvergreenApi, TestStats
from buildscripts.util.teststats import HistoricTaskData, HistoricalTestInformation
LOGGER = structlog.get_logger("buildscripts.resmoke_tests_runtime_validate")
@ -34,17 +34,12 @@ def parse_resmoke_report(report_file: str) -> List[TestInfo]:
return [test_info for test_info in test_report.test_infos if "jstests" in test_info.test_file]
def get_historic_stats(evg_api_config: str, project_id: str, test_files: List[str], task_name: str,
build_variant: str) -> List[TestStats]:
def get_historic_stats(project_id: str, task_name: str,
build_variant: str) -> List[HistoricalTestInformation]:
"""Get historic test stats."""
evg_api = RetryingEvergreenApi.get_api(config_file=evg_api_config)
before_date = datetime.today()
after_date = before_date - timedelta(days=LOOK_BACK_NUM_DAYS)
base_task_name = get_task_name_without_suffix(task_name, build_variant).replace(
BURN_IN_PREFIX, "")
return evg_api.test_stats_by_project(project_id=project_id, after_date=after_date,
before_date=before_date, tests=test_files,
tasks=[base_task_name], variants=[build_variant])
return HistoricTaskData.get_stats_from_s3(project_id, base_task_name, build_variant)
def make_stats_map(stats: List[_TestData]) -> Dict[str, List[float]]:
@ -63,13 +58,10 @@ def make_stats_map(stats: List[_TestData]) -> Dict[str, List[float]]:
@click.command()
@click.option("--resmoke-report-file", type=str, required=True,
help="Location of resmoke's report JSON file.")
@click.option("--evg-api-config", type=str, required=True,
help="Location of evergreen api configuration.")
@click.option("--project-id", type=str, required=True, help="Evergreen project id.")
@click.option("--build-variant", type=str, required=True, help="Evergreen build variant name.")
@click.option("--task-name", type=str, required=True, help="Evergreen task name.")
def main(resmoke_report_file: str, evg_api_config: str, project_id: str, build_variant: str,
task_name: str) -> None:
def main(resmoke_report_file: str, project_id: str, build_variant: str, task_name: str) -> None:
"""Compare resmoke tests runtime with historic stats."""
enable_logging(verbose=False)
@ -79,10 +71,9 @@ def main(resmoke_report_file: str, evg_api_config: str, project_id: str, build_v
for test_info in current_test_infos
])
historic_stats = get_historic_stats(evg_api_config, project_id, list(current_stats_map.keys()),
task_name, build_variant)
historic_stats = get_historic_stats(project_id, task_name, build_variant)
historic_stats_map = make_stats_map([
_TestData(test_stats.test_file, test_stats.avg_duration_pass)
_TestData(test_stats.test_name, test_stats.avg_duration_pass)
for test_stats in historic_stats
])

View File

@ -4,7 +4,9 @@ from datetime import datetime
import time
import os
import psutil
from buildscripts.metrics.resmoke_tooling_metrics import save_resmoke_tooling_metrics
from buildscripts.metrics.metrics_datatypes import ResmokeToolingMetrics
from buildscripts.metrics.tooling_exit_hook import initialize_exit_hook
from buildscripts.metrics.tooling_metrics_utils import register_metrics_collection_atexit
from buildscripts.resmokelib import parser
@ -25,7 +27,8 @@ def main(argv):
"For example: resmoke.py run -h\n"
"Note: bisect and setup-multiversion subcommands have been moved to db-contrib-tool (https://github.com/10gen/db-contrib-tool#readme).\n"
)
try:
subcommand.execute()
finally:
save_resmoke_tooling_metrics(datetime.utcfromtimestamp(__start_time))
register_metrics_collection_atexit(ResmokeToolingMetrics.generate_metrics, {
"utc_starttime": datetime.utcfromtimestamp(__start_time),
"exit_hook": initialize_exit_hook()
})
subcommand.execute()

View File

@ -92,8 +92,9 @@ DEFAULTS = {
"report_failure_status": "fail",
"report_file": None,
"run_all_feature_flag_tests": False,
"run_all_feature_flags_no_tests": False,
"run_no_feature_flag_tests": False,
"additional_feature_flags": None,
"additional_feature_flags_file": None,
"seed": int(time.time() * 256), # Taken from random.py code in Python 2.7.
"service_executor": None,
"shell_conn_string": None,
@ -379,8 +380,11 @@ INSTALL_DIR = None
# Whether to run tests for feature flags.
RUN_ALL_FEATURE_FLAG_TESTS = None
# Whether to run the server with feature flags. Defaults to true if `RUN_ALL_FEATURE_FLAG_TESTS` is true.
RUN_ALL_FEATURE_FLAGS = None
# Whether to run the tests with enabled feature flags
RUN_NO_FEATURE_FLAG_TESTS = None
# the path to a file containing feature flags
ADDITIONAL_FEATURE_FLAGS_FILE = None
# List of enabled feature flags.
ENABLED_FEATURE_FLAGS = []

View File

@ -15,6 +15,7 @@ import shlex
import pymongo.uri_parser
from buildscripts.idl import gen_all_feature_flag_list
from buildscripts.idl.lib import ALL_FEATURE_FLAG_FILE
from buildscripts.resmokelib import config as _config
@ -52,14 +53,9 @@ def _validate_options(parser, args):
"Cannot use --replayFile with additional test files listed on the command line invocation."
)
if args.run_all_feature_flag_tests or args.run_all_feature_flags_no_tests:
if not os.path.isfile(ALL_FEATURE_FLAG_FILE):
parser.error(
"To run tests with all feature flags, the %s file must exist and be placed in"
" your working directory. The file can be downloaded from the artifacts tarball"
" in Evergreen. Alternatively, if you know which feature flags you want to enable,"
" you can use the --additionalFeatureFlags command line argument" %
ALL_FEATURE_FLAG_FILE)
if args.additional_feature_flags_file and not os.path.isfile(
args.additional_feature_flags_file):
parser.error("The specified additional feature flags file does not exist.")
def get_set_param_errors(process_params):
agg_set_params = collections.defaultdict(list)
@ -185,28 +181,36 @@ be invoked as either:
- buildscripts/resmoke.py --installDir {shlex.quote(user_config['install_dir'])}""")
raise RuntimeError(err)
def process_feature_flag_file(path):
with open(path) as fd:
return fd.read().split()
def setup_feature_flags():
_config.RUN_ALL_FEATURE_FLAG_TESTS = config.pop("run_all_feature_flag_tests")
_config.RUN_ALL_FEATURE_FLAGS = config.pop("run_all_feature_flags_no_tests")
_config.RUN_NO_FEATURE_FLAG_TESTS = config.pop("run_no_feature_flag_tests")
_config.ADDITIONAL_FEATURE_FLAGS_FILE = config.pop("additional_feature_flags_file")
# Running all feature flag tests implies running the fixtures with feature flags.
if _config.RUN_ALL_FEATURE_FLAG_TESTS:
_config.RUN_ALL_FEATURE_FLAGS = True
print("Generating: ", ALL_FEATURE_FLAG_FILE)
gen_all_feature_flag_list.gen_all_feature_flags_file()
all_ff = []
enabled_feature_flags = []
try:
with open(ALL_FEATURE_FLAG_FILE) as fd:
all_ff = fd.read().split()
all_ff = process_feature_flag_file(ALL_FEATURE_FLAG_FILE)
except FileNotFoundError:
# If we ask resmoke to run with all feature flags, the feature flags file
# needs to exist.
if _config.RUN_ALL_FEATURE_FLAGS:
if _config.RUN_ALL_FEATURE_FLAG_TESTS or _config.RUN_NO_FEATURE_FLAG_TESTS:
raise
if _config.RUN_ALL_FEATURE_FLAGS:
if _config.RUN_ALL_FEATURE_FLAG_TESTS:
enabled_feature_flags = all_ff[:]
if _config.ADDITIONAL_FEATURE_FLAGS_FILE:
enabled_feature_flags.extend(
process_feature_flag_file(_config.ADDITIONAL_FEATURE_FLAGS_FILE))
# Specify additional feature flags from the command line.
# Set running all feature flag tests to True if this options is specified.
additional_feature_flags = _tags_from_list(config.pop("additional_feature_flags"))
@ -231,7 +235,7 @@ be invoked as either:
_config.EXCLUDE_WITH_ANY_TAGS.extend(
utils.default_if_none(_tags_from_list(config.pop("exclude_with_any_tags")), []))
if _config.RUN_ALL_FEATURE_FLAGS and not _config.RUN_ALL_FEATURE_FLAG_TESTS:
if _config.RUN_NO_FEATURE_FLAG_TESTS:
# Don't run any feature flag tests.
_config.EXCLUDE_WITH_ANY_TAGS.extend(all_feature_flags)
else:

View File

@ -832,15 +832,19 @@ class RunPlugin(PluginInterface):
)
parser.add_argument(
"--runAllFeatureFlagsNoTests", dest="run_all_feature_flags_no_tests",
action="store_true", help=
"Run MongoDB servers with all feature flags enabled but don't run any tests tagged with these feature flags; used for multiversion suites"
)
"--runNoFeatureFlagTests", dest="run_no_feature_flag_tests", action="store_true",
help=("Do not run any tests tagged with enabled feature flags."
" This argument has precedence over --runAllFeatureFlagTests"
"; used for multiversion suites"))
parser.add_argument("--additionalFeatureFlags", dest="additional_feature_flags",
action="append", metavar="featureFlag1, featureFlag2, ...",
help="Additional feature flags")
parser.add_argument("--additionalFeatureFlagsFile", dest="additional_feature_flags_file",
action="store", metavar="FILE",
help="The path to a file with feature flags, delimited by newlines.")
parser.add_argument("--maxTestQueueSize", type=int, dest="max_test_queue_size",
help=argparse.SUPPRESS)
@ -1188,15 +1192,6 @@ def to_local_args(input_args=None):
if origin_suite is not None:
setattr(parsed_args, "suite_files", origin_suite)
# Replace --runAllFeatureFlagTests with an explicit list of feature flags. The former relies on
# all_feature_flags.txt which may not exist in the local dev environment.
run_all_feature_flag_tests = getattr(parsed_args, "run_all_feature_flag_tests", None)
if run_all_feature_flag_tests is not None:
setattr(parsed_args, "additional_feature_flags", config.ENABLED_FEATURE_FLAGS)
del parsed_args.run_all_feature_flag_tests
del parsed_args.run_all_feature_flags_no_tests
# The top-level parser has one subparser that contains all subcommand parsers.
command_subparser = [
action for action in parser._actions # pylint: disable=protected-access

View File

@ -181,7 +181,7 @@ class MongoDFixture(interface.Fixture):
def get_driver_connection_url(self):
"""Return the driver connection URL."""
return "mongodb://" + self.get_internal_connection_string()
return "mongodb://" + self.get_internal_connection_string() + "/?directConnection=true"
# The below parameters define the default 'logComponentVerbosity' object passed to mongod processes
@ -193,15 +193,16 @@ class MongoDFixture(interface.Fixture):
# The default verbosity setting for any tests that are not started with an Evergreen task id. This
# will apply to any tests run locally.
DEFAULT_MONGOD_LOG_COMPONENT_VERBOSITY = {
"replication": {"rollback": 2}, "sharding": {"migration": 2}, "transaction": 4,
"tenantMigration": 4
"replication": {"rollback": 2}, "sharding": {"migration": 2, "rangeDeleter": 2},
"transaction": 4, "tenantMigration": 4
}
# The default verbosity setting for any mongod processes running in Evergreen i.e. started with an
# Evergreen task id.
DEFAULT_EVERGREEN_MONGOD_LOG_COMPONENT_VERBOSITY = {
"replication": {"election": 4, "heartbeats": 2, "initialSync": 2, "rollback": 2},
"sharding": {"migration": 2}, "storage": {"recovery": 2}, "transaction": 4, "tenantMigration": 4
"replication": {"election": 4, "heartbeats": 2, "initialSync": 2,
"rollback": 2}, "sharding": {"migration": 2, "rangeDeleter": 2},
"storage": {"recovery": 2}, "transaction": 4, "tenantMigration": 4
}

View File

@ -1,41 +1,42 @@
"""Unit tests for timeout_service.py."""
import random
import unittest
from datetime import datetime, timedelta
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch
from requests.exceptions import HTTPError
from evergreen import EvergreenApi
import buildscripts.timeouts.timeout_service as under_test
from buildscripts.resmoke_proxy.resmoke_proxy import ResmokeProxyService
from buildscripts.util.teststats import HistoricTaskData
from buildscripts.util.teststats import HistoricTaskData, HistoricTestInfo
# pylint: disable=invalid-name,protected-access
NS = "buildscripts.timeouts.timeout_service"
def build_mock_service(evg_api=None, resmoke_proxy=None):
end_date = datetime.now()
start_date = end_date - timedelta(weeks=2)
timeout_settings = under_test.TimeoutSettings(
end_date=end_date,
start_date=start_date,
)
def ns(relative_name): # pylint: disable=invalid-name
"""Return a full name from a name relative to the test module"s name space."""
return NS + "." + relative_name
def build_mock_service(resmoke_proxy=None):
return under_test.TimeoutService(
evg_api=evg_api if evg_api else MagicMock(spec_set=EvergreenApi),
resmoke_proxy=resmoke_proxy if resmoke_proxy else MagicMock(spec_set=ResmokeProxyService),
timeout_settings=timeout_settings)
resmoke_proxy=resmoke_proxy if resmoke_proxy else MagicMock(spec_set=ResmokeProxyService))
def tst_stat_mock(file, duration, pass_count):
return MagicMock(test_file=file, avg_duration_pass=duration, num_pass=pass_count)
return MagicMock(test_name=file, avg_duration_pass=duration, num_pass=pass_count, hooks=[])
def tst_runtime_mock(file, duration, pass_count):
return MagicMock(test_name=file, avg_duration_pass=duration, num_pass=pass_count)
class TestGetTimeoutEstimate(unittest.TestCase):
def test_no_stats_should_return_default_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
mock_evg_api.test_stats_by_project.return_value = []
timeout_service = build_mock_service(evg_api=mock_evg_api)
@patch(ns("HistoricTaskData.from_s3"))
def test_no_stats_should_return_default_timeout(self, from_s3_mock: MagicMock):
timeout_service = build_mock_service()
from_s3_mock.return_value = []
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -48,13 +49,17 @@ class TestGetTimeoutEstimate(unittest.TestCase):
self.assertFalse(timeout.is_specified())
def test_a_test_with_missing_history_should_cause_a_default_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
test_stats = [tst_stat_mock(f"test_{i}.js", 60, 1) for i in range(30)]
mock_evg_api.test_stats_by_project.return_value = test_stats
@patch(ns("HistoricTaskData.from_s3"))
def test_a_test_with_missing_history_should_cause_a_default_timeout(
self, from_s3_mock: MagicMock):
test_stats = [
HistoricTestInfo(test_name=f"test_{i}.js", avg_duration=60, num_pass=1, hooks=[])
for i in range(30)
]
from_s3_mock.return_value = HistoricTaskData(test_stats)
mock_resmoke_proxy = MagicMock(spec_set=ResmokeProxyService)
mock_resmoke_proxy.list_tests.return_value = ["test_with_no_stats.js"]
timeout_service = build_mock_service(evg_api=mock_evg_api, resmoke_proxy=mock_resmoke_proxy)
timeout_service = build_mock_service(resmoke_proxy=mock_resmoke_proxy)
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -67,14 +72,19 @@ class TestGetTimeoutEstimate(unittest.TestCase):
self.assertFalse(timeout.is_specified())
def test_a_test_with_zero_runtime_history_should_cause_a_default_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
test_stats = [tst_stat_mock(f"test_{i}.js", 60, 1) for i in range(30)]
test_stats.append(tst_stat_mock("zero.js", 0.0, 1))
mock_evg_api.test_stats_by_project.return_value = test_stats
@patch(ns("HistoricTaskData.from_s3"))
def test_a_test_with_zero_runtime_history_should_cause_a_default_timeout(
self, from_s3_mock: MagicMock):
test_stats = [
HistoricTestInfo(test_name=f"test_{i}.js", avg_duration=60, num_pass=1, hooks=[])
for i in range(30)
]
test_stats.append(
HistoricTestInfo(test_name="zero.js", avg_duration=0.0, num_pass=1, hooks=[]))
from_s3_mock.return_value = HistoricTaskData(test_stats)
mock_resmoke_proxy = MagicMock(spec_set=ResmokeProxyService)
mock_resmoke_proxy.list_tests.return_value = [ts.test_file for ts in test_stats]
timeout_service = build_mock_service(evg_api=mock_evg_api, resmoke_proxy=mock_resmoke_proxy)
mock_resmoke_proxy.list_tests.return_value = [ts.test_name for ts in test_stats]
timeout_service = build_mock_service(resmoke_proxy=mock_resmoke_proxy)
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -87,15 +97,19 @@ class TestGetTimeoutEstimate(unittest.TestCase):
self.assertFalse(timeout.is_specified())
def test_all_tests_with_runtime_history_should_use_custom_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
@patch(ns("HistoricTaskData.from_s3"))
def test_all_tests_with_runtime_history_should_use_custom_timeout(self,
from_s3_mock: MagicMock):
n_tests = 30
test_runtime = 600
test_stats = [tst_stat_mock(f"test_{i}.js", test_runtime, 1) for i in range(n_tests)]
mock_evg_api.test_stats_by_project.return_value = test_stats
test_stats = [
HistoricTestInfo(test_name=f"test_{i}.js", avg_duration=test_runtime, num_pass=1,
hooks=[]) for i in range(n_tests)
]
from_s3_mock.return_value = HistoricTaskData(test_stats)
mock_resmoke_proxy = MagicMock(spec_set=ResmokeProxyService)
mock_resmoke_proxy.list_tests.return_value = [ts.test_file for ts in test_stats]
timeout_service = build_mock_service(evg_api=mock_evg_api, resmoke_proxy=mock_resmoke_proxy)
mock_resmoke_proxy.list_tests.return_value = [ts.test_name for ts in test_stats]
timeout_service = build_mock_service(resmoke_proxy=mock_resmoke_proxy)
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -149,10 +163,10 @@ class TestGetTaskHookOverhead(unittest.TestCase):
class TestLookupHistoricStats(unittest.TestCase):
def test_no_stats_from_evergreen_should_return_none(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
mock_evg_api.test_stats_by_project.return_value = []
timeout_service = build_mock_service(evg_api=mock_evg_api)
@patch(ns("HistoricTaskData.from_s3"))
def test_no_stats_from_evergreen_should_return_none(self, from_s3_mock: MagicMock):
from_s3_mock.return_value = None
timeout_service = build_mock_service()
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -165,10 +179,10 @@ class TestLookupHistoricStats(unittest.TestCase):
self.assertIsNone(stats)
def test_errors_from_evergreen_should_return_none(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
mock_evg_api.test_stats_by_project.side_effect = HTTPError("failed to connect")
timeout_service = build_mock_service(evg_api=mock_evg_api)
@patch(ns("HistoricTaskData.from_s3"))
def test_errors_from_evergreen_should_return_none(self, from_s3_mock: MagicMock):
from_s3_mock.side_effect = HTTPError("failed to connect")
timeout_service = build_mock_service()
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -181,11 +195,11 @@ class TestLookupHistoricStats(unittest.TestCase):
self.assertIsNone(stats)
def test_stats_from_evergreen_should_return_the_stats(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
@patch(ns("HistoricTaskData.from_s3"))
def test_stats_from_evergreen_should_return_the_stats(self, from_s3_mock: MagicMock):
test_stats = [tst_stat_mock(f"test_{i}.js", 60, 1) for i in range(100)]
mock_evg_api.test_stats_by_project.return_value = test_stats
timeout_service = build_mock_service(evg_api=mock_evg_api)
from_s3_mock.return_value = HistoricTaskData(test_stats)
timeout_service = build_mock_service()
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",

View File

@ -1,5 +1,7 @@
"""Unit tests for metrics_datatypes.py."""
from datetime import datetime
import os
import sys
import unittest
from unittest.mock import patch
@ -9,6 +11,12 @@ import buildscripts.metrics.metrics_datatypes as under_test
# pylint: disable=unused-argument
# Metrics collection is not supported for Windows
if os.name == "nt":
sys.exit()
MOCK_EXIT_HOOK = MagicMock(exit_code=0)
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_artifact_dir",
return_value='/test')
@ -18,94 +26,89 @@ class TestBuildInfo(unittest.TestCase):
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_options_dict",
return_value={'opt': 'opt'})
def test_build_info_valid(self, mock_env, mock_options, mock_artifact_dir):
build_info = under_test.BuildInfo.get_scons_build_info(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(),
MagicMock())
build_info = under_test.BuildInfo.generate_metrics(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(), MagicMock())
assert not build_info.is_malformed()
def test_build_info_malformed(self, mock_artifact_dir):
build_info = under_test.BuildInfo.get_scons_build_info(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(),
MagicMock())
build_info = under_test.BuildInfo.generate_metrics(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(), MagicMock())
assert build_info.is_malformed()
class TestExitInfo(unittest.TestCase):
@patch("sys.exc_info", return_value=(None, None, None))
def test_resmoke_no_exc_info(self, mock_exc_info):
exit_info = under_test.ExitInfo.get_resmoke_exit_info()
assert not exit_info.is_malformed()
@patch("sys.exc_info", return_value=(None, ValueError(), None))
def test_resmoke_with_exc_info(self, mock_exc_info):
exit_info = under_test.ExitInfo.get_resmoke_exit_info()
assert not exit_info.is_malformed()
def test_scons_exit_info_valid(self):
exit_info = under_test.ExitInfo.get_scons_exit_info(0)
assert not exit_info.is_malformed()
def test_scons_exit_info_malformed(self):
exit_info = under_test.ExitInfo.get_scons_exit_info('string')
assert exit_info.is_malformed()
class TestHostInfo(unittest.TestCase):
@patch("buildscripts.metrics.metrics_datatypes.HostInfo._get_memory", side_effect=Exception())
def test_host_info_with_exc(self, mock_get_memory):
host_info = under_test.HostInfo.get_host_info()
host_info = under_test.HostInfo.generate_metrics()
assert host_info.is_malformed()
# Mock this so that it passes when running the 'buildscripts_test' suite on Windows
@patch("buildscripts.metrics.metrics_datatypes.HostInfo._get_memory", return_value=30)
def test_host_info_no_exc(self, mock_get_memory):
host_info = under_test.HostInfo.get_host_info()
host_info = under_test.HostInfo.generate_metrics()
assert not host_info.is_malformed()
class TestGitInfo(unittest.TestCase):
@patch("git.Repo", side_effect=Exception())
def test_git_info_with_exc(self, mock_repo):
git_info = under_test.GitInfo.get_git_info('.')
git_info = under_test.GitInfo.generate_metrics('.')
assert git_info.is_malformed()
def test_git_info_no_exc(self):
git_info = under_test.GitInfo.get_git_info('.')
git_info = under_test.GitInfo.generate_metrics('.')
assert not git_info.is_malformed()
@patch("git.refs.symbolic.SymbolicReference.is_detached", True)
def test_git_info_detached_head(self):
git_info = under_test.GitInfo.get_git_info('.')
git_info = under_test.GitInfo.generate_metrics('.')
assert not git_info.is_malformed()
# Mock this so that it passes when running the 'buildscripts_test' suite on Windows
@patch("buildscripts.metrics.metrics_datatypes.HostInfo._get_memory", return_value=30)
class TestToolingMetrics(unittest.TestCase):
class TestResmokeToolingMetrics(unittest.TestCase):
@patch("socket.gethostname", side_effect=Exception())
def test_resmoke_tooling_metrics_with_exc(self, mock_gethostname, mock_get_memory):
tooling_metrics = under_test.ToolingMetrics.get_resmoke_metrics(datetime.utcnow())
def test_resmoke_tooling_metrics_valid(self, mock_gethostname):
tooling_metrics = under_test.ResmokeToolingMetrics.generate_metrics(
datetime.utcnow(),
MOCK_EXIT_HOOK,
)
assert tooling_metrics.is_malformed()
def test_resmoke_tooling_metrics_no_exc(self, mock_get_memory):
tooling_metrics = under_test.ToolingMetrics.get_resmoke_metrics(datetime.utcnow())
def test_resmoke_tooling_metrics_malformed(self):
tooling_metrics = under_test.ResmokeToolingMetrics.generate_metrics(
datetime.utcnow(),
MOCK_EXIT_HOOK,
)
assert not tooling_metrics.is_malformed()
class TestSConsToolingMetrics(unittest.TestCase):
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_artifact_dir",
return_value='/test')
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_env_vars_dict",
return_value={'env': 'env'})
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_options_dict",
return_value={'opt': 'opt'})
def test_scons_tooling_metrics_valid(self, mock_options, mock_env, mock_artifact_dir,
mock_get_memory):
def test_scons_tooling_metrics_valid(self, mock_options, mock_env, mock_artifact_dir):
parser = MagicMock()
parser.parse_args = MagicMock(return_value={"opt1": "val1"})
tooling_metrics = under_test.ToolingMetrics.get_scons_metrics(
datetime.utcnow(), {'env': 'env'}, {'opts': 'opts'}, parser, ['test1', 'test2'], 0)
tooling_metrics = under_test.SConsToolingMetrics.generate_metrics(
datetime.utcnow(),
{'env': 'env'},
{'opts': 'opts'},
parser,
['test1', 'test2'],
MOCK_EXIT_HOOK,
)
assert not tooling_metrics.is_malformed()
def test_scons_tooling_metrics_malformed(self, mock_get_memory):
tooling_metrics = under_test.ToolingMetrics.get_scons_metrics(
datetime.utcnow(), {'env': 'env'}, {'opts': 'opts'}, None, [], 0)
def test_scons_tooling_metrics_malformed(self):
tooling_metrics = under_test.SConsToolingMetrics.generate_metrics(
datetime.utcnow(),
{'env': 'env'},
{'opts': 'opts'},
None,
[],
MOCK_EXIT_HOOK,
)
assert tooling_metrics.is_malformed()

View File

@ -3,11 +3,8 @@ import os
import sys
import unittest
from unittest.mock import patch
import mongomock
import pymongo
import buildscripts.metrics.resmoke_tooling_metrics as under_test
from buildscripts.resmoke import entrypoint as resmoke_entrypoint
import buildscripts.resmoke as under_test
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME = 'mongodb://testing:27017'
CURRENT_DATE_TIME = datetime(2022, 10, 4)
@ -19,37 +16,32 @@ if os.name == "nt":
sys.exit()
@patch("buildscripts.metrics.tooling_metrics_utils.INTERNAL_TOOLING_METRICS_HOSTNAME",
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
@patch("buildscripts.resmokelib.logging.flush._FLUSH_THREAD", None)
class TestResmokeMetricsCollection(unittest.TestCase):
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.resmoke_tooling_metrics.should_collect_metrics", return_value=True)
@patch("atexit.register")
class TestResmokeAtExitMetricsCollection(unittest.TestCase):
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
def test_resmoke_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" in atexit_functions
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=False)
def test_no_resmoke_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" not in atexit_functions
@patch("sys.argv", ['buildscripts/resmoke.py', 'run', '--suite', 'buildscripts_test'])
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
@patch("buildscripts.resmokelib.testing.executor.TestSuiteExecutor._run_tests",
side_effect=Exception())
def test_resmoke_metrics_collection_exc(self, mock_executor_run, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
with self.assertRaises(SystemExit):
resmoke_entrypoint()
assert client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.resmoke_tooling_metrics.should_collect_metrics", return_value=True)
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
def test_resmoke_metrics_collection(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
resmoke_entrypoint()
assert client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.resmoke_tooling_metrics.should_collect_metrics",
return_value=False)
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
def test_no_resmoke_metrics_collection(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
resmoke_entrypoint()
assert not client.metrics.tooling_metrics.find_one()
def test_resmoke_at_exit_metrics_collection_exc(
self, mock_exc_method, mock_should_collect_metrics, mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" in atexit_functions

View File

@ -1,15 +1,8 @@
from datetime import datetime
import os
import sys
import unittest
from unittest.mock import MagicMock, patch
import mongomock
import pymongo
import buildscripts.metrics.scons_tooling_metrics as under_test
from buildscripts.scons import entrypoint as scons_entrypoint
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME = 'mongodb://testing:27017'
CURRENT_DATE_TIME = datetime(2022, 10, 4)
from unittest.mock import patch
import buildscripts.scons as under_test
# pylint: disable=unused-argument
# pylint: disable=protected-access
@ -23,52 +16,29 @@ if os.name == "nt":
'buildscripts/scons.py', "CC=/opt/mongodbtoolchain/v3/bin/gcc",
"CXX=/opt/mongodbtoolchain/v3/bin/g++", "NINJA_PREFIX=test_success", "--ninja"
])
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=True)
@patch("atexit.register")
class TestSconsAtExitMetricsCollection(unittest.TestCase):
def test_scons_at_exit_metrics_collection(self, mock_atexit_register,
mock_should_collect_metrics):
with self.assertRaises(SystemExit) as context:
scons_entrypoint()
assert context.exception.code == 0
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
def test_scons_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_scons_tooling_metrics" in atexit_functions
assert "_save_metrics" in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=False)
def test_no_scons_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" not in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
@patch("buildscripts.moduleconfig.get_module_sconscripts", side_effect=Exception())
def test_scons_at_exit_metrics_collection_exc(self, mock_method, mock_atexit_register,
mock_should_collect_metrics):
with self.assertRaises(SystemExit) as context:
scons_entrypoint()
assert context.exception.code == 2
def test_scons_at_exit_metrics_collection_exc(
self, mock_exc_method, mock_should_collect_metrics, mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_scons_tooling_metrics" in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils.INTERNAL_TOOLING_METRICS_HOSTNAME",
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
class TestSconsMetricsCollection(unittest.TestCase):
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=True)
def test_scons_metrics_collection_success(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
under_test._save_scons_tooling_metrics(CURRENT_DATE_TIME, None, None, None, None,
MagicMock(exit_code=0))
assert client.metrics.tooling_metrics.find_one()
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=True)
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
def test_scons_metrics_collection_fail(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
under_test._save_scons_tooling_metrics(None, None, None, None, None, None)
assert not client.metrics.tooling_metrics.find_one()
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=False)
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
def test_no_scons_metrics_collection(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
under_test._save_scons_tooling_metrics(CURRENT_DATE_TIME, None, None, None, None,
MagicMock(exit_code=0))
assert not client.metrics.tooling_metrics.find_one()
assert "_save_metrics" in atexit_functions

View File

@ -1,81 +1,75 @@
"""Unit tests for tooling_metrics.py."""
import asyncio
from datetime import datetime
import os
import sys
import unittest
from unittest.mock import patch
from unittest.mock import mock_open, patch
from mock import MagicMock
import mongomock
import pymongo
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.metrics_datatypes import ResmokeToolingMetrics, SConsToolingMetrics
import buildscripts.metrics.tooling_metrics_utils as under_test
# pylint: disable=unused-argument
# pylint: disable=protected-access
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME = 'mongodb://testing:27017'
CURRENT_DATE_TIME = datetime(2022, 10, 4)
async def extended_sleep(arg):
await asyncio.sleep(2)
RESMOKE_METRICS_ARGS = {
"utc_starttime": datetime(2022, 10, 4),
"exit_hook": MagicMock(exit_code=0),
}
# Metrics collection is not supported for Windows
if os.name == "nt":
sys.exit()
@patch("atexit.register")
class TestRegisterMetricsCollectionAtExit(unittest.TestCase):
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
def test_register_metrics_collection(self, mock_should_collect_metrics, mock_atexit):
under_test.register_metrics_collection_atexit(ResmokeToolingMetrics.generate_metrics,
RESMOKE_METRICS_ARGS)
atexit_functions = [call[0][0].__name__ for call in mock_atexit.call_args_list]
assert "_save_metrics" in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=False)
def test_no_register_metrics_collection(self, mock_should_collect_metrics, mock_atexit):
under_test.register_metrics_collection_atexit(ResmokeToolingMetrics.generate_metrics,
RESMOKE_METRICS_ARGS)
atexit_functions = [call[0][0].__name__ for call in mock_atexit.call_args_list]
assert "_save_metrics" not in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils.INTERNAL_TOOLING_METRICS_HOSTNAME",
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
class TestSaveToolingMetrics(unittest.TestCase):
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
def test_on_virtual_workstation(self):
under_test.save_tooling_metrics(ToolingMetrics.get_resmoke_metrics(CURRENT_DATE_TIME))
def test_save_resmoke_metrics(self):
under_test._save_metrics(ResmokeToolingMetrics.generate_metrics, RESMOKE_METRICS_ARGS)
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.tooling_metrics_utils._save_metrics",
side_effect=pymongo.errors.WriteError(error="Error Information"))
def test_exception_caught(self, mock_save_metrics):
with self.assertLogs('tooling_metrics_utils') as cm:
under_test.save_tooling_metrics(ToolingMetrics.get_resmoke_metrics(CURRENT_DATE_TIME))
@patch("buildscripts.metrics.tooling_metrics_utils._get_internal_tooling_metrics_client",
side_effect=pymongo.errors.ServerSelectionTimeoutError(message="Error Information"))
def test_save_metrics_with_exc(self, mock_save_metrics):
with self.assertLogs('tooling_metrics') as cm:
under_test._save_metrics(ResmokeToolingMetrics.generate_metrics, RESMOKE_METRICS_ARGS)
assert "Error Information" in cm.output[0]
assert "Unexpected: Tooling metrics collection is not available" in cm.output[0]
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.tooling_metrics_utils._save_metrics", side_effect=extended_sleep)
def test_timeout_caught(self, mock_save_metrics):
with self.assertLogs('tooling_metrics_utils') as cm:
under_test.save_tooling_metrics(ToolingMetrics.get_resmoke_metrics(CURRENT_DATE_TIME))
assert "Timeout: Tooling metrics collection is not available" in cm.output[0]
assert "Internal Metrics Collection Failed" in cm.output[0]
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
class TestIsVirtualWorkstation(unittest.TestCase):
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=False)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=True)
def test_no_toolchain_has_email(self, mock_git_user_exists, mock_toolchain_exists):
assert not under_test._is_virtual_workstation()
@patch("builtins.open", mock_open(read_data="ubuntu1804-workstation"))
def test_is_virtual_workstation(self):
assert under_test._is_virtual_workstation() is True
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=True)
def test_has_toolchain_has_email(self, mock_git_user_exists, mock_toolchain_exists):
assert under_test._is_virtual_workstation()
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=False)
def test_has_toolchain_no_email(self, mock_git_user_exists, mock_toolchain_exists):
assert not under_test._is_virtual_workstation()
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=False)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=False)
def test_no_toolchain_no_email(self, mock_git_user_exists, mock_toolchain_exists):
assert not under_test._is_virtual_workstation()
@patch("builtins.open", mock_open(read_data="test"))
def test_is_not_virtual_workstation(self):
assert under_test._is_virtual_workstation() is False
class TestHasMetricsOptOut(unittest.TestCase):
@ -92,9 +86,9 @@ class TestShouldCollectMetrics(unittest.TestCase):
@patch("buildscripts.metrics.tooling_metrics_utils._is_virtual_workstation", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._has_metrics_opt_out", return_value=False)
def test_should_collect_metrics(self, mock_opt_out, mock_is_virtual_env):
assert under_test.should_collect_metrics()
assert under_test._should_collect_metrics()
@patch("buildscripts.metrics.tooling_metrics_utils._is_virtual_workstation", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._has_metrics_opt_out", return_value=True)
def test_no_collect_metrics_opt_out(self, mock_opt_out, mock_is_virtual_env):
assert not under_test.should_collect_metrics()
assert not under_test._should_collect_metrics()

View File

@ -78,7 +78,7 @@ class TestHistoricTaskData(unittest.TestCase):
@staticmethod
def _make_evg_result(test_file="dir/test1.js", num_pass=0, duration=0):
return Mock(
test_file=test_file,
test_name=test_file,
task_name="task1",
variant="variant1",
distro="distro1",

View File

@ -1,5 +1,4 @@
"""Service for determining task timeouts."""
from datetime import datetime
from typing import Any, Dict, NamedTuple, Optional
import inject
@ -31,29 +30,17 @@ class TimeoutParams(NamedTuple):
is_asan: bool
class TimeoutSettings(NamedTuple):
"""Settings for determining timeouts."""
start_date: datetime
end_date: datetime
class TimeoutService:
"""A service for determining task timeouts."""
@inject.autoparams()
def __init__(self, evg_api: EvergreenApi, resmoke_proxy: ResmokeProxyService,
timeout_settings: TimeoutSettings) -> None:
def __init__(self, resmoke_proxy: ResmokeProxyService) -> None:
"""
Initialize the service.
:param evg_api: Evergreen API client.
:param resmoke_proxy: Proxy to query resmoke.
:param timeout_settings: Settings for how timeouts are calculated.
"""
self.evg_api = evg_api
self.resmoke_proxy = resmoke_proxy
self.timeout_settings = timeout_settings
def get_timeout_estimate(self, timeout_params: TimeoutParams) -> TimeoutEstimate:
"""
@ -137,10 +124,8 @@ class TimeoutService:
:return: Historic test results if they exist.
"""
try:
evg_stats = HistoricTaskData.from_evg(
self.evg_api, timeout_params.evg_project, self.timeout_settings.start_date,
self.timeout_settings.end_date, timeout_params.task_name,
timeout_params.build_variant)
evg_stats = HistoricTaskData.from_s3(
timeout_params.evg_project, timeout_params.task_name, timeout_params.build_variant)
if not evg_stats:
LOGGER.warning("No historic runtime information available")
return None

View File

@ -1,15 +1,31 @@
"""Utility to support parsing a TestStat."""
from collections import defaultdict
from dataclasses import dataclass
from datetime import datetime
from itertools import chain
from typing import NamedTuple, List, Callable, Optional
from evergreen import EvergreenApi, TestStats
import requests
from requests.adapters import HTTPAdapter, Retry
from buildscripts.util.testname import split_test_hook_name, is_resmoke_hook, get_short_name_from_test_file
TASK_LEVEL_HOOKS = {"CleanEveryN"}
TESTS_STATS_S3_LOCATION = "https://mongo-test-stats.s3.amazonaws.com"
class HistoricalTestInformation(NamedTuple):
"""
Container for information about the historical runtime of a test.
test_name: Name of test.
avg_duration_pass: Average of runtime of test that passed.
num_pass: Number of times the test has passed.
num_fail: Number of times the test has failed.
"""
test_name: str
num_pass: int
num_fail: int
avg_duration_pass: float
class TestRuntime(NamedTuple):
@ -74,9 +90,9 @@ class HistoricHookInfo(NamedTuple):
avg_duration: float
@classmethod
def from_test_stats(cls, test_stats: TestStats) -> "HistoricHookInfo":
def from_test_stats(cls, test_stats: HistoricalTestInformation) -> "HistoricHookInfo":
"""Create an instance from a test_stats object."""
return cls(hook_id=test_stats.test_file, num_pass=test_stats.num_pass,
return cls(hook_id=test_stats.test_name, num_pass=test_stats.num_pass,
avg_duration=test_stats.avg_duration_pass)
def test_name(self) -> str:
@ -101,10 +117,10 @@ class HistoricTestInfo(NamedTuple):
hooks: List[HistoricHookInfo]
@classmethod
def from_test_stats(cls, test_stats: TestStats,
def from_test_stats(cls, test_stats: HistoricalTestInformation,
hooks: List[HistoricHookInfo]) -> "HistoricTestInfo":
"""Create an instance from a test_stats object."""
return cls(test_name=test_stats.test_file, num_pass=test_stats.num_pass,
return cls(test_name=test_stats.test_name, num_pass=test_stats.num_pass,
avg_duration=test_stats.avg_duration_pass, hooks=hooks)
def normalized_test_name(self) -> str:
@ -137,45 +153,56 @@ class HistoricTaskData(object):
"""Initialize the TestStats with raw results from the Evergreen API."""
self.historic_test_results = historic_test_results
@classmethod
def from_evg(cls, evg_api: EvergreenApi, project: str, start_date: datetime, end_date: datetime,
task: str, variant: str) -> "HistoricTaskData":
@staticmethod
def get_stats_from_s3(project: str, task: str, variant: str) -> List[HistoricalTestInformation]:
"""
Retrieve test stats from evergreen for a given task.
Retrieve test stats from s3 for a given task.
:param project: Project to query.
:param task: Task to query.
:param variant: Build variant to query.
:return: A list of the Test stats for the specified task.
"""
session = requests.Session()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
response = session.get(f"{TESTS_STATS_S3_LOCATION}/{project}/{variant}/{task}")
data = response.json()
return [HistoricalTestInformation(**item) for item in data]
@classmethod
def from_s3(cls, project: str, task: str, variant: str) -> "HistoricTaskData":
"""
Retrieve test stats from s3 for a given task.
:param evg_api: Evergreen API client.
:param project: Project to query.
:param start_date: Start date to query.
:param end_date: End date to query.
:param task: Task to query.
:param variant: Build variant to query.
:return: Test stats for the specified task.
"""
days = (end_date - start_date).days
historic_stats = evg_api.test_stats_by_project(
project, after_date=start_date, before_date=end_date, tasks=[task], variants=[variant],
group_by="test", group_num_days=days)
return cls.from_stats_list(historic_stats)
historical_test_data = cls.get_stats_from_s3(project, task, variant)
return cls.from_stats_list(historical_test_data)
@classmethod
def from_stats_list(cls, historic_stats: List[TestStats]) -> "HistoricTaskData":
def from_stats_list(
cls, historical_test_data: List[HistoricalTestInformation]) -> "HistoricTaskData":
"""
Build historic task data from a list of historic stats.
:param historic_stats: List of historic stats to build from.
:param historical_test_data: A list of information about the runtime of a test.
:return: Historic task data from the list of stats.
"""
hooks = defaultdict(list)
for hook in [stat for stat in historic_stats if is_resmoke_hook(stat.test_file)]:
for hook in [stat for stat in historical_test_data if is_resmoke_hook(stat.test_name)]:
historical_hook = HistoricHookInfo.from_test_stats(hook)
hooks[historical_hook.test_name()].append(historical_hook)
return cls([
HistoricTestInfo.from_test_stats(stat,
hooks[get_short_name_from_test_file(stat.test_file)])
for stat in historic_stats if not is_resmoke_hook(stat.test_file)
hooks[get_short_name_from_test_file(stat.test_name)])
for stat in historical_test_data if not is_resmoke_hook(stat.test_name)
])
def get_tests_runtimes(self) -> List[TestRuntime]:

View File

@ -19,608 +19,8 @@
# (ticket, test_file) pair on the last-lts branch.
#
last-continuous:
all:
- test_file: jstests/core/check_shard_index.js
ticket: SERVER-50792
- test_file: jstests/sharding/refine_collection_shard_key_basic.js
ticket: SERVER-50792
- test_file: jstests/replsets/tenant_migration_fetch_committed_transactions_retry.js
ticket: SERVER-51943
- test_file: jstests/sharding/query/collation_shard_targeting_hashed_shard_key.js
ticket: SERVER-53335
- test_file: jstests/replsets/replSetGetStatus_member_wall_times.js
ticket: SERVER-54909
- test_file: jstests/sharding/cwwc_conflict_add_shard.js
ticket: SERVER-56800
- test_file: jstests/sharding/reconfig_fails_no_cwwc_set_sharding.js
ticket: SERVER-56846
- test_file: jstests/replsets/catchup_takeover_with_higher_config.js
ticket: SERVER-57262
- test_file: jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_recipient_fetches_synthetic_find_and_modify_oplog_entries.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_fetch_committed_transactions_retry.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_retryable_write_retry.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_retryable_write_retry_on_recipient.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_find_and_modify_retry.js
ticket: SERVER-57617
- test_file: jstests/sharding/resharding_min_fetch_ts_with_txn.js
ticket: SERVER-57667
- test_file: jstests/sharding/reshard_collection_joins_existing_operation.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_clones_duplicate_key.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_abort_command.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_clones_initial_data.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_commit.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_collection_cloner_resuming.js
ticket: SERVER-57667
- test_file: jstests/sharding/reshard_collection_existing_sk_index_not_duplicated.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_metrics.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_fails_on_nonempty_stash.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_txn_cloner.js
ticket: SERVER-57667
- test_file: jstests/sharding/reshard_collection_joins_existing_operation.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_size_estimate.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_histogram_metrics.js
ticket: SERVER-57700
- test_file: jstests/sharding/resharding_metrics.js
ticket: SERVER-57766
- test_file: jstests/sharding/rewrite_state_change_errors.js
ticket: SERVER-57772
- test_file: jstests/sharding/query/pipeline_length_limit.js
ticket: SERVER-58203
- test_file: jstests/replsets/tenant_migration_aborted_buildindex.js
ticket: SERVER-58353
- test_file: jstests/replsets/initial_sync_replicate_drop_mid_secondary_batch.js
ticket: SERVER-58636
- test_file: jstests/sharding/implicit_default_write_concern_add_shard.js
ticket: SERVER-58696
- test_file: jstests/replsets/apply_ops_capped_collection.js
ticket: SERVER-58744
- test_file: jstests/replsets/write_concern_write_to_local.js
ticket: SERVER-58898
- test_file: jstests/sharding/resharding_secondary_recovers_temp_ns_metadata.js
ticket: SERVER-59023
- test_file: jstests/replsets/rollback_transaction_table.js
ticket: SERVER-59057
- test_file: jstests/replsets/stepdown_race_with_transaction.js
ticket: SERVER-59108
- test_file: jstests/sharding/change_stream_show_migration_events.js
ticket: SERVER-59424
- test_file: jstests/replsets/tenant_migration_recipient_access_blocker_rollback.js
ticket: SERVER-59525
- test_file: jstests/core/timeseries/timeseries_bucket_rename.js
ticket: SERVER-59666
- test_file: jstests/replsets/sync_source_selection_ignores_minvalid_after_rollback.js
ticket: SERVER-59721
- test_file: jstests/sharding/resharding_secondary_recovers_temp_ns_metadata.js
ticket: SERVER-59721
- test_file: jstests/sharding/test_resharding_test_fixture_shutdown_retry_needed.js
ticket: SERVER-59923
- test_file: jstests/replsets/dont_set_invalid_rwconcern.js
ticket: SERVER-60817
- test_file: jstests/replsets/tenant_migration_donor_resume_on_stepup_and_restart.js
ticket: SERVER-60829
- test_file: jstests/core/sbe/sbe_ixscan_explain.js
ticket: SERVER-61087
- test_file: jstests/replsets/tenant_migration_transaction_boundary.js
ticket: SERVER-61666
- test_file: jstests/sharding/range_deleter_interacts_correctly_with_refine_shard_key.js
ticket: SERVER-61755
- test_file: jstests/replsets/dbcheck.js
ticket: SERVER-61757
- test_file: jstests/replsets/reconfig_may_not_remove_custom_wc_in_use.js
ticket: SERVER-61864
- test_file: jstests/replsets/default_write_concern_race_with_config_tags.js
ticket: SERVER-61864
- test_file: jstests/replsets/config_tags_race_with_default_write_concern.js
ticket: SERVER-61864
- test_file: jstests/auth/dbcheck.js
ticket: SERVER-61955
- test_file: jstests/replsets/rollback_during_step_up.js
ticket: SERVER-61977
- test_file: jstests/replsets/dbcheck_write_concern.js
ticket: SERVER-62212
- test_file: jstests/sharding/recover_multiple_migrations_on_stepup.js
ticket: SERVER-62245
- test_file: jstests/sharding/migration_recovers_unfinished_migrations.js
ticket: SERVER-62296
- test_file: jstests/sharding/max_time_ms_does_not_leak_shard_cursor.js
ticket: SERVER-62710
- test_file: jstests/replsets/apply_ops_dropDatabase.js
ticket: SERVER-62759
- test_file: jstests/noPassthrough/operator_counters_accumulators.js
ticket: SERVER-63049
- test_file: jstests/replsets/tenant_migration_cloning_uses_read_concern_majority.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_collection_ttl.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_concurrent_reads_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_concurrent_writes_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_fetch_committed_transactions_retry.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_recipient_current_op.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_retry_session_migration.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_retryable_write_retry_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_timeseries_retryable_write_retry_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_recipient_initial_sync_recovery.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_recipient_startup_recovery.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_network_error_via_rollback.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_resume_collection_cloner_after_recipient_failover_with_dropped_views.js
ticket: SERVER-63129
- test_file: jstests/replsets/buildindexes_false_commit_quorum.js
ticket: SERVER-63531
- test_file: jstests/core/in_with_mixed_values.js
ticket: SERVER-64141
- test_file: jstests/sharding/refine_collection_shard_key_basic.js
ticket: SERVER-64142
- test_file: jstests/core/plan_cache_sbe.js
ticket: SERVER-64315
- test_file: jstests/core/sbe/plan_cache_sbe_with_or_queries.js
ticket: SERVER-64315
- test_file: jstests/core/sbe_plan_cache_autoparameterize_collscan.js
ticket: SERVER-64315
- test_file: jstests/core/wildcard_index_cached_plans.js
ticket: SERVER-64315
- test_file: jstests/sharding/resharding_metrics_increment.js
ticket: SERVER-64395
- test_file: jstests/sharding/resharding_abort_command.js
ticket: SERVER-64395
- test_file: jstests/sharding/update_with_dollar_fields.js
ticket: SERVER-64485
- test_file: jstests/sharding/resharding_change_stream_namespace_filtering.js
ticket: SERVER-64780
- test_file: jstests/sharding/shard_key_index_must_exist.js
ticket: SERVER-6491
- test_file: jstests/sharding/change_stream_shard_failover.js
ticket: SERVER-65022
- test_file: jstests/sharding/database_versioning_all_commands.js
ticket: SERVER-65101
- test_file: jstests/sharding/sessions_collection_auto_healing.js
ticket: SERVER-65188
- test_file: jstests/replsets/sessions_collection_auto_healing.js
ticket: SERVER-65188
- test_file: jstests/replsets/capped_deletes.js
ticket: SERVER-65261
- test_file: jstests/replsets/tenant_migration_recipient_rollback_recovery.js
ticket: SERVER-65300
- test_file: jstests/aggregation/agg_infinite_recursion.js
ticket: SERVER-65773
- test_file: jstests/sharding/migration_retries_on_write_conflict_exceptions.js
ticket: SERVER-65947
- test_file: jstests/aggregation/match_no_swap_rand.js
ticket: SERVER-66072
- test_file: jstests/sharding/data_size_aware_balancing_sessions_collection.js
ticket: SERVER-66078
- test_file: jstests/replsets/initial_sync_with_partial_transaction.js
ticket: SERVER-66089
- test_file: jstests/core/or_to_in.js
ticket: SERVER-66379
- test_file: jstests/core/where_multiple_plans.js
ticket: SERVER-66389
- test_file: jstests/sharding/resharding_metrics.js
ticket: SERVER-66422
- test_file: jstests/concurrency/fsm_workloads/find_flip_sbe_enabled.js
ticket: SERVER-66445
- test_file: jstests/core/index_stats.js
ticket: SERVER-66445
- test_file: jstests/core/wildcard_index_cached_plans.js
ticket: SERVER-66445
- test_file: jstests/core/index_filter_commands_invalidate_plan_cache_entries.js
ticket: SERVER-66445
- test_file: jstests/core/idhack.js
ticket: SERVER-66445
- test_file: jstests/core/sbe/sbe_explain_rejected_plans.js
ticket: SERVER-66445
- test_file: jstests/core/plan_cache_list_shapes.js
ticket: SERVER-66445
- test_file: jstests/core/plan_cache_list_plans.js
ticket: SERVER-66445
- test_file: jstests/replsets/dbhash_lock_acquisition.js
ticket: SERVER-66719
- test_file: jstests/replsets/prepared_transaction_kill_during_step_up_refresh.js
ticket: SERVER-66854
- test_file: jstests/replsets/step_up_kill_abort_transactions.js
ticket: SERVER-66854
- test_file: jstests/sharding/drop_index_fails_if_multikey_index_is_last_compatible.js
ticket: SERVER-67299
- test_file: jstests/sharding/move_chunk_interrupt_postimage.js
ticket: SERVER-67492
- test_file: jstests/replsets/optime.js
ticket: SERVER-67532
- test_file: jstests/replsets/internal_sessions_reaping_basic.js
ticket: SERVER-67723
- test_file: jstests/sharding/collection_uuid_shard_capped_collection.js
ticket: SERVER-67885
- 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_interrupt_postimage.js
ticket: SERVER-68728
- test_file: jstests/sharding/resharding_critical_section_metrics.js
ticket: SERVER-68932
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/fcbis_cannot_vote_twice_same_term.js
ticket: SERVER-69861
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/fcbis_election_during_storage_change.js
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
all: []
suites: null
last-lts:
all:
- test_file: jstests/core/null_query_semantics.js
ticket: SERVER-21929
- test_file: jstests/core/or_to_in.js
ticket: SERVER-21929
- test_file: jstests/aggregation/sources/lookup/lookup_null_semantics.js
ticket: SERVER-21929
- test_file: jstests/replsets/disallow_adding_initialized_node1.js
ticket: SERVER-35649
- test_file: jstests/replsets/cluster_chaining_override.js
ticket: SERVER-37904
- test_file: jstests/sharding/scaled_collection_stats.js
ticket: SERVER-43902
- test_file: jstests/core/apply_ops_system_dot_views.js
ticket: SERVER-47469
- test_file: jstests/concurrency/fsm_workloads/view_catalog_direct_system_writes.js
ticket: SERVER-47469
- test_file: jstests/replsets/invalidate_sessions_on_stepdown.js
ticket: SERVER-47645
- test_file: jstests/change_streams/report_post_batch_resume_token.js
ticket: SERVER-47810
- test_file: jstests/replsets/reconfig_removes_node_in_rollback.js
ticket: SERVER-48179
- test_file: jstests/core/txns/no_writes_to_config_transactions_with_prepared_transaction.js
ticket: SERVER-48525
- test_file: jstests/replsets/initial_sync_fails_unclean_restart.js
ticket: SERVER-50140
- test_file: jstests/replsets/change_sync_source_in_initial_sync.js
ticket: SERVER-50320
- test_file: jstests/sharding/awaitable_hello_primary_failures.js
ticket: SERVER-50415
- test_file: jstests/replsets/server_status_repl_is_writable_primary.js
ticket: SERVER-50420
- test_file: jstests/sharding/log_remote_op_wait.js
ticket: SERVER-50559
- test_file: jstests/core/views/views_all_commands.js
ticket: SERVER-50640
- test_file: jstests/sharding/read_write_concern_defaults_application.js
ticket: SERVER-50640
- test_file: jstests/sharding/safe_secondary_reads_drop_recreate.js
ticket: SERVER-50640
- test_file: jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
ticket: SERVER-50640
- test_file: jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
ticket: SERVER-50640
- test_file: jstests/core/check_shard_index.js
ticket: SERVER-50792
- test_file: jstests/sharding/refine_collection_shard_key_basic.js
ticket: SERVER-50792
- test_file: jstests/replsets/node_restarts_no_oplog_entry_at_stable.js
ticket: SERVER-51049
- test_file: jstests/replsets/awaitable_hello_errors_on_horizon_change.js
ticket: SERVER-51259
- test_file: jstests/replsets/awaitable_hello_fcv_change.js
ticket: SERVER-51259
- test_file: jstests/replsets/awaitable_hello_metrics_on_state_change.js
ticket: SERVER-51259
- test_file: jstests/replsets/awaitable_hello_on_nodes_with_invalid_configs.js
ticket: SERVER-51259
- test_file: jstests/replsets/awaitable_hello_stepdown_stepup.js
ticket: SERVER-51259
- test_file: jstests/replsets/quiesce_mode.js
ticket: SERVER-51259
- test_file: jstests/sharding/mongos_quiesce_mode.js
ticket: SERVER-51259
- test_file: jstests/replsets/tenant_migration_fetch_committed_transactions_retry.js
ticket: SERVER-51943
- test_file: jstests/core/txns/errors_on_committed_transaction.js
ticket: SERVER-52547
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
ticket: SERVER-52906
- test_file: jstests/sharding/migration_waits_for_majority_commit.js
ticket: SERVER-52906
- test_file: jstests/sharding/migration_ignore_interrupts_1.js
ticket: SERVER-52906
- test_file: jstests/sharding/movechunk_interrupt_at_primary_stepdown.js
ticket: SERVER-52906
- test_file: jstests/sharding/movechunk_parallel.js
ticket: SERVER-52906
- test_file: jstests/sharding/txn_writes_during_movechunk.js
ticket: SERVER-52906
- test_file: jstests/replsets/stepdown_kill_other_ops.js
ticket: SERVER-53431
- test_file: jstests/core/sort_spill_estimate_data_size.js
ticket: SERVER-53760
- test_file: jstests/core/txns/timestamped_reads_wait_for_prepare_oplog_visibility.js
ticket: SERVER-53849
- test_file: jstests/replsets/unconditional_step_down.js
ticket: SERVER-53985
- test_file: jstests/replsets/replSetGetStatus_member_wall_times.js
ticket: SERVER-54909
- test_file: jstests/sharding/transactions_reject_writes_for_moved_chunks.js
ticket: SERVER-55111
- test_file: jstests/replsets/rollback_with_coalesced_txn_table_updates_during_oplog_application.js
ticket: SERVER-55305
- test_file: jstests/replsets/rollback_with_coalesced_txn_table_updates_from_vectored_inserts.js
ticket: SERVER-55305
- test_file: jstests/sharding/time_zone_info_mongos.js
ticket: SERVER-56371
- test_file: jstests/concurrency/fsm_workloads/findAndModify_flip_location.js
ticket: SERVER-56377
- test_file: jstests/sharding/txn_writes_during_movechunk.js
ticket: SERVER-56518
- test_file: jstests/concurrency/fsm_workloads/collmod_writeconflict.js
ticket: SERVER-56772
- test_file: jstests/sharding/cwwc_conflict_add_shard.js
ticket: SERVER-56800
- test_file: jstests/sharding/read_pref_with_hedging_mode.js
ticket: SERVER-57117
- test_file: jstests/replsets/catchup_takeover_with_higher_config.js
ticket: SERVER-57262
- test_file: jstests/replsets/assert_on_prepare_conflict_with_hole.js
ticket: SERVER-57476
- test_file: jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_recipient_fetches_synthetic_find_and_modify_oplog_entries.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_fetch_committed_transactions_retry.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_retryable_write_retry.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_retryable_write_retry_on_recipient.js
ticket: SERVER-57617
- test_file: jstests/replsets/tenant_migration_find_and_modify_retry.js
ticket: SERVER-57617
- test_file: jstests/sharding/resharding_min_fetch_ts_with_txn.js
ticket: SERVER-57667
- test_file: jstests/sharding/reshard_collection_joins_existing_operation.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_clones_duplicate_key.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_abort_command.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_clones_initial_data.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_commit.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_collection_cloner_resuming.js
ticket: SERVER-57667
- test_file: jstests/sharding/reshard_collection_existing_sk_index_not_duplicated.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_metrics.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_fails_on_nonempty_stash.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_txn_cloner.js
ticket: SERVER-57667
- test_file: jstests/sharding/reshard_collection_joins_existing_operation.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_size_estimate.js
ticket: SERVER-57667
- test_file: jstests/sharding/resharding_histogram_metrics.js
ticket: SERVER-57700
- test_file: jstests/core/timeseries/timeseries_bucket_drop.js
ticket: SERVER-57729
- test_file: jstests/sharding/resharding_metrics.js
ticket: SERVER-57766
- test_file: jstests/sharding/query/pipeline_length_limit.js
ticket: SERVER-58203
- test_file: jstests/replsets/tenant_migration_aborted_buildindex.js
ticket: SERVER-58353
- test_file: jstests/replsets/initial_sync_replicate_drop_mid_secondary_batch.js
ticket: SERVER-58636
- test_file: jstests/sharding/implicit_default_write_concern_add_shard.js
ticket: SERVER-58696
- test_file: jstests/replsets/write_concern_write_to_local.js
ticket: SERVER-58898
- test_file: jstests/sharding/resharding_secondary_recovers_temp_ns_metadata.js
ticket: SERVER-59023
- test_file: jstests/replsets/rollback_transaction_table.js
ticket: SERVER-59057
- test_file: jstests/replsets/stepdown_race_with_transaction.js
ticket: SERVER-59108
- test_file: jstests/sharding/change_stream_show_migration_events.js
ticket: SERVER-59424
- test_file: jstests/core/timeseries/timeseries_find.js
ticket: SERVER-59505
- test_file: jstests/replsets/tenant_migration_recipient_access_blocker_rollback.js
ticket: SERVER-59525
- test_file: jstests/replsets/sync_source_selection_ignores_minvalid_after_rollback.js
ticket: SERVER-59721
- test_file: jstests/sharding/resharding_secondary_recovers_temp_ns_metadata.js
ticket: SERVER-59721
- test_file: jstests/aggregation/expressions/date_add_subtract.js
ticket: SERVER-59765
- test_file: jstests/sharding/test_resharding_test_fixture_shutdown_retry_needed.js
ticket: SERVER-59923
- test_file: jstests/sharding/write_transactions_during_migration.js
ticket: SERVER-59952
- test_file: jstests/sharding/retryable_writes.js
ticket: SERVER-59952
- test_file: jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js
ticket: SERVER-59952
- test_file: jstests/replsets/dont_set_invalid_rwconcern.js
ticket: SERVER-60817
- test_file: jstests/replsets/tenant_migration_donor_resume_on_stepup_and_restart.js
ticket: SERVER-60829
- test_file: jstests/core/sbe/sbe_ixscan_explain.js
ticket: SERVER-61087
- test_file: jstests/replsets/tenant_migration_transaction_boundary.js
ticket: SERVER-61666
- test_file: jstests/sharding/range_deleter_interacts_correctly_with_refine_shard_key.js
ticket: SERVER-61755
- test_file: jstests/replsets/dbcheck.js
ticket: SERVER-61757
- test_file: jstests/replsets/reconfig_may_not_remove_custom_wc_in_use.js
ticket: SERVER-61864
- test_file: jstests/replsets/default_write_concern_race_with_config_tags.js
ticket: SERVER-61864
- test_file: jstests/replsets/config_tags_race_with_default_write_concern.js
ticket: SERVER-61864
- test_file: jstests/auth/dbcheck.js
ticket: SERVER-61955
- test_file: jstests/replsets/rollback_during_step_up.js
ticket: SERVER-61977
- test_file: jstests/sharding/recover_multiple_migrations_on_stepup.js
ticket: SERVER-62245
- test_file: jstests/sharding/migration_recovers_unfinished_migrations.js
ticket: SERVER-62296
- test_file: jstests/sharding/max_time_ms_does_not_leak_shard_cursor.js
ticket: SERVER-62710
- test_file: jstests/replsets/apply_ops_dropDatabase.js
ticket: SERVER-62759
- test_file: jstests/replsets/tenant_migration_cloning_uses_read_concern_majority.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_collection_ttl.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_concurrent_reads_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_concurrent_writes_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_fetch_committed_transactions_retry.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_recipient_current_op.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_retry_session_migration.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_retryable_write_retry_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_timeseries_retryable_write_retry_on_recipient.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_recipient_initial_sync_recovery.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_recipient_startup_recovery.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_network_error_via_rollback.js
ticket: SERVER-63122
- test_file: jstests/replsets/tenant_migration_resume_collection_cloner_after_recipient_failover_with_dropped_views.js
ticket: SERVER-63129
- test_file: jstests/replsets/buildindexes_false_commit_quorum.js
ticket: SERVER-63531
- test_file: jstests/sharding/refine_collection_shard_key_basic.js
ticket: SERVER-64142
- test_file: jstests/core/plan_cache_sbe.js
ticket: SERVER-64315
- test_file: jstests/core/sbe/plan_cache_sbe_with_or_queries.js
ticket: SERVER-64315
- test_file: jstests/core/sbe_plan_cache_autoparameterize_collscan.js
ticket: SERVER-64315
- test_file: jstests/core/wildcard_index_cached_plans.js
ticket: SERVER-64315
- test_file: jstests/sharding/resharding_metrics_increment.js
ticket: SERVER-64395
- test_file: jstests/sharding/resharding_abort_command.js
ticket: SERVER-64395
- test_file: jstests/sharding/update_with_dollar_fields.js
ticket: SERVER-64485
- test_file: jstests/sharding/shard_key_index_must_exist.js
ticket: SERVER-6491
- test_file: jstests/sharding/change_stream_shard_failover.js
ticket: SERVER-65022
- test_file: jstests/sharding/database_versioning_all_commands.js
ticket: SERVER-65101
- test_file: jstests/sharding/sessions_collection_auto_healing.js
ticket: SERVER-65188
- test_file: jstests/replsets/sessions_collection_auto_healing.js
ticket: SERVER-65188
- test_file: jstests/replsets/capped_deletes.js
ticket: SERVER-65261
- test_file: jstests/replsets/tenant_migration_recipient_rollback_recovery.js
ticket: SERVER-65300
- test_file: jstests/aggregation/agg_infinite_recursion.js
ticket: SERVER-65773
- test_file: jstests/sharding/migration_retries_on_write_conflict_exceptions.js
ticket: SERVER-65947
- test_file: jstests/aggregation/match_no_swap_rand.js
ticket: SERVER-66072
- test_file: jstests/sharding/data_size_aware_balancing_sessions_collection.js
ticket: SERVER-66078
- test_file: jstests/replsets/initial_sync_with_partial_transaction.js
ticket: SERVER-66089
- test_file: jstests/core/or_to_in.js
ticket: SERVER-66379
- test_file: jstests/core/where_multiple_plans.js
ticket: SERVER-66389
- test_file: jstests/sharding/resharding_metrics.js
ticket: SERVER-66422
- test_file: jstests/concurrency/fsm_workloads/find_flip_sbe_enabled.js
ticket: SERVER-66445
- test_file: jstests/core/index_stats.js
ticket: SERVER-66445
- test_file: jstests/core/wildcard_index_cached_plans.js
ticket: SERVER-66445
- test_file: jstests/core/index_filter_commands_invalidate_plan_cache_entries.js
ticket: SERVER-66445
- test_file: jstests/core/idhack.js
ticket: SERVER-66445
- test_file: jstests/core/sbe/sbe_explain_rejected_plans.js
ticket: SERVER-66445
- test_file: jstests/core/plan_cache_list_shapes.js
ticket: SERVER-66445
- test_file: jstests/core/plan_cache_list_plans.js
ticket: SERVER-66445
- test_file: jstests/replsets/dbhash_lock_acquisition.js
ticket: SERVER-66719
- test_file: jstests/replsets/prepared_transaction_kill_during_step_up_refresh.js
ticket: SERVER-66854
- test_file: jstests/replsets/step_up_kill_abort_transactions.js
ticket: SERVER-66854
- test_file: jstests/sharding/drop_index_fails_if_multikey_index_is_last_compatible.js
ticket: SERVER-67299
- test_file: jstests/sharding/move_chunk_interrupt_postimage.js
ticket: SERVER-67492
- test_file: jstests/replsets/optime.js
ticket: SERVER-67532
- test_file: jstests/replsets/internal_sessions_reaping_basic.js
ticket: SERVER-67723
- test_file: jstests/sharding/collection_uuid_shard_capped_collection.js
ticket: SERVER-67885
- 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_interrupt_postimage.js
ticket: SERVER-68728
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/fcbis_cannot_vote_twice_same_term.js
ticket: SERVER-69861
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/fcbis_election_during_storage_change.js
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
all: []
suites: null

View File

@ -310,34 +310,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
variant: &linux_x86_dynamic_debug_wtdevelop_compile_variant_name linux-x86-dynamic-debug-wtdevelop-compile
- name: version_gen
variant: generate-tasks-for-version
expansions:
use_wt_develop: true
resmoke_jobs_factor: 0.5 # Avoid starting too many mongod's
compile_flags: >-
--dbg=on
--opt=on
-j$(grep -c ^processor /proc/cpuinfo)
--variables-files=etc/scons/mongodbtoolchain_v3_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:
@ -987,7 +959,7 @@ buildvariants:
# To force disable feature flags even on the all feature flags variant, please use this file:
# buildscripts/resmokeconfig/fully_disabled_feature_flags.yml
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=incompatible_with_windows_tls
--excludeWithAnyTags=incompatible_with_shard_merge
external_auth_jobs_max: 1
@ -1577,7 +1549,7 @@ buildvariants:
# To force disable feature flags even on the all feature flags variant, please use this file:
# buildscripts/resmokeconfig/fully_disabled_feature_flags.yml
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=incompatible_with_shard_merge
tasks:
- name: cqf
@ -1873,7 +1845,7 @@ buildvariants:
<<: *linux-x86-multiversion-expansions-template
# No feature flag tests since they aren't compatible with the older binaries.
test_flags: >-
--runAllFeatureFlagsNoTests
--runNoFeatureFlagTests
--excludeWithAnyTags=incompatible_with_shard_merge
- <<: *linux-x86-multiversion-template
@ -2251,7 +2223,7 @@ buildvariants:
# buildscripts/resmokeconfig/fully_disabled_feature_flags.yml
large_distro_name: rhel80-build
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=incompatible_with_shard_merge
separate_debug: off
tasks:
@ -2433,7 +2405,7 @@ buildvariants:
test_flags: >-
--excludeWithAnyTags=requires_ocsp_stapling
--excludeWithAnyTags=incompatible_with_shard_merge
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
multiversion_platform: rhel80
multiversion_edition: enterprise
resmoke_jobs_factor: 0.3 # Avoid starting too many mongod's under UBSAN build.
@ -2616,7 +2588,7 @@ buildvariants:
test_flags: >-
--excludeWithAnyTags=requires_ocsp_stapling
--excludeWithAnyTags=incompatible_with_shard_merge
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
tasks:
- name: jsCore
- name: jsCore_txns
@ -3328,7 +3300,7 @@ buildvariants:
target_resmoke_time: 30
max_sub_suites: 3
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=resource_intensive
--excludeWithAnyTags=incompatible_with_shard_merge
@ -3388,18 +3360,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,336 @@ 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
- &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
- &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
- &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
- &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
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 !.feature_flag_guarded
- 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: .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-required-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
burn_in_tests_build_variant: enterprise-windows-required
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
- name: replica_sets_jscore_passthrough_gen
distros:
- windows-vsCurrent-large
- name: replica_sets_ese_gen
- name: sasl
- name: .sharding .txns
- name: sharding_auth_gen
- name: sharding_auth_audit_gen
- name: sharding_ese_gen
- &enterprise-rhel-80-64-bit-dynamic-required-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
burn_in_tag_buildvariants: >-
enterprise-rhel-80-64-bit-inmem
enterprise-rhel-80-64-bit-multiversion
burn_in_tag_compile_task_group_name: compile_and_archive_dist_test_TG
burn_in_tag_compile_distro: rhel80-xlarge
depends_on:
- name: archive_dist_test
variant: *linux_x86_dynamic_compile_variant_name
- name: version_gen
variant: generate-tasks-for-version
- name: version_burn_in_gen
variant: generate-tasks-for-version
tasks:
# - name: burn_in_tests_gen
- name: .aggfuzzer !.feature_flag_guarded
- name: .aggregation !.feature_flag_guarded
- 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: disk_wiredtiger
- name: .encrypt
- name: idl_tests
- name: initial_sync_fuzzer_gen
- name: jsCore
distros:
- rhel80-xlarge
- name: .jscore .common !jsCore
- name: jsCore_minimum_batch_size
- 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-required-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
# If you add anything to san_options, make sure the appropriate changes are
# also made to SConstruct.
san_options: >-
UBSAN_OPTIONS="print_stacktrace=1:external_symbolizer_path=/opt/mongodbtoolchain/v3/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/v3/bin/llvm-symbolizer"
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-required-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_v3_gcc.vars
--link-model=dynamic
crypt_task_compile_flags: >-
SHLINKFLAGS_EXTRA="-Wl,-Bsymbolic
-Wl,--no-gnu-unique"
CCFLAGS="-fno-gnu-unique"
clang_tidy_toolchain: v3
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.2
- name: wtdevelop
repo: git@github.com:wiredtiger/wiredtiger.git
@ -608,7 +608,7 @@ functions:
"get buildnumber": &get_buildnumber
command: keyval.inc
params:
key: "${build_variant}_master"
key: "${build_variant}_v6.2"
destination: "builder_num"
"run diskstats": &run_diskstats
@ -5017,7 +5017,9 @@ tasks:
- func: "run tests"
vars:
suite: core
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_concurrency
@ -5027,7 +5029,9 @@ tasks:
- func: "run tests"
vars:
suite: concurrency
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_simulate_crash_concurrency_replication
@ -5037,7 +5041,9 @@ tasks:
- func: "run tests"
vars:
suite: simulate_crash_concurrency_replication
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_concurrency_replication
@ -5047,7 +5053,9 @@ tasks:
- func: "run tests"
vars:
suite: concurrency_replication
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_replica_sets_jscore_passthrough
@ -5057,7 +5065,9 @@ tasks:
- func: "run tests"
vars:
suite: replica_sets_jscore_passthrough
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: jsCore_ese
@ -6173,6 +6183,7 @@ tasks:
- func: "generate resmoke tasks"
vars:
use_large_distro: "true"
multiversion_exclude_tags_version: last_lts
- <<: *gen_task_template
name: sharding_opportunistic_secondary_targeting_gen
@ -6827,19 +6838,6 @@ tasks:
- *set_up_venv
- func: "run package test"
- name: test_packages_complete
tags: []
depends_on:
- name: package
commands:
- command: manifest.load
- func: "git get project and add git tag"
- *f_expansions_write
- *kill_processes
- *cleanup_environment
- *set_up_venv
- func: "run complete package test"
- name: package
tags: []
depends_on:

View File

@ -88,17 +88,6 @@ buildvariants:
- name: generate_buildid_to_debug_symbols_mapping
- name: .integration !.audit
- <<: *generic_linux_compile_params
name: &linux-x86-dynamic-debug-wtdevelop-compile linux-x86-dynamic-debug-wtdevelop-compile
display_name: "~ Linux WiredTiger develop DEBUG Compile"
activate: false
modules:
- wtdevelop
expansions:
<<: *linux_debug_compile_expansions
use_wt_develop: true
compile_variant: *linux-x86-dynamic-debug-wtdevelop-compile
- <<: *generic_linux_compile_params
name: &linux-debug-aubsan-compile-required linux-debug-aubsan-compile-required
display_name: "! Linux x86 Shared Library {A,UB}SAN Compile"

View File

@ -590,8 +590,6 @@ buildvariants:
distros:
- amazon2022-arm64-large
- name: .publish_crypt
distros:
- amazon2022-arm64-large
- name: secondary_reads_passthrough_gen
- name: server_discovery_and_monitoring_json_test_TG
- name: .serverless
@ -2097,9 +2095,6 @@ buildvariants:
- name: test_packages
distros:
- ubuntu2204-large
- name: test_packages_complete
distros:
- ubuntu2204-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
@ -2256,9 +2251,6 @@ buildvariants:
- name: test_packages
distros:
- ubuntu2204-arm64-large
- name: test_packages_complete
distros:
- ubuntu2204-arm64-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping

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.2
- name: mongo-tools
repo: git@github.com:mongodb/mongo-tools.git
prefix: mongo-tools/src/github.com/mongodb
@ -320,7 +320,7 @@ functions:
set -o errexit
set -o verbose
source "${workdir}/compile_venv/bin/activate"
python ./buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir src/mongo/db/modules/enterprise/src
python ./buildscripts/idl/gen_all_feature_flag_list.py
mkdir -p mongodb/feature_flags
cp ./all_feature_flags.txt mongodb/feature_flags
- command: shell.exec

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ enterprise_path="src/mongo/db/modules/enterprise"
diff_file_name="with_base_upstream.diff"
# get the list of feature flags from the patched version
$python buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir "$enterprise_path"/src
$python buildscripts/idl/gen_all_feature_flag_list.py
mv all_feature_flags.txt patch_all_feature_flags.txt
# get the list of feature flags from the base commit
@ -29,7 +29,7 @@ if [ -s "$diff_file_name" ]; then
fi
popd
$python buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir "$enterprise_path"/src
$python buildscripts/idl/gen_all_feature_flag_list.py
mv all_feature_flags.txt base_all_feature_flags.txt
# print out the list of tests that previously had feature flag tag, that was

View File

@ -6,4 +6,4 @@ cd src
set -o errexit
set -o verbose
activate_venv
$python buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir src/mongo/db/modules/enterprise/src
$python buildscripts/idl/gen_all_feature_flag_list.py

View File

@ -13,4 +13,5 @@ PATH=$PATH:$HOME:/ ./mongo-task-generator \
--evg-auth-file ./.evergreen.yml \
--evg-project-file ${evergreen_config_file_path} \
--generate-sub-tasks-config etc/generate_subtasks_config.yml \
--s3-test-stats-endpoint https://mongo-test-stats.s3.amazonaws.com \
$@

View File

@ -13,5 +13,6 @@ PATH=$PATH:$HOME:/ ./mongo-task-generator \
--evg-auth-file ./.evergreen.yml \
--evg-project-file ${evergreen_config_file_path} \
--generate-sub-tasks-config etc/generate_subtasks_config.yml \
--s3-test-stats-endpoint https://mongo-test-stats.s3.amazonaws.com \
--burn-in \
$@

View File

@ -6,8 +6,6 @@ cd src/jstestfuzz
set -o errexit
set -o verbose
add_nodejs_to_path
if [ -f "../minimizer-outputs.json" ]; then
eval npm run ${npm_command} -- -j "../minimizer-outputs.json"
eval ./src/scripts/npm_run.sh ${npm_command} -- -j "../minimizer-outputs.json"
fi

View File

@ -1,13 +1,10 @@
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)"
. "$DIR/prelude.sh"
set -evo pipefail
cd src/jstestfuzz
set -o errexit
set -o verbose
add_nodejs_to_path
in_patch_build_flag=""
if [[ "${is_patch}" = "true" ]]; then
case "${npm_command}" in
@ -17,4 +14,4 @@ if [[ "${is_patch}" = "true" ]]; then
esac
fi
eval npm run "${npm_command}" -- "${jstestfuzz_vars}" "${in_patch_build_flag}" --branch "${branch_name}"
./src/scripts/npm_run.sh ${npm_command} -- ${jstestfuzz_vars} ${in_patch_build_flag} --branch ${branch_name}

View File

@ -6,11 +6,4 @@ cd src
set -o errexit
set -o verbose
add_nodejs_to_path
git clone git@github.com:10gen/jstestfuzz.git
pushd jstestfuzz
npm install
npm run prepare
popd

View File

@ -1,17 +1,22 @@
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)"
. "$DIR/prelude.sh"
cd src
cd src/jstestfuzz
set -o pipefail
set -o verbose
add_nodejs_to_path
# Run first with help which will do the install
# Then we can run it in parallel
./src/scripts/npm_run.sh --help
# Run parse-jsfiles on 50 files at a time with 32 processes in parallel.
find "$PWD/jstests" "$PWD/src/mongo/db/modules/enterprise" -name "*.js" -print | xargs -P 32 -L 50 npm run --prefix jstestfuzz parse-jsfiles -- | tee lint_fuzzer_sanity.log
# Skip javascript files in third_party directory
find "$PWD/../jstests" "$PWD/../src/mongo/db/modules/enterprise" -path "$PWD/../jstests/third_party" -prune -o -name "*.js" -print | xargs -P 32 -L 50 ./src/scripts/npm_run.sh parse-jsfiles -- | tee lint_fuzzer_sanity.log
exit_code=$?
# Exit out of the jstestfuzz directory
cd ..
activate_venv
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_all --log-file lint_fuzzer_sanity.log --exit-code $exit_code
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_all --log-file jstestfuzz/lint_fuzzer_sanity.log --exit-code $exit_code
exit $exit_code

View File

@ -7,15 +7,17 @@ set -o pipefail
set -o verbose
activate_venv
add_nodejs_to_path
mkdir -p jstestfuzzinput jstestfuzzoutput
indir="$(pwd)/jstestfuzzinput"
outdir="$(pwd)/jstestfuzzoutput"
# We need to be the jstestfuzz repo for node to install/run
cd jstestfuzz
indir="$(pwd)/../jstestfuzzinput"
outdir="$(pwd)/../jstestfuzzoutput"
# Grep all the js files from modified_and_created_patch_files.txt and put them into $indir.
(grep -v "\.tpl\.js$" modified_and_created_patch_files.txt | grep ".*jstests/.*\.js$" | xargs -I {} cp {} $indir || true)
(grep -v "\.tpl\.js$" ../modified_and_created_patch_files.txt | grep ".*jstests/.*\.js$" | xargs -I {} cp {} $indir || true)
# Count the number of files in $indir.
if [[ "$(ls -A $indir)" ]]; then
@ -26,10 +28,13 @@ if [[ "$(ls -A $indir)" ]]; then
num_files=50
fi
npm run --prefix jstestfuzz jstestfuzz -- --jsTestsDir $indir --out $outdir --numSourceFiles $num_files --numGeneratedFiles 50
./src/scripts/npm_run.sh jstestfuzz -- --jsTestsDir $indir --out $outdir --numSourceFiles $num_files --numGeneratedFiles 50
# Run parse-jsfiles on 50 files at a time with 32 processes in parallel.
ls -1 -d $outdir/* | xargs -P 32 -L 50 npm run --prefix jstestfuzz parse-jsfiles -- | tee lint_fuzzer_sanity.log
ls -1 -d $outdir/* | xargs -P 32 -L 50 ./src/scripts/npm_run.sh parse-jsfiles -- | tee lint_fuzzer_sanity.log
exit_code=$?
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_patch --log-file lint_fuzzer_sanity.log --exit-code $exit_code
# Exit out of the jstestfuzz directory
cd ..
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_patch --log-file jstestfuzz/lint_fuzzer_sanity.log --exit-code $exit_code
fi

View File

@ -32,21 +32,6 @@ unset expansions_default_yaml
unset script
unset evergreen_dir
function add_nodejs_to_path {
# Add node and npm binaries to PATH
if [ "Windows_NT" = "$OS" ]; then
# An "npm" directory might not have been created in %APPDATA% by the Windows installer.
# Work around the issue by specifying a different %APPDATA% path.
# See: https://github.com/nodejs/node-v0.x-archive/issues/8141
export APPDATA=${workdir}/npm-app-data
export PATH="$PATH:/cygdrive/c/Program Files (x86)/nodejs" # Windows location
# TODO: this is to work around BUILD-8652
cd "$(pwd -P | sed 's,cygdrive/c/,cygdrive/z/,')"
else
export PATH="$PATH:/opt/node/bin"
fi
}
function posix_workdir {
if [ "Windows_NT" = "$OS" ]; then
echo $(cygpath -u "${workdir}")

View File

@ -1,6 +1,6 @@
function setup_mongo_task_generator {
if [ ! -f mongo-task-generator ]; then
curl -L https://github.com/mongodb/mongo-task-generator/releases/download/v0.6.6/mongo-task-generator --output mongo-task-generator
curl -L https://github.com/mongodb/mongo-task-generator/releases/download/v0.6.7/mongo-task-generator --output mongo-task-generator
chmod +x mongo-task-generator
fi
}

View File

@ -8,7 +8,7 @@ from pydantic import ValidationError
if __name__ == "__main__" and __package__ is None:
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.metrics_datatypes import ResmokeToolingMetrics, SConsToolingMetrics
from buildscripts.metrics.tooling_metrics_utils import _get_internal_tooling_metrics_client
from evergreen.api import RetryingEvergreenApi
@ -20,43 +20,56 @@ except Exception as exc:
print("Could not connect to Atlas cluster")
raise exc
try:
# Get metrics for the last week
one_week_ago_datetime = datetime.datetime.utcnow() - datetime.timedelta(days=7)
last_week_metrics = client.metrics.tooling_metrics.find(
{"utc_starttime": {"$gt": one_week_ago_datetime}})
malformed_metrics = []
invalid_metrics = []
total_docs = 0
def get_metrics_data(source, MetricsClass, lookback=7):
try:
# Get SCons metrics for the lookback period
lookback_datetime = datetime.datetime.utcnow() - datetime.timedelta(days=lookback)
last_week_metrics = client.metrics.tooling_metrics.find({
"source": source,
"utc_starttime": {"$gt": lookback_datetime},
})
# Find any malformed/invalid documents in the cluster
for doc in last_week_metrics:
total_docs += 1
try:
metrics = ToolingMetrics(**doc)
if metrics.is_malformed():
malformed_metrics.append(doc['_id'])
except ValidationError:
invalid_metrics.append(doc['_id'])
malformed_metrics = []
invalid_metrics = []
total_docs = 0
metrics_detailed = ("METRICS DETAILED:\n"
f"malformed_metrics_last_week: {malformed_metrics}\n"
f"invalid_metrics_last_week: {invalid_metrics}\n"
f"total_docs_last_week: {total_docs}")
metrics_overview = (
"METRICS OVERVIEW:\n"
f"malformed_metrics_last_week: {len(malformed_metrics)} ({len(malformed_metrics)/total_docs*100:.2f}%)\n"
f"invalid_metrics_last_week: {len(invalid_metrics)} ({len(invalid_metrics)/total_docs*100:.2f}%)\n"
f"total_docs_last_week: {total_docs}")
# Find any malformed/invalid documents in the cluster
for doc in last_week_metrics:
total_docs += 1
try:
metrics = MetricsClass(**doc)
if metrics.is_malformed():
malformed_metrics.append(doc['_id'])
except ValidationError:
invalid_metrics.append(doc['_id'])
print(metrics_overview)
print(metrics_detailed)
metrics_detailed = (f"METRICS DETAILED ({source}):\n"
f"malformed_metrics_last_week: {malformed_metrics}\n"
f"invalid_metrics_last_week: {invalid_metrics}\n"
f"total_docs_last_week: {total_docs}\n")
metrics_overview = (
f"METRICS OVERVIEW ({source}):\n"
f"malformed_metrics_last_week: {len(malformed_metrics)} ({len(malformed_metrics)/total_docs*100:.2f}%)\n"
f"invalid_metrics_last_week: {len(invalid_metrics)} ({len(invalid_metrics)/total_docs*100:.2f}%)\n"
f"total_docs_last_week: {total_docs}\n")
# Publish metrics to SDP Slack Channel
evg_api = RetryingEvergreenApi.get_api(config_file="./.evergreen.yml")
evg_api.send_slack_message(target="#server-sdp-bfs", msg=metrics_overview)
print(metrics_overview)
print(metrics_detailed)
except Exception as exc:
print("Unexpected failure while getting metrics")
raise exc
return metrics_overview
except Exception as exc:
print("Unexpected failure while getting metrics")
raise exc
scons_metrics_overview = get_metrics_data("scons", SConsToolingMetrics)
resmoke_metrics_overview = get_metrics_data("resmoke", ResmokeToolingMetrics)
# Publish metrics to SDP Slack Channel
evg_api = RetryingEvergreenApi.get_api(config_file="./.evergreen.yml")
evg_api.send_slack_message(
target="#server-sdp-bfs",
msg=scons_metrics_overview + resmoke_metrics_overview,
)

View File

@ -9,7 +9,6 @@ set -o errexit
activate_venv
$python buildscripts/resmoke_tests_runtime_validate.py \
--resmoke-report-file ./report.json \
--evg-api-config ./.evergreen.yml \
--project-id ${project_id} \
--build-variant ${build_variant} \
--task-name ${task_name}

View File

@ -0,0 +1,30 @@
// Regression test for SERVER-71270.
(function() {
"use strict";
load('jstests/aggregation/extras/utils.js'); // For assertArrayEq.
const doc = {
_id: 0,
time: new Date('2019-01-18T13:24:15.443Z'),
tag: {},
};
db.ts.drop();
db.coll.drop();
db.createCollection('ts', {timeseries: {timeField: 'time', metaField: 'tag'}});
db.createCollection('coll');
db.ts.insertOne(doc);
db.coll.insertOne(doc);
const pipeline = [
{$project: {'time': 0}},
{$match: {'time': {$lte: new Date('2019-02-13T11:36:03.481Z')}}},
];
const ts = db.ts.aggregate(pipeline).toArray();
const vanilla = db.coll.aggregate(pipeline).toArray();
assertArrayEq({
actual: ts,
expected: vanilla,
});
}());

View File

@ -34,7 +34,6 @@ load("jstests/libs/doc_validation_utils.js");
const dbName = 'bypass_document_validation';
const collName = 'bypass_document_validation';
const outputCollName = 'bypass_output_coll';
const myDb = db.getSiblingDB(dbName);
const coll = myDb[collName];
@ -65,6 +64,7 @@ function runBypassDocumentValidationTest(validator) {
}
// Test the aggregation command with a $out stage.
const outputCollName = 'bypass_output_coll';
const outputColl = myDb[outputCollName];
outputColl.drop();
assert.commandWorked(myDb.createCollection(outputCollName, {validator: validator}));
@ -199,8 +199,4 @@ runBypassDocumentValidationTest({a: {$exists: true}});
// Run the test again with an equivalent JSON Schema validator.
runBypassDocumentValidationTest({$jsonSchema: {required: ['a']}});
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(myDb.runCommand({collMod: collName, validationAction: "warn"}));
assert.commandWorked(myDb.runCommand({collMod: outputCollName, validationAction: "warn"}));
})();

View File

@ -3,7 +3,7 @@
* @tags: [
* assumes_unsharded_collection,
* requires_non_retryable_writes,
* requires_fcv_60,
* requires_fcv_62,
* # This test could produce unexpected explain output if additional indexes are created.
* assumes_no_implicit_index_creation,
* # TODO SERVER-67506: Dotted path equality to null matches non-object array elements in CQF.

View File

@ -15,48 +15,41 @@ const encryptedBinDataElement = BinData(6, "AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
const nonEncryptedBinDataElement = BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
// Only elements of type BinData with subtype '6' should match.
assertSchemaMatch(coll, {properties: {bin: {encrypt: {}}}}, {bin: encryptedBinDataElement}, true);
assertSchemaMatch(coll, {properties: {bin: {encrypt: {}}}}, {bin: {}}, false);
assertSchemaMatch(
coll, {properties: {bin: {encrypt: {}}}}, {bin: encryptedBinDataElement}, true, true);
assertSchemaMatch(coll, {properties: {bin: {encrypt: {}}}}, {bin: {}}, false, true);
assertSchemaMatch(
coll, {properties: {bin: {encrypt: {}}}}, {bin: nonEncryptedBinDataElement}, false, true);
coll, {properties: {bin: {encrypt: {}}}}, {bin: nonEncryptedBinDataElement}, false);
// Nested in object.
assertSchemaMatch(coll,
{properties: {obj: {type: 'object', properties: {a: {encrypt: {}}}}}},
{obj: {a: encryptedBinDataElement}},
true,
true);
assertSchemaMatch(coll,
{properties: {obj: {type: 'object', properties: {a: {encrypt: {}}}}}},
{obj: {a: {}}},
false,
true);
false);
assertSchemaMatch(coll,
{properties: {obj: {type: 'object', properties: {a: {encrypt: {}}}}}},
{obj: {a: nonEncryptedBinDataElement}},
false,
true);
false);
// Nested in array.
assertSchemaMatch(coll,
{properties: {arr: {type: 'array', items: {encrypt: {}}}}},
{arr: [encryptedBinDataElement, encryptedBinDataElement]},
true,
true);
assertSchemaMatch(
coll, {properties: {arr: {type: 'array', items: {encrypt: {}}}}}, {arr: [{}, {}]}, false, true);
coll, {properties: {arr: {type: 'array', items: {encrypt: {}}}}}, {arr: [{}, {}]}, false);
assertSchemaMatch(coll,
{properties: {arr: {type: 'array', items: {encrypt: {}}}}},
{arr: [encryptedBinDataElement, nonEncryptedBinDataElement]},
false,
true);
false);
// If array is not specified, should not traverse array of encrypted BinData's.
assertSchemaMatch(coll,
{properties: {bin: {encrypt: {}}}},
{bin: [encryptedBinDataElement, encryptedBinDataElement]},
false,
true);
false);
// Encrypt alongside type/bsontype should fail to parse.
assert.commandFailedWithCode(

View File

@ -0,0 +1,55 @@
/**
* Tests that an operation requiring more cache than available fails instead of retrying infinitely.
*
* @tags: [
* does_not_support_config_fuzzer,
* requires_fcv_62,
* requires_persistence,
* requires_non_retryable_writes,
* requires_wiredtiger,
* ]
*/
(function() {
load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
load("jstests/libs/storage_engine_utils.js");
// TODO (SERVER-39362): remove once parallel suite respects tags properly.
if (!storageEngineIsWiredTiger()) {
jsTestLog("Skipping test because storage engine is not WiredTiger.");
return;
}
const doc = {
x: []
};
for (var j = 0; j < 334000; j++) {
doc.x.push("" + Math.random() + Math.random());
}
const coll = db[jsTestName()];
coll.drop();
// Maximum amount of indexes is 64. _id is implicit, and sharded collections also have an index on
// the shard key.
assert.commandWorked(coll.createIndex({x: "text"}));
for (let i = 0; i < 61; i++) {
assert.commandWorked(coll.createIndex({x: 1, ["field" + i]: 1}));
}
// Retry the operation until we eventually hit the TransactionTooLargeForCache. Retry on
// WriteConflict or TemporarilyUnavailable errors, as those are expected to be returned if the
// threshold for TransactionTooLargeForCache is not reached, possibly due to concurrent operations.
assert.soon(() => {
let result;
try {
result = coll.insert(doc);
assert.commandFailedWithCode(result, ErrorCodes.TransactionTooLargeForCache);
return true;
} catch (e) {
assert.commandFailedWithCode(result,
[ErrorCodes.WriteConflict, ErrorCodes.TemporarilyUnavailable]);
return false;
}
}, "Expected operation to eventually fail with TransactionTooLargeForCache error.");
}());

View File

@ -0,0 +1,85 @@
/**
* Tests a multi-document transaction requiring more cache than available fails with the expected
* error code instead of a generic WriteConflictException.
*
* @tags: [
* does_not_support_config_fuzzer,
* requires_fcv_62,
* requires_persistence,
* requires_non_retryable_writes,
* requires_wiredtiger,
* uses_transactions,
* ]
*/
(function() {
load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
load('jstests/libs/transactions_util.js');
function getWtCacheSizeBytes() {
let serverStatus;
if (FixtureHelpers.isReplSet(db) || FixtureHelpers.isMongos(db)) {
serverStatus = FixtureHelpers.getPrimaries(db)[0].getDB('admin').serverStatus();
} else {
serverStatus = db.serverStatus();
}
assert.commandWorked(serverStatus);
return serverStatus.wiredTiger.cache["maximum bytes configured"];
}
const doc1 = {
x: []
};
for (var j = 0; j < 100000; j++) {
doc1.x.push("" + Math.random() + Math.random());
}
const session = db.getMongo().startSession();
const sessionDb = session.getDatabase(db.getName());
const coll = sessionDb[jsTestName()];
coll.drop();
// Scale the load in proportion to WT cache size, to reduce test run time.
// A single collection can only have up to 64 indexes. Cap at _id + 1 text index + 62 indexes.
const nIndexes = Math.min(Math.ceil(getWtCacheSizeBytes() * 2 / (1024 * 1024 * 1024)), 62);
assert.commandWorked(coll.createIndex({x: "text"}));
for (let i = 0; i < nIndexes; i++) {
assert.commandWorked(coll.createIndex({x: 1, ["field" + i]: 1}));
}
// Retry the transaction until we eventually hit the TransactionTooLargeForCache. Only retry on
// WriteConflict error, which is the only expected error besides TransactionTooLargeForCache.
assert.soon(() => {
session.startTransaction();
// Keep inserting documents in the transaction until we eventually hit the cache limit.
let insertCount = 0;
let result;
try {
while (true) {
try {
++insertCount;
result = coll.insert(doc1);
assert.commandWorked(result);
} catch (e) {
session.abortTransaction();
assert.commandFailedWithCode(result, ErrorCodes.TransactionTooLargeForCache);
break;
}
}
} catch (e) {
assert.commandFailedWithCode(result, ErrorCodes.WriteConflict);
return false;
}
// The error should not have a transient transaction error label. At this point the error must
// have been TransactionTooLargeForCache. We do this check here to avoid having to check
// exception types in the outermost catch, in case this assertion fires.
assert(!TransactionsUtil.isTransientTransactionError(result), result);
jsTestLog("Iterations until TransactionTooLargeForCache occured: " + insertCount);
return true;
}, "Expected a transaction to eventually fail with TransactionTooLargeForCache error.");
}());

View File

@ -113,8 +113,7 @@ function runTest(badViewDefinition) {
}
assert.commandWorked(
viewsDB.runCommand(
{collMod: "collection", validator: {x: {$type: "string"}}, validationAction: "warn"}),
viewsDB.runCommand({collMod: "collection", validator: {x: {$type: "string"}}}),
makeErrorMessage("collMod"));
const renameCommand = {

View File

@ -151,10 +151,6 @@ assert.commandWorked(viewsDB.runCommand({
assert.commandWorked(
viewsDB.runCommand({aggregate: "largeView", pipeline: [{$sort: {x: -1}}], cursor: {}}),
"Expected aggregate to succeed since 'allowDiskUse' is true by default");
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(
viewsDB.runCommand({collMod: validatedCollName, validationAction: "warn"}));
})();
// Test explain modes on a view.

View File

@ -45,28 +45,6 @@ const isIgnorableError = function ignorableError(codeName) {
*/
const validateCollectionsBackgroundThread = function validateCollectionsBackground(
host, isIgnorableErrorFunc) {
// Some tests explicitly mess with schema validation. We will skip running background validation
// on those collections.
const skippedCollections = new Set([
"collectionWithValidator",
"jstests_schema_encrypt",
"json_schema_additional_items",
"schema_allowed_properties",
"jstests_schema_bsontype",
"jstests_schema_dependencies",
"jstests_schema_encrypt",
"json_schema_items",
"jstests_json_schema",
"jstests_json_schema_logical",
"json_schema_min_max_items",
"jstests_schema_min_max_properties",
"schema_pattern_properties",
"jstests_schema_required",
"json_schema_unique_items",
"json_schema_test_corpus",
"jstests_json_schema_ignore_unsupported",
]);
// Calls 'func' with the print() function overridden to be a no-op.
const quietly = (func) => {
const printOriginal = print;
@ -128,9 +106,6 @@ const validateCollectionsBackgroundThread = function validateCollectionsBackgrou
});
for (let collectionName of collectionNames) {
if (dbName == "bypass_document_validation" || skippedCollections.has(collectionName)) {
continue;
}
let res = conn.getDB(dbName).getCollection(collectionName).runCommand({
"validate": collectionName,
background: true,

View File

@ -10,7 +10,7 @@
* Asserts that 'doc' matches 'schema' if and only if 'valid' is true. Drops 'coll' in the process,
* so do not pass a collection whose contents you wish to preserve.
*/
function assertSchemaMatch(coll, schema, doc, valid, removeValidator = false) {
function assertSchemaMatch(coll, schema, doc, valid) {
const errmsg = "Document " + tojson(doc) +
(valid ? " should have matched the schema " : " unexpectedly matched the schema ") +
tojson(schema);
@ -60,12 +60,4 @@ function assertSchemaMatch(coll, schema, doc, valid, removeValidator = false) {
ErrorCodes.DocumentValidationFailure,
errmsg + " during update document validation in strict mode");
}
if (removeValidator) {
// Remove the validator to avoid failing collection validation.
assert.commandWorked(coll.runCommand("collMod", {validator: {}}));
} else {
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(coll.runCommand("collMod", {validationAction: "warn"}));
}
}

View File

@ -32,7 +32,8 @@ assert.commandFailed(setParameter(adminDb, {"diagnosticDataCollectionStatsNamesp
assert.eq(getParameter(adminDb, "diagnosticDataCollectionStatsNamespaces"), ["local.startup_log"]);
// Validate that collection stats are collected for runtime collections
// Validate that collection stats are collected for runtime collections and that we do not crash
// for a non-existent collection
assert.commandWorked(setParameter(
adminDb,
{"diagnosticDataCollectionStatsNamespaces": ["admin.system.version", "admin.does_not_exist"]}));
@ -41,8 +42,7 @@ assert.soon(() => {
jsTestLog("Collected: " + tojson(result));
let collectionStats = result.data.collectionStats;
return collectionStats.hasOwnProperty("admin.system.version") &&
collectionStats["admin.system.version"].ns == "admin.system.version" &&
collectionStats["admin.does_not_exist"].ns == "admin.does_not_exist" != undefined;
collectionStats["admin.system.version"].ns == "admin.system.version";
});
// Validate that when it is disabled, we stop collecting

View File

@ -29,7 +29,7 @@ const collName = "collectionWithMalformedValidator";
assert.commandWorked(
testDB.runCommand({collMod: collName, validator: {email: {$regex: invalidRegex}}}));
MongoRunner.stopMongod(conn, null, {skipValidation: true});
MongoRunner.stopMongod(conn);
})();
(function startUpWithMalformedValidator() {
@ -48,6 +48,6 @@ const collName = "collectionWithMalformedValidator";
assert.commandWorked(testDB.someOtherCollection.insert({a: 1}));
assert.eq(testDB.someOtherCollection.find().itcount(), 1);
MongoRunner.stopMongod(conn, null, {skipValidation: true});
MongoRunner.stopMongod(conn);
})();
})();

View File

@ -253,8 +253,5 @@ bulkOp.find({$expr: {$eq: ["$x", 2]}}).update({$set: {x: 10}});
bulkOp.find({$expr: {$lt: ["$x", 1]}}).remove();
checkCounters(() => assert.commandWorked(bulkOp.execute()), {"$eq": 1, "$lt": 1});
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(testColl.runCommand("collMod", {validationAction: "warn"}));
MongoRunner.stopMongod(mongod);
})();

View File

@ -18,6 +18,10 @@ function getPlanCacheSize() {
return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalSizeEstimateBytes;
}
function getGlobalPlanCacheNumEntries() {
return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalQueryShapes;
}
/**
* Helper class that creates a collection, indexes on it, and makes a few queries to add entries to
* the plan cache.
@ -37,20 +41,21 @@ class TestCollection {
assert.gt(getPlanCacheSize(), 0);
this.nCacheEntries = this.getNumberOfPlanCacheEntries();
this.nCacheEntries = this.getNumberOfCollectionPlanCacheEntries();
assert.eq(2, this.nCacheEntries);
}
getNumberOfPlanCacheEntries() {
// The following three helper functions concern plan cache entries specific to a given
// collection, and not the entire/global plan cache
getNumberOfCollectionPlanCacheEntries() {
return this.coll.getPlanCache().list().length;
}
assertAllCollectionCacheEntriesRemoved() {
assert.eq(0, this.getNumberOfPlanCacheEntries());
assert.eq(0, this.getNumberOfCollectionPlanCacheEntries());
}
assertCacheEntriesNotRemoved() {
assert.eq(this.nCacheEntries, this.getNumberOfPlanCacheEntries());
assertCollectionCacheEntriesNotRemoved() {
assert.eq(this.nCacheEntries, this.getNumberOfCollectionPlanCacheEntries());
}
}
@ -59,23 +64,28 @@ class TestCollection {
const test = new TestCollection();
assert.gt(getPlanCacheSize(), initialPlanCacheSize);
assert.eq(getGlobalPlanCacheNumEntries(), 2);
assert(test.coll.drop());
assert.eq(getPlanCacheSize(), initialPlanCacheSize);
assert.eq(getGlobalPlanCacheNumEntries(), 0);
}());
(function cacheEntriesNotRemovedIfAnotherCollectedDropped() {
const test = new TestCollection("coll1");
const cacheSizeForOneTestCollection = getPlanCacheSize();
assert.eq(getGlobalPlanCacheNumEntries(), 2);
const anotherTest = new TestCollection("coll2");
const cacheSizeForTwoTestCollections = getPlanCacheSize();
assert.eq(getGlobalPlanCacheNumEntries(), 4);
assert.gt(cacheSizeForTwoTestCollections, cacheSizeForOneTestCollection);
assert(anotherTest.coll.drop());
assert.eq(cacheSizeForOneTestCollection, getPlanCacheSize());
test.assertCacheEntriesNotRemoved();
// Entries associated with anotherTest.coll are booted from the plan cache.
assert.eq(getGlobalPlanCacheNumEntries(), 2);
test.assertCollectionCacheEntriesNotRemoved();
}());
(function cacheEntriesRemovedIfANewIndexCreated() {
@ -107,14 +117,13 @@ class TestCollection {
db.runCommand({collMod: collectionName, validator: {text: {$type: "string"}}}));
assert.eq(getPlanCacheSize(), initialPlanCacheSize);
test.assertCacheEntriesNotRemoved();
test.assertCollectionCacheEntriesNotRemoved();
}());
(function cacheEntriesRemovedIfIndexChanged() {
const collectionName = "coll";
const test = new TestCollection(collectionName);
const initialPlanCacheSize = getPlanCacheSize();
assert.commandWorked(db.runCommand({
collMod: collectionName,
index: {
@ -122,7 +131,6 @@ class TestCollection {
hidden: true,
}
}));
assert.lt(getPlanCacheSize(), initialPlanCacheSize);
test.assertAllCollectionCacheEntriesRemoved();
}());
@ -143,16 +151,16 @@ class TestCollection {
(function oneCacheEntryRemovedOnClearPlanCacheWithQueryCommand() {
const collectionName = "coll";
const test = new TestCollection(collectionName);
const numberOfCacheEntries = test.getNumberOfPlanCacheEntries();
const numberOfCacheEntries = getGlobalPlanCacheNumEntries();
test.coll.find({a: 1, b: 2, c: 3, d: 4}).itcount();
assert.eq(numberOfCacheEntries + 1, test.getNumberOfPlanCacheEntries());
assert.eq(numberOfCacheEntries + 1, getGlobalPlanCacheNumEntries());
const planCacheSize = getPlanCacheSize();
assert.commandWorked(
db.runCommand({planCacheClear: collectionName, query: {a: 1, b: 2, c: 3, d: 4}}));
assert.lt(getPlanCacheSize(), planCacheSize);
assert.eq(numberOfCacheEntries, test.getNumberOfPlanCacheEntries());
assert.eq(numberOfCacheEntries, getGlobalPlanCacheNumEntries());
}());
MongoRunner.stopMongod(conn);

View File

@ -45,6 +45,9 @@ function getPlanCacheSize() {
return db.serverStatus().metrics.query.planCacheTotalSizeEstimateBytes;
}
function getPlanCacheNumEntries() {
return db.serverStatus().metrics.query.planCacheTotalQueryShapes;
}
function assertQueryInPlanCache(coll, query) {
const explainResult = assert.commandWorked(coll.explain().find(query).finish());
const queryHash = getQueryHashFromExplain(explainResult, db);
@ -65,7 +68,7 @@ assert.commandWorked(coll.createIndex({a: 1, b: 1}));
const initialPlanCacheSize = getPlanCacheSize();
// Plan cache must be empty.
assert.eq(0, coll.getPlanCache().list().length);
assert.eq(0, getPlanCacheNumEntries());
const sbeQuery = {
a: 1
@ -79,7 +82,7 @@ const classicQuery = {
assert.eq(1, coll.find(sbeQuery).itcount());
assertQueryInPlanCache(coll, sbeQuery);
// Plan Cache must contain exactly 1 entry.
assert.eq(1, coll.getPlanCache().list().length);
assert.eq(1, getPlanCacheNumEntries());
// Assert metric is incremented for new cache entry.
const afterSbePlanCacheSize = getPlanCacheSize();
@ -92,7 +95,7 @@ assert.commandWorked(
assert.eq(1, coll.find(classicQuery).itcount());
assertQueryInPlanCache(coll, classicQuery);
// Plan Cache must contain exactly 2 entries.
assert.eq(2, coll.getPlanCache().list().length);
assert.eq(2, getPlanCacheNumEntries());
// Assert metric is incremented for new cache entry.
const afterClassicPlanCacheSize = getPlanCacheSize();

View File

@ -4,6 +4,10 @@
(function() {
"use strict";
// Disable the testing proctor. When the testing proctor is enabled, 'validate' will only warn about
// non-compliant documents, even when the validation action is 'error'.
TestData.testingDiagnosticsEnabled = false;
const conn = MongoRunner.runMongod();
const dbName = "test";

View File

@ -18,15 +18,12 @@ var coll = primary.getDB('test').getCollection(name);
assert.commandWorked(coll.insert({_id: 0, x: 1}));
assert.commandWorked(coll.runCommand("collMod", {"validator": {a: {$exists: true}}}));
secondary = replSet.restart(secondary, {startClean: true, skipValidation: true});
secondary = replSet.restart(secondary, {startClean: true});
replSet.awaitReplication();
replSet.awaitSecondaryNodes();
assert.eq(1, secondary.getDB("test")[name].count());
assert.docEq({_id: 0, x: 1}, secondary.getDB("test")[name].findOne());
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(coll.runCommand("collMod", {validationAction: "warn"}));
replSet.stopSet();
})();

View File

@ -5,6 +5,8 @@
(function() {
"use strict";
load("jstests/replsets/rslib.js");
// Skip db hash check because secondary is left with a different config.
TestData.skipCheckDBHashes = true;
@ -33,6 +35,10 @@ const lastOp = primaryOplog.find(expectedNoOp).sort({'$natural': -1}).limit(1).t
assert(lastOp.length > 0);
replTest.awaitReplication();
// Make sure that all nodes have installed the config before moving on.
replTest.waitForConfigReplication(primary, nodes);
assert.soonNoExcept(() => isConfigCommitted(primary));
jsTestLog("Invalid reconfig");
config.version++;
var badMember = {_id: numNodes, host: "localhost:12345", priority: "High"};

View File

@ -32,9 +32,9 @@ function printCollectionOptions(rollbackTest, time) {
let CommonOps = (node) => {
let testDb = node.getDB(dbName);
assert.commandWorked(testDb[coll1Name].insert({a: 1, b: 1}));
assert.commandWorked(testDb[coll2Name].insert({a: 1, b: 1}));
assert.commandWorked(testDb[coll3Name].insert({a: 1, b: 1}));
assert.commandWorked(testDb[coll4Name].insert({a: 1, b: 1}));
assert.commandWorked(testDb[coll2Name].insert({a: 2, b: 2}));
assert.commandWorked(testDb[coll3Name].insert({a: 3, b: 3}));
assert.commandWorked(testDb[coll4Name].insert({a: 4, b: 4}));
// Start with no validation action.
assert.commandWorked(testDb.runCommand({

View File

@ -175,6 +175,10 @@ for (let i = numCollections / 2; i < numCollections; i++) {
checkResults(outputData, checksToDo);
})();
// Test valid query with empty specification
assert.commandWorked(
adminDb.runCommand({aggregate: 1, pipeline: [{$_internalAllCollectionStats: {}}], cursor: {}}));
// Test invalid queries/values.
assert.commandFailedWithCode(
adminDb.runCommand({aggregate: 1, pipeline: [{$_internalAllCollectionStats: 3}], cursor: {}}),

View File

@ -1,7 +1,7 @@
/**
* SERVER-57469: Test that the 'allowPartialResults' option to find is respected when used together
* with 'maxTimeMS' and only a subset of the shards provide data before the timeout.
* Uses both failpoints and MongoBridge to simulate MaxTimeMSExpired.
* Uses three methods to simulate MaxTimeMSExpired: failpoints, MongoBridge, and $where + sleep.
*
* @tags: [
* requires_sharding,
@ -33,15 +33,15 @@ function isError(res) {
// Set up a 2-shard single-node replicaset cluster with MongoBridge.
const st = new ShardingTest({name: jsTestName(), shards: 2, useBridge: true, rs: {nodes: 1}});
const dbName = "test-SERVER-57469";
const collName = "test-SERVER-57469-coll";
const dbName = "test-SERVER-57469-failpoints";
const collName = "test-SERVER-57469-failpoints-coll";
const coll = st.s0.getDB(dbName)[collName];
function initDb(numSamples, splitPoint) {
coll.drop();
// Use ranged sharding with 50% of the data on the second shard.
// Use ranged sharding with a specified fraction of the data on the second shard.
st.shardColl(
coll,
{_id: 1}, // shard key
@ -57,26 +57,30 @@ function initDb(numSamples, splitPoint) {
}
// Insert some data.
const size = 1000;
const splitPoint = Math.max(1, size / 2);
initDb(size, splitPoint);
const nDocs = 200;
const splitPoint = Math.max(1, nDocs / 2);
initDb(nDocs, splitPoint);
// We will sometimes use $where expressions to inject delays in processing documents on some shards.
// Maps from shard to a snippet of JS code. This is modified by FindWhereSleepController
let whereExpressions = {};
function whereCode() {
return Object.values(whereExpressions).join("") + "return 1;";
}
function runQueryWithTimeout(doAllowPartialResults, timeout) {
return coll.runCommand({
find: collName,
filter: {$where: Object.values(whereExpressions).join("") + "return 1;"},
filter: {$where: whereCode()},
allowPartialResults: doAllowPartialResults,
batchSize: size,
batchSize: nDocs,
maxTimeMS: timeout
});
}
// Set ampleTimeMS to at least two seconds, plus ten times the basic query runtime.
// This timeout will provide ample time for our queries to run to completion.
// Set ampleTimeMS to at least 2000ms, plus ten times the basic query runtime.
// This timeout must provide ample time for our queries to run to completion, even on passthrough
// suites with resource contention.
const ampleTimeMS = 2000 + 10 * runtimeMillis(() => runQueryWithTimeout(true, 999999999));
print("ampleTimeMS: " + ampleTimeMS);
@ -96,16 +100,14 @@ function runQuery(doAllowPartialResults) {
fpMongos.off();
}
const batchSizeForGetMore = 10;
// Simulate mongos timeout during getMore.
function getMoreMongosTimeout(allowPartialResults) {
function getMoreMongosTimeout(allowPartialResults, batchSize) {
// Get the first batch.
const res = assert.commandWorked(coll.runCommand({
find: collName,
filter: {$where: Object.values(whereExpressions).join("") + "return 1;"},
filter: {$where: whereCode()},
allowPartialResults: allowPartialResults,
batchSize: batchSizeForGetMore,
batchSize: batchSize,
maxTimeMS: ampleTimeMS
}));
assert(!res.cursor.hasOwnProperty("partialResultsReturned"));
@ -115,10 +117,10 @@ function getMoreMongosTimeout(allowPartialResults) {
// Run getmores repeatedly until we exhaust the cache on mongos.
// Eventually we should get either a MaxTimeMS error or partial results because a shard is down.
let numReturned = batchSizeForGetMore; // One batch was returned so far.
let numReturned = batchSize; // One batch was returned so far.
while (true) {
const res2 = coll.runCommand(
{getMore: res.cursor.id, collection: collName, batchSize: batchSizeForGetMore});
const res2 =
coll.runCommand({getMore: res.cursor.id, collection: collName, batchSize: batchSize});
if (isError(res2)) {
assert.commandFailedWithCode(
res2, ErrorCodes.MaxTimeMSExpired, "failure should be due to MaxTimeMSExpired");
@ -128,20 +130,45 @@ function getMoreMongosTimeout(allowPartialResults) {
// are returned even if MaxTimeMS expired on mongos.
numReturned += res2.cursor.nextBatch.length;
print(numReturned + " docs returned so far");
assert.neq(numReturned, size, "Got full results even through mongos had MaxTimeMSExpired.");
assert.neq(
numReturned, nDocs, "Got full results even through mongos had MaxTimeMSExpired.");
if (res2.cursor.partialResultsReturned) {
assert(allowPartialResults);
assert.lt(numReturned, size);
assert.lt(numReturned, nDocs);
break;
}
}
fpMongos.off();
}
getMoreMongosTimeout(true);
getMoreMongosTimeout(false);
// Run the getMore tests with two batch sizes.
// In the first case, we have (splitPoint % batchSizeForGetMore == 0) and the getMores will likely
// exhaust the live shard without requiring any data from the dead shard. When the getMore to
// the dead shard times out, it will be the only unexhausted remote.
// In the second case, choosing (splitPoint % batchSizeForGetMore != 0) the final getMore will be
// requesting data from both shards. Data from the live shard should be returned despite the dead
// shard timing out.
const batchSizesForGetMore = [50, 47];
assert.eq(splitPoint % batchSizesForGetMore[0], 0);
assert.neq(splitPoint % batchSizesForGetMore[1], 0);
assert.lt(batchSizesForGetMore[0], splitPoint);
assert.lt(batchSizesForGetMore[1], splitPoint);
// Test shard timeouts. These are the scenario that we expect to be possible in practice.
// Test using both failpoints and mongo bridge, testing slightly different execution paths.
function withEachBatchSize(callback) {
callback(batchSizesForGetMore[0]);
callback(batchSizesForGetMore[1]);
}
function withEachValueOfAllowPartialResults(callback) {
callback(true);
callback(false);
}
withEachValueOfAllowPartialResults(
allowPartialResults =>
withEachBatchSize(batchSize => getMoreMongosTimeout(allowPartialResults, batchSize)));
// Test shard timeouts. These are the scenario that we expect to be likely in practice.
// Test using 3 different types of simulated timeouts, giving slightly different execution paths.
class MaxTimeMSFailpointFailureController {
constructor(mongoInstance) {
@ -161,6 +188,7 @@ class MaxTimeMSFailpointFailureController {
class NetworkFailureController {
constructor(shard) {
this.shard = shard;
this.delayTime = Math.round(1.1 * ampleTimeMS);
}
enable() {
@ -169,12 +197,13 @@ class NetworkFailureController {
// lost. We delay instead of dropping messages because this lets the shard request proceed
// without connection failure and retry (which has its own driver-controlled timeout,
// typically 15s).
this.shard.getPrimary().delayMessagesFrom(st.s, 2 * ampleTimeMS);
this.shard.getPrimary().delayMessagesFrom(st.s, this.delayTime);
}
disable() {
this.shard.getPrimary().delayMessagesFrom(st.s, 0);
sleep(2 * ampleTimeMS); // Allow time for delayed messages to be flushed.
// Allow time for delayed messages to be flushed so that the next request is not delayed.
sleep(this.delayTime);
}
}
@ -205,10 +234,10 @@ class FindWhereSleepController {
// Add a $where expression to find command that sleeps when processing a document on the
// shard of interest.
let slowDocId = (this.shard == st.shard0) ? 0 : splitPoint;
// Offset the slowDocId by batchSizeForGetMore so that when testing getMore, we quickly
// return enough documents to serve the first batch without timing out.
slowDocId += batchSizeForGetMore;
const sleepTimeMS = 2 * ampleTimeMS;
// Offset the slowDocId by at least the getMore batch size so that when testing getMore,
// we quickly return enough documents to serve the first batch without timing out.
slowDocId += Math.max(...batchSizesForGetMore);
const sleepTimeMS = Math.round(1.1 * ampleTimeMS);
whereExpressions[this.shard] = `if (this._id == ${slowDocId}) {sleep(${sleepTimeMS})};`;
}
@ -232,26 +261,53 @@ const allShardsSleepFailure = new MultiFailureController([shard0SleepFailure, sh
const allshardsMixedFailures = new MultiFailureController([shard0NetworkFailure, shard1Failpoint]);
function getMoreShardTimeout(allowPartialResults, failureController) {
// Due to the hack with sleepFailures below, this has to be the innermost parameterizing function.
function withEachSingleShardFailure(callback) {
callback(shard0Failpoint);
callback(shard1Failpoint);
callback(shard0NetworkFailure);
callback(shard1NetworkFailure);
// The FindWhereSleepFailureController must be set before the first "find" because that's when
// the $where clause is set.
shard0SleepFailure.enable();
callback(shard0SleepFailure);
shard0SleepFailure.disable();
shard1SleepFailure.enable();
callback(shard1SleepFailure);
shard1NetworkFailure.disable();
}
function withEachAllShardFailure(callback) {
callback(allShardsFailpoint);
callback(allshardsNetworkFailure);
callback(allShardsSleepFailure);
callback(allshardsMixedFailures);
}
function getMoreShardTimeout(allowPartialResults, failureController, batchSize) {
// Get the first batch.
const res = assert.commandWorked(coll.runCommand({
find: collName,
filter: {$where: Object.values(whereExpressions).join("") + "return 1;"},
filter: {$where: whereCode()},
// FindWhereSleepController only works with getMore if docs are _id-ordered. We use a hint
// instead of sort here because we want to avoid blocking on missing docs -- we want the
// AsyncResultsMerger to return results from the live shard while the other is failing.
hint: {_id: 1},
allowPartialResults: allowPartialResults,
batchSize: batchSizeForGetMore,
batchSize: batchSize,
maxTimeMS: ampleTimeMS
}));
assert.eq(undefined, res.cursor.partialResultsReturned);
assert.gt(res.cursor.id, 0);
// Stop a shard and run getMore.
failureController.enable();
let numReturned = batchSizeForGetMore; // One batch was returned so far.
let numReturned = batchSize; // One batch was returned so far.
print(numReturned + " docs returned in the first batch");
while (true) {
// Run getmores repeatedly until we exhaust the cache on mongos.
// Eventually we should get partial results or an error because a shard is down.
const res2 = coll.runCommand(
{getMore: res.cursor.id, collection: collName, batchSize: batchSizeForGetMore});
const res2 =
coll.runCommand({getMore: res.cursor.id, collection: collName, batchSize: batchSize});
if (allowPartialResults) {
assert.commandWorked(res2);
} else {
@ -263,10 +319,10 @@ function getMoreShardTimeout(allowPartialResults, failureController) {
}
numReturned += res2.cursor.nextBatch.length;
print(numReturned + " docs returned so far");
assert.neq(numReturned, size, "Entire collection seemed to be cached by the first find!");
assert.neq(numReturned, nDocs, "Entire collection seemed to be cached by the first find!");
if (res2.cursor.partialResultsReturned) {
if (allowPartialResults) {
assert.lt(numReturned, size);
assert.lt(numReturned, nDocs);
break;
} else {
assert(false, "Partial results should not have been allowed.");
@ -275,29 +331,11 @@ function getMoreShardTimeout(allowPartialResults, failureController) {
}
failureController.disable();
}
// getMore timeout with allowPartialResults=true.
getMoreShardTimeout(true, shard0Failpoint);
getMoreShardTimeout(true, shard1Failpoint);
getMoreShardTimeout(true, shard0NetworkFailure);
getMoreShardTimeout(true, shard1NetworkFailure);
// The FindWhereSleepFailureController must be set before the first "find" because that's when the
// $where clause is set.
shard0SleepFailure.enable();
getMoreShardTimeout(true, shard0SleepFailure);
shard1SleepFailure.enable();
getMoreShardTimeout(true, shard1SleepFailure);
// getMore timeout with allowPartialResults=false.
getMoreShardTimeout(false, shard0Failpoint);
getMoreShardTimeout(false, shard1Failpoint);
getMoreShardTimeout(false, shard0NetworkFailure);
getMoreShardTimeout(false, shard1NetworkFailure);
// The FindWhereSleepFailureController must be set before the first "find" because that's when the
// $where clause is set.
shard0SleepFailure.enable();
getMoreShardTimeout(false, shard0SleepFailure);
shard1SleepFailure.enable();
getMoreShardTimeout(false, shard1SleepFailure);
withEachValueOfAllowPartialResults(
allowPartialResults => withEachBatchSize(
batchSize => withEachSingleShardFailure(
failure => getMoreShardTimeout(allowPartialResults, failure, batchSize))));
// With 'allowPartialResults: true', if a shard times out on the first batch then return
// partial results.
@ -305,16 +343,11 @@ function partialResultsTrueFirstBatch(failureController) {
failureController.enable();
const res = assert.commandWorked(runQuery(true));
assert(res.cursor.partialResultsReturned);
assert.eq(res.cursor.firstBatch.length, size / 2);
assert.eq(res.cursor.firstBatch.length, nDocs / 2);
assert.eq(0, res.cursor.id);
failureController.disable();
}
partialResultsTrueFirstBatch(shard0Failpoint);
partialResultsTrueFirstBatch(shard1Failpoint);
partialResultsTrueFirstBatch(shard0NetworkFailure);
partialResultsTrueFirstBatch(shard1NetworkFailure);
partialResultsTrueFirstBatch(shard0SleepFailure);
partialResultsTrueFirstBatch(shard1SleepFailure);
withEachSingleShardFailure(failure => partialResultsTrueFirstBatch(failure));
// With 'allowPartialResults: false', if one shard times out then return a timeout error.
function partialResultsFalseOneFailure(failureController) {
@ -322,12 +355,7 @@ function partialResultsFalseOneFailure(failureController) {
assert.commandFailedWithCode(runQuery(false), ErrorCodes.MaxTimeMSExpired);
failureController.disable();
}
partialResultsFalseOneFailure(shard0Failpoint);
partialResultsFalseOneFailure(shard1Failpoint);
partialResultsFalseOneFailure(shard0NetworkFailure);
partialResultsFalseOneFailure(shard1NetworkFailure);
partialResultsFalseOneFailure(shard0SleepFailure);
partialResultsFalseOneFailure(shard1SleepFailure);
withEachSingleShardFailure(failure => partialResultsFalseOneFailure(failure));
// With 'allowPartialResults: false', if both shards time out then return a timeout error.
function allowPartialResultsFalseAllFailed(failureController) {
@ -335,10 +363,7 @@ function allowPartialResultsFalseAllFailed(failureController) {
assert.commandFailedWithCode(runQuery(false), ErrorCodes.MaxTimeMSExpired);
failureController.disable();
}
allowPartialResultsFalseAllFailed(allShardsFailpoint);
allowPartialResultsFalseAllFailed(allshardsNetworkFailure);
allowPartialResultsFalseAllFailed(allshardsMixedFailures);
allowPartialResultsFalseAllFailed(allShardsSleepFailure);
withEachAllShardFailure(failure => allowPartialResultsFalseAllFailed(failure));
// With 'allowPartialResults: true', if both shards time out then return empty "partial" results.
function allowPartialResultsTrueAllFailed(failureController) {
@ -349,10 +374,7 @@ function allowPartialResultsTrueAllFailed(failureController) {
assert.eq(res.cursor.firstBatch.length, 0);
failureController.disable();
}
allowPartialResultsTrueAllFailed(allShardsFailpoint);
allowPartialResultsTrueAllFailed(allshardsNetworkFailure);
allowPartialResultsTrueAllFailed(allshardsMixedFailures);
allowPartialResultsTrueAllFailed(allShardsSleepFailure);
withEachAllShardFailure(failure => allowPartialResultsTrueAllFailed(failure));
st.stop();
}());

View File

@ -63,8 +63,5 @@ assert.eq(125,
"Number of documents on the recipient shard after moveChunk is incorrect.");
assert.eq(175, testColl.find().itcount(), "Number of total documents is incorrect");
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(testColl.runCommand("collMod", {validationAction: "warn"}));
st.stop();
})();

View File

@ -16,13 +16,17 @@ function getConnAcquiredToWireMicros(conn) {
.metrics.network.totalTimeForEgressConnectionAcquiredToWireMicros;
}
// Set it so that we log the intended metrics only on the mongos.
const paramsDoc = {
mongosOptions: {setParameter: {connectionAcquisitionToWireLoggingRate: 1.0}},
shardOptions: {setParameter: {connectionAcquisitionToWireLoggingRate: 0.0}},
configOptions: {setParameter: {connectionAcquisitionToWireLoggingRate: 0.0}},
const setParamOptions = {
"failpoint.alwaysLogConnAcquisitionToWireTime": tojson({mode: "alwaysOn"}),
logComponentVerbosity: tojson({network: {verbosity: 2}})
};
const st = new ShardingTest({shards: 1, mongos: 1, other: paramsDoc});
const st = new ShardingTest({
shards: 1,
rs: {nodes: 1, setParameter: setParamOptions},
mongos: 1,
mongosOptions: {setParameter: setParamOptions}
});
let initialConnAcquiredToWireTime = getConnAcquiredToWireMicros(st.s);
jsTestLog(`Initial metric value for mongos totalTimeForEgressConnectionAcquiredToWireMicros: ${
tojson(initialConnAcquiredToWireTime)}`);
@ -39,22 +43,9 @@ assert.gt(afterConnAcquiredToWireTime,
initialConnAcquiredToWireTime,
st.s.adminCommand({serverStatus: 1}));
// Test that setting the logging rate to 0 results in silencing of the logs.
st.s.adminCommand({setParameter: 1, connectionAcquisitionToWireLoggingRate: 0.0});
assert.commandWorked(st.s.adminCommand({clearLog: 'global'}));
assert.commandWorked(st.s.getDB(jsTestName())["test"].insert({x: 2}));
try {
checkLog.containsJson(st.s, 6496702, null, 5 * 1000);
assert(false);
} catch (e) {
jsTestLog("Waited long enough to believe logs were correctly silenced.");
}
// Test with mirrored reads to execute the 'fireAndForget' path and verify logs are still correctly
// printed.
const shardPrimary = st.rs0.getPrimary();
assert.commandWorked(
shardPrimary.adminCommand({setParameter: 1, connectionAcquisitionToWireLoggingRate: 1.0}));
assert.commandWorked(shardPrimary.adminCommand({clearLog: 'global'}));
initialConnAcquiredToWireTime = getConnAcquiredToWireMicros(shardPrimary);
jsTestLog(`Initial metric value for mongod totalTimeForEgressConnectionAcquiredToWireMicros: ${

View File

@ -24,7 +24,7 @@ const st = new ShardingTest({
const configPrimary = st.configRS.getPrimary();
const serverStatusCmd = ({serverStatus: 1, shardingStatistics: 1});
let res = assert.commandWorked(configPrimary.adminCommand(serverStatusCmd));
assert(!res.hasOwnProperty("shardingStatistics"), res.shardingStatistics);
assert(!res.shardingStatistics.hasOwnProperty("globalIndex"), res.shardingStatistics);
const shardPrimary = st.shard0.rs.getPrimary();
res = assert.commandWorked(shardPrimary.adminCommand(serverStatusCmd));

View File

@ -46,7 +46,7 @@ assert.commandFailedWithCode(
const serverStatusCmd = ({serverStatus: 1, shardingStatistics: 1});
let res = assert.commandWorked(configPrimary.adminCommand(serverStatusCmd));
assert(!res.hasOwnProperty("shardingStatistics"), res.shardingStatistics);
assert(!res.shardingStatistics.hasOwnProperty("resharding"), res.shardingStatistics);
const shardPrimary = st.shard0.rs.getPrimary();
res = assert.commandWorked(shardPrimary.adminCommand(serverStatusCmd));

View File

@ -54,10 +54,6 @@ for (let [_, shardReplSet] of Object.entries(topology.shards)) {
allNodes.push(topology.configsvr.primary);
allNodes.forEach((hostName) => {
const status = new Mongo(hostName).getDB('admin').serverStatus({});
if (hostName == topology.configsvr.primary) {
assert(!status.hasOwnProperty('shardingStatistics'));
return;
}
const shardingStats = status.shardingStatistics;
assert(!shardingStats.hasOwnProperty('resharding'));
});

View File

@ -64,6 +64,13 @@ function checkServerStatusAbortedMigrationCount(shardConn, count) {
assert.eq(count, shardStats.countDonorMoveChunkAbortConflictingIndexOperation);
}
function checkServerStatusNumShardedCollections(conn, count) {
const shardStats =
assert.commandWorked(conn.adminCommand({serverStatus: 1})).shardingStatistics;
assert(shardStats.hasOwnProperty("numShardedCollections"));
assert.eq(count, shardStats.numShardedCollections);
}
function runConcurrentMoveChunk(host, ns, toShard) {
const mongos = new Mongo(host);
// Helper function to run moveChunk, retrying on ConflictingOperationInProgress. We need to
@ -132,6 +139,17 @@ st.ensurePrimaryShard(coll.getDB() + "", st.shard0.shardName);
assert.commandWorked(admin.runCommand({shardCollection: coll + "", key: {_id: 1}}));
assert.commandWorked(admin.runCommand({split: coll + "", middle: {_id: 0}}));
// Check the number of sharded collections.
const testDB = st.rs0.getPrimary().getDB(dbName);
const fcvDoc = testDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1});
if (MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version, '6.2') >= 0) {
st.shardColl(dbName + ".coll2", {_id: 1}, false);
st.shardColl(dbName + ".coll3", {_id: 1}, false);
const configCollections = mongos.getCollection("config.collections");
checkServerStatusNumShardedCollections(st.configRS.getPrimary(),
configCollections.countDocuments({}));
}
// Move chunk from shard0 to shard1 without docs.
assert.commandWorked(
mongos.adminCommand({moveChunk: coll + '', find: {_id: 1}, to: st.shard1.shardName}));

View File

@ -0,0 +1,80 @@
/**
* Test that telemetry key generation works for queries with non-object fields.
*/
load('jstests/libs/analyze_plan.js');
load("jstests/libs/feature_flag_util.js");
(function() {
"use strict";
if (!FeatureFlagUtil.isEnabled(db, "Telemetry")) {
return;
}
// Turn on the collecting of telemetry metrics.
let options = {
setParameter: {internalQueryConfigureTelemetrySamplingRate: 2147483647},
};
const conn = MongoRunner.runMongod(options);
const testDB = conn.getDB('test');
var collA = testDB[jsTestName()];
var collB = db[jsTestName() + 'Two'];
collA.drop();
collB.drop();
for (var i = 0; i < 200; i++) {
collA.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
collA.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
collB.insert({foo: Math.floor(Math.random() * 2), bar: Math.floor(Math.random() * 2)});
}
function confirmAggSuccess(collName, pipeline) {
const command = {aggregate: collName, cursor: {}};
command.pipeline = pipeline;
assert.commandWorked(testDB.runCommand(command));
}
// Test with non-object fields $limit and $skip.
confirmAggSuccess(collA.getName(), [{$sort: {bar: -1}}, {$limit: 2}, {$match: {foo: {$lte: 2}}}]);
confirmAggSuccess(collA.getName(), [{$sort: {bar: -1}}, {$skip: 50}, {$match: {foo: {$lte: 2}}}]);
confirmAggSuccess(collA.getName(),
[{$sort: {bar: -1}}, {$limit: 2}, {$skip: 50}, {$match: {foo: 0}}]);
// Test non-object field, $unionWith.
confirmAggSuccess(collA.getName(), [{$unionWith: collB.getName()}]);
// Test $limit in $setWindowFields for good measure.
confirmAggSuccess(collA.getName(), [
{$_internalInhibitOptimization: {}},
{
$setWindowFields: {
sortBy: {foo: 1},
output: {sum: {$sum: "$bar", window: {documents: ["unbounded", "current"]}}}
}
},
{$sort: {foo: 1}},
{$limit: 5}
]);
// Test find commands containing non-object fields
assert.commandWorked(testDB.runCommand({find: collA.getName(), limit: 20}));
assert.commandWorked(testDB.runCommand({find: collA.getName(), skip: 199}));
collA.find().skip(100);
// findOne has a nonobject field, $limit.
collB.findOne();
collB.findOne({foo: 1});
// Test non-object field $unwind
confirmAggSuccess(
collA.getName(), [{
"$facet": {
"productOfJoin": [
{"$lookup": {"from": collB.getName(), "pipeline": [{"$match": {}}], "as": "join"}},
{"$unwind": "$join"},
{"$project": {"str": 1}}
]
}
}]);
MongoRunner.stopMongod(conn);
}());

View File

@ -1,15 +1,18 @@
/**
* Test that the telemetry metrics are updated correctly across getMores.
*/
load('jstests/libs/analyze_plan.js');
load("jstests/libs/profiler.js"); // For getLatestProfilerEntry.
(function() {
"use strict";
// Turn on the collection of telemetry metrics.
if (!FeatureFlagUtil.isEnabled(db, "Telemetry")) {
return;
}
// Turn on the collecting of telemetry metrics.
let options = {
setParameter: "internalQueryConfigureTelemetrySamplingRate=2147483647",
setParameter: {internalQueryConfigureTelemetrySamplingRate: 2147483647},
};
const conn = MongoRunner.runMongod(options);
@ -18,6 +21,10 @@ var coll = testDB[jsTestName()];
var collTwo = db[jsTestName() + 'Two'];
coll.drop();
// Make it easier to extract correct telemetry store entry for purposes of this test.
assert.commandWorked(testDB.adminCommand(
{setParameter: 1, internalQueryConfigureTelemetryFieldNameRedactionStrategy: "none"}));
function verifyMetrics(batch) {
batch.forEach(element => {
assert(element.metrics.docsScanned.sum > element.metrics.docsScanned.min);
@ -73,11 +80,14 @@ verifyMetrics(telStore.cursor.firstBatch);
// Ensure that for queries using an index, keys scanned is nonzero.
assert.commandWorked(coll.createIndex({bar: 1}));
coll.aggregate([{$match: {bar: 1}}], {cursor: {batchSize: 2}});
coll.aggregate([{$match: {$or: [{bar: 1, foo: 1}]}}], {cursor: {batchSize: 2}});
// This filters telemetry entries to just the one entered for the above agg command.
telStore = testDB.adminCommand({
aggregate: 1,
pipeline: [{$telemetry: {}}, {$match: {"key.pipeline.$match.bar": {$eq: "###"}}}],
pipeline: [
{$telemetry: {}},
{$match: {"key.pipeline.$match.$or": {$eq: [{'bar': '###', 'foo': '###'}]}}}
],
cursor: {}
});
assert(telStore.cursor.firstBatch[0].metrics.keysScanned.sum > 0);

View File

@ -506,6 +506,8 @@ error_codes:
- {code: 387, name: EncounteredFLEPayloadWhileRedacting}
- {code: 388, name: TransactionTooLargeForCache}
# Error codes 4000-8999 are reserved.
# Non-sequential error codes for compatibility only)

View File

@ -95,9 +95,10 @@ public:
* BinData (0x05)
*/
BSONBinData BinData() const {
uint8_t subtype = ConstDataView(value() + kCountBytes).read<LittleEndian<uint8_t>>();
return {value() + kCountBytes + kBinDataSubTypeBytes,
ConstDataView(value()).read<LittleEndian<int>>(),
static_cast<BinDataType>(*(value() + kCountBytes))};
static_cast<BinDataType>(subtype)};
}
/**

View File

@ -255,7 +255,6 @@ env.Library(
target='async_client',
source=[
'async_client.cpp',
env.Idlc('async_client.idl')[0],
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/wire_version',

View File

@ -35,7 +35,6 @@
#include <memory>
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/client/async_client_gen.h"
#include "mongo/client/authenticate.h"
#include "mongo/client/sasl_client_authenticate.h"
#include "mongo/config.h"
@ -63,6 +62,7 @@
namespace mongo {
MONGO_FAIL_POINT_DEFINE(pauseBeforeMarkKeepOpen);
MONGO_FAIL_POINT_DEFINE(alwaysLogConnAcquisitionToWireTime)
namespace {
bool connHealthMetricsEnabled() {
@ -316,14 +316,14 @@ Future<rpc::UniqueReply> AsyncDBClient::runCommand(
durationCount<Microseconds>(fromConnAcquiredTimer.get()->elapsed());
totalTimeForEgressConnectionAcquiredToWireMicros.increment(timeElapsedMicros);
if (timeElapsedMicros >= 1000 ||
_random.nextCanonicalDouble() <= gConnectionAcquisitionToWireLoggingRate.load()) {
LOGV2_INFO(6496702,
"Acquired connection for remote operation and completed writing to wire",
"durationMicros"_attr = timeElapsedMicros);
} else {
MONGO_unlikely(alwaysLogConnAcquisitionToWireTime.shouldFail())) {
// Log slow acquisition times at info level but rate limit it to prevent spamming
// users.
static auto& logSeverity = *new logv2::SeveritySuppressor{
Seconds{1}, logv2::LogSeverity::Info(), logv2::LogSeverity::Debug(2)};
LOGV2_DEBUG(
6496701,
2,
6496702,
logSeverity().toInt(),
"Acquired connection for remote operation and completed writing to wire",
"durationMicros"_attr = timeElapsedMicros);
}

View File

@ -37,6 +37,7 @@
#include "mongo/executor/network_connection_hook.h"
#include "mongo/executor/remote_command_request.h"
#include "mongo/executor/remote_command_response.h"
#include "mongo/logv2/log_severity_suppressor.h"
#include "mongo/rpc/unique_message.h"
#include "mongo/transport/baton.h"
#include "mongo/transport/message_compressor_manager.h"
@ -51,10 +52,7 @@ public:
explicit AsyncDBClient(const HostAndPort& peer,
transport::SessionHandle session,
ServiceContext* svcCtx)
: _peer(std::move(peer)),
_session(std::move(session)),
_svcCtx(svcCtx),
_random{PseudoRandom(SecureRandom().nextInt64())} {}
: _peer(std::move(peer)), _session(std::move(session)), _svcCtx(svcCtx) {}
using Handle = std::shared_ptr<AsyncDBClient>;
@ -104,6 +102,7 @@ public:
const HostAndPort& remote() const;
const HostAndPort& local() const;
static constexpr Seconds kSlowConnAcquiredToWireLogSuppresionPeriod{5};
private:
Future<executor::RemoteCommandResponse> _continueReceiveExhaustResponse(
@ -123,7 +122,6 @@ private:
transport::SessionHandle _session;
ServiceContext* const _svcCtx;
MessageCompressorManager _compressorManager;
PseudoRandom _random;
};
} // namespace mongo

View File

@ -444,6 +444,30 @@ See
[wtRcToStatus](https://github.com/mongodb/mongo/blob/c799851554dc01493d35b43701416e9c78b3665c/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp#L178-L183)
where we throw the exception in WiredTiger.
See [TemporarilyUnavailableException](https://github.com/mongodb/mongo/blob/c799851554dc01493d35b43701416e9c78b3665c/src/mongo/db/concurrency/temporarily_unavailable_exception.h#L39-L45).
## TransactionTooLargeForCacheException
A TransactionTooLargeForCacheException may be thrown inside the server to indicate that an operation
was rolled-back and is unlikely to ever complete because the storage engine cache is insufficient,
even in the absence of concurrent operations. This is determined by a simple heuristic wherein,
after a rollback, a threshold on the proportion of total dirty cache bytes the running transaction
can represent and still be considered fullfillable is checked. The threshold can be tuned with the
`transactionTooLargeForCacheThreshold` parameter. Setting this threshold to its maximum value (1.0)
causes the check to be skipped and TransactionTooLargeForCacheException to be disabled.
On replica sets, if an operation succeeds on a primary, it should also succeed on a secondary. It
would be possible to convert to both TemporarilyUnavailableException and WriteConflictException,
as if TransactionTooLargeForCacheException was disabled. But on secondaries the only
difference between the two is the rate at which the operation is retried. Hence,
TransactionTooLargeForCacheException is always converted to a WriteConflictException, which retries
faster, to avoid stalling replication longer than necessary.
Prior to 6.3, or when TransactionTooLargeForCacheException is disabled, multi-document
transactions always return a WriteConflictException, which may result in drivers retrying an
operation indefinitely. For non-multi-document operations, there is a limited number of retries on
TemporarilyUnavailableException, but it might still be beneficial to not retry operations which are
unlikely to complete and are disruptive for concurrent operations.
## Collection and Index Writes
Collection write operations (inserts, updates, and deletes) perform storage engine writes to both

View File

@ -133,7 +133,9 @@ void schemaValidationFailed(CollectionValidation::ValidateState* state,
state->setCollectionSchemaViolated();
if (Collection::SchemaValidationResult::kWarn == result) {
// When testing is enabled, only warn about non-compliant documents to prevent test failures.
if (TestingProctor::instance().isEnabled() ||
Collection::SchemaValidationResult::kWarn == result) {
results->warnings.push_back(kSchemaValidationFailedReason);
} else if (Collection::SchemaValidationResult::kError == result) {
results->errors.push_back(kSchemaValidationFailedReason);

View File

@ -57,7 +57,7 @@ void ChangeStreamOptionsManager::create(ServiceContext* service) {
getChangeStreamOptionsManager(service).emplace(service);
}
const ChangeStreamOptions& ChangeStreamOptionsManager::getOptions(OperationContext* opCtx) {
ChangeStreamOptions ChangeStreamOptionsManager::getOptions(OperationContext* opCtx) const {
stdx::lock_guard<Latch> L(_mutex);
return _changeStreamOptions;
}

View File

@ -68,7 +68,7 @@ public:
/**
* Returns the change-streams options.
*/
const ChangeStreamOptions& getOptions(OperationContext* opCtx);
ChangeStreamOptions getOptions(OperationContext* opCtx) const;
/**
* Sets the provided change-streams options. Returns OK on success, otherwise appropriate error
@ -87,7 +87,7 @@ public:
private:
ChangeStreamOptions _changeStreamOptions;
Mutex _mutex = MONGO_MAKE_LATCH("ChangeStreamOptionsManager::mutex");
mutable Mutex _mutex = MONGO_MAKE_LATCH("ChangeStreamOptionsManager::mutex");
};
} // namespace mongo

View File

@ -284,12 +284,21 @@ public:
auto keyPattern = cmd.getKeyPattern().get_value_or({});
const bool estimate = cmd.getEstimate();
AutoGetCollectionForReadCommand collection(opCtx, nss);
Reply reply;
auto collDesc = CollectionShardingState::assertCollectionLockedAndAcquire(opCtx, nss)
->getCollectionDescription(opCtx);
if (collDesc.isSharded()) {
const ShardKeyPattern shardKeyPattern(collDesc.getKeyPattern());
AutoGetCollectionForReadCommand autoColl(opCtx, nss);
const auto& collection = autoColl.getCollection();
if (!collection) {
// Collection does not exist
reply.setNumObjects(0);
reply.setSize(0);
reply.setMillis(timer.millis());
return reply;
}
if (collection.isSharded()) {
const ShardKeyPattern shardKeyPattern(collection.getShardKeyPattern());
uassert(ErrorCodes::BadValue,
"keyPattern must be empty or must be an object that equals the shard key",
keyPattern.isEmpty() ||
@ -307,12 +316,7 @@ public:
max = shardKeyPattern.normalizeShardKey(max);
}
long long numRecords = 0;
if (collection) {
numRecords = collection->numRecords(opCtx);
}
Reply reply;
const long long numRecords = collection->numRecords(opCtx);
reply.setNumObjects(numRecords);
if (numRecords == 0) {
@ -335,10 +339,8 @@ public:
reply.setMillis(timer.millis());
return reply;
}
exec =
InternalPlanner::collectionScan(opCtx,
&collection.getCollection(),
PlanYieldPolicy::YieldPolicy::INTERRUPT_ONLY);
exec = InternalPlanner::collectionScan(
opCtx, &collection, PlanYieldPolicy::YieldPolicy::YIELD_AUTO);
} else {
if (keyPattern.isEmpty()) {
// if keyPattern not provided, try to infer it from the fields in 'min'
@ -346,7 +348,7 @@ public:
}
auto shardKeyIdx = findShardKeyPrefixedIndex(opCtx,
*collection,
collection,
collection->getIndexCatalog(),
keyPattern,
/*requireSingleKey=*/true);
@ -360,14 +362,13 @@ public:
min = Helpers::toKeyFormat(kp.extendRangeBound(min, false));
max = Helpers::toKeyFormat(kp.extendRangeBound(max, false));
exec = InternalPlanner::shardKeyIndexScan(
opCtx,
&collection.getCollection(),
*shardKeyIdx,
min,
max,
BoundInclusion::kIncludeStartKeyOnly,
PlanYieldPolicy::YieldPolicy::INTERRUPT_ONLY);
exec = InternalPlanner::shardKeyIndexScan(opCtx,
&collection,
*shardKeyIdx,
min,
max,
BoundInclusion::kIncludeStartKeyOnly,
PlanYieldPolicy::YieldPolicy::YIELD_AUTO);
}
CurOpFailpointHelpers::waitWhileFailPointEnabled(

View File

@ -712,7 +712,7 @@ public:
// The stats collected here will not get overwritten, as the service entry
// point layer will only set these stats when they're not empty.
CurOp::get(opCtx)->debug().storageStats =
opCtx->recoveryUnit()->getOperationStatistics();
opCtx->recoveryUnit()->computeOperationStatisticsSinceLastCall();
}
} else {
endQueryOp(opCtx, collection, *exec, numResults, cursorId);

View File

@ -919,7 +919,7 @@ private:
// TODO (SERVER-70763): Remove once FCV 7.0 becomes last-lts.
void _removeSchemaOnConfigSettings(
OperationContext* opCtx, const multiversion::FeatureCompatibilityVersion requestedVersion) {
if (!feature_flags::gGlobalIndexesShardingCatalog.isEnabledOnVersion(requestedVersion)) {
if (!feature_flags::gConfigSettingsSchema.isEnabledOnVersion(requestedVersion)) {
LOGV2(6885201, "Removing schema on config.settings");
CollMod collModCmd{NamespaceString::kConfigSettingsNamespace};
collModCmd.getCollModRequest().setValidator(BSONObj());

View File

@ -1225,9 +1225,9 @@ public:
return false;
}
const auto& insertResult = swResult.getValue();
const auto& batch = insertResult.batch;
batches.emplace_back(batch, index);
auto& insertResult = swResult.getValue();
batches.emplace_back(std::move(insertResult.batch), index);
const auto& batch = batches.back().first;
if (isTimeseriesWriteRetryable(opCtx)) {
stmtIds[batch->bucket().id].push_back(stmtId);
}

View File

@ -27,6 +27,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/commands/server_status_core',
'$BUILD_DIR/mongo/db/curop',
'$BUILD_DIR/mongo/db/server_base',
'$BUILD_DIR/mongo/db/server_options_servers',
'$BUILD_DIR/mongo/db/storage/recovery_unit_base',

View File

@ -33,6 +33,7 @@
#include "mongo/db/concurrency/exception_util_gen.h"
#include "mongo/db/namespace_string.h"
#include "mongo/logv2/log.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/duration.h"
#include "mongo/util/log_and_backoff.h"
@ -59,6 +60,11 @@ CounterMetric temporarilyUnavailableErrorsEscaped{"operation.temporarilyUnavaila
CounterMetric temporarilyUnavailableErrorsConvertedToWriteConflict{
"operation.temporarilyUnavailableErrorsConvertedToWriteConflict"};
CounterMetric transactionTooLargeForCacheErrors{"operation.transactionTooLargeForCacheErrors"};
CounterMetric transactionTooLargeForCacheErrorsConvertedToWriteConflict{
"operation.transactionTooLargeForCacheErrorsConvertedToWriteConflict"};
} // namespace
void handleTemporarilyUnavailableException(OperationContext* opCtx,
@ -66,6 +72,8 @@ void handleTemporarilyUnavailableException(OperationContext* opCtx,
StringData opStr,
StringData ns,
const TemporarilyUnavailableException& e) {
CurOp::get(opCtx)->debug().additiveMetrics.incrementTemporarilyUnavailableErrors(1);
opCtx->recoveryUnit()->abandonSnapshot();
temporarilyUnavailableErrors.increment(1);
if (opCtx->getClient()->isFromUserConnection() &&
@ -107,4 +115,27 @@ void handleTemporarilyUnavailableExceptionInTransaction(OperationContext* opCtx,
throwWriteConflictException(e.reason());
}
void handleTransactionTooLargeForCacheException(OperationContext* opCtx,
int* writeConflictAttempts,
StringData opStr,
StringData ns,
const TransactionTooLargeForCacheException& e) {
transactionTooLargeForCacheErrors.increment(1);
if (opCtx->writesAreReplicated()) {
// Surface error on primaries.
throw e;
}
// If an operation succeeds on primary, it should always be retried on secondaries. Secondaries
// always retry TemporarilyUnavailableExceptions and WriteConflictExceptions indefinitely, the
// only difference being the rate of retry. We prefer retrying faster, by converting to
// WriteConflictException, to avoid stalling replication longer than necessary.
transactionTooLargeForCacheErrorsConvertedToWriteConflict.increment(1);
// Handle as write conflict.
CurOp::get(opCtx)->debug().additiveMetrics.incrementWriteConflicts(1);
logWriteConflictAndBackoff(*writeConflictAttempts, opStr, ns);
++(*writeConflictAttempts);
opCtx->recoveryUnit()->abandonSnapshot();
}
} // namespace mongo

View File

@ -61,6 +61,12 @@ void handleTemporarilyUnavailableExceptionInTransaction(OperationContext* opCtx,
StringData ns,
const TemporarilyUnavailableException& e);
void handleTransactionTooLargeForCacheException(OperationContext* opCtx,
int* writeConflictAttempts,
StringData opStr,
StringData ns,
const TransactionTooLargeForCacheException& e);
/**
* A `WriteConflictException` is thrown if during a write, two or more operations conflict with each
* other. For example if two operations get the same version of a document, and then both try to
@ -84,6 +90,16 @@ void handleTemporarilyUnavailableExceptionInTransaction(OperationContext* opCtx,
iasserted({ErrorCodes::TemporarilyUnavailable, context});
}
/**
* A `TransactionTooLargeForCache` is thrown if it has been determined that it is unlikely to
* ever complete the operation because the configured cache is insufficient to hold all the
* transaction state. This helps to avoid retrying, maybe indefinitely, a transaction which would
* never be able to complete.
*/
[[noreturn]] inline void throwTransactionTooLargeForCache(StringData context) {
iasserted({ErrorCodes::TransactionTooLargeForCache, context});
}
/**
* Runs the argument function f as many times as needed for f to complete or throw an exception
* other than WriteConflictException or TemporarilyUnavailableException. For each time f throws
@ -119,19 +135,20 @@ auto writeConflictRetry(OperationContext* opCtx, StringData opStr, StringData ns
}
}
int attempts = 0;
int writeConflictAttempts = 0;
int attemptsTempUnavailable = 0;
while (true) {
try {
return f();
} catch (WriteConflictException const&) {
CurOp::get(opCtx)->debug().additiveMetrics.incrementWriteConflicts(1);
logWriteConflictAndBackoff(attempts, opStr, ns);
++attempts;
logWriteConflictAndBackoff(writeConflictAttempts, opStr, ns);
++writeConflictAttempts;
opCtx->recoveryUnit()->abandonSnapshot();
} catch (TemporarilyUnavailableException const& e) {
CurOp::get(opCtx)->debug().additiveMetrics.incrementTemporarilyUnavailableErrors(1);
handleTemporarilyUnavailableException(opCtx, ++attemptsTempUnavailable, opStr, ns, e);
} catch (TransactionTooLargeForCacheException const& e) {
handleTransactionTooLargeForCacheException(opCtx, &writeConflictAttempts, opStr, ns, e);
}
}
}

View File

@ -57,3 +57,18 @@ server_parameters:
default: 1000
validator:
gte: 0
transactionTooLargeForCacheThreshold:
description: "Threshold on the proportion of total dirty cache bytes that the running
transaction's dirty cache bytes can represent and still be considered
fullfillable on retry. If this threshold is exceeded, a
TransactionTooLargeForCache exception is thrown. Setting this parameter to 1.0
causes this check to be disabled, and TransactionTooLargeForCache exceptions
will not be thrown."
set_at: [ startup, runtime ]
cpp_varname: 'gTransactionTooLargeForCacheThreshold'
cpp_vartype: AtomicWord<double>
default: 0.75
validator:
gte: 0.0
lte: 1.0

View File

@ -479,7 +479,8 @@ bool CurOp::completeAndLogOperation(OperationContext* opCtx,
MODE_IS,
Date_t::now() + Milliseconds(500),
Lock::InterruptBehavior::kThrow);
_debug.storageStats = opCtx->recoveryUnit()->getOperationStatistics();
_debug.storageStats =
opCtx->recoveryUnit()->computeOperationStatisticsSinceLastCall();
} catch (const DBException& ex) {
LOGV2_WARNING_OPTIONS(20526,
{component},

View File

@ -326,7 +326,7 @@ public:
AdditiveMetrics additiveMetrics;
// Stores storage statistics.
std::shared_ptr<StorageStats> storageStats;
std::unique_ptr<StorageStats> storageStats;
bool waitingForFlowControl{false};

View File

@ -248,6 +248,11 @@ boost::optional<StringData> checkComparisonPredicateErrors(
return "can't handle a computed field"_sd;
}
// We must avoid mapping predicates on fields removed by $project.
if (!determineIncludeField(matchExprPath, bucketSpec.behavior(), bucketSpec.fieldSet())) {
return "can't handle a field removed by projection"_sd;
}
const auto isTimeField = (matchExprPath == bucketSpec.timeField());
if (isTimeField && matchExprData.type() != BSONType::Date) {
// Users are not allowed to insert non-date measurements into time field. So this query
@ -885,10 +890,8 @@ std::pair<bool, BSONObj> BucketSpec::pushdownPredicate(
metaField.map([](StringData s) { return s.toString(); }),
// Since we are operating on a collection, not a query-result,
// there are no inclusion/exclusion projections we need to apply
// to the buckets before unpacking.
{},
// And there are no computed projections.
{},
// to the buckets before unpacking. So we can use default values for the rest of
// the arguments.
},
maxSpanSeconds,
collationMatchesDefault,
@ -924,7 +927,6 @@ public:
int j,
const BucketSpec& spec,
const std::set<std::string>& unpackFieldsToIncludeExclude,
BucketUnpacker::Behavior behavior,
const BSONObj& bucket,
const Value& metaValue,
bool includeTimeField,
@ -976,7 +978,6 @@ public:
int j,
const BucketSpec& spec,
const std::set<std::string>& unpackFieldsToIncludeExclude,
BucketUnpacker::Behavior behavior,
const BSONObj& bucket,
const Value& metaValue,
bool includeTimeField,
@ -988,7 +989,7 @@ private:
BSONObjIterator _timeFieldIter;
// Iterators used to unpack the columns of the above bucket that are populated during the reset
// phase according to the provided 'Behavior' and 'BucketSpec'.
// phase according to the provided 'BucketSpec'.
std::vector<std::pair<std::string, BSONObjIterator>> _fieldIters;
};
@ -1063,7 +1064,6 @@ void BucketUnpackerV1::extractSingleMeasurement(
int j,
const BucketSpec& spec,
const std::set<std::string>& unpackFieldsToIncludeExclude,
BucketUnpacker::Behavior behavior,
const BSONObj& bucket,
const Value& metaValue,
bool includeTimeField,
@ -1078,7 +1078,7 @@ void BucketUnpackerV1::extractSingleMeasurement(
for (auto&& dataElem : dataRegion) {
const auto& colName = dataElem.fieldNameStringData();
if (!determineIncludeField(colName, behavior, unpackFieldsToIncludeExclude)) {
if (!determineIncludeField(colName, spec.behavior(), unpackFieldsToIncludeExclude)) {
continue;
}
auto value = dataElem[targetIdx];
@ -1110,7 +1110,6 @@ public:
int j,
const BucketSpec& spec,
const std::set<std::string>& unpackFieldsToIncludeExclude,
BucketUnpacker::Behavior behavior,
const BSONObj& bucket,
const Value& metaValue,
bool includeTimeField,
@ -1140,7 +1139,7 @@ private:
ColumnStore _timeColumn;
// Iterators used to unpack the columns of the above bucket that are populated during the reset
// phase according to the provided 'Behavior' and 'BucketSpec'.
// phase according to the provided 'BucketSpec'.
std::vector<ColumnStore> _fieldColumns;
// Element count
@ -1200,7 +1199,6 @@ void BucketUnpackerV2::extractSingleMeasurement(
int j,
const BucketSpec& spec,
const std::set<std::string>& unpackFieldsToIncludeExclude,
BucketUnpacker::Behavior behavior,
const BSONObj& bucket,
const Value& metaValue,
bool includeTimeField,
@ -1236,9 +1234,11 @@ std::size_t BucketUnpackerV2::numberOfFields() {
BucketSpec::BucketSpec(const std::string& timeField,
const boost::optional<std::string>& metaField,
const std::set<std::string>& fields,
Behavior behavior,
const std::set<std::string>& computedProjections,
bool usesExtendedRange)
: _fieldSet(fields),
_behavior(behavior),
_computedMetaProjFields(computedProjections),
_timeField(timeField),
_timeFieldHashed(FieldNameHasher().hashedFieldName(_timeField)),
@ -1251,6 +1251,7 @@ BucketSpec::BucketSpec(const std::string& timeField,
BucketSpec::BucketSpec(const BucketSpec& other)
: _fieldSet(other._fieldSet),
_behavior(other._behavior),
_computedMetaProjFields(other._computedMetaProjFields),
_timeField(other._timeField),
_timeFieldHashed(HashedFieldName{_timeField, other._timeFieldHashed->hash()}),
@ -1263,6 +1264,7 @@ BucketSpec::BucketSpec(const BucketSpec& other)
BucketSpec::BucketSpec(BucketSpec&& other)
: _fieldSet(std::move(other._fieldSet)),
_behavior(other._behavior),
_computedMetaProjFields(std::move(other._computedMetaProjFields)),
_timeField(std::move(other._timeField)),
_timeFieldHashed(HashedFieldName{_timeField, other._timeFieldHashed->hash()}),
@ -1276,6 +1278,7 @@ BucketSpec::BucketSpec(BucketSpec&& other)
BucketSpec& BucketSpec::operator=(const BucketSpec& other) {
if (&other != this) {
_fieldSet = other._fieldSet;
_behavior = other._behavior;
_computedMetaProjFields = other._computedMetaProjFields;
_timeField = other._timeField;
_timeFieldHashed = HashedFieldName{_timeField, other._timeFieldHashed->hash()};
@ -1325,8 +1328,8 @@ BucketUnpacker::BucketUnpacker(BucketUnpacker&& other) = default;
BucketUnpacker::~BucketUnpacker() = default;
BucketUnpacker& BucketUnpacker::operator=(BucketUnpacker&& rhs) = default;
BucketUnpacker::BucketUnpacker(BucketSpec spec, Behavior unpackerBehavior) {
setBucketSpecAndBehavior(std::move(spec), unpackerBehavior);
BucketUnpacker::BucketUnpacker(BucketSpec spec) {
setBucketSpec(std::move(spec));
}
void BucketUnpacker::addComputedMetaProjFields(const std::vector<StringData>& computedFieldNames) {
@ -1335,7 +1338,7 @@ void BucketUnpacker::addComputedMetaProjFields(const std::vector<StringData>& co
// If we're already specifically including fields, we need to add the computed fields to
// the included field set to indicate they're in the output doc.
if (_unpackerBehavior == BucketUnpacker::Behavior::kInclude) {
if (_spec.behavior() == BucketSpec::Behavior::kInclude) {
_spec.addIncludeExcludeField(field);
} else {
// Since exclude is applied after addComputedMetaProjFields, we must erase the new field
@ -1387,7 +1390,6 @@ Document BucketUnpacker::extractSingleMeasurement(int j) {
j,
_spec,
fieldsToIncludeExcludeDuringUnpack(),
_unpackerBehavior,
_bucket,
_metaValue,
_includeTimeField,
@ -1501,10 +1503,10 @@ void BucketUnpacker::reset(BSONObj&& bucket, bool bucketMatchedQuery) {
continue;
}
// Includes a field when '_unpackerBehavior' is 'kInclude' and it's found in 'fieldSet' or
// _unpackerBehavior is 'kExclude' and it's not found in 'fieldSet'.
// Includes a field when '_spec.behavior()' is 'kInclude' and it's found in 'fieldSet' or
// _spec.behavior() is 'kExclude' and it's not found in 'fieldSet'.
if (determineIncludeField(
colName, _unpackerBehavior, fieldsToIncludeExcludeDuringUnpack())) {
colName, _spec.behavior(), fieldsToIncludeExcludeDuringUnpack())) {
_unpackingImpl->addField(elem);
}
}
@ -1555,7 +1557,7 @@ int BucketUnpacker::computeMeasurementCount(const BSONObj& bucket, StringData ti
}
void BucketUnpacker::determineIncludeTimeField() {
const bool isInclude = _unpackerBehavior == BucketUnpacker::Behavior::kInclude;
const bool isInclude = _spec.behavior() == BucketSpec::Behavior::kInclude;
const bool fieldSetContainsTime =
_spec.fieldSet().find(_spec.timeField()) != _spec.fieldSet().end();
@ -1575,22 +1577,21 @@ void BucketUnpacker::eraseMetaFromFieldSetAndDetermineIncludeMeta() {
} else if (auto itr = _spec.fieldSet().find(*_spec.metaField());
itr != _spec.fieldSet().end()) {
_spec.removeIncludeExcludeField(*_spec.metaField());
_includeMetaField = _unpackerBehavior == BucketUnpacker::Behavior::kInclude;
_includeMetaField = _spec.behavior() == BucketSpec::Behavior::kInclude;
} else {
_includeMetaField = _unpackerBehavior == BucketUnpacker::Behavior::kExclude;
_includeMetaField = _spec.behavior() == BucketSpec::Behavior::kExclude;
}
}
void BucketUnpacker::eraseExcludedComputedMetaProjFields() {
if (_unpackerBehavior == BucketUnpacker::Behavior::kExclude) {
if (_spec.behavior() == BucketSpec::Behavior::kExclude) {
for (const auto& field : _spec.fieldSet()) {
_spec.eraseFromComputedMetaProjFields(field);
}
}
}
void BucketUnpacker::setBucketSpecAndBehavior(BucketSpec&& bucketSpec, Behavior behavior) {
_unpackerBehavior = behavior;
void BucketUnpacker::setBucketSpec(BucketSpec&& bucketSpec) {
_spec = std::move(bucketSpec);
eraseMetaFromFieldSetAndDetermineIncludeMeta();
@ -1616,7 +1617,7 @@ const std::set<std::string>& BucketUnpacker::fieldsToIncludeExcludeDuringUnpack(
_unpackFieldsToIncludeExclude = std::set<std::string>();
const auto& metaProjFields = _spec.computedMetaProjFields();
if (_unpackerBehavior == BucketUnpacker::Behavior::kInclude) {
if (_spec.behavior() == BucketSpec::Behavior::kInclude) {
// For include, we unpack fieldSet - metaProjFields.
for (auto&& field : _spec.fieldSet()) {
if (metaProjFields.find(field) == metaProjFields.cend()) {

View File

@ -54,10 +54,16 @@ namespace mongo {
*/
class BucketSpec {
public:
// When unpackin buckets with kInclude we must produce measurements that contain the
// set of fields. Otherwise, if the kExclude option is used, the measurements will include the
// set difference between all fields in the bucket and the provided fields.
enum class Behavior { kInclude, kExclude };
BucketSpec() = default;
BucketSpec(const std::string& timeField,
const boost::optional<std::string>& metaField,
const std::set<std::string>& fields = {},
Behavior behavior = Behavior::kExclude,
const std::set<std::string>& computedProjections = {},
bool usesExtendedRange = false);
BucketSpec(const BucketSpec&);
@ -93,6 +99,14 @@ public:
return _fieldSet;
}
void setBehavior(Behavior behavior) {
_behavior = behavior;
}
Behavior behavior() const {
return _behavior;
}
void addComputedMetaProjFields(const StringData& field) {
_computedMetaProjFields.emplace(field);
}
@ -211,6 +225,7 @@ public:
private:
// The set of field names in the data region that should be included or excluded.
std::set<std::string> _fieldSet;
Behavior _behavior = Behavior::kExclude;
// Set of computed meta field projection names. Added at the end of materialized
// measurements.
@ -229,10 +244,6 @@ private:
*/
class BucketUnpacker {
public:
// When BucketUnpacker is created with kInclude it must produce measurements that contain the
// set of fields. Otherwise, if the kExclude option is used, the measurements will include the
// set difference between all fields in the bucket and the provided fields.
enum class Behavior { kInclude, kExclude };
/**
* Returns the number of measurements in the bucket in O(1) time.
*/
@ -242,7 +253,7 @@ public:
static const std::set<StringData> reservedBucketFieldNames;
BucketUnpacker();
BucketUnpacker(BucketSpec spec, Behavior unpackerBehavior);
BucketUnpacker(BucketSpec spec);
BucketUnpacker(const BucketUnpacker& other) = delete;
BucketUnpacker(BucketUnpacker&& other);
~BucketUnpacker();
@ -274,7 +285,6 @@ public:
*/
BucketUnpacker copy() const {
BucketUnpacker unpackerCopy;
unpackerCopy._unpackerBehavior = _unpackerBehavior;
unpackerCopy._spec = _spec;
unpackerCopy._includeMetaField = _includeMetaField;
unpackerCopy._includeTimeField = _includeTimeField;
@ -286,8 +296,8 @@ public:
*/
void reset(BSONObj&& bucket, bool bucketMatchedQuery = false);
Behavior behavior() const {
return _unpackerBehavior;
BucketSpec::Behavior behavior() const {
return _spec.behavior();
}
const BucketSpec& bucketSpec() const {
@ -338,7 +348,7 @@ public:
return std::string{timeseries::kControlMaxFieldNamePrefix} + field;
}
void setBucketSpecAndBehavior(BucketSpec&& bucketSpec, Behavior behavior);
void setBucketSpec(BucketSpec&& bucketSpec);
void setIncludeMinTimeAsMetadata();
void setIncludeMaxTimeAsMetadata();
@ -363,7 +373,6 @@ private:
void eraseExcludedComputedMetaProjFields();
BucketSpec _spec;
Behavior _unpackerBehavior;
std::unique_ptr<UnpackingImpl> _unpackingImpl;
@ -418,9 +427,9 @@ private:
* Determines if an arbitrary field should be included in the materialized measurements.
*/
inline bool determineIncludeField(StringData fieldName,
BucketUnpacker::Behavior unpackerBehavior,
BucketSpec::Behavior unpackerBehavior,
const std::set<std::string>& unpackFieldsToIncludeExclude) {
const bool isInclude = unpackerBehavior == BucketUnpacker::Behavior::kInclude;
const bool isInclude = unpackerBehavior == BucketSpec::Behavior::kInclude;
const bool unpackFieldsContains = unpackFieldsToIncludeExclude.find(fieldName.toString()) !=
unpackFieldsToIncludeExclude.cend();
return isInclude == unpackFieldsContains;

View File

@ -57,12 +57,12 @@ public:
* before actually doing any unpacking.
*/
BucketUnpacker makeBucketUnpacker(std::set<std::string> fields,
BucketUnpacker::Behavior behavior,
BucketSpec::Behavior behavior,
BSONObj bucket,
boost::optional<std::string> metaFieldName = boost::none) {
auto spec = BucketSpec{kUserDefinedTimeName.toString(), metaFieldName, std::move(fields)};
BucketUnpacker unpacker{std::move(spec), behavior};
auto spec =
BucketSpec{kUserDefinedTimeName.toString(), metaFieldName, std::move(fields), behavior};
BucketUnpacker unpacker{std::move(spec)};
unpacker.reset(std::move(bucket));
return unpacker;
}
@ -72,12 +72,13 @@ public:
* the given 'bucket'. Asserts that 'reset()' throws the given 'errorCode'.
*/
void assertUnpackerThrowsCode(std::set<std::string> fields,
BucketUnpacker::Behavior behavior,
BucketSpec::Behavior behavior,
BSONObj bucket,
boost::optional<std::string> metaFieldName,
int errorCode) {
auto spec = BucketSpec{kUserDefinedTimeName.toString(), metaFieldName, std::move(fields)};
BucketUnpacker unpacker{std::move(spec), behavior};
auto spec =
BucketSpec{kUserDefinedTimeName.toString(), metaFieldName, std::move(fields), behavior};
BucketUnpacker unpacker{std::move(spec)};
ASSERT_THROWS_CODE(unpacker.reset(std::move(bucket)), AssertionException, errorCode);
}
@ -178,7 +179,7 @@ TEST_F(BucketUnpackerTest, UnpackBasicIncludeAllMeasurementFields) {
"a:{'0':1, '1':2}, b:{'1':1}}}");
auto unpacker = makeBucketUnpacker(std::move(fields),
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(bucket),
kUserDefinedMetaName.toString());
@ -202,7 +203,7 @@ TEST_F(BucketUnpackerTest, ExcludeASingleField) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
@ -231,7 +232,7 @@ TEST_F(BucketUnpackerTest, EmptyIncludeGetsEmptyMeasurements) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(bucket),
kUserDefinedMetaName.toString());
@ -258,7 +259,7 @@ TEST_F(BucketUnpackerTest, EmptyExcludeMaterializesAllFields) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -287,7 +288,7 @@ TEST_F(BucketUnpackerTest, SparseColumnsWhereOneColumnIsExhaustedBeforeTheOther)
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -315,7 +316,7 @@ TEST_F(BucketUnpackerTest, UnpackBasicIncludeWithDollarPrefix) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -343,7 +344,7 @@ TEST_F(BucketUnpackerTest, BucketsWithMetadataOnly) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -370,7 +371,7 @@ TEST_F(BucketUnpackerTest, UnorderedRowKeysDoesntAffectMaterialization) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -400,7 +401,7 @@ TEST_F(BucketUnpackerTest, MissingMetaFieldDoesntMaterializeMetadata) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -428,7 +429,7 @@ TEST_F(BucketUnpackerTest, MissingMetaFieldDoesntMaterializeMetadataUnorderedKey
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -456,7 +457,7 @@ TEST_F(BucketUnpackerTest, ExcludedMetaFieldDoesntMaterializeMetadataWhenBucketH
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -484,7 +485,7 @@ TEST_F(BucketUnpackerTest, UnpackerResetThrowsOnUndefinedMeta) {
auto test = [&](BSONObj bucket) {
assertUnpackerThrowsCode(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString(),
5369600);
@ -505,7 +506,7 @@ TEST_F(BucketUnpackerTest, UnpackerResetThrowsOnUnexpectedMeta) {
auto test = [&](BSONObj bucket) {
assertUnpackerThrowsCode(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
boost::none /* no metaField provided */,
5369601);
@ -525,7 +526,7 @@ TEST_F(BucketUnpackerTest, NullMetaInBucketMaterializesAsNull) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -558,7 +559,7 @@ TEST_F(BucketUnpackerTest, GetNextHandlesMissingMetaInBucket) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(fields,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
std::move(bucket),
kUserDefinedMetaName.toString());
ASSERT_TRUE(unpacker.hasNext());
@ -588,7 +589,7 @@ TEST_F(BucketUnpackerTest, EmptyDataRegionInBucketIsTolerated) {
auto test = [&](BSONObj bucket) {
auto unpacker = makeBucketUnpacker(
fields, BucketUnpacker::Behavior::kExclude, bucket, kUserDefinedMetaName.toString());
fields, BucketSpec::Behavior::kExclude, bucket, kUserDefinedMetaName.toString());
ASSERT_FALSE(unpacker.hasNext());
};
@ -600,7 +601,7 @@ TEST_F(BucketUnpackerTest, UnpackerResetThrowsOnEmptyBucket) {
auto bucket = Document{};
assertUnpackerThrowsCode(std::move(fields),
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
bucket.toBson(),
kUserDefinedMetaName.toString(),
5346510);
@ -618,48 +619,52 @@ TEST_F(BucketUnpackerTest, EraseMetaFromFieldSetAndDetermineIncludeMeta) {
}
})");
auto unpacker = makeBucketUnpacker(empFields,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(bucket),
kUserDefinedMetaName.toString());
// Tests a spec with 'metaField' in include list.
std::set<std::string> fields{kUserDefinedMetaName.toString()};
auto specWithMetaInclude = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(fields)};
auto specWithMetaInclude = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fields),
BucketSpec::Behavior::kInclude};
// This calls eraseMetaFromFieldSetAndDetermineIncludeMeta.
unpacker.setBucketSpecAndBehavior(std::move(specWithMetaInclude),
BucketUnpacker::Behavior::kInclude);
unpacker.setBucketSpec(std::move(specWithMetaInclude));
ASSERT_TRUE(unpacker.includeMetaField());
ASSERT_EQ(unpacker.bucketSpec().fieldSet().count(kUserDefinedMetaName.toString()), 0);
std::set<std::string> fieldsNoMetaInclude{"foo"};
auto specWithFooInclude = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fieldsNoMetaInclude)};
std::move(fieldsNoMetaInclude),
BucketSpec::Behavior::kInclude};
std::set<std::string> fieldsNoMetaExclude{"foo"};
auto specWithFooExclude = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fieldsNoMetaExclude)};
std::move(fieldsNoMetaExclude),
BucketSpec::Behavior::kExclude};
unpacker.setBucketSpecAndBehavior(std::move(specWithFooExclude),
BucketUnpacker::Behavior::kExclude);
unpacker.setBucketSpec(std::move(specWithFooExclude));
ASSERT_TRUE(unpacker.includeMetaField());
unpacker.setBucketSpecAndBehavior(std::move(specWithFooInclude),
BucketUnpacker::Behavior::kInclude);
unpacker.setBucketSpec(std::move(specWithFooInclude));
ASSERT_FALSE(unpacker.includeMetaField());
// Tests a spec with 'metaField' not in exclude list.
std::set<std::string> excludeFields{};
auto specMetaExclude = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(excludeFields)};
auto specMetaExclude = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(excludeFields),
BucketSpec::Behavior::kExclude};
auto specMetaInclude = specMetaExclude;
unpacker.setBucketSpecAndBehavior(std::move(specMetaExclude),
BucketUnpacker::Behavior::kExclude);
specMetaInclude.setBehavior(BucketSpec::Behavior::kInclude);
unpacker.setBucketSpec(std::move(specMetaExclude));
ASSERT_TRUE(unpacker.includeMetaField());
unpacker.setBucketSpecAndBehavior(std::move(specMetaInclude),
BucketUnpacker::Behavior::kInclude);
unpacker.setBucketSpec(std::move(specMetaInclude));
ASSERT_FALSE(unpacker.includeMetaField());
}
@ -674,21 +679,25 @@ TEST_F(BucketUnpackerTest, DetermineIncludeTimeField) {
})");
std::set<std::string> unpackerFields{kUserDefinedTimeName.toString()};
auto unpacker = makeBucketUnpacker(unpackerFields,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(bucket),
kUserDefinedMetaName.toString());
std::set<std::string> includeFields{kUserDefinedTimeName.toString()};
auto includeSpec = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(includeFields)};
auto includeSpec = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(includeFields),
BucketSpec::Behavior::kInclude};
// This calls determineIncludeTimeField.
unpacker.setBucketSpecAndBehavior(std::move(includeSpec), BucketUnpacker::Behavior::kInclude);
unpacker.setBucketSpec(std::move(includeSpec));
ASSERT_TRUE(unpacker.includeTimeField());
std::set<std::string> excludeFields{kUserDefinedTimeName.toString()};
auto excludeSpec = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(excludeFields)};
unpacker.setBucketSpecAndBehavior(std::move(excludeSpec), BucketUnpacker::Behavior::kExclude);
auto excludeSpec = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(excludeFields),
BucketSpec::Behavior::kExclude};
unpacker.setBucketSpec(std::move(excludeSpec));
ASSERT_FALSE(unpacker.includeTimeField());
}
@ -703,24 +712,26 @@ TEST_F(BucketUnpackerTest, DetermineIncludeFieldIncludeMode) {
{"data", Document{}}}
.toBson();
auto spec = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(fields)};
auto spec = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fields),
BucketSpec::Behavior::kInclude};
BucketUnpacker includeUnpacker;
includeUnpacker.setBucketSpecAndBehavior(std::move(spec), BucketUnpacker::Behavior::kInclude);
includeUnpacker.setBucketSpec(std::move(spec));
// Need to call reset so that the private method calculateFieldsToIncludeExcludeDuringUnpack()
// is called, and _unpackFieldsToIncludeExclude gets filled with fields.
includeUnpacker.reset(std::move(bucket));
// Now the spec knows which fields to include/exclude.
ASSERT_TRUE(determineIncludeField(kUserDefinedTimeName,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
includeUnpacker.fieldsToIncludeExcludeDuringUnpack()));
ASSERT_TRUE(determineIncludeField(includedMeasurementField,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
includeUnpacker.fieldsToIncludeExcludeDuringUnpack()));
ASSERT_FALSE(determineIncludeField(excludedMeasurementField,
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
includeUnpacker.fieldsToIncludeExcludeDuringUnpack()));
}
@ -735,21 +746,23 @@ TEST_F(BucketUnpackerTest, DetermineIncludeFieldExcludeMode) {
{"data", Document{}}}
.toBson();
auto spec = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(fields)};
auto spec = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fields),
BucketSpec::Behavior::kExclude};
BucketUnpacker excludeUnpacker;
excludeUnpacker.setBucketSpecAndBehavior(std::move(spec), BucketUnpacker::Behavior::kExclude);
excludeUnpacker.setBucketSpec(std::move(spec));
excludeUnpacker.reset(std::move(bucket));
ASSERT_FALSE(determineIncludeField(kUserDefinedTimeName,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
excludeUnpacker.fieldsToIncludeExcludeDuringUnpack()));
ASSERT_FALSE(determineIncludeField(includedMeasurementField,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
excludeUnpacker.fieldsToIncludeExcludeDuringUnpack()));
ASSERT_TRUE(determineIncludeField(excludedMeasurementField,
BucketUnpacker::Behavior::kExclude,
BucketSpec::Behavior::kExclude,
excludeUnpacker.fieldsToIncludeExcludeDuringUnpack()));
}
@ -767,9 +780,11 @@ auto expectedTimestampObjSize(int32_t rowKeyOffset, int32_t n) {
TEST_F(BucketUnpackerTest, ExtractSingleMeasurement) {
std::set<std::string> fields{
"_id", kUserDefinedMetaName.toString(), kUserDefinedTimeName.toString(), "a", "b"};
auto spec = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(fields)};
auto unpacker = BucketUnpacker{std::move(spec), BucketUnpacker::Behavior::kInclude};
auto spec = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fields),
BucketSpec::Behavior::kInclude};
auto unpacker = BucketUnpacker{std::move(spec)};
auto d1 = dateFromISOString("2020-02-17T00:00:00.000Z").getValue();
auto d2 = dateFromISOString("2020-02-17T01:00:00.000Z").getValue();
@ -812,9 +827,11 @@ TEST_F(BucketUnpackerTest, ExtractSingleMeasurement) {
TEST_F(BucketUnpackerTest, ExtractSingleMeasurementSparse) {
std::set<std::string> fields{
"_id", kUserDefinedMetaName.toString(), kUserDefinedTimeName.toString(), "a", "b"};
auto spec = BucketSpec{
kUserDefinedTimeName.toString(), kUserDefinedMetaName.toString(), std::move(fields)};
auto unpacker = BucketUnpacker{std::move(spec), BucketUnpacker::Behavior::kInclude};
auto spec = BucketSpec{kUserDefinedTimeName.toString(),
kUserDefinedMetaName.toString(),
std::move(fields),
BucketSpec::Behavior::kInclude};
auto unpacker = BucketUnpacker{std::move(spec)};
auto d1 = dateFromISOString("2020-02-17T00:00:00.000Z").getValue();
auto d2 = dateFromISOString("2020-02-17T01:00:00.000Z").getValue();
@ -902,7 +919,7 @@ TEST_F(BucketUnpackerTest, TamperedCompressedCountLess) {
auto modifiedCompressedBucket = modifyCompressedBucketElementCount(*compressedBucket, -1);
auto unpacker = makeBucketUnpacker(std::move(fields),
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(modifiedCompressedBucket),
kUserDefinedMetaName.toString());
@ -938,7 +955,7 @@ TEST_F(BucketUnpackerTest, TamperedCompressedCountMore) {
auto modifiedCompressedBucket = modifyCompressedBucketElementCount(*compressedBucket, 1);
auto unpacker = makeBucketUnpacker(std::move(fields),
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(modifiedCompressedBucket),
kUserDefinedMetaName.toString());
@ -974,7 +991,7 @@ TEST_F(BucketUnpackerTest, TamperedCompressedCountMissing) {
auto modifiedCompressedBucket = modifyCompressedBucketElementCount(*compressedBucket, 0);
auto unpacker = makeBucketUnpacker(std::move(fields),
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(modifiedCompressedBucket),
kUserDefinedMetaName.toString());
@ -1012,7 +1029,7 @@ TEST_F(BucketUnpackerTest, TamperedCompressedElementMismatchDataField) {
modifyCompressedBucketRemoveLastInField(*compressedBucket, "a"_sd);
auto unpacker = makeBucketUnpacker(std::move(fields),
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(modifiedCompressedBucket),
kUserDefinedMetaName.toString());
@ -1048,7 +1065,7 @@ TEST_F(BucketUnpackerTest, TamperedCompressedElementMismatchTimeField) {
modifyCompressedBucketRemoveLastInField(*compressedBucket, "time"_sd);
auto unpacker = makeBucketUnpacker(std::move(fields),
BucketUnpacker::Behavior::kInclude,
BucketSpec::Behavior::kInclude,
std::move(modifiedCompressedBucket),
kUserDefinedMetaName.toString());

View File

@ -1033,7 +1033,9 @@ inline size_t getBSONBinDataSize(TypeTags tag, Value val) {
inline BinDataType getBSONBinDataSubtype(TypeTags tag, Value val) {
invariant(tag == TypeTags::bsonBinData);
return static_cast<BinDataType>((getRawPointerView(val) + sizeof(uint32_t))[0]);
uint8_t subtype =
ConstDataView(getRawPointerView(val) + sizeof(uint32_t)).read<LittleEndian<uint8_t>>();
return static_cast<BinDataType>(subtype);
}
inline uint8_t* getBSONBinData(TypeTags tag, Value val) {

View File

@ -82,8 +82,12 @@ public:
auto result = CommandHelpers::runCommandDirectly(
opCtx,
OpMsgRequest::fromDBAndBody(
ns.db(), BSON("collStats" << ns.coll() << "waitForLock" << false)));
builder.append(nsStr, result);
ns.db(),
BSON("aggregate" << ns.coll() << "cursor" << BSONObj{} << "pipeline"
<< BSON_ARRAY(BSON("$collStats" << BSON(
"storageStats" << BSON(
"waitForLock" << false)))))));
builder.append(nsStr, result["cursor"]["firstBatch"]["0"].Obj());
} catch (...) {
Status s = exceptionToStatus();
@ -110,14 +114,16 @@ void registerMongoDCollectors(FTDCController* controller) {
BSON("replSetGetStatus" << 1 << "initialSync" << 0)));
// CollectionStats
controller->addPeriodicCollector(
std::make_unique<FTDCSimpleInternalCommandCollector>("collStats",
"local.oplog.rs.stats",
"local",
BSON("collStats"
<< "oplog.rs"
<< "waitForLock" << false
<< "numericOnly" << true)));
controller->addPeriodicCollector(std::make_unique<FTDCSimpleInternalCommandCollector>(
"aggregate",
"local.oplog.rs.stats",
"local",
BSON("aggregate"
<< "oplog.rs"
<< "cursor" << BSONObj{} << "pipeline"
<< BSON_ARRAY(BSON("$collStats" << BSON(
"storageStats" << BSON(
"waitForLock" << false << "numericOnly" << true)))))));
if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {
// GetDefaultRWConcern
controller->addOnRotateCollector(std::make_unique<FTDCSimpleInternalCommandCollector>(

View File

@ -181,8 +181,11 @@ FTDCSimpleInternalCommandCollector::FTDCSimpleInternalCommandCollector(StringDat
}
void FTDCSimpleInternalCommandCollector::collect(OperationContext* opCtx, BSONObjBuilder& builder) {
auto result = CommandHelpers::runCommandDirectly(opCtx, _request);
builder.appendElements(result);
if (auto result = CommandHelpers::runCommandDirectly(opCtx, _request);
result.hasElement("cursor"))
builder.appendElements(result["cursor"]["firstBatch"]["0"].Obj());
else
builder.appendElements(result);
}
std::string FTDCSimpleInternalCommandCollector::name() const {

Some files were not shown because too many files have changed in this diff Show More