Compare commits

...

99 Commits

Author SHA1 Message Date
Aaron Morand
015a334997 STAR-2531 Bump commit for the 6.1.0 GA release 2022-10-04 16:35:11 -04:00
Gregory Noma
b6e0525d6d SERVER-69389 Populate shadow collection catalog on clean shutdown
(cherry picked from commit 5457b45279)
2022-10-03 20:11:34 +00:00
Gregory Wlodarek
c72363a277 SERVER-60753 Skip removing index build entries explicitly from 'config.system.indexBuilds' when recovering from the oplog as a standalone
(cherry picked from commit c7f9bb9676)
2022-10-03 18:13:20 +00:00
Jacob Evans
1d5760aab2 SERVER-68371 Allow search queries to pass through query analysis 2022-10-03 16:40:29 +00:00
Sophia Tan
5f3a51a85a SERVER-66737 performing reads for retryable writes should not be recorded in Operation Metrics 2022-09-30 20:09:33 +00:00
Faustoleyva54
564b1554dc SERVER-68394 Ensure we do not yield strong locks upon startup recovery when _id index is missing 2022-09-30 18:43:15 +00:00
joshua
c8980c27cc SERVER-68115 Do not drop empty path component from elemMatch path during index selection 2022-09-30 16:33:10 +00:00
Jordi Olivares Provencio
619c6e89ea SERVER-69530 Skip sharding DB check during index builds 2022-09-28 13:41:46 +00:00
Abdul Qadeer
2af7b4b1a2 SERVER-69700 Await secondaries' readiness
(cherry picked from commit 6eaf0ea0d0)
2022-09-27 19:28:11 +00:00
Luke Chen
3c29923bb5 Import wiredtiger: 0e90362a6e0ec654480da2ffce384c6b53a06be6 from branch mongodb-6.1
ref: 0af906ba58..0e90362a6e
for: 6.1.0-rc3

WT-9870 Fix the global time window state before performing rollback to stable (#8280) (#8288)
2022-09-26 15:52:51 +10:00
Luke Chen
59018abb95 Import wiredtiger: 0af906ba5866a9dd3de643e1daf8d983028f88f4 from branch mongodb-6.1
ref: b12072d37a..0af906ba58
for: 6.1.0-rc3

WT-9863 - Downgrade assertion in __hs_delete_reinsert_from_pos (#8268)
2022-09-26 15:52:48 +10:00
Daniel Gottlieb
14b1ea6d58 SERVER-69001: Have initial sync persist its last oplog time into the minvalid document.
(cherry picked from commit ff2fffdf49)
2022-09-21 19:59:09 +00:00
Nikita Lapkov
9d71aeee1e SERVER-69793 Disable memory underflow check in the query system
(cherry picked from commit 4d58e73a53)
2022-09-21 08:53:02 +00:00
nandinibhartiyaMDB
6d0624e75a SERVER-68139: Test resharding success with limited memory
(cherry picked from commit 901ce6eed0)
2022-09-21 05:03:36 +00:00
Varun Ravichandran
cf6bde6ffd Revert "SERVER-67464 Add base64url encode/decode"
This reverts commit ef8c3a1546.

(cherry picked from commit b97bcd00e8)
2022-09-20 20:53:22 +00:00
Varun Ravichandran
597ebc2163 Revert "SERVER-65843: Feature flag for OIDC authentication spike"
This reverts commit efde5e5d4a.

(cherry picked from commit ec2724c6a4)
2022-09-20 20:53:22 +00:00
Varun Ravichandran
ed2177d7d5 Revert "SERVER-67552: Creates a generic RsaPublicKey class that serves as a wrapper around RSA public key material in OpenSSL."
This reverts commit 8f895e99ad.

(cherry picked from commit bc19fa9af3)
2022-09-20 20:53:22 +00:00
Varun Ravichandran
ae3b498a0a Revert "SERVER-67660 Add JWKManager"
This reverts commit 338cdd44e4.

(cherry picked from commit ba91e172b1)
2022-09-20 20:53:22 +00:00
Varun Ravichandran
0d202a5f19 Revert "SERVER-67551: Asymmetric Key class"
This reverts commit b6f2d94e35.

(cherry picked from commit 489dcc7c68)
2022-09-20 20:53:22 +00:00
Andrew Witten
d5004b929a SERVER-67653 don't initiate critical section if remainingMillis is omitted
(cherry picked from commit abd6330d79)

SERVER-69693 use lambda instead of repeating code

(cherry picked from commit dd9d37fa07)
2022-09-20 19:57:17 +00:00
Matt Boros
832151ec17 SERVER-69005 $internalBoundedSort should not accept empty sort pattern
(cherry picked from commit a14ebbf41e)
2022-09-20 15:28:47 +00:00
Mickey. J Winters
d4297ee553 SERVER-69785 robustify change_streams_per_shard_cursor.js
(cherry-picked from 1219ff764c)
2022-09-20 14:51:43 +00:00
Kyle Suarez
e8ed64ed04 SERVER-67715 escape $changeStream regex
(cherry picked from commit c9fe899fff)
2022-09-19 23:55:45 +00:00
Vojislav Stojkovic
6424b1f1f1 SERVER-69584 Pass ConnectionMetrics by shared_ptr
(cherry picked from commit f810937135)
2022-09-19 23:54:31 +00:00
Josef Ahmad
3217b54dde SERVER-69611 Set the -ffp-contract=off compiler option by default
(cherry picked from commit d8901a2835)
2022-09-19 23:02:21 +00:00
Tausif Rahman
763a3efc81 SERVER-68003 Make experiment_unified_ninja.vars the default
(cherry picked from commit 41d0a45aaf)
(cherry picked from commit 6e2d63630e)
2022-09-19 15:55:19 +00:00
Luke Chen
cc34fa291c Import wiredtiger: b12072d37a533c8f57b65beb00020ba099e75505 from branch mongodb-6.1
ref: 3b7547744a..b12072d37a
for: 6.1.0-rc3

WT-9805 Save the updates need to be deleted from history store and delete them later (#8262)
2022-09-19 14:23:25 +10:00
Luke Chen
05e07fbe36 Import wiredtiger: 3b7547744a48b59e8efee92083c4832a550e5340 from branch mongodb-6.1
ref: 2a3bf2949e..3b7547744a
for: 6.1.0-rc3

WT-9792 Fix RTS to remove globally visible update of the data store update from the history store (#8261)
2022-09-19 14:23:25 +10:00
Aaron Morand
53fbcb16c2 STAR-3029 Updated the FCV constant in the logkeeper snapshot workload for 6.1 (#1492) 2022-09-16 17:52:29 -04:00
Yoonsoo Kim
3c4ff87b9f SERVER-69707 Fix undefined slot error for $group with conditional expression
(cherry picked from commit 8e990303de)
2022-09-16 21:28:57 +00:00
Amirsaman Memaripour
8f1e14b436 SERVER-68680 Avoid deadlocks when recursively invoking opportunisticRead/Write
(cherry picked from commit e884fbf3ac)
2022-09-15 18:08:16 +00:00
Brett Nawrocki
f0aa22b7dd SERVER-68783 Disambiguate 0 time estimate from no estimate in resharding
(cherry picked from commit 54dfa66ba8)
2022-09-13 19:05:02 +00:00
Allison Easton
e2023e4001 SERVER-69399 Wait for primary after replica set restart in disable_resumable_range_deleter.js
(cherry picked from commit ddc6e3f3d2)
2022-09-13 07:05:51 +00:00
Sergi Mateo Bellido
8a86f72b69 SERVER-69207 Coverity fix use after move
(cherry picked from commit 310dd9f04a)
2022-09-12 12:51:00 +00:00
Luke Chen
7cda3b8762 Import wiredtiger: 2a3bf2949e4e75dab96fc0e8fb1c1fd67eb243c3 from branch mongodb-6.1
ref: 672be218bf..2a3bf2949e
for: 6.1.0-rc2

Revert "WT-9792 Fix RTS to remove globally visible update of the data store update from the history store (#8240)" (#8253)
2022-09-09 06:34:14 +00:00
Luke Chen
adbe39ee1e Import wiredtiger: 672be218bfa99c082c1bcd62f53bf1ad2211239e from branch mongodb-6.1
ref: 30c7dcaef3..672be218bf
for: 6.1.0-rc2

WT-9838 Allow checkpoint when creating first object. (#8250)
2022-09-09 06:34:14 +00:00
Luke Chen
45a16968d4 Import wiredtiger: 30c7dcaef3d9593e1985eed2132c39d0d4f1b66a from branch mongodb-6.1
ref: 987bc122e7..30c7dcaef3
for: 6.1.0-rc2

WT-9841 Fix tracking of live_open variable, so it works both in diagnostic and non-diagnostic mode (#8252)
2022-09-09 06:34:14 +00:00
Luke Chen
08344712d5 Import wiredtiger: 987bc122e766ff2147e512b05e42a8434ccf1924 from branch mongodb-6.1
ref: 8be0aa4ba3..987bc122e7
for: 6.1.0-rc2

WT-9405 Fix segfault when opening history store cursor during rollback (#8239)
2022-09-09 06:34:14 +00:00
Luke Chen
bf56db18c0 Import wiredtiger: 8be0aa4ba3878c34dbcd956e12ecc44cba094f30 from branch mongodb-6.1
ref: fe32af9801..8be0aa4ba3
for: 6.1.0-rc2

WT-9839 Disable stress testing in test_tiered08. (#8251)
2022-09-09 06:34:14 +00:00
Luke Chen
5c952f408e Import wiredtiger: fe32af9801bbfe192afeca271072250f35af6160 from branch mongodb-6.1
ref: c4fa0f7511..fe32af9801
for: 6.1.0-rc2

WT-9457 Preserve ckpt_most_recent value across restart (#8245)
2022-09-09 06:34:14 +00:00
Luke Chen
63d2ed6429 Import wiredtiger: c4fa0f7511202f4b9908e0b70a444197dddd07c2 from branch mongodb-6.1
ref: 2537dbfc79..c4fa0f7511
for: 6.1.0-rc2

WT-9792 Fix RTS to remove globally visible update of the data store update from the history store (#8240)
2022-09-09 06:34:14 +00:00
Luke Chen
123941cc37 Import wiredtiger: 2537dbfc7938d44113f355000c677bc8badb2969 from branch mongodb-6.1
ref: fc5838e909..2537dbfc79
for: 6.1.0-rc2

WT-9143 Refactor and review existing CppSuite bounded cursor stress for improvement (#8223)
2022-09-09 06:34:14 +00:00
Luke Chen
eac2f0e5cd Import wiredtiger: fc5838e9095b279533f151b03dc31ff2f3756b00 from branch mongodb-6.1
ref: c004346e10..fc5838e909
for: 6.1.0-rc2

WT-9816 Add session_flush_tier_readonly for readonly connections. (#8242)
2022-09-09 06:34:14 +00:00
Luke Chen
ae9ebae348 Import wiredtiger: c004346e10b186c1ecea4a1ee3186619666c9c17 from branch mongodb-6.1
ref: bb64c7cdca..c004346e10
for: 6.1.0-rc2

WT-7833 wt_btree_switch_object needs to coordinate with concurrent write requests to btree (#8044)
2022-09-09 06:34:14 +00:00
Luke Chen
ccc7ca852e Import wiredtiger: bb64c7cdcac3638b66ecea5c240df1448d409ab8 from branch mongodb-6.1
ref: cfb48c05eb..bb64c7cdca
for: 6.1.0-rc2

WT-9751 Fix memory leak if we fail eviction in single page rewrite (#8214)
2022-09-09 06:34:13 +00:00
Luke Chen
dd101c2823 Import wiredtiger: cfb48c05ebcc12aa122d245430dbda07c5f0513a from branch mongodb-6.1
ref: e217c5727a..cfb48c05eb
for: 6.1.0-rc2

WT-9781 Fix search near exact edge case with bounded cursor (#8231)
2022-09-09 06:34:13 +00:00
Luke Chen
1446eda8a1 Import wiredtiger: e217c5727a0922118d3d294729864605c2e8bacc from branch mongodb-6.1
ref: 0ac82ac3fb..e217c5727a
for: 6.1.0-rc2

WT-9758 Only reset cursor bounds when calling cursor reset externally (#8208)
2022-09-09 06:34:13 +00:00
Luke Chen
f01a90978a Import wiredtiger: 0ac82ac3fb889ed948dcb23ef77b3cd82d6de935 from branch mongodb-6.1
ref: e605c3eee1..0ac82ac3fb
for: 6.1.0-rc2

WT-9799 Only reconfigure every 2+ seconds. (#8233)
2022-09-09 06:34:13 +00:00
Luke Chen
907fc9e6cd Import wiredtiger: e605c3eee1daaf355d7a498dd3dc89036c43c2d8 from branch mongodb-6.1
ref: 064bbe0878..e605c3eee1
for: 6.1.0-rc2

WT-9591 Adapt to LLVM v9.0+ for a Symoblizer call (#8198)
2022-09-09 06:34:13 +00:00
Luke Chen
c4cdb28205 Import wiredtiger: 064bbe0878ef559d76339d7812ef141e89436eaa from branch mongodb-6.1
ref: dd3f4cb274..064bbe0878
for: 6.1.0-rc2

WT-9772 Fix RTS to abort the updates using the recovered checkpoint snapshot (#8229)
2022-09-09 06:34:13 +00:00
Luke Chen
b74a7fa06a Import wiredtiger: dd3f4cb2749cfd33551d66762a49063bb19459fd from branch mongodb-6.1
ref: fbae1a2989..dd3f4cb274
for: 6.1.0-rc2

WT-9776 Opening checkpoint cursor on column store table fails (#8234)
2022-09-09 06:34:13 +00:00
nandinibhartiyaMDB
f83bf6c4be SERVER-68094: Use $replaceRoot instead of $project
(cherry picked from commit 015dc2badc)
2022-09-08 13:52:37 +00:00
Enrico Golfieri
ca0b75fbe2 SERVER-69398 filler_collection should be dropped in explain_missing_collection.js 2022-09-08 10:17:07 +00:00
Dianna Hohensee
afbc967e8c SERVER-69493 Disable SBE yielding changes in 6.1 branch 2022-09-07 17:30:07 +00:00
Josef Ahmad
fd61bf1c37 SERVER-67538 Make multi-doc txns return WCE on index catalog changes
Background: SERVER-47866 stopped bumping the collection's minimum
visibility timestamp on catalog changes related to an index; only the
index's minimum visibility snapshot continues to be updated. One side
effect of this change is that a multi-document transaction can read a
at a snapshot where the index is not yet ready and commit at a
timestamp when the index is ready, which not intended behaviour and
can open the opportunity for a race to happen.

This patch introduces a check for the indices' minimum visible timestamp.
Attempting to write to an index entry while reading at an incompatible
timestamp returns a write conflict exception. Locking rules guarantee that
we see a consistent in-memory view of the indices' minimum visible
snapshot.

(cherry picked from commit a4bd3ce360)
2022-09-07 07:45:10 +00:00
Allison Easton
6863b64003 SERVER-69180 Split and Merge commands need to refresh filtering metadata before checking preconditions
(cherry picked from commit 3f101399b8)
2022-09-05 06:48:32 +00:00
Luke Chen
cd67916e3d Import wiredtiger: fbae1a2989c947f4f8d17ac433e93edf85251900 from branch mongodb-6.1
ref: 84ea010e09..fbae1a2989
for: 6.1.0-rc1

WT-9797 Add more trace messages to test format. (#8232)
2022-09-05 04:37:07 +00:00
Luke Chen
63c5901e2b Import wiredtiger: 84ea010e09c6079b2d6d98d7b1ab97075115e70a from branch mongodb-6.1
ref: d619c325f8..84ea010e09
for: 6.1.0-rc1

WT-9787 Add printing of update structure flags. (#8227)
2022-09-05 04:37:07 +00:00
Luke Chen
24143f27c9 Import wiredtiger: d619c325f86cd59ee25d4bcf43b738afcf7bfdf9 from branch mongodb-6.1
ref: 478f555081..d619c325f8
for: 6.1.0-rc1

WT-9720 Clean up and reorganize the fast-truncate code (#8188)
2022-09-05 04:37:06 +00:00
Luke Chen
b06609850b Import wiredtiger: 478f5550817985718478ac04f3295e88440f8c3e from branch mongodb-6.1
ref: f0a6a61bfc..478f555081
for: 6.1.0-rc1

WT-9765 Fix handling a prepared commit after a prepared rollback with eviction failure (#8213)
2022-09-05 04:37:06 +00:00
Luke Chen
a5a26be2e8 Import wiredtiger: f0a6a61bfcd2f4a6ab670a59d603a69f59e54906 from branch mongodb-6.1
ref: c4ff543d29..f0a6a61bfc
for: 6.1.0-rc1

WT-9705 Fix accidentally freeing update on the update chain in prepared commit (#8211)
2022-09-05 04:37:06 +00:00
Luke Chen
2f7eb41c22 Import wiredtiger: c4ff543d29fb4d02ba62f4349652477f46eb7b6f from branch mongodb-6.1
ref: f45ebf82db..c4ff543d29
for: 6.1.0-rc1

WT-9683 Coverity analysis defect 124895: Parse warning (#8226)
2022-09-05 04:37:06 +00:00
Luke Chen
22450cd55f Import wiredtiger: f45ebf82dba6e0d88edccb6c3047a717669b4562 from branch mongodb-6.1
ref: 2861a11653..f45ebf82db
for: 6.1.0-rc1

WT-9763 Return EBUSY if the time window of inserting record does not match with history store time window (#8218)
2022-09-05 04:37:06 +00:00
Luke Chen
0eac00554b Import wiredtiger: 2861a1165302d7a2ddf7b384922b2a022cc23897 from branch mongodb-6.1
ref: 42ee89096f..2861a11653
for: 6.1.0-rc1

WT-9771 Fix generating incompatible transaction configurations (#8224)
2022-09-05 04:37:06 +00:00
Luke Chen
4e215cded5 Import wiredtiger: 42ee89096f8306dbdcbd1a9416c308cf2e0ccf7e from branch mongodb-6.1
ref: bb704a1689..42ee89096f
for: 6.1.0-rc1

WT-9590 Fixing linking to tcmalloc for S3 extension (#8217)
2022-09-05 04:37:06 +00:00
Luke Chen
3b86f77155 Import wiredtiger: bb704a1689ed8b1681bb2dd6bd576c4a40d391f3 from branch mongodb-6.1
ref: a0ef087624..bb704a1689
for: 6.1.0-rc1

WT-9760 Fix implicit conversion in workgen.cxx (#8219)
2022-09-05 04:37:06 +00:00
Luke Chen
7ce0332a70 Import wiredtiger: a0ef0876244f2f8636a36ab012b790244a676290 from branch mongodb-6.1
ref: 7adc445f75..a0ef087624
for: 6.1.0-rc1

WT-9554 Implement truncate and prepare in the cursor bounds fuzz tester python test (#8203)
2022-09-05 04:37:06 +00:00
Allison Easton
8e62da90c4 SERVER-69357 Make no-indexes version boost::none instead of Timestamp(0, 0)
(cherry picked from commit 3b63216fb7)
2022-09-02 07:46:56 +00:00
David Storch
fd671b6b1e SERVER-69103 Always use the classic engine on the inner side of DocumentSourceLookup or $graphLookup
(cherry picked from commit 331e44c65a)
2022-08-31 20:46:15 +00:00
Mikhail Shchatko
7182f9d06e SERVER-69265 Increase config_fuzzer_replica_sets_jscore_passthrough timeout
(cherry picked from commit 0cb24e4b94)
2022-08-31 16:36:09 +00:00
Jason Zhang
a58b2debd6 SERVER-69118 Have retryable findAndModify failover internal transaction test wait until lastCommittedOpTime is recovered after failover
(cherry picked from commit cabbf002ee)
2022-08-31 15:14:00 +00:00
Benety Goh
eb45396105 SERVER-68477 createIndexes overwrites NaN expireAfterSeconds before starting index build
(cherry picked from commit 58796facf4)
2022-08-31 13:01:30 +00:00
Benety Goh
a29518c420 SERVER-68477 TTLMonitor fixes NaN expireAfterSeconds on TTL indexes during step up
(cherry picked from commit b8eb75f99a)
2022-08-31 13:01:30 +00:00
Benety Goh
c72e1a93ce SERVER-68477 remove epoch restriction on ttl indexes
(cherry picked from commit eb2f7f03f8)
2022-08-31 12:12:05 +00:00
Benety Goh
cf72acd7f8 SERVER-68477 listIndexes repairs TTL indexes with NaN expireAfterSeconds
(cherry picked from commit d6528bf96f)
2022-08-31 12:12:05 +00:00
Benety Goh
daaff3b144 SERVER-68477 TTL monitor skips indexes with NaN expireAfterSeconds
(cherry-picked from commit 14c07b5318)

(cherry picked from commit 7d76329f89)
2022-08-31 12:12:05 +00:00
Benety Goh
0c4e155bf4 SERVER-68477 add startup warning for TTL indexes with NaN 'expireAfterSeconds'
(partially cherry-picked from commit abdedd367e)

(cherry picked from commit 5d21e0115e)
2022-08-31 12:12:05 +00:00
Benety Goh
c91d35a92b SERVER-68477 add TTLMonitor::onStepUp()
(cherry picked from commit 3b17e5f791)
2022-08-31 10:59:31 +00:00
Benety Goh
20504d1d14 SERVER-68477 include 'expireAfterSeconds' type information when registering TTL indexes with the TTLCollectionCache
(cherry picked from commit cc3ae631bc)
2022-08-31 10:59:31 +00:00
Benety Goh
559d9f496e SERVER-68477 add unit test for TTLCollectionCache
(cherry picked from commit f32f550aff)
2022-08-31 10:59:31 +00:00
Abdul Qadeer
da44564ea5 SERVER-68869 Wait for retried _configsvrReshardCollection cmd
(cherry picked from commit a2b63a5e8d)
2022-08-30 12:48:17 +00:00
Daniel Moody
96cdc44b67 SERVER-68475 only use custom configure check with gcc and clang.
(cherry picked from commit 53aa9bec47)
2022-08-29 18:28:36 +00:00
Daniel Moody
e810b3d11d SERVER-68475 use debug-types-section to reduce debug info
(cherry picked from commit b41c85c2e7)
2022-08-29 18:28:36 +00:00
Davis Haupt
004a674a84 SERVER-68766 add server parameter to enable single value reduce optimization 2022-08-29 17:57:19 +00:00
Gregory Noma
69c423f89e SERVER-69141 Move forward TSBS version 2022-08-29 16:24:39 +00:00
Gregory Wlodarek
bc94a2eaad SERVER-68925 Reintroduce check table logging settings at startup
(cherry picked from commit 994562a9c8)
2022-08-26 09:17:09 +00:00
Dan Larkin-York
e727f8d673 SERVER-69052 Ensure bucket collection is valid when checking for extended range
(cherry picked from commit 97989ceff0)
(cherry picked from commit f374f58e55)
2022-08-25 20:14:14 +00:00
Ryan Egesdahl
c972dc2930 SERVER-69127 Add more missing version expansions
(cherry picked from commit 79662a1b0d)
2022-08-25 03:00:19 +00:00
Mikhail Shchatko
e678887c8d SERVER-68505 Disable in-memory buildvariants 2022-08-24 13:56:05 +00:00
Mikhail Shchatko
15b767ef70 SERVER-69107 Temporary disable burn_in_tags 2022-08-24 13:25:14 +00:00
Mikhail Shchatko
4e18d134ba SERVER-68505 Remove all feature flags buildvariants from system-perf.yml 2022-08-23 19:22:51 +03:00
Mikhail Shchatko
4f43d4cfdd SERVER-68505 Fix Copy required and commit queue buildvariants to evergreen_nightly.yml 2022-08-23 19:09:54 +03:00
Mikhail Shchatko
b809265967 SERVER-68505 Disable renew_ssl_cert in sys-perf 2022-08-23 18:55:15 +03:00
Mikhail Shchatko
c001aaccbf SERVER-68505 Update perf.yml 2022-08-23 18:53:35 +03:00
Mikhail Shchatko
b5d984a43a SERVER-68505 Update suffixes in generate_version_expansions.py 2022-08-23 18:52:07 +03:00
Mikhail Shchatko
57054f63b1 SERVER-68505 Copy required and commit queue buildvariants to evergreen_nightly.yml 2022-08-23 18:43:06 +03:00
Mikhail Shchatko
a73c751ddd SERVER-68505 Remove wtdevelop buildvariants 2022-08-23 18:29:01 +03:00
Mikhail Shchatko
5e5a1d5d90 SERVER-68505 Update definitions.yml 2022-08-23 18:25:12 +03:00
Mikhail Shchatko
cf68cf1fdc SERVER-68505 Update system_perf.yml 2022-08-23 18:20:43 +03:00
263 changed files with 8213 additions and 4322 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

@ -3,6 +3,7 @@
import atexit
import copy
import errno
import functools
import json
import os
import re
@ -1016,17 +1017,10 @@ env_vars.Add(
converter=variable_shlex_converter,
)
default_destdir = '$BUILD_ROOT/install'
if get_option('ninja') != 'disabled':
# Workaround for SERVER-53952 where issues wih different
# ninja files building to the same install dir. Different
# ninja files need to build to different install dirs.
default_destdir = '$BUILD_DIR/install'
env_vars.Add(
'DESTDIR',
help='Where builds will install files',
default=default_destdir,
default='$BUILD_ROOT/install',
)
env_vars.Add(
@ -1220,7 +1214,7 @@ env_vars.Add(
env_vars.Add(
'NINJA_BUILDDIR',
help="Location for shared Ninja state",
default="$BUILD_DIR/ninja",
default="$BUILD_ROOT/ninja",
)
env_vars.Add(
@ -2486,6 +2480,15 @@ for suboption in get_option('experimental-runtime-hardening'):
elif suboption.startswith('+'):
selected_experimental_runtime_hardenings.add(suboption[1:])
# Disable floating-point contractions such as forming of fused multiply-add operations.
if env.ToolchainIs('clang', 'gcc'):
env.Append(CCFLAGS=["-ffp-contract=off"])
else:
# msvc defaults to /fp:precise. Visual Studio 2022 does not emit floating-point contractions
# with /fp:precise, but previous versions can. Disable contractions altogether by using
# /fp:strict.
env.Append(CCFLAGS=["/fp:strict"])
if env.TargetOSIs('linux'):
env.Append(LIBS=["m"])
if not env.TargetOSIs('android'):
@ -3251,7 +3254,7 @@ def doConfigure(myenv):
conf.Finish()
def AddFlagIfSupported(env, tool, extension, flag, link, **mutation):
def CheckFlag(env, flag, tool, extension, link, **mutation):
def CheckFlagTest(context, tool, extension, flag):
if link:
if tool == 'C':
@ -3327,34 +3330,33 @@ def doConfigure(myenv):
)
available = conf.CheckFlag()
conf.Finish()
return available
def AddFlagIfSupported(env, flag, tool, extension, link, **mutation):
available = CheckFlag(env, flag, tool, extension, link, **mutation)
if available:
env.Append(**mutation)
return available
def AddToCFLAGSIfSupported(env, flag):
return AddFlagIfSupported(env, 'C', '.c', flag, False, CFLAGS=[flag])
conf_check_vars = {
'CFLAGS': {'tool': 'C', 'extension': '.c', 'link': False},
'CCFLAGS': {'tool': 'C', 'extension': '.c', 'link': False},
'CXXFLAGS': {'tool': 'C++', 'extension': '.cpp', 'link': False},
'LINKFLAGS': {'tool': 'C', 'extension': '.c', 'link': True},
'SHLINKFLAGS': {'tool': 'C', 'extension': '.c', 'link': True},
}
env.AddMethod(AddToCFLAGSIfSupported)
def var_func(env, flag, var, func):
kwargs = dict({var: [flag]}, **conf_check_vars[var])
return func(env, flag, **kwargs)
def AddToCCFLAGSIfSupported(env, flag):
return AddFlagIfSupported(env, 'C', '.c', flag, False, CCFLAGS=[flag])
env.AddMethod(AddToCCFLAGSIfSupported)
def AddToCXXFLAGSIfSupported(env, flag):
return AddFlagIfSupported(env, 'C++', '.cpp', flag, False, CXXFLAGS=[flag])
env.AddMethod(AddToCXXFLAGSIfSupported)
def AddToLINKFLAGSIfSupported(env, flag):
return AddFlagIfSupported(env, 'C', '.c', flag, True, LINKFLAGS=[flag])
env.AddMethod(AddToLINKFLAGSIfSupported)
def AddToSHLINKFLAGSIfSupported(env, flag):
return AddFlagIfSupported(env, 'C', '.c', flag, True, SHLINKFLAGS=[flag])
env.AddMethod(AddToSHLINKFLAGSIfSupported)
for var in conf_check_vars:
myenv.AddMethod(
functools.partial(var_func, var=var, func=AddFlagIfSupported), f"AddTo{var}IfSupported")
myenv.AddMethod(
functools.partial(var_func, var=var, func=CheckFlag), f"Check{var}Supported")
if myenv.ToolchainIs('gcc', 'clang'):
# This tells clang/gcc to use the gold linker if it is available - we prefer the gold linker
@ -3378,20 +3380,20 @@ def doConfigure(myenv):
#
# We should revisit all of these issues the next time we upgrade our clang minimum.
if get_option('separate-debug') == 'off' and get_option('link-model') != 'dynamic':
if not AddToLINKFLAGSIfSupported(myenv, '-fuse-ld=lld'):
AddToLINKFLAGSIfSupported(myenv, '-fuse-ld=gold')
if not myenv.AddToLINKFLAGSIfSupported('-fuse-ld=lld'):
myenv.AddToLINKFLAGSIfSupported('-fuse-ld=gold')
else:
AddToLINKFLAGSIfSupported(myenv, '-fuse-ld=gold')
myenv.AddToLINKFLAGSIfSupported('-fuse-ld=gold')
elif link_model.startswith("dynamic") and linker_ld == 'bfd':
# BFD is not supported due to issues with it causing warnings from some of
# the third party libraries that mongodb is linked with:
# https://jira.mongodb.org/browse/SERVER-49465
myenv.FatalError(f"Linker {linker_ld} is not supported with dynamic link model builds.")
else:
if not AddToLINKFLAGSIfSupported(myenv, f'-fuse-ld={linker_ld}'):
if not myenv.AddToLINKFLAGSIfSupported(f'-fuse-ld={linker_ld}'):
myenv.FatalError(f"Linker {linker_ld} could not be configured.")
if has_option('gcov') and AddToCCFLAGSIfSupported(myenv, '-fprofile-update=single'):
if has_option('gcov') and myenv.AddToCCFLAGSIfSupported('-fprofile-update=single'):
myenv.AppendUnique(LINKFLAGS=['-fprofile-update=single'])
detectCompiler = Configure(
@ -3424,11 +3426,11 @@ def doConfigure(myenv):
if myenv.ToolchainIs('clang', 'gcc'):
# This warning was added in g++-4.8.
AddToCCFLAGSIfSupported(myenv, '-Wno-unused-local-typedefs')
myenv.AddToCCFLAGSIfSupported('-Wno-unused-local-typedefs')
# Clang likes to warn about unused functions, which seems a tad aggressive and breaks
# -Werror, which we want to be able to use.
AddToCCFLAGSIfSupported(myenv, '-Wno-unused-function')
myenv.AddToCCFLAGSIfSupported('-Wno-unused-function')
# TODO: Note that the following two flags are added to CCFLAGS even though they are
# really C++ specific. We need to do this because SCons passes CXXFLAGS *before*
@ -3438,79 +3440,79 @@ def doConfigure(myenv):
#
# Clang likes to warn about unused private fields, but some of our third_party
# libraries have such things.
AddToCCFLAGSIfSupported(myenv, '-Wno-unused-private-field')
myenv.AddToCCFLAGSIfSupported('-Wno-unused-private-field')
# Prevents warning about using deprecated features (such as auto_ptr in c++11)
# Using -Wno-error=deprecated-declarations does not seem to work on some compilers,
# including at least g++-4.6.
AddToCCFLAGSIfSupported(myenv, "-Wno-deprecated-declarations")
myenv.AddToCCFLAGSIfSupported("-Wno-deprecated-declarations")
# As of clang-3.4, this warning appears in v8, and gets escalated to an error.
AddToCCFLAGSIfSupported(myenv, "-Wno-tautological-constant-out-of-range-compare")
myenv.AddToCCFLAGSIfSupported("-Wno-tautological-constant-out-of-range-compare")
# As of clang in Android NDK 17, these warnings appears in boost and/or ICU, and get escalated to errors
AddToCCFLAGSIfSupported(myenv, "-Wno-tautological-constant-compare")
AddToCCFLAGSIfSupported(myenv, "-Wno-tautological-unsigned-zero-compare")
AddToCCFLAGSIfSupported(myenv, "-Wno-tautological-unsigned-enum-zero-compare")
myenv.AddToCCFLAGSIfSupported("-Wno-tautological-constant-compare")
myenv.AddToCCFLAGSIfSupported("-Wno-tautological-unsigned-zero-compare")
myenv.AddToCCFLAGSIfSupported("-Wno-tautological-unsigned-enum-zero-compare")
# New in clang-3.4, trips up things mostly in third_party, but in a few places in the
# primary mongo sources as well.
AddToCCFLAGSIfSupported(myenv, "-Wno-unused-const-variable")
myenv.AddToCCFLAGSIfSupported("-Wno-unused-const-variable")
# Prevents warning about unused but set variables found in boost version 1.49
# in boost/date_time/format_date_parser.hpp which does not work for compilers
# GCC >= 4.6. Error explained in https://svn.boost.org/trac/boost/ticket/6136 .
AddToCCFLAGSIfSupported(myenv, "-Wno-unused-but-set-variable")
myenv.AddToCCFLAGSIfSupported("-Wno-unused-but-set-variable")
# This has been suppressed in gcc 4.8, due to false positives, but not in clang. So
# we explicitly disable it here.
AddToCCFLAGSIfSupported(myenv, "-Wno-missing-braces")
myenv.AddToCCFLAGSIfSupported("-Wno-missing-braces")
# Suppress warnings about not consistently using override everywhere in a class. It seems
# very pedantic, and we have a fair number of instances.
AddToCCFLAGSIfSupported(myenv, "-Wno-inconsistent-missing-override")
myenv.AddToCCFLAGSIfSupported("-Wno-inconsistent-missing-override")
# Don't issue warnings about potentially evaluated expressions
AddToCCFLAGSIfSupported(myenv, "-Wno-potentially-evaluated-expression")
myenv.AddToCCFLAGSIfSupported("-Wno-potentially-evaluated-expression")
# Warn about moves of prvalues, which can inhibit copy elision.
AddToCXXFLAGSIfSupported(myenv, "-Wpessimizing-move")
myenv.AddToCXXFLAGSIfSupported("-Wpessimizing-move")
# Disable warning about variables that may not be initialized
# Failures are triggered in the case of boost::optional in GCC 4.8.x
# TODO: re-evaluate when we move to GCC 5.3
# see: http://stackoverflow.com/questions/21755206/how-to-get-around-gcc-void-b-4-may-be-used-uninitialized-in-this-funct
AddToCXXFLAGSIfSupported(myenv, "-Wno-maybe-uninitialized")
myenv.AddToCXXFLAGSIfSupported("-Wno-maybe-uninitialized")
# Disable warning about templates that can't be implicitly instantiated. It is an attempt to
# make a link error into an easier-to-debug compiler failure, but it triggers false
# positives if explicit instantiation is used in a TU that can see the full definition. This
# is a problem at least for the S2 headers.
AddToCXXFLAGSIfSupported(myenv, "-Wno-undefined-var-template")
myenv.AddToCXXFLAGSIfSupported("-Wno-undefined-var-template")
# This warning was added in clang-4.0, but it warns about code that is required on some
# platforms. Since the warning just states that 'explicit instantiation of [a template] that
# occurs after an explicit specialization has no effect', it is harmless on platforms where
# it isn't required
AddToCXXFLAGSIfSupported(myenv, "-Wno-instantiation-after-specialization")
myenv.AddToCXXFLAGSIfSupported("-Wno-instantiation-after-specialization")
# This warning was added in clang-5 and flags many of our lambdas. Since it isn't actively
# harmful to capture unused variables we are suppressing for now with a plan to fix later.
AddToCCFLAGSIfSupported(myenv, "-Wno-unused-lambda-capture")
myenv.AddToCCFLAGSIfSupported("-Wno-unused-lambda-capture")
# Enable sized deallocation support.
AddToCXXFLAGSIfSupported(myenv, '-fsized-deallocation')
myenv.AddToCXXFLAGSIfSupported('-fsized-deallocation')
# This warning was added in Apple clang version 11 and flags many explicitly defaulted move
# constructors and assignment operators for being implicitly deleted, which is not useful.
AddToCXXFLAGSIfSupported(myenv, "-Wno-defaulted-function-deleted")
myenv.AddToCXXFLAGSIfSupported("-Wno-defaulted-function-deleted")
# SERVER-44856: Our windows builds complain about unused
# exception parameters, but GCC and clang don't seem to do
# that for us automatically. In the interest of making it more
# likely to catch these errors early, add the (currently clang
# only) flag that turns it on.
AddToCXXFLAGSIfSupported(myenv, "-Wunused-exception-parameter")
myenv.AddToCXXFLAGSIfSupported("-Wunused-exception-parameter")
# TODO(SERVER-60151): Avoid the dilemma identified in
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100493. Unfortunately,
@ -3522,7 +3524,7 @@ def doConfigure(myenv):
# TODO(SERVER-60175): In fact we will want to explicitly opt
# in to -Wdeprecated, since clang doesn't include it in -Wall.
if get_option('cxx-std') == "20":
AddToCXXFLAGSIfSupported(myenv, '-Wno-deprecated')
myenv.AddToCXXFLAGSIfSupported('-Wno-deprecated')
# Check if we can set "-Wnon-virtual-dtor" when "-Werror" is set. The only time we can't set it is on
# clang 3.4, where a class with virtual function(s) and a non-virtual destructor throws a warning when
@ -3568,18 +3570,18 @@ def doConfigure(myenv):
# by -Wall), in order to enforce that -mXXX-version-min=YYY
# will enforce that you don't use APIs from ZZZ.
if env.TargetOSIs('darwin'):
AddToCCFLAGSIfSupported(env, '-Wunguarded-availability')
env.AddToCCFLAGSIfSupported('-Wunguarded-availability')
if get_option('runtime-hardening') == "on":
# Enable 'strong' stack protection preferentially, but fall back to 'all' if it is not
# available. Note that we need to add these to the LINKFLAGS as well, since otherwise we
# might not link libssp when we need to (see SERVER-12456).
if myenv.ToolchainIs('gcc', 'clang'):
if AddToCCFLAGSIfSupported(myenv, '-fstack-protector-strong'):
if myenv.AddToCCFLAGSIfSupported('-fstack-protector-strong'):
myenv.Append(LINKFLAGS=[
'-fstack-protector-strong',
], )
elif AddToCCFLAGSIfSupported(myenv, '-fstack-protector-all'):
elif myenv.AddToCCFLAGSIfSupported('-fstack-protector-all'):
myenv.Append(LINKFLAGS=[
'-fstack-protector-all',
], )
@ -3590,10 +3592,10 @@ def doConfigure(myenv):
], )
if 'stackclash' in selected_experimental_runtime_hardenings:
AddToCCFLAGSIfSupported(myenv, "-fstack-clash-protection")
myenv.AddToCCFLAGSIfSupported("-fstack-clash-protection")
if 'controlflow' in selected_experimental_runtime_hardenings:
AddToCCFLAGSIfSupported(myenv, "-fcf-protection=full")
myenv.AddToCCFLAGSIfSupported("-fcf-protection=full")
if myenv.ToolchainIs('clang'):
# TODO: There are several interesting things to try here, but they each have
@ -3636,7 +3638,7 @@ def doConfigure(myenv):
if has_option('libc++'):
if not myenv.ToolchainIs('clang'):
myenv.FatalError('libc++ is currently only supported for clang')
if AddToCXXFLAGSIfSupported(myenv, '-stdlib=libc++'):
if myenv.AddToCXXFLAGSIfSupported('-stdlib=libc++'):
myenv.Append(LINKFLAGS=['-stdlib=libc++'])
else:
myenv.ConfError('libc++ requested, but compiler does not support -stdlib=libc++')
@ -3673,13 +3675,13 @@ def doConfigure(myenv):
myenv.AppendUnique(CCFLAGS=['/std:c++20'])
else:
if get_option('cxx-std') == "17":
if not AddToCXXFLAGSIfSupported(myenv, '-std=c++17'):
if not myenv.AddToCXXFLAGSIfSupported('-std=c++17'):
myenv.ConfError('Compiler does not honor -std=c++17')
elif get_option('cxx-std') == "20":
if not AddToCXXFLAGSIfSupported(myenv, '-std=c++20'):
if not myenv.AddToCXXFLAGSIfSupported('-std=c++20'):
myenv.ConfError('Compiler does not honor -std=c++20')
if not AddToCFLAGSIfSupported(myenv, '-std=c11'):
if not myenv.AddToCFLAGSIfSupported('-std=c11'):
myenv.ConfError("C++17 mode selected for C++ files, but can't enable C11 for C files")
if using_system_version_of_cxx_libraries():
@ -4002,7 +4004,7 @@ def doConfigure(myenv):
sanitizer_option = '-fsanitize=' + ','.join(sanitizer_list)
if AddToCCFLAGSIfSupported(myenv, sanitizer_option):
if myenv.AddToCCFLAGSIfSupported(sanitizer_option):
myenv.Append(LINKFLAGS=[sanitizer_option])
myenv.Append(CCFLAGS=['-fno-omit-frame-pointer'])
else:
@ -4013,7 +4015,7 @@ def doConfigure(myenv):
if has_option('sanitize-coverage') and using_fsan:
sanitize_coverage_list = get_option('sanitize-coverage')
sanitize_coverage_option = '-fsanitize-coverage=' + sanitize_coverage_list
if AddToCCFLAGSIfSupported(myenv, sanitize_coverage_option):
if myenv.AddToCCFLAGSIfSupported(sanitize_coverage_option):
myenv.Append(LINKFLAGS=[sanitize_coverage_option])
else:
myenv.ConfError('Failed to enable -fsanitize-coverage with flag: {0}',
@ -4036,7 +4038,7 @@ def doConfigure(myenv):
supportedDenyfiles = []
denyfilesTestEnv = myenv.Clone()
for denyfile in denyfiles:
if AddToCCFLAGSIfSupported(denyfilesTestEnv, f"-fsanitize-blacklist={denyfile}"):
if denyfilesTestEnv.AddToCCFLAGSIfSupported(f"-fsanitize-blacklist={denyfile}"):
supportedDenyfiles.append(denyfile)
denyfilesTestEnv = None
supportedDenyfiles = sorted(supportedDenyfiles)
@ -4219,8 +4221,8 @@ def doConfigure(myenv):
# have renamed the flag.
# However, this flag cannot be included when using the fuzzer sanitizer
# if we want to suppress errors to uncover new ones.
if not using_fsan and not AddToCCFLAGSIfSupported(myenv, "-fno-sanitize-recover"):
AddToCCFLAGSIfSupported(myenv, "-fno-sanitize-recover=undefined")
if not using_fsan and not myenv.AddToCCFLAGSIfSupported("-fno-sanitize-recover"):
myenv.AddToCCFLAGSIfSupported("-fno-sanitize-recover=undefined")
myenv.AppendUnique(CPPDEFINES=['UNDEFINED_BEHAVIOR_SANITIZER'])
# If anything is changed, added, or removed in ubsan_options, be
@ -4242,7 +4244,7 @@ def doConfigure(myenv):
# same as the correct link graph for a regular dynamic
# build.
if link_model == "dynamic":
if AddToCCFLAGSIfSupported(myenv, "-fno-sanitize=vptr"):
if myenv.AddToCCFLAGSIfSupported("-fno-sanitize=vptr"):
myenv.AppendUnique(LINKFLAGS=["-fno-sanitize=vptr"])
if myenv.ToolchainIs('msvc') and optBuild != "off":
@ -4259,21 +4261,28 @@ def doConfigure(myenv):
# Usually, --gdb-index is too expensive in big static binaries, but for dynamic
# builds it works well.
if link_model.startswith("dynamic"):
AddToLINKFLAGSIfSupported(myenv, '-Wl,--gdb-index')
myenv.AddToLINKFLAGSIfSupported('-Wl,--gdb-index')
if link_model != 'dynamic':
# This will create an extra section where debug types can be referred from,
# reducing other section sizes. This helps most with big static links as there
# will be lots of duplicate debug type info.
myenv.AddToCCFLAGSIfSupported('-fdebug-types-section')
myenv.AddToLINKFLAGSIfSupported('-fdebug-types-section')
# Our build is already parallel.
AddToLINKFLAGSIfSupported(myenv, '-Wl,--no-threads')
myenv.AddToLINKFLAGSIfSupported('-Wl,--no-threads')
# Explicitly enable GNU build id's if the linker supports it.
AddToLINKFLAGSIfSupported(myenv, '-Wl,--build-id')
myenv.AddToLINKFLAGSIfSupported('-Wl,--build-id')
# Explicitly use the new gnu hash section if the linker offers
# it, except on android since older runtimes seem to not
# support it. For that platform, use 'both'.
if env.TargetOSIs('android'):
AddToLINKFLAGSIfSupported(myenv, '-Wl,--hash-style=both')
myenv.AddToLINKFLAGSIfSupported('-Wl,--hash-style=both')
else:
AddToLINKFLAGSIfSupported(myenv, '-Wl,--hash-style=gnu')
myenv.AddToLINKFLAGSIfSupported('-Wl,--hash-style=gnu')
# Try to have the linker tell us about ODR violations. Don't
# use it when using clang with libstdc++, as libstdc++ was
@ -4288,17 +4297,17 @@ def doConfigure(myenv):
env.FatalError(
'The --detect-odr-violations flag is expected to only be reliable with --opt=off'
)
AddToLINKFLAGSIfSupported(myenv, '-Wl,--detect-odr-violations')
myenv.AddToLINKFLAGSIfSupported('-Wl,--detect-odr-violations')
# Disallow an executable stack. Also, issue a warning if any files are found that would
# cause the stack to become executable if the noexecstack flag was not in play, so that we
# can find them and fix them. We do this here after we check for ld.gold because the
# --warn-execstack is currently only offered with gold.
AddToLINKFLAGSIfSupported(myenv, "-Wl,-z,noexecstack")
AddToLINKFLAGSIfSupported(myenv, "-Wl,--warn-execstack")
myenv.AddToLINKFLAGSIfSupported("-Wl,-z,noexecstack")
myenv.AddToLINKFLAGSIfSupported("-Wl,--warn-execstack")
# If possible with the current linker, mark relocations as read-only.
AddToLINKFLAGSIfSupported(myenv, "-Wl,-z,relro")
myenv.AddToLINKFLAGSIfSupported("-Wl,-z,relro")
# As far as we know these flags only apply on posix-y systems,
# and not on Darwin.
@ -4331,11 +4340,9 @@ def doConfigure(myenv):
compress_type = "zlib-gabi"
compress_flag = "compress-debug-sections"
AddToCCFLAGSIfSupported(
myenv,
myenv.AddToCCFLAGSIfSupported(
f"-Wa,--{compress_flag}={compress_type}"
if "as" in debug_compress else f"-Wa,--no{compress_flag}",
)
if "as" in debug_compress else f"-Wa,--no{compress_flag}", )
# We shouldn't enable debug compression in the linker
# (meaning our final binaries contain compressed debug
@ -4371,22 +4378,16 @@ def doConfigure(myenv):
conf.Finish()
if have_shf_compressed and 'ld' in debug_compress:
AddToLINKFLAGSIfSupported(
myenv,
f"-Wl,--{compress_flag}={compress_type}",
)
myenv.AddToLINKFLAGSIfSupported(f"-Wl,--{compress_flag}={compress_type}", )
else:
AddToLINKFLAGSIfSupported(
myenv,
f"-Wl,--{compress_flag}=none",
)
myenv.AddToLINKFLAGSIfSupported(f"-Wl,--{compress_flag}=none", )
if "fnsi" in selected_experimental_optimizations:
AddToCCFLAGSIfSupported(myenv, "-fno-semantic-interposition")
myenv.AddToCCFLAGSIfSupported("-fno-semantic-interposition")
# Avoid deduping symbols on OS X debug builds, as it takes a long time.
if optBuild == "off" and myenv.ToolchainIs('clang') and env.TargetOSIs('darwin'):
AddToLINKFLAGSIfSupported(myenv, "-Wl,-no_deduplicate")
myenv.AddToLINKFLAGSIfSupported("-Wl,-no_deduplicate")
# Apply any link time optimization settings as selected by the 'lto' option.
if has_option('lto'):
@ -4403,13 +4404,13 @@ def doConfigure(myenv):
elif myenv.ToolchainIs('gcc', 'clang'):
# For GCC and clang, the flag is -flto, and we need to pass it both on the compile
# and link lines.
if not AddToCCFLAGSIfSupported(myenv, '-flto') or \
not AddToLINKFLAGSIfSupported(myenv, '-flto'):
if not myenv.AddToCCFLAGSIfSupported('-flto') or \
not myenv.AddToLINKFLAGSIfSupported('-flto'):
myenv.ConfError("Link time optimization requested, "
"but selected compiler does not honor -flto")
if myenv.TargetOSIs('darwin'):
AddToLINKFLAGSIfSupported(myenv, '-Wl,-object_path_lto,${TARGET}.lto')
myenv.AddToLINKFLAGSIfSupported('-Wl,-object_path_lto,${TARGET}.lto')
else:
myenv.ConfError("Don't know how to enable --lto on current toolchain")
@ -4525,7 +4526,7 @@ def doConfigure(myenv):
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43052
if myenv.ToolchainIs('gcc') and (env['TARGET_ARCH'] in ['i386', 'x86_64']):
if not 'builtin-memcmp' in selected_experimental_optimizations:
AddToCCFLAGSIfSupported(myenv, '-fno-builtin-memcmp')
myenv.AddToCCFLAGSIfSupported('-fno-builtin-memcmp')
# pthread_setname_np was added in GLIBC 2.12, and Solaris 11.3
if posix_system:
@ -5179,7 +5180,7 @@ def doConfigure(myenv):
myenv = conf.Finish()
if env['TARGET_ARCH'] == "aarch64":
AddToCCFLAGSIfSupported(myenv, "-moutline-atomics")
myenv.AddToCCFLAGSIfSupported("-moutline-atomics")
conf = Configure(myenv)
usdt_enabled = get_option('enable-usdt-probes')
@ -5494,10 +5495,12 @@ if get_option('separate-debug') == "on" or env.TargetOSIs("windows"):
)
separate_debug(env)
# TODO: SERVER-68475
# temp fix for BF-25986, should be removed when better solution is found
if env['SPLIT_DWARF'] == "auto":
env['SPLIT_DWARF'] = env.ToolchainIs('gcc') and not link_model == "dynamic"
# For static builds, splitting out the dwarf info reduces memory requirments, link time
# and binary size significantly. It's affect is less prominent in dynamic builds. The downside
# is .dwo files use absolute paths in the debug info, so it's not relocatable.
env['SPLIT_DWARF'] = not link_model == "dynamic" and env.ToolchainIs(
'gcc', 'clang') and env.CheckCCFLAGSSupported('-gsplit-dwarf')
if env['SPLIT_DWARF']:
env.Tool('split_dwarf')

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

View File

@ -256,9 +256,6 @@ selector:
- jstests/core/index_check6.js
- jstests/core/index_check7.js
- jstests/core/index_decimal.js
- jstests/core/index_elemmatch1.js
- jstests/core/index_elemmatch2.js
- jstests/core/index_elemmatch2.js
- jstests/core/index_filter_commands.js
- jstests/core/index_filter_on_hidden_index.js
- jstests/core/index_multiple_compatibility.js
@ -506,8 +503,6 @@ selector:
- jstests/core/in7.js
- jstests/core/index13.js
- jstests/core/index_check2.js
- jstests/core/index_elemmatch1.js
- jstests/core/index_elemmatch2.js
- jstests/core/indexl.js
- jstests/core/json_schema/misc_validation.js
- jstests/core/ne_array.js
@ -756,7 +751,6 @@ selector:
- jstests/core/geonear_key.js
- jstests/core/getmore_invalidated_documents.js
- jstests/core/hidden_index.js
- jstests/core/index_elemmatch2.js
- jstests/core/index_partial_2dsphere.js
- jstests/core/json_schema/misc_validation.js
- jstests/core/list_collections_filter.js

View File

@ -276,16 +276,15 @@ class PeriodicKillSecondariesTestCase(interface.DynamicTestCase):
secondary.await_ready()
client = secondary.mongo_client()
minvalid_doc = client.local["replset.minvalid"].find_one()
oplog_truncate_after_doc = client.local["replset.oplogTruncateAfterPoint"].find_one()
recovery_timestamp_res = client.admin.command("replSetTest",
getLastStableRecoveryTimestamp=True)
latest_oplog_doc = client.local["oplog.rs"].find_one(sort=[("$natural",
pymongo.DESCENDING)])
self.logger.info("Checking invariants: minValid: {}, oplogTruncateAfterPoint: {},"
self.logger.info("Checking replication invariants. oplogTruncateAfterPoint: {},"
" stable recovery timestamp: {}, latest oplog doc: {}".format(
minvalid_doc, oplog_truncate_after_doc, recovery_timestamp_res,
oplog_truncate_after_doc, recovery_timestamp_res,
latest_oplog_doc))
null_ts = bson.Timestamp(0, 0)
@ -299,13 +298,6 @@ class PeriodicKillSecondariesTestCase(interface.DynamicTestCase):
raise errors.ServerFailure(
"Latest oplog entry had no 'ts' field: {}".format(latest_oplog_doc))
# The "oplogTruncateAfterPoint" document may not exist at startup. If so, we default
# it to null.
oplog_truncate_after_ts = null_ts
if oplog_truncate_after_doc is not None:
oplog_truncate_after_ts = oplog_truncate_after_doc.get(
"oplogTruncateAfterPoint", null_ts)
# The "lastStableRecoveryTimestamp" field is present if the storage engine supports
# "recover to a timestamp". If it's a null timestamp on a durable storage engine, that
# means we do not yet have a stable checkpoint timestamp and must be restarting at the
@ -328,94 +320,6 @@ class PeriodicKillSecondariesTestCase(interface.DynamicTestCase):
recovery_timestamp, latest_oplog_entry_ts,
recovery_timestamp_res, latest_oplog_doc))
if minvalid_doc is not None:
applied_through_ts = minvalid_doc.get("begin", {}).get("ts", null_ts)
minvalid_ts = minvalid_doc.get("ts", null_ts)
# The "appliedThrough" value should always equal the "last stable recovery
# timestamp", AKA the stable checkpoint for durable engines, on server restart.
#
# The written "appliedThrough" time is updated with the latest timestamp at the end
# of each batch application, and batch boundaries are the only valid stable
# timestamps on secondaries. Therefore, a non-null appliedThrough timestamp must
# equal the checkpoint timestamp, because any stable timestamp that the checkpoint
# could use includes an equal persisted appliedThrough timestamp.
if (recovery_timestamp != null_ts and applied_through_ts != null_ts
and (not recovery_timestamp == applied_through_ts)):
raise errors.ServerFailure(
"The condition last stable recovery timestamp ({}) == appliedThrough ({})"
" doesn't hold: minValid document={},"
" getLastStableRecoveryTimestamp result={}, last oplog entry={}".format(
recovery_timestamp, applied_through_ts, minvalid_doc,
recovery_timestamp_res, latest_oplog_doc))
if applied_through_ts == null_ts:
# We clear "appliedThrough" to represent having applied through the top of the
# oplog in PRIMARY state or immediately after "rollback via refetch".
# If we are using a storage engine that supports "recover to a timestamp,"
# then we will have a "last stable recovery timestamp" and we should use that
# as our "appliedThrough" (similarly to why we assert their equality above).
# If both are null, then we are in PRIMARY state on a storage engine that does
# not support "recover to a timestamp" or in RECOVERING immediately after
# "rollback via refetch". Since we do not update "minValid" in PRIMARY state,
# we leave "appliedThrough" as null so that the invariants below hold, rather
# than substituting the latest oplog entry for the "appliedThrough" value.
applied_through_ts = recovery_timestamp
if minvalid_ts == null_ts:
# The server treats the "ts" field in the minValid document as missing when its
# value is the null timestamp.
minvalid_ts = applied_through_ts
if latest_oplog_entry_ts == null_ts:
# If the oplog is empty, we treat the "minValid" as the latest oplog entry.
latest_oplog_entry_ts = minvalid_ts
if oplog_truncate_after_ts == null_ts:
# The server treats the "oplogTruncateAfterPoint" field as missing when its
# value is the null timestamp. When it is null, the oplog is complete and
# should not be truncated, so it is effectively the top of the oplog.
oplog_truncate_after_ts = latest_oplog_entry_ts
# Check the ordering invariants before the secondary has reconciled the end of
# its oplog.
# The "oplogTruncateAfterPoint" is set to the first timestamp of each batch of
# oplog entries before they are written to the oplog. Thus, it can be ahead
# of the top of the oplog before any oplog entries are written, and behind it
# after some are written. Thus, we cannot compare it to the top of the oplog.
# appliedThrough <= minValid
# appliedThrough represents the end of the previous batch, so it is always the
# earliest.
if applied_through_ts > minvalid_ts:
raise errors.ServerFailure(
"The condition appliedThrough <= minValid ({} <= {}) doesn't hold: minValid"
" document={}, latest oplog entry={}".format(
applied_through_ts, minvalid_ts, minvalid_doc, latest_oplog_doc))
# minValid <= oplogTruncateAfterPoint
# This is true because this hook is never run after a rollback. Thus, we only
# move "minValid" to the end of each batch after the batch is written to the oplog.
# We reset the "oplogTruncateAfterPoint" to null before we move "minValid" from
# the end of the previous batch to the end of the current batch. Thus "minValid"
# must be less than or equal to the "oplogTruncateAfterPoint".
if minvalid_ts > oplog_truncate_after_ts:
raise errors.ServerFailure(
"The condition minValid <= oplogTruncateAfterPoint ({} <= {}) doesn't"
" hold: minValid document={}, oplogTruncateAfterPoint document={},"
" latest oplog entry={}".format(minvalid_ts, oplog_truncate_after_ts,
minvalid_doc, oplog_truncate_after_doc,
latest_oplog_doc))
# minvalid <= latest oplog entry
# "minValid" is set to the end of a batch after the batch is written to the oplog.
# Thus it is always less than or equal to the top of the oplog.
if minvalid_ts > latest_oplog_entry_ts:
raise errors.ServerFailure(
"The condition minValid <= top of oplog ({} <= {}) doesn't"
" hold: minValid document={}, latest oplog entry={}".format(
minvalid_ts, latest_oplog_entry_ts, minvalid_doc, latest_oplog_doc))
try:
secondary.teardown()
except errors.ServerFailure:

View File

@ -282,6 +282,8 @@ last-continuous:
test_file: jstests/sharding/move_chunk_interrupt_postimage.js
- ticket: SERVER-64741
test_file: jstests/sharding/append_oplog_note_mongos.js
- ticket: SERVER-68115
test_file: jstests/core/elemmatch_index.js
# Tests that should only be excluded from particular suites should be listed under that suite.
suites:
@ -697,6 +699,8 @@ last-lts:
test_file: jstests/sharding/move_chunk_interrupt_postimage.js
- ticket: SERVER-64741
test_file: jstests/sharding/append_oplog_note_mongos.js
- ticket: SERVER-68115
test_file: jstests/core/elemmatch_index.js
# Tests that should only be excluded from particular suites should be listed under that suite.
suites:

View File

@ -57,6 +57,7 @@ include:
- filename: etc/evergreen_yml_components/variants/task_generation.yml
- filename: etc/evergreen_yml_components/variants/sanitizer.yml
- filename: etc/evergreen_yml_components/variants/in_memory.yml
- filename: etc/evergreen_yml_components/variants/ninja.yml
variables:
- &libfuzzertests
@ -274,21 +275,6 @@ buildvariants:
- rhel80-large
- name: generate_buildid_to_debug_symbols_mapping
- <<: *linux-64-debug-required-template
name: linux-64-debug-wtdevelop
display_name: "~ Linux DEBUG WiredTiger develop"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- wtdevelop
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
- name: tla-plus
display_name: TLA+
run_on:
@ -936,21 +922,6 @@ buildvariants:
# distros:
# - windows-vsCurrent-xlarge
- name: enterprise-windows-ninja
display_name: "Ninja Build: Enterprise Windows"
cron: "0 4 * * *" # From the ${project_nightly_cron} parameter.
modules:
- enterprise
expansions:
compile_flags: --ssl MONGO_DISTMOD=windows CPPPATH="c:/sasl/include" LIBPATH="c:/sasl/lib" -j$(bc <<< "$(grep -c '^processor' /proc/cpuinfo) / 1.5") --win-version-min=win10
tasks:
- name: compile_ninja_next_TG
distros:
- windows-vsCurrent-large
- name: compile_ninja_TG
distros:
- windows-vsCurrent-large
- name: enterprise-windows-cxx20-debug-experimental
display_name: "~ Enterprise Windows C++20 DEBUG"
cron: "0 4 * * *" # From the ${project_nightly_cron} parameter.
@ -1070,20 +1041,6 @@ buildvariants:
- name: unittest_shell_hang_analyzer_gen
- name: generate_buildid_to_debug_symbols_mapping
- name: macos-enterprise-ninja
display_name: "Ninja Build: macOS Enterprise"
cron: "0 4 * * *" # From the ${project_nightly_cron} parameter.
modules:
- enterprise
run_on:
- macos-1100
expansions:
compile_env: DEVELOPER_DIR=/Applications/Xcode13.app
compile_flags: --ssl -j$(sysctl -n hw.logicalcpu) --libc++ --variables-files=etc/scons/xcode_macosx.vars
tasks:
- name: compile_ninja_next_TG
- name: compile_ninja_TG
- name: enterprise-macos-rosetta-2
display_name: "Enterprise macOS Via Rosetta 2"
cron: "0 4 * * *" # From the ${project_nightly_cron} parameter.
@ -1382,26 +1339,6 @@ buildvariants:
<<: *enterprise-rhel-80-64-bit-dynamic-required-expansions
compile_flags: --ssl MONGO_DISTMOD=rhel80 -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars --link-model=dynamic --use-glibcxx-debug --dbg=on --allocator=system
- name: enterprise-rhel-80-64-bit-dynamic-required-ninja
display_name: "Ninja Build: Enterprise RHEL 8.0"
cron: "0 4 * * *" # From the ${project_nightly_cron} parameter.
modules:
- enterprise
run_on:
- rhel80-small
stepback: false
expansions:
compile_flags: --ssl --ocsp-stapling=off MONGO_DISTMOD=rhel80 -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars --link-model=dynamic
repo_edition: enterprise
has_packages: false
tasks:
- name: compile_ninja_next_TG
distros:
- rhel80-xlarge
- name: compile_ninja_TG
distros:
- rhel80-xlarge
- &enterprise-rhel-80-64-bit-dynamic-all-feature-flags-required-template
name: enterprise-rhel-80-64-bit-dynamic-all-feature-flags-required
display_name: "! Shared Library Enterprise RHEL 8.0 (all feature flags)"
@ -3105,17 +3042,6 @@ buildvariants:
- windows-vsCurrent-large
- name: .benchmarks !benchmarks_orphaned
- <<: *enterprise-windows-nopush-template
name: 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
### QO & QE Patch-Specific Build Variants ###
- <<: *enterprise-windows-nopush-template
name: windows-compile-query-patch-only

View File

@ -6,14 +6,386 @@ 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
#- 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
parameters:
- key: evergreen_config_file_path
value: "etc/evergreen_nightly.yml"
description: "path to this file"
buildvariants:
- &linux-64-debug-required-template
name: linux-64-debug-required
display_name: "! Shared Library Linux 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
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_scope: shared
scons_cache_mode: all
test_flags: --excludeWithAnyTags=requires_http_client
target_resmoke_time: 15
max_sub_suites: 5
num_scons_link_jobs_available: 0.99
large_distro_name: rhel80-medium
tasks:
- name: compile_test_and_package_parallel_core_stream_TG
distros:
- rhel80-xlarge
- name: compile_test_and_package_parallel_unittest_stream_TG
distros:
- rhel80-xlarge
- name: compile_test_and_package_parallel_dbtest_stream_TG
distros:
- rhel80-xlarge
- 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: .integration !.audit
- 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
- name: .stitch
- name: server_discovery_and_monitoring_json_test_TG
distros:
- rhel80-large
- name: server_selection_json_test_TG
distros:
- rhel80-large
- name: generate_buildid_to_debug_symbols_mapping
- &enterprise-windows-required-template
name: 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:
burn_in_tests_build_variant: enterprise-windows-required
exe: ".exe"
additional_package_targets: archive-mongocryptd archive-mongocryptd-debug msi archive-mh archive-mh-debug
content_type: application/zip
compile_flags: --ssl MONGO_DISTMOD=windows CPPPATH="c:/sasl/include" LIBPATH="c:/sasl/lib" -j$(bc <<< "$(grep -c '^processor' /proc/cpuinfo) / 1.8") --win-version-min=win10
num_scons_link_jobs_available: 0.2
python: '/cygdrive/c/python/python37/python.exe'
ext: zip
scons_cache_scope: shared
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: compile_test_and_package_serial_TG
distros:
- windows-vsCurrent-xlarge
- name: compile_build_tools_next_TG
distros:
- windows-vsCurrent-xlarge
- name: burn_in_tests_gen
- name: audit
- name: auth_audit_gen
- name: buildscripts_test
- name: causally_consistent_jscore_txns_passthrough
distros:
- windows-vsCurrent-large
- name: .crypt
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
distros:
- windows-vsCurrent-large
- name: replica_sets_ese_gen
- name: sasl
- name: server_discovery_and_monitoring_json_test_TG
- name: server_selection_json_test_TG
- name: .sharding .txns
- name: sharding_auth_gen
- name: sharding_auth_audit_gen
- name: sharding_ese_gen
- name: sharding_opportunistic_secondary_targeting_gen
- name: unittest_shell_hang_analyzer_gen
- &enterprise-rhel-80-64-bit-dynamic-required-template
name: 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-required-expansions
additional_package_targets: archive-mongocryptd archive-mongocryptd-debug archive-mh archive-mh-debug
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"
multiversion_platform: rhel80
multiversion_edition: enterprise
has_packages: false
scons_cache_scope: shared
scons_cache_mode: all
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
num_scons_link_jobs_available: 0.99
tasks:
- name: compile_test_and_package_parallel_core_stream_TG
distros:
- rhel80-xlarge
# - name: compile_test_and_package_parallel_unittest_stream_with_recording_TG
# distros:
# - rhel80-xlarge
- name: compile_test_and_package_parallel_unittest_stream_TG
distros:
- rhel80-xlarge
- name: compile_test_and_package_parallel_dbtest_stream_TG
distros:
- rhel80-xlarge
- name: .lint
- name: lint_fuzzer_sanity_patch
- name: test_api_version_compatibility
- name: burn_in_tests_gen
- name: check_feature_flag_tags
- name: check_for_todos
- name: .aggfuzzer !.feature_flag_guarded
- name: .aggregation !.feature_flag_guarded
- name: audit
- name: .auth
# - name: burn_in_tags_gen
- name: buildscripts_test
- name: resmoke_end2end_tests
- name: unittest_shell_hang_analyzer_gen
- name: .causally_consistent !.sharding
- name: .change_streams
- name: .change_stream_fuzzer
- name: .misc_js
- name: .concurrency !.large !.ubsan !.no_txns !.debug_only
- name: .concurrency .large !.ubsan !.no_txns !.debug_only
distros:
- rhel80-medium
- name: config_fuzzer_concurrency
- name: config_fuzzer_simulate_crash_concurrency_replication
distros:
- rhel80-large
- name: config_fuzzer_concurrency_replication
distros:
- rhel80-large
- name: config_fuzzer_jsCore
- name: config_fuzzer_replica_sets_jscore_passthrough
distros:
- rhel80-large
- name: disk_wiredtiger
- name: .encrypt
- name: idl_tests
- name: initial_sync_fuzzer_gen
- name: .integration
distros:
- rhel80-medium
- 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: .multiversion_sanity_check
- 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: sharding_opportunistic_secondary_targeting_gen
- name: .stitch
- name: .crypt
distros:
- rhel80-xlarge
- name: crypt_build_debug_and_test
distros:
- rhel80-xlarge
- name: .updatefuzzer
- name: secondary_reads_passthrough_gen
- name: server_discovery_and_monitoring_json_test_TG
- name: .serverless
distros:
- rhel80-xlarge
- name: server_selection_json_test_TG
distros:
- rhel80-xlarge
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-rhel80-dynamic-clang-tidy-required
display_name: "! Enterprise Clang Tidy"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- enterprise
run_on:
- rhel80-xxlarge
expansions:
lang_environment: LANG=C
compile_flags: --link-model=dynamic -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_${clang_tidy_toolchain}_clang.vars
scons_cache_scope: shared
scons_cache_mode: all
show_scons_timings: false
clang_tidy_toolchain: v3
clang_tidy_file: .clang-tidy-extra-checks
tasks:
- name: clang_tidy_TG
- &rhel80-debug-aubsan-lite-required-template
name: 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
stepback: true
expansions:
additional_package_targets: archive-mongocryptd archive-mongocryptd-debug
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"
compile_flags: --variables-files=etc/scons/mongodbtoolchain_v3_clang.vars --dbg=on --opt=on --allocator=system --sanitize=undefined,address --ssl --ocsp-stapling=off -j$(grep -c ^processor /proc/cpuinfo) --link-model=dynamic
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
scons_cache_scope: shared
scons_cache_mode: all
max_sub_suites: 3
num_scons_link_jobs_available: 0.99
separate_debug: off
large_distro_name: rhel80-build
tasks:
- name: compile_test_and_package_parallel_core_stream_TG
distros:
- rhel80-xlarge
- name: compile_test_and_package_parallel_unittest_stream_TG
distros:
- rhel80-xlarge
- name: compile_test_and_package_parallel_dbtest_stream_TG
distros:
- rhel80-xlarge
- name: jsCore
- name: jsCore_txns
- name: unittest_shell_hang_analyzer_gen
- name: generate_buildid_to_debug_symbols_mapping
- <<: *enterprise-rhel-80-64-bit-dynamic-required-template
name: commit-queue
display_name: "~ Commit Queue"
cron: "0 4 * * 0" # From the ${project_weekly_cron} parameter
stepback: false
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

View File

@ -35,6 +35,8 @@ overrides:
enterprise-rhel-80-64-bit-dynamic-required:
- task: replica_sets_large_txns_format
exec_timeout: 120 # 2 hours.
- task: config_fuzzer_replica_sets_jscore_passthrough
exec_timeout: 150 # 2.5 hours.
enterprise-rhel80-debug-tsan:
- task: run_unittests

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.1
- name: wtdevelop
repo: git@github.com:wiredtiger/wiredtiger.git
@ -304,7 +304,6 @@ variables:
- enterprise-windows-debug-unoptimized
- enterprise-windows-inmem
- enterprise-windows-required
- enterprise-windows-wtdevelop
- ubuntu1804-debug-asan
- ubuntu1804-debug-ubsan
- ubuntu1804-debug-aubsan-lite-required
@ -578,7 +577,7 @@ functions:
"get buildnumber": &get_buildnumber
command: keyval.inc
params:
key: "${build_variant}_master"
key: "${build_variant}_v6.1"
destination: "builder_num"
"run diskstats": &run_diskstats
@ -1039,6 +1038,8 @@ functions:
- *f_expansions_write
- *kill_processes
- *cleanup_environment
- *get_version_expansions
- *apply_version_expansions
- *fetch_venv
- *adjust_venv
- *f_expansions_write
@ -1179,6 +1180,15 @@ functions:
args:
- "src/evergreen/scons_compile.sh"
"ninja compile":
- *f_expansions_write
- command: subprocess.exec
type: test
params:
binary: bash
args:
- "./src/evergreen/ninja_compile.sh"
"generate version expansions": &generate_version_expansions
command: subprocess.exec
params:
@ -2303,11 +2313,93 @@ tasks:
task_compile_flags: >-
--ninja
- *f_expansions_write
- command: subprocess.exec
params:
binary: bash
args:
- "./src/evergreen/ninja_compile.sh"
- func: "ninja compile"
vars:
ninja_file: "build.ninja"
- name: compile_ninja_default_profile
tags: []
depends_on:
- name: version_expansions_gen
variant: generate-tasks-for-version
commands:
- func: "scons compile"
vars:
generating_for_ninja: true
separate_debug: off
task_install_action:
default
task_compile_flags: >-
--build-profile=default
--variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars
--ninja
- *f_expansions_write
- func: "ninja compile"
vars:
ninja_file: "build.ninja"
- name: compile_ninja_opt_profile
tags: []
depends_on:
- name: version_expansions_gen
variant: generate-tasks-for-version
commands:
- func: "scons compile"
vars:
generating_for_ninja: true
separate_debug: off
task_install_action:
default
task_compile_flags: >-
--build-profile=opt
CCACHE=
ICECC=
- *f_expansions_write
- func: "ninja compile"
vars:
ninja_file: "opt.ninja"
- name: compile_ninja_fast_profile
tags: []
depends_on:
- name: version_expansions_gen
variant: generate-tasks-for-version
commands:
- func: "scons compile"
vars:
generating_for_ninja: true
separate_debug: off
task_install_action:
default
task_compile_flags: >-
--build-profile=fast
CCACHE=
ICECC=
- *f_expansions_write
- func: "ninja compile"
vars:
ninja_file: "fast.ninja"
- name: compile_ninja_san_profile
tags: []
depends_on:
- name: version_expansions_gen
variant: generate-tasks-for-version
commands:
- func: "scons compile"
vars:
generating_for_ninja: true
separate_debug: off
task_install_action:
default
task_compile_flags: >-
--build-profile=san
CCACHE=
ICECC=
- *f_expansions_write
- func: "ninja compile"
vars:
ninja_file: "san.ninja"
- name: compile_ninja_next
tags: []
@ -2325,11 +2417,9 @@ tasks:
--build-tools=next
--ninja
- *f_expansions_write
- command: subprocess.exec
params:
binary: bash
args:
- "./src/evergreen/ninja_compile.sh"
- func: "ninja compile"
vars:
ninja_file: "build.ninja"
- name: compile_build_tools_next
tags: []
@ -2895,7 +2985,7 @@ tasks:
task_compile_flags: >-
--allocator=system
--enable-free-mon=off
--enterprise-features=fle
--enterprise-features=fle,search
--js-engine=none
--link-model=dynamic-sdk
--enable-http-client=off
@ -2933,7 +3023,7 @@ tasks:
--opt=off
--allocator=system
--enable-free-mon=off
--enterprise-features=fle
--enterprise-features=fle,search
--js-engine=none
--link-model=dynamic-sdk
DESTDIR='$BUILD_ROOT/crypt-lib-$MONGO_VERSION'
@ -2973,7 +3063,7 @@ tasks:
task_compile_flags: >-
--allocator=system
--enable-free-mon=off
--enterprise-features=fle
--enterprise-features=fle,search
--js-engine=none
--link-model=static
DESTDIR='$BUILD_ROOT/crypt-lib-$MONGO_VERSION'
@ -6586,6 +6676,7 @@ tasks:
commands:
- command: manifest.load
- func: "git get project and add git tag"
- func: "get and apply version expansions"
- func: "f_expansions_write"
- func: "kill processes"
- func: "cleanup environment"
@ -7487,6 +7578,26 @@ task_groups:
content_type: text/plain
display_name: build.ninja
- <<: *compile_task_group_template
name: compile_ninja_default_profile_TG
tasks:
- compile_ninja_default_profile
- <<: *compile_task_group_template
name: compile_ninja_opt_profile_TG
tasks:
- compile_ninja_opt_profile
- <<: *compile_task_group_template
name: compile_ninja_san_profile_TG
tasks:
- compile_ninja_san_profile
- <<: *compile_task_group_template
name: compile_ninja_fast_profile_TG
tasks:
- compile_ninja_fast_profile
- <<: *compile_task_group_template
name: server_discovery_and_monitoring_json_test_TG
tasks:

View File

@ -0,0 +1,74 @@
buildvariants:
- name: enterprise-windows-ninja
display_name: "Ninja Build: Enterprise Windows"
cron: "0 4 * * 0" # Run once a week to ensure no failures introduced to ninja builds
modules:
- enterprise
expansions:
compile_flags: --ssl MONGO_DISTMOD=windows CPPPATH="c:/sasl/include c:/snmp/include" LIBPATH="c:/sasl/lib c:/snmp/lib" -j$(bc <<< "$(grep -c '^processor' /proc/cpuinfo) / 1.5") --win-version-min=win10
tasks:
- name: compile_ninja_next_TG
distros:
- windows-vsCurrent-large
- name: compile_ninja_TG
distros:
- windows-vsCurrent-large
- name: macos-enterprise-ninja
display_name: "Ninja Build: macOS Enterprise"
cron: "0 4 * * 0" # Run once a week to ensure no failures introduced to ninja builds
modules:
- enterprise
run_on:
- macos-1100
expansions:
compile_env: DEVELOPER_DIR=/Applications/Xcode13.app
compile_flags: --ssl -j$(sysctl -n hw.logicalcpu) --libc++ --variables-files=etc/scons/xcode_macosx.vars
tasks:
- name: compile_ninja_next_TG
- name: compile_ninja_TG
- name: ubuntu1804-ninja-build-profiles
display_name: "Ninja Build Profiles: Ubuntu 18.04"
cron: "0 4 * * 0" # Run once a week to ensure no failures introduced to build profiles
modules:
- enterprise
run_on:
- ubuntu1804-small
stepback: false
expansions:
compile_flags: --ssl --ocsp-stapling=off MONGO_DISTMOD=ubuntu1804 -j$(grep -c ^processor /proc/cpuinfo)
repo_edition: enterprise
has_packages: false
tasks:
- name: compile_ninja_default_profile_TG
distros:
- ubuntu1804-xlarge
- name: compile_ninja_opt_profile_TG
distros:
- ubuntu1804-xlarge
- name: compile_ninja_san_profile_TG
distros:
- ubuntu1804-xlarge
- name: compile_ninja_fast_profile_TG
distros:
- ubuntu1804-xlarge
- name: enterprise-rhel-80-64-bit-dynamic-required-ninja
display_name: "Ninja Build: Enterprise RHEL 8.0"
cron: "0 4 * * 0" # Run once a week to ensure no failures introduced to ninja builds
modules:
- enterprise
run_on:
- rhel80-small
expansions:
compile_flags: --ssl MONGO_DISTMOD=rhel80 -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars --link-model=dynamic
has_packages: false
tasks:
- name: compile_ninja_next_TG
distros:
- rhel80-xlarge
- name: compile_ninja_TG
distros:
- rhel80-xlarge

View File

@ -104,7 +104,7 @@ modules:
- name: enterprise
repo: git@github.com:10gen/mongo-enterprise-modules.git
prefix: src/mongo/db/modules
branch: master
branch: v6.1
- name: mongo-tools
repo: git@github.com:mongodb/mongo-tools.git
prefix: mongo-tools/src/github.com/mongodb
@ -336,10 +336,7 @@ functions:
set -o errexit
set -o verbose
source "${workdir}/compile_venv/bin/activate"
# TODO: SERVER-68475
# remove this when a better solution is found
extra_args="SPLIT_DWARF_DWP_FILES=1"
python ./buildscripts/scons.py ${compile_flags|} ${scons_cache_args|} $extra_args install-core install-jstestshell MONGO_VERSION=${version} DESTDIR=$(pwd)/mongodb ${patch_compile_flags|}
python ./buildscripts/scons.py ${compile_flags|} ${scons_cache_args|} $extra_args install-core install-jstestshell SPLIT_DWARF=0 MONGO_VERSION=${version} DESTDIR=$(pwd)/mongodb ${patch_compile_flags|}
mkdir -p mongodb/jstests/hooks
if [ -d jstests/hooks ]
then

View File

@ -1,6 +1,9 @@
# This file is now empty and the settings have been made the default.
# This file exists only to prevent breakage when used with existing command line invocations.
# Configures the build for building with a unified ninja
# Each configuration will share a ninja log
# This allows the output binaries of each configuration to share a common directory
NINJA_BUILDDIR="$BUILD_ROOT/ninja"
DESTDIR="$BUILD_ROOT/install"
# NINJA_BUILDDIR="$BUILD_ROOT/ninja"
# DESTDIR="$BUILD_ROOT/install"

View File

@ -101,8 +101,7 @@ modules:
- name: tsbs
repo: git@github.com:gregorynoma/tsbs.git
prefix: ${workdir}/src
branch: master
ref: 027f4b2d83267ae69d2740855654b4a7cac72498
branch: production
- name: mongo-perf
repo: git@github.com:mongodb/mongo-perf.git
prefix: ${workdir}/src
@ -127,7 +126,7 @@ modules:
- name: enterprise
repo: git@github.com:10gen/mongo-enterprise-modules.git
prefix: src/mongo/db/modules
branch: master
branch: v6.1
- name: mongo-tools
repo: git@github.com:mongodb/mongo-tools.git
prefix: mongo-tools/src/github.com/mongodb
@ -366,10 +365,7 @@ functions:
set -o errexit
set -o verbose
source "${workdir}/compile_venv/bin/activate"
# TODO: SERVER-68475
# remove this when a better solution is found
extra_args="SPLIT_DWARF_DWP_FILES=1"
python ./buildscripts/scons.py ${compile_flags|} ${scons_cache_args|} $extra_args install-core install-jstestshell MONGO_VERSION=${version} DESTDIR=$(pwd)/mongodb ${patch_compile_flags|}
python ./buildscripts/scons.py ${compile_flags|} ${scons_cache_args|} $extra_args install-core install-jstestshell SPLIT_DWARF=0 MONGO_VERSION=${version} DESTDIR=$(pwd)/mongodb ${patch_compile_flags|}
mkdir -p mongodb/jstests/hooks
if [ -d jstests/hooks ]
then
@ -506,43 +502,6 @@ tasks:
mongo-tools: ${mongo-tools_rev}
- func: "compile mongodb"
- name: renew_ssl_cert
commands:
- command: git.get_project
params:
directory: *src_dir
revisions:
dsi: ${dsi_rev}
# Run the script to generate ssl cert files
- command: shell.exec
params:
script: AWS_ACCESS_KEY_ID=${terraform_key} AWS_SECRET_ACCESS_KEY=${terraform_secret} ./src/dsi/run-dsi generate_ssl_cert
# Upload files for further DSI usage
- command: s3.put
params:
aws_key: ${aws_key}
aws_secret: ${aws_secret}
local_file: member.pem
# path to the remote file is intended to be static
remote_file: dsi/ssl/member.pem
bucket: mciuploads
# the visibility has to be public for consumption by DSI
permissions: public-read
content_type: text/plain
display_name: member.pem
- command: s3.put
params:
aws_key: ${aws_key}
aws_secret: ${aws_secret}
local_file: root.crt
# path to the remote file is intended to be static
remote_file: dsi/ssl/root.crt
bucket: mciuploads
# the visibility has to be public for consumption by DSI
permissions: public-read
content_type: text/plain
display_name: root.crt
- name: linkbench
priority: 5
commands:
@ -957,7 +916,7 @@ tasks:
test_control: "initialsync-logkeeper"
mongodb_setup: "initialsync-logkeeper-short"
# Logkeeper dataset with FCV set to 6.0
mongodb_dataset: "https://s3-us-west-2.amazonaws.com/dsi-donot-remove/InitialSyncLogKeeper/logkeeper-slice-data-mongodb-6.0.tgz"
mongodb_dataset: "https://dsi-donot-remove.s3-us-west-2.amazonaws.com/InitialSyncLogKeeper/logkeeper-slice-data-mongodb-6.1.tgz"
- name: initialsync-logkeeper-short-fcbis
priority: 5
@ -967,7 +926,7 @@ tasks:
test_control: "initialsync-logkeeper"
mongodb_setup: "initialsync-logkeeper-short-fcbis"
# Logkeeper dataset with FCV set to 6.0
mongodb_dataset: "https://s3-us-west-2.amazonaws.com/dsi-donot-remove/InitialSyncLogKeeper/logkeeper-slice-data-mongodb-6.0.tgz"
mongodb_dataset: "https://dsi-donot-remove.s3-us-west-2.amazonaws.com/InitialSyncLogKeeper/logkeeper-slice-data-mongodb-6.1.tgz"
- name: initialsync-logkeeper
priority: 5
@ -999,7 +958,7 @@ tasks:
test_control: "initialsync-logkeeper-short-s3-update"
mongodb_setup: "initialsync-logkeeper-short-s3-update"
# Update this to Logkeeper dataset with FCV set to latest after each LTS release.
mongodb_dataset: "https://s3-us-west-2.amazonaws.com/dsi-donot-remove/InitialSyncLogKeeper/logkeeper-slice-data-mongodb-6.0.tgz"
mongodb_dataset: "https://dsi-donot-remove.s3-us-west-2.amazonaws.com/InitialSyncLogKeeper/logkeeper-slice-data-mongodb-6.1.tgz"
- name: initialsync-logkeeper-snapshot-update
priority: 5
@ -1171,41 +1130,6 @@ buildvariants:
- name: tpch_10_normalized
- name: tpch_10_denormalized
- name: linux-standalone-all-feature-flags
display_name: Linux Standalone (all feature flags)
cron: "0 0 * * *" # Everyday at 00:00
modules: *modules
expansions:
mongodb_setup: standalone-all-feature-flags
infrastructure_provisioning: single
platform: linux
project_dir: *project_dir
authentication: enabled
storageEngine: wiredTiger
run_on:
- "rhel70-perf-single"
depends_on: *_compile_amazon2
tasks:
- name: schedule_patch_auto_tasks
- name: schedule_variant_auto_tasks
- name: industry_benchmarks
- name: ycsb_60GB
- name: ycsb_60GB.long
- name: crud_workloads
- name: bestbuy_agg
- name: bestbuy_agg_merge_different_db
- name: bestbuy_agg_merge_same_db
- name: bestbuy_agg_merge_wordcount
- name: bestbuy_query
- name: cursor_manager
- name: map_reduce_workloads
- name: tpcc
- name: tpch_1_normalized
- name: tpch_1_denormalized
- name: tpch_10_normalized
- name: tpch_10_denormalized
- name: column_store_index_charts_events_1G
- name: linux-standalone-classic-query-engine
display_name: Linux Standalone (Classic Query Engine)
cron: "0 0 * * 4" # 00:00 on Thursday
@ -1658,26 +1582,6 @@ buildvariants:
- name: industry_benchmarks
- name: linkbench
- name: linux-shard-lite-all-feature-flags
display_name: Linux Shard Lite (all feature flags)
cron: "0 0 * * 4" # 00:00 on Thursday
modules: *modules
expansions:
mongodb_setup: shard-lite-all-feature-flags
infrastructure_provisioning: shard-lite
platform: linux
project_dir: *project_dir
authentication: enabled
storageEngine: wiredTiger
run_on:
- "rhel70-perf-shard-lite"
depends_on: *_compile_amazon2
tasks:
- name: schedule_patch_auto_tasks
- name: schedule_variant_auto_tasks
- name: change_streams_preimage_throughput
- name: change_streams_preimage_latency
- name: linux-shard-single
display_name: Linux Shard Single
cron: "0 0 * * 0,4" # 00:00 on Sunday,Thursday
@ -1869,67 +1773,6 @@ buildvariants:
- name: sb_large_scale
- name: sb_timeseries
# Note that the "disabled-feature-flags" part of the name is kept to avoid breaking
# history even though the display name is "all feature flags"
- name: linux-3-node-replSet-disabled-feature-flags
display_name: Linux 3-Node ReplSet (all feature flags)
cron: "0 0 * * 4" # 00:00 on Thursday
modules: *modules
expansions:
mongodb_setup: replica-all-feature-flags
infrastructure_provisioning: replica
platform: linux
project_dir: *project_dir
authentication: enabled
storageEngine: wiredTiger
run_on:
- "rhel70-perf-replset"
depends_on: *_compile_amazon2
tasks:
- name: schedule_patch_auto_tasks
- name: schedule_variant_auto_tasks
- name: industry_benchmarks
- name: ycsb_60GB
- name: ycsb_60GB.long
- name: industry_benchmarks_secondary_reads
- name: crud_workloads
- name: crud_workloads_majority
- name: mixed_workloads
- name: misc_workloads
- name: map_reduce_workloads
- name: refine_shard_key_transaction_stress
- name: smoke_test
- name: retryable_writes_workloads
- name: industry_benchmarks_wmajority
- name: secondary_performance # Uses a special 2 node mongodb setup
- name: non_sharded_workloads
- name: bestbuy_agg
- name: bestbuy_agg_merge_different_db
- name: bestbuy_agg_merge_same_db
- name: bestbuy_agg_merge_wordcount
- name: bestbuy_query
- name: change_streams_throughput
- name: change_streams_latency
- name: change_streams_listen_throughput
- name: change_streams_preimage_throughput
- name: change_streams_preimage_latency
- name: snapshot_reads
- name: secondary_reads
- name: tpcc
- name: tpch_1_normalized
- name: tpch_1_denormalized
# TODO: Enable in SERVER-66572.
# - name: tpch_10_normalized
# - name: tpch_10_denormalized
- name: linkbench
- name: linkbench2
# Time-series collections are available since v5.0.
# - name: tsbs_load
# - name: tsbs_query
# - name: tsbs_query_manual_bucketing
- name: sb_large_scale
- name: sb_timeseries
- name: linux-3-node-replSet-noflowcontrol
display_name: Linux 3-Node ReplSet (Flow Control off)
cron: "0 0 * * 4" # 00:00 on Thursday
@ -2041,7 +1884,7 @@ buildvariants:
mongodb_setup: initialsync-logkeeper
infrastructure_provisioning: initialsync-logkeeper
# EBS logkeeper snapshot with FCV set to 6.0
snapshotId: snap-0306dce35f030ebec
snapshotId: snap-0716ed59d18225693
platform: linux
authentication: disabled
storageEngine: wiredTiger
@ -2065,7 +1908,7 @@ buildvariants:
# mongodb_setup: initialsync-logkeeper-snapshot-update
# infrastructure_provisioning: initialsync-logkeeper-snapshot-update
# # Update this to latest snapshot after each LTS release.
# snapshotId: snap-0306dce35f030ebec
# snapshotId: snap-0716ed59d18225693
# platform: linux
# authentication: disabled
# storageEngine: wiredTiger
@ -2160,12 +2003,3 @@ buildvariants:
- name: tpcc
- name: linkbench
- name: linkbench2
- name: renew-ssl-cert
display_name: Renew SSL Cert
cron: "0 0 * * 4" # 00:00 on Thursday
modules: *modules
run_on: # Certbot with route53 plugin is installed on Ubuntu 20.04
- "ubuntu2004-small"
tasks:
- name: renew_ssl_cert

View File

@ -5,6 +5,7 @@ cd src
set -o errexit
set -o verbose
activate_venv
python -m pip install ninja
if [ "Windows_NT" = "$OS" ]; then
@ -13,8 +14,8 @@ if [ "Windows_NT" = "$OS" ]; then
for i in "${compile_env[@]}"; do
echo "set $i" >> msvc.bat
done
echo "ninja install-core" >> msvc.bat
echo "ninja -f ${ninja_file} install-core" >> msvc.bat
cmd /C msvc.bat
else
eval ${compile_env} ninja install-core
eval ${compile_env} ninja -f ${ninja_file} install-core
fi

View File

@ -58,9 +58,7 @@ else
extra_args="$extra_args --release"
fi
# TODO: SERVER-68475
# remove this when a better solution is found
extra_args="$extra_args SPLIT_DWARF_DWP_FILES=1"
extra_args="$extra_args SPLIT_DWARF=0"
if [ "${generating_for_ninja}" = "true" ] && [ "Windows_NT" = "$OS" ]; then
vcvars="$(vswhere -latest -property installationPath | tr '\\' '/' | dos2unix.exe)/VC/Auxiliary/Build/"

View File

@ -1084,5 +1084,29 @@ verifyOnWholeCluster(
{change_stream_match_pushdown_and_rewrite_and_rewrite: {dropDatabase: [dbName, dbName]}},
1 /* expectedOplogRetDocsForEachShard */);
// Create two sharded collections in the main test database, then start a new change stream to get a
// fresh resume token.
const collWithDot =
createShardedCollection(st, "_id" /* shardKey */, dbName, "foo.bar", 2 /*splitAt */);
const collWithUnderscore =
createShardedCollection(st, "_id" /* shardKey */, dbName, "foo_bar", 2 /*splitAt */);
const thirdResumeAfterToken =
db.getSiblingDB("admin").watch([], {allChangesForCluster: true}).getResumeToken();
// Insert one document per collection, per shard. The test cases below verify the behavior of regex
// matches with escaped characters on collections with special names (e.g. containing dots). This
// exercises the fix for SERVER-67715.
assert.commandWorked(collWithDot.insert({_id: 1}));
assert.commandWorked(collWithDot.insert({_id: 3}));
assert.commandWorked(collWithUnderscore.insert({_id: 1}));
assert.commandWorked(collWithUnderscore.insert({_id: 3}));
// Ensure that a regex match properly respects escaped characters (here, testing that the escaped
// "." character is treated as a literal dot).
verifyOnWholeCluster(thirdResumeAfterToken,
{$match: {"ns.coll": {$nin: [/^foo\./]}}},
{"foo_bar": {insert: [1, 3]}},
1 /* expectedOplogRetDocsForEachShard */);
st.stop();
})();

View File

@ -816,5 +816,48 @@ verifyOnWholeCluster(
},
[9, 3] /* expectedOplogRetDocsForEachShard */);
// Create a new change stream and resume token for replaying the stream after this point.
const thirdResumeAfterToken =
db.getSiblingDB("admin").watch([], {allChangesForCluster: true}).getResumeToken();
// The test cases below verify the behavior of regex matches with escaped characters on collections
// with special names (e.g. containing dots). This exercises the fix for SERVER-67715.
const collWithDot =
createShardedCollection(st, "_id" /* shardKey */, dbName, "foo.bar", 2 /*splitAt */);
assert.commandWorked(collWithDot.createIndex({x: 1}));
assert.commandWorked(collWithDot.insert({_id: 1}));
assert.commandWorked(collWithDot.insert({_id: 3}));
assert.commandWorked(
collWithDot.runCommand({collMod: "foo.bar", index: {keyPattern: {x: 1}, hidden: true}}));
assert.commandWorked(collWithDot.runCommand({dropIndexes: "foo.bar", index: {x: 1}}));
const collWithUnderscore =
createShardedCollection(st, "_id" /* shardKey */, dbName, "foo_bar", 2 /*splitAt */);
assert.commandWorked(collWithUnderscore.createIndex({x: 1}));
assert.commandWorked(collWithUnderscore.insert({_id: 1}));
assert.commandWorked(collWithUnderscore.insert({_id: 3}));
assert.commandWorked(
collWithUnderscore.runCommand({collMod: "foo_bar", index: {keyPattern: {x: 1}, hidden: true}}));
assert.commandWorked(collWithUnderscore.runCommand({dropIndexes: "foo_bar", index: {x: 1}}));
// Ensure that a regex match properly respects escaped characters (here, testing that the escaped
// "." character is treated as a literal dot). Note that we expect 5 extra oplog entries on shard0:
// - 1 from the "create" event (which only appears on shard0)
// - 4 no-op entries from sharding the two collections that are not affected by the filter pushdown
// (2 "shardCollection" + 2 "migrateChunkToNewShard")
verifyOnWholeCluster(thirdResumeAfterToken,
{$match: {"ns.coll": {$nin: [/^foo\./]}}},
{
"foo_bar": {
create: ["foo_bar"],
shardCollection: ["foo_bar"],
createIndexes: ["foo_bar", "foo_bar"],
insert: [1, 3],
modify: ["foo_bar", "foo_bar"],
dropIndexes: ["foo_bar", "foo_bar"]
}
},
[9, 4] /* expectedOplogRetDocsForEachShard */);
st.stop();
})();

View File

@ -39,13 +39,6 @@ assert.commandFailedWithCode(
db.runCommand({"collMod": collName, "index": {"keyPattern": {a: 1}, "expireAfterSeconds": -1}}),
ErrorCodes.InvalidOptions);
// Tries to modify with an 'expireAfterSeconds' value too large.
assert.commandFailedWithCode(db.runCommand({
"collMod": collName,
"index": {"keyPattern": {a: 1}, "expireAfterSeconds": 10000000000000}
}),
ErrorCodes.InvalidOptions);
// Successfully converts to a TTL index.
assert.commandWorked(db.runCommand(
{"collMod": collName, "index": {"keyPattern": {a: 1}, "expireAfterSeconds": 100}}));

View File

@ -2,6 +2,7 @@
* Test that queries containing $elemMatch correctly use an index if each child expression is
* compatible with the index.
* @tags: [
* assumes_balancer_off,
* assumes_read_concern_local,
* ]
*/
@ -64,4 +65,51 @@ assertIndexResults(coll, {a: {$elemMatch: {$not: {$in: [/^a/]}}}}, false, 3);
coll.dropIndexes();
assert.commandWorked(coll.createIndex({a: 1}));
assertIndexResults(coll, {a: {$elemMatch: {$not: {$in: [/^a/]}}}}, false, 3);
(function() {
assert(coll.drop());
assert.commandWorked(coll.insert({a: [{b: {c: "x"}}]}));
assert.commandWorked(coll.createIndex({"a.b.c": 1}));
// Tests $elemMatch with path components that are empty strings. The system should not attempt to
// use the index for these queries.
assertIndexResults(coll, {"": {$elemMatch: {"a.b.c": "x"}}}, false, 0);
assertIndexResults(coll, {"": {$all: [{$elemMatch: {"a.b.c": "x"}}]}}, false, 0);
assertIndexResults(coll, {a: {$elemMatch: {"": {$elemMatch: {"b.c": "x"}}}}}, false, 0);
// Tests $elemMatch with supporting index and no path components that are empty strings.
assertIndexResults(coll, {a: {$elemMatch: {"b.c": "x"}}}, true, 1);
assertIndexResults(coll, {a: {$all: [{$elemMatch: {"b.c": "x"}}]}}, true, 1);
})();
(function() {
const coll = db.index_elemmatch1;
coll.drop();
let x = 0;
let y = 0;
const bulk = coll.initializeUnorderedBulkOp();
for (let a = 0; a < 10; a++) {
for (let b = 0; b < 10; b++) {
bulk.insert({a: a, b: b % 10, arr: [{x: x++ % 10, y: y++ % 10}]});
}
}
assert.commandWorked(bulk.execute());
assert.commandWorked(coll.createIndex({a: 1, b: 1}));
assert.commandWorked(coll.createIndex({"arr.x": 1, a: 1}));
const query = {
a: 5,
b: {$in: [1, 3, 5]},
arr: {$elemMatch: {x: 5, y: 5}}
};
const count = coll.find(query).itcount();
assert.eq(count, 1);
const explain = coll.find(query).hint({"arr.x": 1, a: 1}).explain("executionStats");
assert.commandWorked(explain);
assert.eq(count, explain.executionStats.totalKeysExamined, explain);
})();
})();

View File

@ -5,6 +5,7 @@
* ]
*/
(function() {
db.filler_collection.drop();
assert.commandWorked(db.createCollection("filler_collection"));
var missingColl = db.explain_null_collection;

View File

@ -1,39 +0,0 @@
/**
* Tests find with $elemMatch when supporting indexes are in place.
* @tags: [
* assumes_balancer_off,
* assumes_read_concern_local,
* ]
*/
(function() {
"use strict";
const coll = db.index_elemmatch1;
coll.drop();
let x = 0;
let y = 0;
const bulk = coll.initializeUnorderedBulkOp();
for (let a = 0; a < 10; a++) {
for (let b = 0; b < 10; b++) {
bulk.insert({a: a, b: b % 10, arr: [{x: x++ % 10, y: y++ % 10}]});
}
}
assert.commandWorked(bulk.execute());
assert.commandWorked(coll.createIndex({a: 1, b: 1}));
assert.commandWorked(coll.createIndex({"arr.x": 1, a: 1}));
const query = {
a: 5,
b: {$in: [1, 3, 5]},
arr: {$elemMatch: {x: 5, y: 5}}
};
const count = coll.find(query).itcount();
assert.eq(count, 1);
const explain = coll.find(query).hint({"arr.x": 1, a: 1}).explain("executionStats");
assert.commandWorked(explain);
assert.eq(count, explain.executionStats.totalKeysExamined, explain);
})();

View File

@ -0,0 +1,18 @@
(function() {
"use strict";
const coll = db.bar;
assert.commandWorked(coll.insert({x: 1}));
const map = function() {
emit(0, "mapped value");
};
const reduce = function(key, values) {
return "reduced value";
};
const res = assert.commandWorked(
db.runCommand({mapReduce: 'bar', map: map, reduce: reduce, out: {inline: 1}}));
assert.eq(res.results[0], {_id: 0, value: "reduced value"});
}());

View File

@ -1,7 +1,10 @@
/**
* Ensures that the options passed in for TTL indexes are validated during index creation.
*
* @tags: [requires_ttl_index]
* @tags: [
* requires_fcv_61,
* requires_ttl_index,
* ]
*/
(function() {
'use strict';
@ -16,11 +19,10 @@ assert.commandFailedWithCode(
assert.commandFailedWithCode(coll.createIndexes([{x: 1}], {expireAfterSeconds: 9999999999999999}),
ErrorCodes.CannotCreateIndex);
// Ensure that we cannot provide a time that is larger than the current epoch time.
// Ensure that we can provide a time that is larger than the current epoch time.
let secondsSinceEpoch = Date.now() / 1000;
assert.commandFailedWithCode(
coll.createIndexes([{x: 1}], {expireAfterSeconds: secondsSinceEpoch + 1000}),
ErrorCodes.CannotCreateIndex);
assert.commandWorked(
coll.createIndexes([{x_before_epoch: 1}], {expireAfterSeconds: secondsSinceEpoch + 1000}));
// 'expireAfterSeconds' cannot be less than 0.
assert.commandFailedWithCode(coll.createIndexes([{x: 1}], {expireAfterSeconds: -1}),

View File

@ -8,6 +8,43 @@
load('jstests/disk/libs/wt_file_helper.js');
function checkTableLogSettings(conn, enabled) {
conn.getDBNames().forEach(function(d) {
let collNames =
conn.getDB(d)
.runCommand({listCollections: 1, nameOnly: true, filter: {type: "collection"}})
.cursor.firstBatch;
collNames.forEach(function(c) {
let stats = conn.getDB(d).runCommand({collStats: c.name});
let logStr = "log=(enabled=" + (enabled ? "true" : "false") + ")";
if (d == "local") {
if (c.name == "replset.minvalid" && !enabled) {
// This collection is never logged in a replica set.
logStr = "log=(enabled=false)";
} else {
// All other collections and indexes in the 'local' database have table
// logging enabled always.
logStr = "log=(enabled=true)";
}
}
assert.eq(true, stats.wiredTiger.creationString.includes(logStr));
Object.keys(stats.indexDetails).forEach(function(i) {
assert.eq(true, stats.indexDetails[i].creationString.includes(logStr));
});
});
});
}
function checkTableChecksFileRemoved(dbpath) {
let files = listFiles(dbpath);
for (file of files) {
assert.eq(false, file.name.includes("_wt_table_checks"));
}
}
// Create a bunch of collections under various database names.
let conn = MongoRunner.runMongod({});
const dbpath = conn.dbpath;
@ -16,112 +53,75 @@ for (let i = 0; i < 10; i++) {
assert.commandWorked(conn.getDB(i.toString()).createCollection(i.toString()));
}
checkTableLogSettings(conn, /*enabled=*/true);
MongoRunner.stopMongod(conn);
/**
* Test 1. The regular case, where no table logging setting modifications are needed.
* Test 1. Change into a single node replica set, which requires all of the table logging settings
* to be updated. Write the '_wt_table_checks' file and check that it gets removed.
*/
jsTest.log("Test 1.");
conn = startMongodOnExistingPath(dbpath, {});
checkLog.containsJson(conn, 4366408, {loggingEnabled: true});
writeFile(dbpath + "/_wt_table_checks", "");
conn = startMongodOnExistingPath(
dbpath, {replSet: "mySet", setParameter: {logComponentVerbosity: tojson({verbosity: 1})}});
checkTableChecksFileRemoved(dbpath);
// Changing table logging settings.
checkLog.containsJson(conn, 22432);
MongoRunner.stopMongod(conn);
/**
* Test 2. Repair checks all of the table logging settings.
* Test 2. Restart in standalone mode with wiredTigerSkipTableLoggingChecksOnStartup. No table log
* settings are updated. Write the '_wt_table_checks' file and check that it gets removed.
*/
jsTest.log("Test 2.");
assertRepairSucceeds(dbpath, conn.port, {});
// Cannot use checkLog here as the server is no longer running.
let logContents = rawMongoProgramOutput();
assert(logContents.indexOf(
"Modifying the table logging settings for all existing WiredTiger tables") > 0);
/**
* Test 3. Explicitly create the '_wt_table_checks' file to force all of the table logging setting
* modifications to be made.
*/
jsTest.log("Test 3.");
let files = listFiles(dbpath);
for (f in files) {
assert(!files[f].name.includes("_wt_table_checks"));
}
writeFile(dbpath + "/_wt_table_checks", "");
// Cannot skip table logging checks on startup when there are previously incomplete table checks.
assert.throws(() => startMongodOnExistingPath(
dbpath, {setParameter: "wiredTigerSkipTableLoggingChecksOnStartup=true"}));
conn = startMongodOnExistingPath(dbpath, {});
checkLog.containsJson(
conn, 4366405, {loggingEnabled: true, repair: false, hasPreviouslyIncompleteTableChecks: true});
MongoRunner.stopMongod(conn);
/**
* Test 4. Change into a single replica set, which requires all of the table logging settings to be
* updated. But simulate an interruption/crash while starting up during the table logging check
* phase.
*
* The next start up will detect an unclean shutdown causing all of the table logging settings to be
* updated.
*/
jsTest.log("Test 4.");
assert.throws(() => startMongodOnExistingPath(dbpath, {
replSet: "mySet",
setParameter: "failpoint.crashAfterUpdatingFirstTableLoggingSettings=" +
tojson({"mode": "alwaysOn"})
}));
// Cannot use checkLog here as the server is no longer running.
logContents = rawMongoProgramOutput();
assert(logContents.indexOf(
"Crashing due to 'crashAfterUpdatingFirstTableLoggingSettings' fail point") > 0);
// The '_wt_table_checks' still exists, so all table logging settings should be modified.
conn = startMongodOnExistingPath(dbpath, {});
checkLog.containsJson(
conn, 4366405, {loggingEnabled: true, repair: false, hasPreviouslyIncompleteTableChecks: true});
MongoRunner.stopMongod(conn);
/**
* Test 5. Change into a single node replica set, which requires all of the table logging settings
* to be updated as the node was successfully started up as a standalone the last time.
*/
jsTest.log("Test 5.");
conn = startMongodOnExistingPath(dbpath, {replSet: "mySet"});
checkLog.containsJson(conn, 4366406, {loggingEnabled: false});
MongoRunner.stopMongod(conn);
/**
* Test 6. Restart as a standalone and skip table logging checks on startup. Verify that restarting
* as a replica set again does not require any table logging modifications.
*/
jsTest.log("Test 6.");
conn = startMongodOnExistingPath(dbpath, {
setParameter: {
wiredTigerSkipTableLoggingChecksOnStartup: true,
logComponentVerbosity: tojson({verbosity: 1})
}
});
checkTableChecksFileRemoved(dbpath);
// Skipping table logging checks for all existing tables.
checkLog.containsJson(conn, 5548301, {wiredTigerSkipTableLoggingChecksOnStartup: true});
// Log level 1 prints each individual table it skips table logging checks for.
// Skipping table logging checks.
checkLog.containsJson(conn, 5548302);
// Changing table logging settings.
assert(checkLog.checkContainsWithCountJson(conn, 22432, undefined, 0));
checkTableLogSettings(conn, /*enabled=*/false);
MongoRunner.stopMongod(conn);
conn = startMongodOnExistingPath(dbpath, {replSet: "mySet"});
/**
* Test 3. Change into a single node replica set again. Table log settings are checked but none are
* changed. Write the '_wt_table_checks' file and check that it gets removed.
*/
jsTestLog("Test 3.");
writeFile(dbpath + "/_wt_table_checks", "");
conn = startMongodOnExistingPath(
dbpath, {replSet: "mySet", setParameter: {logComponentVerbosity: tojson({verbosity: 1})}});
checkTableChecksFileRemoved(dbpath);
// No table logging settings modifications are required.
checkLog.containsJson(conn, 4366408);
// Changing table logging settings.
assert(checkLog.checkContainsWithCountJson(conn, 22432, undefined, 0));
MongoRunner.stopMongod(conn);
/**
* Test 4. Back to standalone. Check that the table log settings are enabled. Write the
* '_wt_table_checks' file and check that it gets removed.
*/
jsTest.log("Test 4.");
writeFile(dbpath + "/_wt_table_checks", "");
conn = startMongodOnExistingPath(dbpath,
{setParameter: {logComponentVerbosity: tojson({verbosity: 1})}});
checkTableChecksFileRemoved(dbpath);
// Changing table logging settings.
checkLog.containsJson(conn, 22432);
// Skipping table logging checks.
assert(checkLog.checkContainsWithCountJson(conn, 5548302, undefined, 0));
checkTableLogSettings(conn, /*enabled=*/true);
MongoRunner.stopMongod(conn);
}());

View File

@ -138,7 +138,10 @@ function assertNumMatchingOplogEventsForShard(stats, shardName, expectedTotalRet
assert(stats.shards.hasOwnProperty(shardName), stats);
assert.eq(Object.keys(stats.shards[shardName].stages[0])[0], "$cursor", stats);
const executionStats = stats.shards[shardName].stages[0].$cursor.executionStats;
assert.eq(executionStats.nReturned, expectedTotalReturned, executionStats);
assert.eq(executionStats.nReturned,
expectedTotalReturned,
() => `Expected ${expectedTotalReturned} events on shard ${shardName} but got ` +
`${executionStats.nReturned}. Execution stats:\n${tojson(executionStats)}`);
}
// Returns a newly created sharded collection sharded by caller provided shard key.
@ -180,7 +183,10 @@ function verifyChangeStreamOnWholeCluster(
eventIdentifierList.forEach(eventIdentifier => {
assert.soon(() => cursor.hasNext(), {op: op, eventIdentifier: eventIdentifier});
const event = cursor.next();
assert.eq(event.operationType, op, event);
assert.eq(event.operationType,
op,
() => `Expected "${op}" but got "${event.operationType}". Full event: ` +
`${tojson(event)}`);
if (op == "dropDatabase") {
assert.eq(event.ns.db, eventIdentifier, event);

View File

@ -98,7 +98,7 @@ let c = pscWatch(sdb, "coll", shardId);
for (let i = 1; i <= 4; i++) {
sdb.coll.insertOne({location: 2, i});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
}
assert(!c.hasNext());
@ -108,12 +108,12 @@ c = pscWatch(sdb, 1, shardId);
sdb.coll.insertOne({location: 3});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
sdb.coll2.insertOne({location: 4});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
assert(!c.hasNext());
@ -129,7 +129,7 @@ assert(!c.hasNext());
sdb.toBeCreated.insertOne({location: 8});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
assert(!c.hasNext());
@ -164,7 +164,7 @@ c = pscWatch(sdb, "coll", shardId);
sdb.coll.insertOne({location: 5, _id: -2});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
sdb.coll.insertOne({location: 6, _id: 2});
@ -176,12 +176,12 @@ c = pscWatch(sdb.getSiblingDB("admin"), 1, shardId, {}, {allChangesForCluster: t
sdb.coll.insertOne({location: 7, _id: -3});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
sdb.coll2.insertOne({location: 8, _id: -4});
assert(!c.isExhausted());
assert(c.hasNext());
assert.soon(() => c.hasNext());
c.next();
sdb.coll.insertOne({location: 9, _id: 3});

View File

@ -0,0 +1,47 @@
/**
* Validates that the server doesn't use fused multiply-add instructions (-ffp-contract=off).
*
* @tags: [
* multiversion_incompatible,
* ]
*/
(function() {
'use strict';
const conn = MongoRunner.runMongod();
const coll = conn.getDB('test').getCollection('c');
assert.commandWorked(coll.createIndex({loc: "2dsphere"}));
assert.commandWorked(coll.insertOne({
"loc": {
"type": "Polygon",
"coordinates": [[
[-85.0329458713531, 41.3677690255613],
[-85.0296092033386, 41.3677690255613],
[-85.0296092033386, 41.360594065847],
[-85.0329458713531, 41.360594065847],
[-85.0329458713531, 41.3677690255613]
]]
}
}));
// Assert that the query returns the document. If the query does not return any result, then
// this is likely because of different rounding due to fused multiply-add instructions on platforms
// that have native support, like arm64.
assert.eq(
1,
coll.find({
"loc": {
"$near": {
"$geometry":
{"type": "Point", "coordinates": [-85.031218528747559, 41.364586470348961]},
"$maxDistance": 0
}
}
})
.itcount());
MongoRunner.stopMongod(conn);
}());

View File

@ -0,0 +1,29 @@
(function() {
"use strict";
// See SERVER-68766. Verify that the reduce function is not run on a single value if the relevant
// flag is enabled.
const conn = MongoRunner.runMongod({setParameter: {mrEnableSingleReduceOptimization: true}});
const testDB = conn.getDB('foo');
const coll = testDB.bar;
assert.commandWorked(coll.insert({x: 1}));
const map = function() {
emit(0, "mapped value");
};
const reduce = function(key, values) {
return "reduced value";
};
let res = assert.commandWorked(
testDB.runCommand({mapReduce: 'bar', map: map, reduce: reduce, out: {inline: 1}}));
assert.eq(res.results[0], {_id: 0, value: "mapped value"});
assert.commandWorked(coll.insert({x: 2}));
res = assert.commandWorked(
testDB.runCommand({mapReduce: 'bar', map: map, reduce: reduce, out: {inline: 1}}));
assert.eq(res.results[0], {_id: 0, value: "reduced value"});
MongoRunner.stopMongod(conn);
}());

View File

@ -0,0 +1,146 @@
/**
* Tests resource consumption metrics for retryable writes.
* Retryable writes persist transaction documents in "config.transaction" and all reads and writes
* to "config.transaction" should not trigger any operation metrics.
*
* @tags: [
* requires_replication,
* ]
*/
(function() {
"use strict";
load("jstests/libs/retryable_writes_util.js");
function setupReplicaSet() {
var rst = new ReplSetTest({
nodes: 2,
nodeOptions: {setParameter: {"aggregateOperationResourceConsumptionMetrics": true}}
});
rst.startSet();
rst.initiate();
return rst;
}
function clearMetrics(conn) {
conn.getDB('admin').aggregate([{$operationMetrics: {clearMetrics: true}}]);
}
function getMetrics(conn) {
const cursor = conn.getDB('admin').aggregate([{$operationMetrics: {}}]);
let allMetrics = {};
while (cursor.hasNext()) {
let doc = cursor.next();
allMetrics[doc.db] = doc;
}
return allMetrics;
}
function assertMetricsZeroRead(metrics, dbName) {
assert(metrics[dbName]);
assert.eq(metrics[dbName].primaryMetrics.docBytesRead, 0);
assert.eq(metrics[dbName].primaryMetrics.docUnitsRead, 0);
assert.eq(metrics[dbName].primaryMetrics.idxEntryBytesRead, 0);
assert.eq(metrics[dbName].primaryMetrics.idxEntryUnitsRead, 0);
}
function assertMetricsWritten(metrics, dbName, expectedWritten) {
assert(metrics[dbName]);
assert.eq(metrics[dbName].docBytesWritten, expectedWritten.docBytesWritten);
assert.eq(metrics[dbName].docUnitsWritten, expectedWritten.docUnitsWritten);
assert.eq(metrics[dbName].idxEntryBytesWritten, expectedWritten.idxEntryBytesWritten);
assert.eq(metrics[dbName].idxEntryUnitsWritten, expectedWritten.idxEntryUnitsWritten);
assert.eq(metrics[dbName].totalUnitsWritten, expectedWritten.totalUnitsWritten);
}
function runRetryableTransaction(sessionDb, txnNumber, cmdObj) {
let cmd = Object.assign(
{}, cmdObj, {txnNumber: NumberLong(txnNumber), startTransaction: true, autocommit: false});
assert.commandWorked(sessionDb.runCommand(cmd));
assert.commandWorked(sessionDb.adminCommand({
commitTransaction: 1,
txnNumber: NumberLong(txnNumber),
autocommit: false,
writeConcern: {w: "majority"}
}));
}
function runRetryableWriteCmd(sessionDb, txnNumber, cmdObj) {
let cmd = Object.assign({}, cmdObj, {txnNumber: NumberLong(txnNumber)});
jsTest.log("run retryable write with command :" + tojson(cmd));
assert.commandWorked(sessionDb.runCommand(cmd));
}
const rst = setupReplicaSet();
const primary = rst.getPrimary();
const kDbName = "testDb";
const kCollName = "testColl";
const testDb = primary.getDB(kDbName);
assert.commandWorked(testDb.createCollection(kCollName));
const session = testDb.getMongo().startSession();
let sessionDB = session.getDatabase(kDbName);
let txnNumber = 0;
let makeInsertCmdObj = (docs) => {
return {insert: kCollName, documents: docs, ordered: false};
};
let makeDocs = (fromId, toId) => {
let docs = [];
for (let i = fromId; i <= toId; i++) {
docs.push({_id: i, number: i});
}
return docs;
};
let expectedWritten;
jsTest.log("Tests non-retryable insert comamnd which has no transaction number.");
{
clearMetrics(primary);
let cmdObj = makeInsertCmdObj(makeDocs(1, 3));
assert.commandWorked(testDb.runCommand(cmdObj));
let metrics = getMetrics(primary);
assertMetricsZeroRead(metrics, kDbName);
// Init the expected doc, index and total data written. The following retryable writes
// should have the same output as the size of inserted user data is same.
expectedWritten = {
docBytesWritten: metrics[kDbName].docBytesWritten,
docUnitsWritten: metrics[kDbName].docUnitsWritten,
idxEntryBytesWritten: metrics[kDbName].idxEntryBytesWritten,
idxEntryUnitsWritten: metrics[kDbName].idxEntryUnitsWritten,
totalUnitsWritten: metrics[kDbName].totalUnitsWritten
};
}
jsTest.log("Tests retryable commitTransaction command which inserts documents.");
{
clearMetrics(primary);
let cmdObj = makeInsertCmdObj(makeDocs(4, 6));
runRetryableTransaction(sessionDB, txnNumber, cmdObj);
let metrics = getMetrics(primary);
assertMetricsZeroRead(metrics, kDbName);
assertMetricsWritten(metrics, kDbName, expectedWritten);
}
txnNumber++;
jsTest.log("Tests retryable insert command.");
{
clearMetrics(primary);
let cmdObj = makeInsertCmdObj(makeDocs(7, 9));
runRetryableWriteCmd(sessionDB, txnNumber, cmdObj);
let metrics = getMetrics(primary);
assertMetricsZeroRead(metrics, kDbName);
assertMetricsWritten(metrics, kDbName, expectedWritten);
}
session.endSession();
rst.stopSet();
}());

View File

@ -0,0 +1,120 @@
/**
* Tests TTL indexes with NaN for 'expireAfterSeconds'.
*
* Existing TTL indexes from older versions of the server may contain a NaN for the duration.
* Newer server versions (5.0+) normalize the TTL duration to 0.
*
* @tags: [
* requires_replication,
* ]
*/
(function() {
'use strict';
load("jstests/libs/fail_point_util.js");
load('jstests/noPassthrough/libs/index_build.js');
const rst = new ReplSetTest({
nodes: [{}, {rsConfig: {votes: 0, priority: 0}}],
nodeOptions: {setParameter: {ttlMonitorSleepSecs: 5}},
// Sync from primary only so that we have a well-defined node to check listIndexes behavior.
settings: {chainingAllowed: false},
});
rst.startSet();
rst.initiate();
let primary = rst.getPrimary();
const db = primary.getDB('test');
const coll = db.t;
// The test cases here revolve around having a TTL index in the catalog with a NaN
// 'expireAfterSeconds'. The current createIndexes behavior will overwrite NaN with int32::max
// unless we use a fail point.
const fp = configureFailPoint(primary, 'skipTTLIndexNaNExpireAfterSecondsValidation');
try {
assert.commandWorked(coll.createIndex({t: 1}, {expireAfterSeconds: NaN}));
} finally {
fp.off();
}
assert.commandWorked(coll.insert({_id: 0, t: ISODate()}));
// Wait for "TTL indexes require the expire field to be numeric, skipping TTL job" log message.
checkLog.containsJson(primary, 22542, {ns: coll.getFullName()});
// TTL index should be replicated to the secondary with a NaN 'expireAfterSeconds'.
const secondary = rst.getSecondary();
checkLog.containsJson(secondary, 20384, {
namespace: coll.getFullName(),
properties: (spec) => {
jsTestLog('TTL index on secondary: ' + tojson(spec));
return isNaN(spec.expireAfterSeconds);
}
});
assert.eq(
coll.countDocuments({}), 1, 'ttl index with NaN duration should not remove any documents.');
// Confirm that TTL index is replicated with a non-zero 'expireAfterSeconds' during initial sync.
const newNode = rst.add({rsConfig: {votes: 0, priority: 0}});
rst.reInitiate();
rst.waitForState(newNode, ReplSetTest.State.SECONDARY);
rst.awaitReplication();
let newNodeTestDB = newNode.getDB(db.getName());
let newNodeColl = newNodeTestDB.getCollection(coll.getName());
const newNodeIndexes = IndexBuildTest.assertIndexes(newNodeColl, 2, ['_id_', 't_1']);
const newNodeSpec = newNodeIndexes.t_1;
jsTestLog('TTL index on initial sync node: ' + tojson(newNodeSpec));
assert(newNodeSpec.hasOwnProperty('expireAfterSeconds'),
'Index was not replicated as a TTL index during initial sync.');
assert.gt(newNodeSpec.expireAfterSeconds,
0,
'NaN expireAferSeconds was replicated as zero during initial sync.');
// Check that listIndexes on the primary logged a "Fixing expire field from TTL index spec" message
// during the NaN 'expireAfterSeconds' conversion.
checkLog.containsJson(primary, 6835900, {namespace: coll.getFullName()});
// Confirm that a node with an existing TTL index with NaN 'expireAfterSeconds' will convert the
// duration on the TTL index from NaN to a large positive value when it becomes the primary node.
// When stepping down the primary, we use 'force' because there's no other electable node.
// Subsequently, we wait for the stepped down node to become primary again.
// To confirm that the TTL index has been fixed, we check the oplog for a collMod operation on the
// TTL index that changes the `expireAfterSeconds` field from NaN to a large positive value.
assert.commandWorked(primary.adminCommand({replSetStepDown: 5, force: true}));
primary = rst.waitForPrimary();
const collModOplogEntries =
rst.findOplog(primary,
{
op: 'c',
ns: coll.getDB().getCollection('$cmd').getFullName(),
'o.collMod': coll.getName(),
'o.index.name': 't_1',
'o.index.expireAfterSeconds': newNodeSpec.expireAfterSeconds
},
/*limit=*/1)
.toArray();
assert.eq(collModOplogEntries.length,
1,
'TTL index with NaN expireAfterSeconds was not fixed using collMod during step-up: ' +
tojson(rst.findOplog(primary, {op: {$ne: 'n'}}, /*limit=*/10).toArray()));
// Confirm that createIndexes will overwrite a NaN 'expireAfterSeconds' in a TTL index before saving
// it to the catalog and replicating it downstream.
const coll2 = db.w;
assert.commandWorked(coll2.createIndex({t: 1}, {expireAfterSeconds: NaN}));
assert.commandWorked(coll2.insert({_id: 0, t: ISODate()}));
// TTL index should be replicated to the secondary with a non-NaN 'expireAfterSeconds'.
checkLog.containsJson(secondary, 20384, {
namespace: coll2.getFullName(),
properties: (spec) => {
jsTestLog('TTL index on secondary (with overwritten NaN expireAfterSeconds): ' +
tojson(spec));
return spec.hasOwnProperty('expireAfterSeconds') && !isNaN(spec.expireAfterSeconds) &&
spec.expireAfterSeconds === newNodeSpec.expireAfterSeconds;
}
});
rst.stopSet();
})();

View File

@ -0,0 +1,56 @@
/**
* Tests that a server containing a TTL index with NaN for 'expireAfterSeconds'
* will log a warning on startup.
*
* @tags: [
* requires_persistence,
* requires_replication,
* ]
*/
(function() {
'use strict';
load("jstests/libs/fail_point_util.js");
load('jstests/noPassthrough/libs/index_build.js');
const rst = new ReplSetTest({nodes: [{}, {rsConfig: {votes: 0, priority: 0}}]});
rst.startSet();
rst.initiate();
let primary = rst.getPrimary();
const db = primary.getDB('test');
const coll = db.t;
// The test cases here revolve around having a TTL index in the catalog with a NaN
// 'expireAfterSeconds'. The current createIndexes behavior will overwrite NaN with int32::max
// unless we use a fail point.
const fp = configureFailPoint(primary, 'skipTTLIndexNaNExpireAfterSecondsValidation');
try {
assert.commandWorked(coll.createIndex({t: 1}, {expireAfterSeconds: NaN}));
} finally {
fp.off();
}
assert.commandWorked(coll.insert({_id: 0, t: ISODate()}));
// Force checkpoint in storage engine to ensure index is part of the catalog in
// in finished state at startup.
rst.awaitReplication();
let secondary = rst.getSecondary();
assert.commandWorked(secondary.adminCommand({fsync: 1}));
// Restart the secondary and check for the startup warning in the logs.
secondary = rst.restart(secondary);
rst.waitForState(secondary, ReplSetTest.State.SECONDARY);
// Wait for "Found an existing TTL index with NaN 'expireAfterSeconds' in the catalog" log message.
checkLog.containsJson(secondary, 6852200, {
ns: coll.getFullName(),
spec: (spec) => {
jsTestLog('TTL index on secondary at startup: ' + tojson(spec));
return isNaN(spec.expireAfterSeconds);
}
});
rst.stopSet();
})();

View File

@ -0,0 +1,80 @@
/**
* Verifies that a multi-document transaction aborts with WriteConflictError if an index build has
* committed since the transaction's read snapshot.
*
* @tags: [
* requires_replication,
* ]
*/
(function() {
'use strict';
const replTest = new ReplSetTest({nodes: 2});
replTest.startSet();
replTest.initiate();
const primary = replTest.getPrimary();
const db = primary.getDB('test');
// Transaction inserting an index key.
{
assert.commandWorked(db['c'].insertOne({_id: 0, num: 0}));
const s0 = db.getMongo().startSession();
s0.startTransaction();
assert.commandWorked(s0.getDatabase('test')['c'].deleteOne({_id: 0}));
s0.commitTransaction();
const clusterTime = s0.getClusterTime().clusterTime;
assert.commandWorked(db['c'].createIndex({num: 1}));
// Start a transaction whose snapshot predates the completion of the index build, and which
// reserves an oplog entry after the index build commits.
try {
const s1 = db.getMongo().startSession();
s1.startTransaction({readConcern: {level: "snapshot", atClusterTime: clusterTime}});
s1.getDatabase('test').c.insertOne({_id: 1, num: 1});
// Transaction should have failed.
assert(0);
} catch (e) {
assert(e.hasOwnProperty("errorLabels"), tojson(e));
assert.contains("TransientTransactionError", e.errorLabels, tojson(e));
assert.eq(e["code"], ErrorCodes.WriteConflict, tojson(e));
}
}
db.c.drop();
// Transaction deleting an index key.
{
assert.commandWorked(db.createCollection('c'));
const s0 = db.getMongo().startSession();
s0.startTransaction();
assert.commandWorked(s0.getDatabase('test')['c'].insertOne({_id: 0, num: 0}));
s0.commitTransaction();
const clusterTime = s0.getClusterTime().clusterTime;
assert.commandWorked(db['c'].createIndex({num: 1}));
// Start a transaction whose snapshot predates the completion of the index build, and which
// reserves an oplog entry after the index build commits.
try {
const s1 = db.getMongo().startSession();
s1.startTransaction({readConcern: {level: "snapshot", atClusterTime: clusterTime}});
s1.getDatabase('test').c.deleteOne({_id: 0});
// Transaction should have failed.
assert(0);
} catch (e) {
assert(e.hasOwnProperty("errorLabels"), tojson(e));
assert.contains("TransientTransactionError", e.errorLabels, tojson(e));
assert.eq(e["code"], ErrorCodes.WriteConflict, tojson(e));
}
}
replTest.stopSet();
})();

View File

@ -247,6 +247,194 @@ assertResultsMatchWithAndWithoutPushdown(
assertResultsMatchWithAndWithoutPushdown(
coll, pipeline, [{_id: "a", ss: 30}, {_id: "b", ss: 60}, {_id: "c", ss: 10}], 2));
// The second $group stage refers to a top-field below a $switch
assertResultsMatchWithAndWithoutPushdown(coll,
[
{$group: {_id: {$divide: ["$price", 5]}}},
{
$group: {
_id: null,
lowp: {
$sum: {
$switch: {
branches: [{
case: {$lte: ["$_id", 3]},
then: 1
}],
default: 0
}
}
},
highp: {
$sum: {
$switch: {
branches: [{
case: {$gt: ["$_id", 3]},
then: 1
}],
default: 0
}
}
}
}
}
],
[{"_id": null, "lowp": 2, "highp": 1}],
2);
// The second $group stage refers to a top-field below a $cond
assertResultsMatchWithAndWithoutPushdown(
coll,
[
{$group: {_id: {$divide: ["$price", 5]}}},
{
$group: {
_id: null,
lowp: {$sum: {$cond: [{$lte: ["$_id", 3]}, 1, 0]}},
highp: {$sum: {$cond: [{$gt: ["$_id", 3]}, 1, 0]}}
}
}
],
[{"_id": null, "lowp": 2, "highp": 1}],
2);
// The second $group stage refers to a top-field below a nested $cond / $ifNull
assertResultsMatchWithAndWithoutPushdown(coll,
[
{$group: {_id: {$divide: ["$price", 5]}}},
{
$group: {
_id: null,
lowp: {
$sum: {
$cond: [
{
$lte:
[{$ifNull: ["$_id", 0]}, 3]
},
1,
0
]
}
},
highp: {
$sum: {
$cond: [
{$gt: [{$ifNull: ["$_id", 0]}, 3]},
1,
0
]
}
}
}
}
],
[{"_id": null, "lowp": 2, "highp": 1}],
2);
// The second $group stage refers to top-fields below a $filter
assertResultsMatchWithAndWithoutPushdown(
coll,
[
{$group: {_id: "$item", prices: {$push: "$price"}}},
{
$group: {
_id: "$_id",
o: {$push: {$filter: {input: "$prices", as: "p", cond: {$gte: ["$$p", 5]}}}}
}
}
],
[{"_id": "a", "o": [[10, 5]]}, {"_id": "b", "o": [[20, 10]]}, {"_id": "c", "o": [[5]]}],
2);
// The second $group stage refers to top-fields below a $let
assertResultsMatchWithAndWithoutPushdown(
coll,
[
{$group: {
_id: "$item", maxp: {$max: "$price"}, minp: {$min: "$price"}, count: {$count: {}}
}},
{$group: {_id: "$_id", o: {$sum: {
$let: {
vars: {
minPlusMax: {$add: ["$maxp", "$minp"]},
count: "$count"
},
in: {$multiply: ["$$minPlusMax", "$$count"]}
}
}}}}
],
[{ "_id" : "a", "o" : 30 }, { "_id" : "c", "o" : 10 }, { "_id" : "b", "o" : 60 }],
2);
// The second $group stage refers to top-fields below a $and
assertResultsMatchWithAndWithoutPushdown(coll,
[
{
$group: {
_id: "$item",
maxp: {$max: "$price"},
minp: {$min: "$price"}
}
},
{
$group:
{
_id: "$_id",
o:
{
$sum:
{
$and: [
{$gt: ["$maxp", 15]},
{$lt: ["$minp", 10]}
]
}
}
}
}
],
[
{"_id": "a", "o": 0},
{"_id": "c", "o": 0},
{"_id": "b", "o": 0}
],
2);
// The second $group stage refers to top-fields below a $or
assertResultsMatchWithAndWithoutPushdown(coll,
[
{
$group: {
_id: "$item",
maxp: {$max: "$price"},
minp: {$min: "$price"}
}
},
{
$group:
{
_id: "$_id",
o:
{
$sum:
{
$or: [
{$gt: ["$maxp", 15]},
{$lt: ["$minp", 10]}
]
}
}
}
}
],
[
{"_id": "a", "o": 0},
{"_id": "c", "o": 0},
{"_id": "b", "o": 0}
],
2);
// The second $group stage refers to both a top-level field and a sub-field twice which does not
// exist.
assertResultsMatchWithAndWithoutPushdown(

View File

@ -53,8 +53,13 @@ admin_s1.runCommand({replSetFreeze: 999999});
print("6. Bring up #3");
var hostname = getHostName();
var secondary2 =
MongoRunner.runMongod(Object.merge({replSet: basename, oplogSize: 2}, x509_options2));
var secondary2 = MongoRunner.runMongod(Object.merge({
replSet: basename,
oplogSize: 2,
// Preserve the initial sync state to validate an assertion.
setParameter: {"failpoint.skipClearInitialSyncState": tojson({mode: 'alwaysOn'})}
},
x509_options2));
var local_s2 = secondary2.getDB("local");
var admin_s2 = secondary2.getDB("admin");
@ -108,5 +113,11 @@ assert.commandWorked(bulk.execute());
print("11. Everyone happy eventually");
replTest.awaitReplication();
// SERVER-69001: Assert that the last oplog for initial sync was persisted in the minvalid document.
let syncingNodeMinvalid = secondary2.getDB("local").replset.minvalid.findOne()["ts"];
let lastInitialSyncOp =
secondary2.adminCommand("replSetGetStatus")["initialSyncStatus"]["initialSyncOplogEnd"];
assert.eq(lastInitialSyncOp, syncingNodeMinvalid);
MongoRunner.stopMongod(secondary2);
replTest.stopSet();

View File

@ -57,6 +57,11 @@ node = rst.restart(node, {
noReplSet: true,
setParameter: {recoverFromOplogAsStandalone: true, logComponentVerbosity: logLevel}
});
// Verify that the 'config.system.indexBuilds' collection is empty after recovering from the oplog
// in standalone mode.
assert.eq(0, node.getCollection("config.system.indexBuilds").count());
reconnect(node);
rst.stopSet();

View File

@ -21,8 +21,7 @@ assert.throwsWithCode(() => {
st.rs0.getPrimary().getDB(dbName).runCommand({
checkShardingIndex: ns,
keyPattern: {x: 1},
shardVersion:
{e: ObjectId(), t: Timestamp(1, 1), v: Timestamp(99, 10101), i: Timestamp(0, 0)},
shardVersion: {e: ObjectId(), t: Timestamp(1, 1), v: Timestamp(99, 10101)},
});
}, ErrorCodes.StaleConfig);

View File

@ -74,6 +74,7 @@ st.rs1.restart(0, {
startClean: false,
setParameter: "disableResumableRangeDeleter=true"
});
st.rs1.waitForPrimary();
jsTest.log("Shard0 should be able to donate a chunk and shard1 should be able to receive it.");
// disableResumableRangeDeleter should not prevent a shard from donating a chunk, and should not
@ -88,6 +89,7 @@ st.rs0.restart(0, {
startClean: false,
setParameter: "disableResumableRangeDeleter=false"
});
st.rs0.waitForPrimary();
jsTest.log("Shard0 should now be able to re-receive the chunk it failed to receive earlier.");
assert.commandWorked(st.s.adminCommand({moveChunk: ns, find: {_id: 0}, to: st.shard0.shardName}));
@ -110,6 +112,7 @@ st.rs1.restart(0, {
});
st.rs0.getPrimary().adminCommand({setParameter: 1, receiveChunkWaitForRangeDeleterTimeoutMS: 500});
st.rs1.waitForPrimary();
let bulkOp = st.s.getCollection(ns).initializeUnorderedBulkOp();

View File

@ -67,12 +67,6 @@ function runTest(st, stepDownShard0PrimaryFunc, testOpts = {
const prepareTxnRes = assert.commandWorked(testDB.adminCommand(prepareCmdObj));
commitCmdObj.commitTimestamp = prepareTxnRes.prepareTimestamp;
// It is possible that a secondary that steps up could use a stale majority-committed snapshot,
// so we want to wait until the prepareTransaction is visible in the majority-committed snapshot
// view for all nodes in the replica set. We do this because commitTransaction for a prepared
// transaction cannot be run before its prepare oplog entry has been majority committed
st.rs0.awaitLastOpCommitted();
stepDownShard0PrimaryFunc();
testDB = st.rs0.getPrimary().getDB(kDbName);
@ -174,9 +168,9 @@ function runTest(st, stepDownShard0PrimaryFunc, testOpts = {
st.rs0.stopSet(null /* signal */, true /*forRestart */);
st.rs0.startSet({restart: true});
st.rs0.getPrimary();
// Wait for replication since it is illegal to run commitTransaction before the prepare
// oplog entry has been majority committed.
st.rs0.awaitReplication();
// Wait for replication to recover the lastCommittedOpTime since it is illegal to run
// commitTransaction before the prepare oplog entry has been majority committed.
st.rs0.awaitLastOpCommitted();
};
// Test findAnModify without pre/post image.

View File

@ -8,8 +8,7 @@ var ShardVersioningUtil = (function() {
const kIgnoredShardVersion = {
e: ObjectId("00000000ffffffffffffffff"),
t: Timestamp(Math.pow(2, 32) - 1, Math.pow(2, 32) - 1),
v: Timestamp(0, 0),
i: Timestamp(0, 0)
v: Timestamp(0, 0)
};
/*

View File

@ -21,7 +21,8 @@ const sourceCollection = reshardingTest.createShardedCollection({
});
const mongos = sourceCollection.getMongo();
const topology = DiscoverTopology.findConnectedNodes(mongos);
const ns = sourceCollection.getFullName();
let topology = DiscoverTopology.findConnectedNodes(mongos);
const recipientShardNames = reshardingTest.recipientShardNames;
const recipient = new Mongo(topology.shards[recipientShardNames[0]].primary);
@ -38,6 +39,13 @@ const shardsvrAbortReshardCollectionFailpoint = configureFailPoint(recipient, "f
failCommands: ["_shardsvrAbortReshardCollection"],
});
// We pause the _configsvrReshardCollection command upon joining an existing ReshardingCoordinator
// instance on all of the config server replica set because we don't know which node will be elected
// primary from calling stepUpNewPrimaryOnShard().
const configsvrConnections = topology.configsvr.nodes.map(host => new Mongo(host));
const reshardCollectionJoinedFailPointsList = configsvrConnections.map(
conn => configureFailPoint(conn, "reshardCollectionJoinedExistingOperation"));
let awaitAbort;
reshardingTest.withReshardingInBackground(
{
@ -48,7 +56,6 @@ reshardingTest.withReshardingInBackground(
// Wait until participants are aware of the resharding operation.
reshardingTest.awaitCloneTimestampChosen();
const ns = sourceCollection.getFullName();
awaitAbort = startParallelShell(funWithArgs(function(ns) {
db.adminCommand({abortReshardCollection: ns});
}, ns), mongos.port);
@ -70,13 +77,12 @@ reshardingTest.withReshardingInBackground(
// Mongos automatically retries the abortReshardCollection command on retryable errors.
// We interrupt the abortReshardCollection command running on mongos to verify that the
// ReshardingCoordinator recovers the decision on its own.
const ops =
mongos.getDB("admin")
.aggregate([
{$currentOp: {localOps: true}},
{$match: {"command.abortReshardCollection": sourceCollection.getFullName()}}
])
.toArray();
const ops = mongos.getDB("admin")
.aggregate([
{$currentOp: {localOps: true}},
{$match: {"command.abortReshardCollection": ns}}
])
.toArray();
assert.neq([], ops, "failed to find abortReshardCollection command running on mongos");
assert.eq(
@ -88,6 +94,28 @@ reshardingTest.withReshardingInBackground(
assert.commandWorked(mongos.getDB("admin").killOp(ops[0].opid));
reshardingTest.stepUpNewPrimaryOnShard(reshardingTest.configShardName);
// After a stepdown, the _configsvrReshardCollection command will be retried by the
// primary shard. We use the reshardCollectionJoinedExistingOperation failpoint to
// ensure the primary shard upon retrying finds the ongoing resharding operation on the
// new config server primary. It would otherwise be possible for the
// reshardingPauseCoordinatorBeforeCompletion failpoint to be released by the
// ReshardingTest fixture after this function returns, for the ongoing resharding
// operation to complete, and for the retried _configsvrReshardCollection command to
// spawn an entirely new resharding operation which won't get aborted by the test
// client.
topology = DiscoverTopology.findConnectedNodes(mongos);
const configsvrPrimary = new Mongo(topology.configsvr.primary);
const idx = reshardCollectionJoinedFailPointsList.findIndex(fp => fp.conn.host ===
configsvrPrimary.host);
reshardCollectionJoinedFailPointsList[idx].wait();
// Wait for secondaries to recover and catchup with primary before turning off the
// failpoints as a replication roll back can disconnect the test client.
const configRS = reshardingTest.getReplSetForShard(reshardingTest.configShardName);
configRS.awaitSecondaryNodes();
configRS.awaitReplication();
reshardCollectionJoinedFailPointsList.forEach(fp => fp.off());
shardsvrAbortReshardCollectionFailpoint.off();
},
});

View File

@ -94,8 +94,6 @@ reshardingTest.withReshardingInBackground(
assert(curOpSection.hasOwnProperty('recipientState'), tojson(curOpSection));
assert(curOpSection.hasOwnProperty('documentsCopied'), tojson(curOpSection));
assert(curOpSection.hasOwnProperty('oplogEntriesApplied'), tojson(curOpSection));
assert(curOpSection.hasOwnProperty('remainingOperationTimeEstimatedSecs'),
tojson(curOpSection));
});
const curOpSection =

View File

@ -83,7 +83,7 @@ BUILD_PROFILES = {
sanitize="undefined,address",
link_model="dynamic",
dbg="on",
opt="off",
opt="debug",
ICECC="icecc",
CCACHE="ccache",
NINJA_PREFIX="san",

View File

@ -488,8 +488,6 @@ error_codes:
- {code: 376, name: ChangeStreamNotEnabled}
- {code: 377, name: FLEMaxTagLimitExceeded }
- {code: 378, name: NonConformantBSON, categories: [ValidationError]}
- {code: 379, name: InvalidSignature}
# Error codes 4000-8999 are reserved.

View File

@ -67,7 +67,7 @@ Future<AsyncDBClient::Handle> AsyncDBClient::connect(
ServiceContext* const context,
transport::ReactorHandle reactor,
Milliseconds timeout,
ConnectionMetrics* connectionMetrics,
std::shared_ptr<ConnectionMetrics> connectionMetrics,
std::shared_ptr<const transport::SSLConnectionContext> transientSSLContext) {
auto tl = context->getTransportLayer();
return tl

View File

@ -61,7 +61,7 @@ public:
ServiceContext* context,
transport::ReactorHandle reactor,
Milliseconds timeout,
ConnectionMetrics* connectionMetrics, // must remain valid until the future is ready
std::shared_ptr<ConnectionMetrics> connectionMetrics,
std::shared_ptr<const transport::SSLConnectionContext> transientSSLContext = nullptr);
Future<executor::RemoteCommandResponse> runCommandRequest(

View File

@ -63,27 +63,6 @@ cryptoEnv.Library(
],
)
cryptoEnv.Library(
target='rsa_public_key',
source=[
'rsa_public_key.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
],
)
cryptoEnv.Library(
target='asymmetric_crypto',
source=[
'asymmetric_crypto_{}.cpp'.format(ssl_provider),
],
LIBDEPS=[
'$BUILD_DIR/mongo/util/net/openssl_init' if ssl_provider == 'openssl' else '',
'rsa_public_key',
],
)
env.Library(
target="aead_encryption",
source=[
@ -147,11 +126,9 @@ env.CppUnitTest(
target='crypto_test',
source=[
'aead_encryption_test.cpp',
'asymmetric_crypto_openssl_test.cpp',
'encryption_fields_util_test.cpp',
'fle_crypto_test.cpp',
'mechanism_scram_test.cpp',
'rsa_public_key_test.cpp',
'sha1_block_test.cpp',
'sha256_block_test.cpp',
'sha512_block_test.cpp',
@ -162,37 +139,8 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/base/secure_allocator',
'$BUILD_DIR/mongo/util/net/openssl_init' if ssl_provider == 'openssl' else '',
'aead_encryption',
'asymmetric_crypto',
'encrypted_field_config',
'fle_crypto',
'rsa_public_key',
'sha_block_${MONGO_CRYPTO}',
],
)
env.Library(
target='jwt',
source=[
'jwt_types.idl',
'jwk_manager.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/idl/idl_parser',
'rsa_public_key',
],
)
env.CppUnitTest(
target='jwt_test',
source=[
'jwt_test.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'jwt',
'rsa_public_key',
],
)

View File

@ -1,48 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/base/data_range.h"
#include "mongo/base/status.h"
#include "mongo/crypto/rsa_public_key.h"
namespace mongo::crypto {
enum class HashingAlgorithm { SHA256 };
class RSAKeySignatureVerifier {
public:
virtual ~RSAKeySignatureVerifier() = default;
virtual Status verifySignature(ConstDataRange msg, ConstDataRange signature) = 0;
static StatusWith<std::unique_ptr<RSAKeySignatureVerifier>> create(const RsaPublicKey& pubKey,
HashingAlgorithm hashAlg);
};
} // namespace mongo::crypto

View File

@ -1,52 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/asymmetric_crypto.h"
#include "mongo/base/error_codes.h"
namespace mongo::crypto {
namespace {
class RsaKeySignatureVerifierApple : public RSAKeySignatureVerifier {
public:
RsaKeySignatureVerifierApple(){};
Status verifySignature(ConstDataRange msg, ConstDataRange signature) final {
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
};
} // namespace
// TODO: SERVER-68518, remove or implement this class
StatusWith<std::unique_ptr<RSAKeySignatureVerifier>> RSAKeySignatureVerifier::create(
const RsaPublicKey& pubKey, HashingAlgorithm hashAlg) {
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
} // namespace mongo::crypto

View File

@ -1,54 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/asymmetric_crypto.h"
#include "mongo/base/error_codes.h"
namespace mongo::crypto {
namespace {
class RSAKeySignatureVerifierNone : public RSAKeySignatureVerifier {
public:
RSAKeySignatureVerifierNone(){};
Status verifySignature(ConstDataRange msg, ConstDataRange signature) final {
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
};
} // namespace
// TODO: SERVER-68518, remove or implement this class
StatusWith<std::unique_ptr<RSAKeySignatureVerifier>> RSAKeySignatureVerifier::create(
const RsaPublicKey& pubKey, HashingAlgorithm hashAlg) {
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
} // namespace mongo::crypto

View File

@ -1,142 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/asymmetric_crypto.h"
#include <memory>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/ossl_typ.h>
#include <openssl/rsa.h>
#include "mongo/base/status.h"
#include "mongo/crypto/rsa_public_key.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/net/ssl_manager.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
namespace {
// Copies of OpenSSL 1.1.0 and later define new EVP digest routines. We must
// polyfill used definitions to interact with older OpenSSL versions.
EVP_MD_CTX* EVP_MD_CTX_new() {
return EVP_MD_CTX_create();
}
void EVP_MD_CTX_free(EVP_MD_CTX* ctx) {
EVP_MD_CTX_destroy(ctx);
}
} // namespace
#endif
namespace mongo::crypto {
namespace {
using UniqueRSA = std::unique_ptr<RSA, OpenSSLDeleter<decltype(RSA_free), RSA_free>>;
using UniqueEVPPKey =
std::unique_ptr<EVP_PKEY, OpenSSLDeleter<decltype(EVP_PKEY_free), EVP_PKEY_free>>;
using UniqueBIGNUM = std::unique_ptr<BIGNUM, OpenSSLDeleter<decltype(BN_free), BN_free>>;
class RSAKeySignatureVerifierOpenSSL : public RSAKeySignatureVerifier {
public:
RSAKeySignatureVerifierOpenSSL(const RsaPublicKey& pubKey, HashingAlgorithm hashAlg)
: _verificationCtx(EVP_MD_CTX_new()) {
#if OPENSSL_VERSION_NUMBER > 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER > 0x2070000fL)
const auto* pubKeyNData = pubKey.getN().data<unsigned char>();
UniqueBIGNUM n(BN_bin2bn(pubKeyNData, pubKey.getN().length(), nullptr));
uassertOpenSSL("Failed creating modulus", n.get() != nullptr);
const auto* pubKeyEData = pubKey.getE().data<unsigned char>();
UniqueBIGNUM e(BN_bin2bn(pubKeyEData, pubKey.getE().length(), nullptr));
uassertOpenSSL("Failed creating exponent", e.get() != nullptr);
UniqueRSA rsa(RSA_new());
uassertOpenSSL("Failed creating RSAKey", rsa.get() != nullptr);
uassertOpenSSL("RSA key setup failed",
RSA_set0_key(rsa.get(), n.get(), e.get(), nullptr) == 1);
n.release(); // Now owned by rsa
e.release(); // Now owned by rsa
UniqueEVPPKey evpKey(EVP_PKEY_new());
uassertOpenSSL("Failed creating EVP_PKey", evpKey.get() != nullptr);
uassertOpenSSL("EVP_PKEY assignment failed",
EVP_PKEY_assign_RSA(evpKey.get(), rsa.get()) == 1);
rsa.release(); // Now owned by evpKey
uassert(6755199, "Unknown hashing algorithm", hashAlg == HashingAlgorithm::SHA256);
uassertOpenSSL("DigestVerifyInit failed",
EVP_DigestVerifyInit(
_verificationCtx.get(), nullptr, EVP_sha256(), nullptr, evpKey.get()) ==
1);
#endif
}
Status verifySignature(ConstDataRange msg, ConstDataRange signature) final {
#if OPENSSL_VERSION_NUMBER > 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER > 0x2070000fL)
uassertOpenSSL("DigestVerifyUpdate failed",
EVP_DigestVerifyUpdate(
_verificationCtx.get(), msg.data<std::uint8_t>(), msg.length()) == 1);
int verifyRes = EVP_DigestVerifyFinal(
_verificationCtx.get(), signature.data<std::uint8_t>(), signature.length());
if (verifyRes == 0) {
return {ErrorCodes::InvalidSignature, "OpenSSL: Signature is invalid"};
} else if (verifyRes != 1) {
return {ErrorCodes::UnknownError,
SSLManagerInterface::getSSLErrorMessage(ERR_get_error())};
}
return Status::OK();
#endif
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
private:
std::unique_ptr<EVP_MD_CTX, OpenSSLDeleter<decltype(EVP_MD_CTX_free), ::EVP_MD_CTX_free>>
_verificationCtx;
static void uassertOpenSSL(StringData context, bool success) {
uassert(ErrorCodes::OperationFailed,
str::stream() << context << ": "
<< SSLManagerInterface::getSSLErrorMessage(ERR_get_error()),
success);
}
};
} // namespace
StatusWith<std::unique_ptr<RSAKeySignatureVerifier>> RSAKeySignatureVerifier::create(
const RsaPublicKey& pubKey, HashingAlgorithm hashAlg) try {
return std::make_unique<RSAKeySignatureVerifierOpenSSL>(pubKey, hashAlg);
} catch (const DBException& e) {
return e.toStatus();
}
} // namespace mongo::crypto

View File

@ -1,170 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/asymmetric_crypto.h"
#include <iostream>
#include <string>
#include <vector>
#include "mongo/base/data_range.h"
#include "mongo/base/status.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/bsontypes.h"
#include "mongo/config.h"
#include "mongo/crypto/rsa_public_key.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/base64.h"
#include "mongo/util/hex.h"
#if MONGO_CONFIG_SSL_PROVIDER == MONGO_CONFIG_SSL_PROVIDER_OPENSSL
namespace mongo::crypto {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
class AsymmetricCryptoTestVectors : public unittest::Test {
public:
class RSAKeySignatureVerificationVector {
public:
RSAKeySignatureVerificationVector(StringData keyID,
StringData e,
StringData n,
StringData msg,
StringData signature,
bool shouldPass) {
this->keyID = keyID.toString();
std::string strE = hexblob::decode(e);
std::string base64E = base64url::encode(StringData(strE.data(), strE.length()));
this->e = base64E;
std::string strN = hexblob::decode(n);
std::string base64N = base64url::encode(StringData(strN.data(), strN.length()));
this->n = base64N;
this->msg = hexblob::decode(msg);
this->signature = hexblob::decode(signature);
this->shouldPass = shouldPass;
}
std::string keyID;
std::string e;
std::string n;
std::string msg;
std::string signature;
bool shouldPass;
};
void evaluate(RSAKeySignatureVerificationVector test) {
RsaPublicKey rsaKey(test.keyID, test.e, test.n);
HashingAlgorithm hashAlg = HashingAlgorithm::SHA256;
auto asymmetricKey = uassertStatusOK(RSAKeySignatureVerifier::create(rsaKey, hashAlg));
Status result = asymmetricKey->verifySignature(
ConstDataRange(test.msg.data(), test.msg.length()),
ConstDataRange(test.signature.data(), test.signature.length()));
if (test.shouldPass == false) {
ASSERT_NOT_OK(result);
} else if (test.shouldPass == true) {
ASSERT_OK(result);
}
}
};
/**
* RSA test vectors are otained from FIPS 186-4 RSA:
* https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Digital-Signatures#rsa2vs
*/
TEST_F(AsymmetricCryptoTestVectors, RSASignatureVerificationTest1) {
evaluate(RSAKeySignatureVerificationVector(
"0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd,
"49d2a1"_sd,
"c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9bb66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e61d891c4da29f2d65f34cbb"_sd,
"95123c8d1b236540b86976a11cea31f8bd4e6c54c235147d20ce722b03a6ad756fbd918c27df8ea9ce3104444c0bbe877305bc02e35535a02a58dcda306e632ad30b3dc3ce0ba97fdf46ec192965dd9cd7f4a71b02b8cba3d442646eeec4af590824ca98d74fbca934d0b6867aa1991f3040b707e806de6e66b5934f05509bea"_sd,
"51265d96f11ab338762891cb29bf3f1d2b3305107063f5f3245af376dfcc7027d39365de70a31db05e9e10eb6148cb7f6425f0c93c4fb0e2291adbd22c77656afc196858a11e1c670d9eeb592613e69eb4f3aa501730743ac4464486c7ae68fd509e896f63884e9424f69c1c5397959f1e52a368667a598a1fc90125273d9341295d2f8e1cc4969bf228c860e07a3546be2eeda1cde48ee94d062801fe666e4a7ae8cb9cd79262c017b081af874ff00453ca43e34efdb43fffb0bb42a4e2d32a5e5cc9e8546a221fe930250e5f5333e0efe58ffebf19369a3b8ae5a67f6a048bc9ef915bda25160729b508667ada84a0c27e7e26cf2abca413e5e4693f4a9405"_sd,
true));
}
TEST_F(AsymmetricCryptoTestVectors, RSASignatureVerificationTest2) {
evaluate(RSAKeySignatureVerificationVector(
"0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd,
"49d2a1"_sd,
"c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9bb66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e61d891c4da29f2d65f34cbb"_sd,
"f89fd2f6c45a8b5066a651410b8e534bfec0d9a36f3e2b887457afd44dd651d1ec79274db5a455f182572fceea5e9e39c3c7c5d9e599e4fe31c37c34d253b419c3e8fb6b916aef6563f87d4c37224a456e5952698ba3d01b38945d998a795bd285d69478e3131f55117284e27b441f16095dca7ce9c5b68890b09a2bfbb010a5"_sd,
"ba48538708512d45c0edcac57a9b4fb637e9721f72003c60f13f5c9a36c968cef9be8f54665418141c3d9ecc02a5bf952cfc055fb51e18705e9d8850f4e1f5a344af550de84ffd0805e27e557f6aa50d2645314c64c1c71aa6bb44faf8f29ca6578e2441d4510e36052f46551df341b2dcf43f761f08b946ca0b7081dadbb88e955e820fd7f657c4dd9f4554d167dd7c9a487ed41ced2b40068098deedc951060faf7e15b1f0f80ae67ff2ee28a238d80bf72dd71c8d95c79bc156114ece8ec837573a4b66898d45b45a5eacd0b0e41447d8fa08a367f437645e50c9920b88a16bc0880147acfb9a79de9e351b3fa00b3f4e9f182f45553dffca55e393c5eab6"_sd,
false));
}
TEST_F(AsymmetricCryptoTestVectors, RSASignatureVerificationTest3) {
evaluate(RSAKeySignatureVerificationVector(
"0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd,
"49d2a1"_sd,
"c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9bb66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e61d891c4da29f2d65f34cbb"_sd,
"915c5e4c16acfa0f49de43d6491f0060a944034475ba518572c08366a8d36c7f1e6afc11e5e4649757bf7b9da10a61d57f1d626847871d8a2948e551b54167c79de88d3ebd40a3e35809b996a53348f98a9918c7a7ec606896ed30c271e00c51953dd97aa6a8fe1cd423c3695c83fcf45120ec0a9cd1644642182b60e599a246"_sd,
"3d57ea5961db8fc144301ca4278f799911229d865ea3e992c7fbc4d03c6551729e26034e95dd71da312340e4051c9dd9b12f7700a821fe3b7c37785d5106350b667ac255a57c13da5842d90bcadea9e6b1f720c607d6893a2caa3c5f3c4074e914451a45380a767c291a67cac3f1cab1fbd05adc37036856a8404e7cea3654019466de449ad6e92b27254f3d25949b1b860065406455a13db7c5fe25d1af7a84cddf7792c64e16260c950d60bd86d005924148ad097c126b84947ab6e89d48f61e711d62522b6e48f16186d1339e6ab3f58c359eb24cb68043737591cd7d9390a468c0022b3b253be52f1a7fc408f84e9ffb4c34fa9e01605851d6583aa13032"_sd,
false));
}
TEST_F(AsymmetricCryptoTestVectors, RSASignatureVerificationTest4) {
evaluate(RSAKeySignatureVerificationVector(
"0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd,
"7485b2"_sd,
"c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9bb66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e61d891c4da29f2d65f34cbb"_sd,
"3d2f0693517cffb2b724c1f30502c5359c051c1bcd88dc1dd54b89e6981009d275a813b2bf016b74d0f6ed0d91e62d0884785c9afd8fd1fb7e99246cd4005cdda71a39cb649197a996d8ad2d23fdfb6bb015f24ec3d7f88af64fb83b4b525eb06607d133eec834cf7d6c9ab817b4c0dda370459d9cfba05ad0c1adc86a909fe1"_sd,
"511abd82218cab344979b2887b02600d2427f1eb12ac01d97684c2a443a9272834c3f79cded07a39dbee3770dde827a74dc994b17bfd8a26d07b239d26d58c42f79d560264c31b7e1c3dddef6d7556f228c394414f4cec561c3da2686a8eebec7702f32850809a93deeb84b2a02fcdba224d2fd9efb8e056e796f49b57d56e9f3e90d0b49b08bdee93a2e12e676fb4d4fa838c5bd88eda008f1b592a72465587be0ae17d9b156b904f44a7e04d3b58d24ad67b71b0f4c699fa51639546b62b9f83597ff03d465f1bb396ae15e92d0e92e85647d5df113e2c7518d0e3ad2e7aa7dac720c98347aa151e4f37fea081dbed350cc9c93f606b38f21a3e5de6d140d2"_sd,
false));
}
TEST_F(AsymmetricCryptoTestVectors, RSASignatureVerificationTest5) {
evaluate(RSAKeySignatureVerificationVector(
"0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd,
"49d2a1"_sd,
"c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9bb66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e61d891c4da29f2d65f34cbb"_sd,
"dffe42bfda886e1a73fe8a8dfcf71c9fb44deb054588a9bb9199d554aecce08f2ff88f2aa6f8a0fb675fb03c8e685c27432ca7c33c189bfd849d34fa7b2979ac1f57eca389632426bae0b98398ad60a3342557e14e96041c1bf4d90b46cf7ad1348322d28caf43c4f7e86c0924ae703c109ec50a84ea2a43df078c3015a52b28"_sd,
"8f4dd479239f2d08dc05d7d40539288b67c4d77210ecb16be76f0b1925e8b088570831e361a1ca57893135f8af64b8e2996b8d635899da4e04c68acb9b1b3813697d57da90c57f18509e0ab6705c704feb448cca5c07d258ecd884ab93f508cefdb25f2bc3061c4006099e2e33b27972c3edb0a0a33114d381c82ab506d041ff680af595ef3400a8bb6774030d2e38dd304272092bd32a553017f7bda4b998b27aa8aca12def327b1f11063a5342b0d55738183417d321c5682fc4ab64e79174216feebb989521e1e3d827647068003be34fe1d093964d28f4877c49b4065672448597a89b91919cfb55ca13836e7e6f3b3fd04f417cf1c16d9872538bf4e87a"_sd,
false));
}
TEST_F(AsymmetricCryptoTestVectors, RSASignatureVerificationTest6) {
evaluate(RSAKeySignatureVerificationVector(
"0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd,
"49d2a1"_sd,
"c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9bb66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e61d891c4da29f2d65f34cbb"_sd,
"cfe99788f55ec6944942bd0a187d51b80fd8bd4051bd4f07c73e614eb75a8b9f997b176b2642b5f1b1877061ba9ce142c1d2a311583f072b7cbe08ed253681191c209d7b0d438fcdddc284d93d59d6dd80e48333a921dd31c9b6834f88768f8701e01102d3e8bdf074fbe0b8c93d9951f41545ef6eeb3be35530babc079f1fb3"_sd,
"9fd6f6107e838107f906c26cb2910704599f175b6a84db485fbc30776eb7fd53bfe20c38c537b154a3e519b662bd9fdc8e3045e21f6e5ae97d0ff6a9d8632825544525d84f99f80e3ed4e69dc5e219d59ccfbb37c23c84fe3b3e6fb22f402f94e5225c6387fdf8bcdb3508f8832908fe05771521e92234348004e8fe19a8f24bebcab9f074327c88d066bc12081748d696be6135c6aea32220ea786ebd7800e6936365ff25831c28cb6c8a59237ff84f5cf89036cff188ee0f9a6195f2b1aca2e4442af8369f1b49322fa2f891b83a14a97b60c6aeafd6c2928047affda9c8d869ff5294bb5943ad14a6d64e784d126c469d51e292b9ce33e1d8371ba5f467b3"_sd,
false));
}
#endif
} // namespace mongo::crypto
#endif

View File

@ -1,53 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/asymmetric_crypto.h"
#include "mongo/base/error_codes.h"
namespace mongo::crypto {
namespace {
class RSAKeySignatureVerifierWindows : public RSAKeySignatureVerifier {
public:
RSAKeySignatureVerifierWindows(){};
Status verifySignature(ConstDataRange msg, ConstDataRange signature) final {
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
};
} // namespace
// TODO: SERVER-68518, remove or implement this class
StatusWith<std::unique_ptr<RSAKeySignatureVerifier>> RSAKeySignatureVerifier::create(
const RsaPublicKey& pubKey, HashingAlgorithm hashAlg) {
return {ErrorCodes::OperationFailed, "Signature Verification Not Available"};
}
} // namespace mongo::crypto

View File

@ -1,92 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/jwk_manager.h"
#include "mongo/bson/json.h"
#include "mongo/crypto/jwt_types_gen.h"
#include "mongo/logv2/log.h"
#include "mongo/util/base64.h"
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kAccessControl
namespace mongo::crypto {
namespace {
constexpr auto kMinKeySizeBytes = 512 >> 3;
// Strip insignificant leading zeroes to determine the key's true size.
StringData reduceInt(StringData value) {
std::size_t ofs = 0;
while ((ofs < value.size()) && (value[ofs] == 0)) {
++ofs;
}
return value.substr(ofs);
}
} // namespace
JWKManager::JWKManager(BSONObj data) {
auto keys = JWKSet::parse(IDLParserContext{"JWKSet"}, data);
for (const auto& key : keys.getKeys()) {
uassert(ErrorCodes::BadValue,
str::stream() << "Only RSA key types are accepted at this time",
key.getType() == "RSA"_sd);
uassert(ErrorCodes::BadValue, "Key ID must be non-empty", !key.getKeyId().empty());
// Sanity check so that we don't load a dangerously small key.
auto N = reduceInt(key.getN());
uassert(ErrorCodes::BadValue,
str::stream() << "Key scale is smaller (" << (N.size() << 3)
<< " bits) than minimum required: " << (kMinKeySizeBytes << 3),
N.size() >= kMinKeySizeBytes);
// Sanity check so that we don't load an insensible encrypt component.
auto E = reduceInt(key.getE());
uassert(ErrorCodes::BadValue,
str::stream() << "Public key component invalid: " << base64url::encode(key.getE()),
(E.size() > 1) || ((E.size() == 1) && (E[0] >= 3)));
auto keyId = key.getKeyId().toString();
uassert(ErrorCodes::DuplicateKey,
str::stream() << "Key IDs must be unique, duplicate '" << keyId << "'",
_keys.find(keyId) == _keys.end());
LOGV2_DEBUG(6766000, 5, "Loaded JWK Key", "kid"_attr = key.getKeyId());
_keys.insert({keyId, {key.getKeyId(), {E.rawData(), E.size()}, {N.rawData(), N.size()}}});
}
}
const RsaPublicKey& JWKManager::getKey(StringData keyId) const {
auto it = _keys.find(keyId.toString());
uassert(
ErrorCodes::NoSuchKey, str::stream() << "Unknown key '" << keyId << "'", it != _keys.end());
return it->second;
}
} // namespace mongo::crypto

View File

@ -1,52 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include <map>
#include <string>
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/crypto/rsa_public_key.h"
namespace mongo::crypto {
class JWKManager {
public:
JWKManager() = default;
explicit JWKManager(BSONObj data);
const RsaPublicKey& getKey(StringData keyId) const;
private:
std::map<std::string, RsaPublicKey> _keys;
};
} // namespace mongo::crypto

View File

@ -1,85 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/platform/basic.h"
#include "mongo/crypto/jwk_manager.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/assert_util.h"
namespace mongo::crypto {
namespace {
// Test key source: RFC 7515 "JSON Web Key" Appendix B.
constexpr auto k512BitKeyE = "AQAB"_sd;
constexpr auto k512BitKeyN =
"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08PLbK_PdiVGKPrqzmDIsL"
"I7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Qu2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7i"
"I7w0LK9orSMhBEwwZDCxTWq4aYWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy"
"1wgzjYQDwHMTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMvVfJb6"
"jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ"_sd;
BSONObj getTestJWKSet(StringData e, StringData n) {
BSONObjBuilder set;
BSONArrayBuilder keys(set.subarrayStart("keys"_sd));
{
BSONObjBuilder key(keys.subobjStart());
key.append("kty", "RSA");
key.append("kid", "numberOneKey");
key.append("e", e);
key.append("n", n);
key.doneFast();
}
keys.doneFast();
return set.obj();
}
TEST(JWKManager, parseJWKSetBasic) {
// Parse the test JWKSet and pull out numberOneKey, then compare it to the inputs.
auto basic = getTestJWKSet(k512BitKeyE, k512BitKeyN);
JWKManager manager(basic);
auto key = manager.getKey("numberOneKey");
ASSERT_BSONOBJ_EQ(key.toBSON(), basic["keys"_sd].Obj()[0].Obj());
}
TEST(JWKManager, parseJWKSetEmptyComponents) {
auto emptyE = getTestJWKSet("", k512BitKeyN);
ASSERT_THROWS_WHAT(JWKManager(emptyE), DBException, "Public key component invalid: ");
auto emptyN = getTestJWKSet(k512BitKeyE, "");
ASSERT_THROWS_WHAT(JWKManager(emptyN),
DBException,
"Key scale is smaller (0 bits) than minimum required: 512");
}
} // namespace
} // namespace mongo::crypto

View File

@ -1,64 +0,0 @@
# Copyright (C) 2022-present MongoDB, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the Server Side Public License, version 1,
# as published by MongoDB, Inc.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Server Side Public License for more details.
#
# You should have received a copy of the Server Side Public License
# along with this program. If not, see
# <http://www.mongodb.com/licensing/server-side-public-license>.
#
# As a special exception, the copyright holders give permission to link the
# code of portions of this program with the OpenSSL library under certain
# conditions as described in each individual source file and distribute
# linked combinations including the program with the OpenSSL library. You
# must comply with the Server Side Public License in all respects for
# all of the code used other than as permitted herein. If you modify file(s)
# with this exception, you may extend this exception to your version of the
# file(s), but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version. If you delete this
# exception statement from all source files in the program, then also delete
# it in the license file.
global:
cpp_namespace: "mongo::crypto"
imports:
- "mongo/idl/basic_types.idl"
structs:
JWK:
# RFC 7515 Section 4
description: JSON Web Key
fields:
kty:
description: Key type
type: string
cpp_name: type
kid:
description: Unique Key ID
type: string
cpp_name: keyId
# RSA specific fields
n:
description: Modulus of the RSA Key
type: base64urlstring
e:
description: Public key component of the RSA Key
type: base64urlstring
JWKSet:
# RFC 7517 Section 5
description: A set of JSON Web Keys
fields:
keys:
description: The JWK objects
type: array<JWK>

View File

@ -1,51 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/rsa_public_key.h"
#include "mongo/crypto/jwt_types_gen.h"
#include "mongo/util/base64.h"
namespace mongo::crypto {
namespace {
std::vector<std::uint8_t> vectorFromCDR(ConstDataRange cdr) {
return {cdr.data(), cdr.data() + cdr.length()};
}
} // namespace
RsaPublicKey::RsaPublicKey(StringData keyId, ConstDataRange e, ConstDataRange n)
: _keyId(keyId.toString()), _e(vectorFromCDR(e)), _n(vectorFromCDR(n)) {}
void RsaPublicKey::appendToBSON(BSONObjBuilder* builder) const {
builder->append(JWK::kTypeFieldName, "RSA"_sd);
builder->append(JWK::kKeyIdFieldName, _keyId);
builder->append(JWK::kEFieldName, base64url::encode(_e.data(), _e.size()));
builder->append(JWK::kNFieldName, base64url::encode(_n.data(), _n.size()));
}
} // namespace mongo::crypto

View File

@ -1,83 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include <string>
#include <vector>
#include "mongo/base/data_range.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
namespace mongo::crypto {
/**
* Provides an interface for managing parameters to an RSA signing operation.
* Note that this key contains public material only, and is not suitable for decryption.
*/
class RsaPublicKey {
public:
/**
* Creates an `RsaPublicKey` instance identified by the opaque string name {keyId}.
* The RSA operation parameters of {E} and {N} must be passed as Base64URL encoded values (RFC
* 4648 §5).
*/
RsaPublicKey(StringData keyId, ConstDataRange e, ConstDataRange n);
std::size_t getKeySizeBytes() const {
return _n.size();
}
ConstDataRange getE() const {
return ConstDataRange(_e);
}
ConstDataRange getN() const {
return ConstDataRange(_n);
}
StringData getKeyId() const {
return _keyId;
}
void appendToBSON(BSONObjBuilder* builder) const;
BSONObj toBSON() const {
BSONObjBuilder builder;
appendToBSON(&builder);
return builder.obj();
}
private:
std::string _keyId;
std::vector<std::uint8_t> _e;
std::vector<std::uint8_t> _n;
};
} // namespace mongo::crypto

View File

@ -1,63 +0,0 @@
/**
* Copyright (C) 2022-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/crypto/rsa_public_key.h"
#include <iostream>
#include <vector>
#include "mongo/base/string_data.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/base64.h"
namespace mongo::crypto {
TEST(RSAPublickKeyTest, rsaKeyDecode) {
const auto keyID = "0UhWwyvtfIdxPvR9zCWYJB5_AM0LE2qc6RGOcI0cQjw"_sd;
const auto e = "AQAB"_sd;
const auto n =
"ionlnDDd4AG2rRFgjEowRUiZ8x7LTfM-cwwBTuV4TAWgZKb3RycprPwdPODtbKSxnyoM6-Bi-"
"qM0FInx13vsC3h3xxzMIreH-vRQPWWocsJ6CZrgfbXyUclcLzgJX_E2V_6hpG0CeUBfNYsgfgwm4Y_"
"wjUu3HKsKPdIPqjf6zdrgv8W3OySt-QSFVBy_OQXraZ2wA7gJPyPmNhBr8L9M3AYRS_"
"E1XRpsldMSrIe8bfxGyP2B9txiUQXIycWLC-e172SPjAjdUyaK3YLqGRtki6EgQ3qlzRPjoQheE-"
"r3l62UaaAgHOo6FercdjdsIzT2-vhqZMQk59WhGuvygymiLw"_sd;
auto eStr = base64url::decode(e);
auto nStr = base64url::decode(n);
RsaPublicKey key(keyID, {eStr.c_str(), eStr.size()}, {nStr.c_str(), nStr.size()});
std::string strE;
strE.assign(key.getE().data(), key.getE().length());
ASSERT_EQ(base64url::encode(strE), e);
std::string strN;
strN.assign(key.getN().data(), key.getN().length());
ASSERT_EQ(base64url::encode(strN), n);
}
} // namespace mongo::crypto

View File

@ -1301,9 +1301,11 @@ env.Library(
'$BUILD_DIR/mongo/db/commands/fsync_locked',
'$BUILD_DIR/mongo/db/ops/write_ops',
'$BUILD_DIR/mongo/db/record_id_helpers',
'$BUILD_DIR/mongo/db/repl/replica_set_aware_service',
'$BUILD_DIR/mongo/db/repl/tenant_migration_access_blocker',
'$BUILD_DIR/mongo/db/s/sharding_runtime_d',
'$BUILD_DIR/mongo/idl/server_parameter',
'catalog/catalog_helpers',
'catalog/database_holder',
'commands/server_status_core',
'service_context',
@ -2517,6 +2519,7 @@ if wiredtiger:
'transaction/transaction_history_iterator_test.cpp',
'transaction/transaction_participant_retryable_writes_test.cpp',
'transaction/transaction_participant_test.cpp',
'ttl_collection_cache_test.cpp',
'ttl_test.cpp',
'update_index_data_test.cpp',
'vector_clock_mongod_test.cpp',
@ -2617,6 +2620,7 @@ if wiredtiger:
'snapshot_window_options',
'startup_warnings_mongod',
'time_proof_service',
'ttl_collection_cache',
'ttl_d',
'update_index_data',
'vector_clock',

View File

@ -187,7 +187,6 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/idl/server_parameter',
'oidc_authentication_config',
],
)
@ -437,8 +436,6 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base/secure_allocator',
'$BUILD_DIR/mongo/crypto/asymmetric_crypto',
'$BUILD_DIR/mongo/crypto/rsa_public_key',
'$BUILD_DIR/mongo/crypto/sha_block_${MONGO_CRYPTO}',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/util/icu',
@ -538,20 +535,6 @@ env.Library(
],
)
env.Library(
target="oidc_authentication_config",
source=[
"oidc_authentication.idl",
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/idl/feature_flag',
'$BUILD_DIR/mongo/idl/idl_parser',
],
)
env.CppUnitTest(
target='db_auth_test',
source=[

View File

@ -149,8 +149,7 @@ void reopenAllDatabasesAndReloadCollectionCatalog(OperationContext* opCtx,
// Opening CollectionCatalog: The collection catalog is now in sync with the storage engine
// catalog. Clear the pre-closing state.
CollectionCatalog::write(opCtx,
[&](CollectionCatalog& catalog) { catalog.onOpenCatalog(opCtx); });
CollectionCatalog::write(opCtx, [](CollectionCatalog& catalog) { catalog.onOpenCatalog(); });
opCtx->getServiceContext()->incrementCatalogGeneration();
LOGV2(20278, "openCatalog: finished reloading collection catalog");
}
@ -210,14 +209,13 @@ PreviousCatalogState closeCatalog(OperationContext* opCtx) {
// Need to mark the CollectionCatalog as open if we our closeAll fails, dismissed if successful.
ScopeGuard reopenOnFailure([opCtx] {
CollectionCatalog::write(opCtx,
[&](CollectionCatalog& catalog) { catalog.onOpenCatalog(opCtx); });
[](CollectionCatalog& catalog) { catalog.onOpenCatalog(); });
});
// Closing CollectionCatalog: only lookupNSSByUUID will fall back to using pre-closing state to
// allow authorization for currently unknown UUIDs. This is needed because authorization needs
// to work before acquiring locks, and might otherwise spuriously regard a UUID as unknown
// while reloading the catalog.
CollectionCatalog::write(opCtx,
[&](CollectionCatalog& catalog) { catalog.onCloseCatalog(opCtx); });
CollectionCatalog::write(opCtx, [](CollectionCatalog& catalog) { catalog.onCloseCatalog(); });
LOGV2_DEBUG(20270, 1, "closeCatalog: closing collection catalog");

View File

@ -246,7 +246,8 @@ StatusWith<std::pair<ParsedCollModRequest, BSONObj>> parseCollModRequest(Operati
"TTL indexes are not supported for capped collections."};
}
if (auto status = index_key_validate::validateExpireAfterSeconds(
*cmdIndex.getExpireAfterSeconds());
*cmdIndex.getExpireAfterSeconds(),
index_key_validate::ValidateExpireAfterSecondsMode::kSecondaryTTLIndex);
!status.isOK()) {
return {ErrorCodes::InvalidOptions, status.reason()};
}
@ -530,7 +531,9 @@ StatusWith<std::pair<ParsedCollModRequest, BSONObj>> parseCollModRequest(Operati
},
[&oplogEntryBuilder](std::int64_t value) {
oplogEntryBuilder.append(CollMod::kExpireAfterSecondsFieldName, value);
return index_key_validate::validateExpireAfterSeconds(value);
return index_key_validate::validateExpireAfterSeconds(
value,
index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex);
},
},
*expireAfterSeconds);
@ -593,7 +596,8 @@ void _setClusteredExpireAfterSeconds(
if (!oldExpireAfterSeconds) {
auto ttlCache = &TTLCollectionCache::get(opCtx->getServiceContext());
opCtx->recoveryUnit()->onCommit([ttlCache, uuid = coll->uuid()](auto _) {
ttlCache->registerTTLInfo(uuid, TTLCollectionCache::ClusteredId());
ttlCache->registerTTLInfo(
uuid, TTLCollectionCache::Info{TTLCollectionCache::ClusteredId{}});
});
}

View File

@ -69,8 +69,10 @@ void _processCollModIndexRequestExpireAfterSeconds(OperationContext* opCtx,
// Do not refer to 'idx' within this commit handler as it may be be invalidated by
// IndexCatalog::refreshEntry().
opCtx->recoveryUnit()->onCommit(
[ttlCache, uuid = coll->uuid(), indexName = idx->indexName()](auto _) {
ttlCache->registerTTLInfo(uuid, indexName);
[ttlCache, uuid = coll->uuid(), indexName = idx->indexName(), indexExpireAfterSeconds](
auto _) {
ttlCache->registerTTLInfo(
uuid, TTLCollectionCache::Info{indexName, /*isExpireAfterSecondsNaN=*/false});
});
// Change the value of "expireAfterSeconds" on disk.
@ -79,6 +81,29 @@ void _processCollModIndexRequestExpireAfterSeconds(OperationContext* opCtx,
return;
}
// If the current `expireAfterSeconds` is NaN, it can never be equal to
// 'indexExpireAfterSeconds'.
if (oldExpireSecsElement.isNaN()) {
// Setting *oldExpireSecs is mostly for informational purposes.
// We could also use index_key_validate::kExpireAfterSecondsForInactiveTTLIndex but
// 0 is more consistent with the previous safeNumberLong() behavior and avoids potential
// showing the same value for the new and old values in the collMod response.
*oldExpireSecs = 0;
// Change the value of "expireAfterSeconds" on disk.
autoColl->getWritableCollection(opCtx)->updateTTLSetting(
opCtx, idx->indexName(), indexExpireAfterSeconds);
// Keep the TTL information maintained by the TTLCollectionCache in sync so that we don't
// try to fix up the TTL index during the next step-up.
auto ttlCache = &TTLCollectionCache::get(opCtx->getServiceContext());
const auto& coll = autoColl->getCollection();
opCtx->recoveryUnit()->onCommit(
[ttlCache, uuid = coll->uuid(), indexName = idx->indexName(), indexExpireAfterSeconds](
auto _) { ttlCache->unsetTTLIndexExpireAfterSecondsNaN(uuid, indexName); });
return;
}
// This collection is already TTL. Compare the requested value against the existing setting
// before updating the catalog.
*oldExpireSecs = oldExpireSecsElement.safeNumberLong();

View File

@ -733,16 +733,17 @@ void CollectionCatalog::onCloseDatabase(OperationContext* opCtx, DatabaseName db
_viewsForDatabase.erase(dbName);
}
void CollectionCatalog::onCloseCatalog(OperationContext* opCtx) {
invariant(opCtx->lockState()->isW());
invariant(!_shadowCatalog);
void CollectionCatalog::onCloseCatalog() {
if (_shadowCatalog) {
return;
}
_shadowCatalog.emplace();
for (auto& entry : _catalog)
_shadowCatalog->insert({entry.first, entry.second->ns()});
}
void CollectionCatalog::onOpenCatalog(OperationContext* opCtx) {
invariant(opCtx->lockState()->isW());
void CollectionCatalog::onOpenCatalog() {
invariant(_shadowCatalog);
_shadowCatalog.reset();
++_epoch;

View File

@ -522,14 +522,14 @@ public:
*
* Must be called with the global lock acquired in exclusive mode.
*/
void onCloseCatalog(OperationContext* opCtx);
void onCloseCatalog();
/**
* Puts the catalog back in open state, removing the pre-close state. See onCloseCatalog.
*
* Must be called with the global lock acquired in exclusive mode.
*/
void onOpenCatalog(OperationContext* opCtx);
void onOpenCatalog();
/**
* The epoch is incremented whenever the catalog is closed and re-opened.

View File

@ -523,7 +523,7 @@ TEST_F(CollectionCatalogTest, RenameCollection) {
TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsOldNSSIfDropped) {
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onCloseCatalog(opCtx.get());
catalog.onCloseCatalog();
}
catalog.deregisterCollection(opCtx.get(), colUUID, /*isDropPending=*/false);
@ -532,7 +532,7 @@ TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsOldNSSIfDrop
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onOpenCatalog(opCtx.get());
catalog.onOpenCatalog();
}
ASSERT_EQUALS(catalog.lookupNSSByUUID(opCtx.get(), colUUID), boost::none);
@ -547,7 +547,7 @@ TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsNewlyCreated
// Ensure that looking up non-existing UUIDs doesn't affect later registration of those UUIDs.
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onCloseCatalog(opCtx.get());
catalog.onCloseCatalog();
}
ASSERT(catalog.lookupCollectionByUUID(opCtx.get(), newUUID) == nullptr);
@ -559,7 +559,7 @@ TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsNewlyCreated
// Ensure that collection still exists after opening the catalog again.
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onOpenCatalog(opCtx.get());
catalog.onOpenCatalog();
}
ASSERT_EQUALS(catalog.lookupCollectionByUUID(opCtx.get(), newUUID), newCol);
@ -573,7 +573,7 @@ TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsFreshestNSS)
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onCloseCatalog(opCtx.get());
catalog.onCloseCatalog();
}
catalog.deregisterCollection(opCtx.get(), colUUID, /*isDropPending=*/false);
@ -586,7 +586,7 @@ TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsFreshestNSS)
// Ensure that collection still exists after opening the catalog again.
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onOpenCatalog(opCtx.get());
catalog.onOpenCatalog();
}
ASSERT_EQUALS(catalog.lookupCollectionByUUID(opCtx.get(), colUUID), newCol);
@ -599,8 +599,8 @@ TEST_F(CollectionCatalogTest, CollectionCatalogEpoch) {
{
Lock::GlobalLock globalLk(opCtx.get(), MODE_X);
catalog.onCloseCatalog(opCtx.get());
catalog.onOpenCatalog(opCtx.get());
catalog.onCloseCatalog();
catalog.onOpenCatalog();
}
auto incrementedEpoch = catalog.getEpoch();

View File

@ -409,11 +409,11 @@ void CollectionImpl::init(OperationContext* opCtx) {
if (opCtx->lockState()->inAWriteUnitOfWork()) {
opCtx->recoveryUnit()->onCommit([svcCtx, uuid](auto ts) {
TTLCollectionCache::get(svcCtx).registerTTLInfo(
uuid, TTLCollectionCache::ClusteredId{});
uuid, TTLCollectionCache::Info{TTLCollectionCache::ClusteredId{}});
});
} else {
TTLCollectionCache::get(svcCtx).registerTTLInfo(uuid,
TTLCollectionCache::ClusteredId{});
TTLCollectionCache::get(svcCtx).registerTTLInfo(
uuid, TTLCollectionCache::Info{TTLCollectionCache::ClusteredId{}});
}
}
}

View File

@ -118,7 +118,9 @@ Status validateClusteredIndexSpec(OperationContext* opCtx,
if (expireAfterSeconds) {
// Not included in the indexSpec itself.
auto status = index_key_validate::validateExpireAfterSeconds(*expireAfterSeconds);
auto status = index_key_validate::validateExpireAfterSeconds(
*expireAfterSeconds,
index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex);
if (!status.isOK()) {
return status;
}
@ -378,8 +380,9 @@ Status _createTimeseries(OperationContext* opCtx,
// Cluster time-series buckets collections by _id.
auto expireAfterSeconds = options.expireAfterSeconds;
if (expireAfterSeconds) {
uassertStatusOK(
index_key_validate::validateExpireAfterSeconds(*expireAfterSeconds));
uassertStatusOK(index_key_validate::validateExpireAfterSeconds(
*expireAfterSeconds,
index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex));
bucketsOptions.expireAfterSeconds = expireAfterSeconds;
}

View File

@ -278,7 +278,10 @@ void IndexBuildBlock::success(OperationContext* opCtx, Collection* collection) {
// Note that TTL deletion is supported on capped clustered collections via bounded
// collection scan, which does not use an index.
if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName) && !coll->isCapped()) {
TTLCollectionCache::get(svcCtx).registerTTLInfo(coll->uuid(), indexName);
TTLCollectionCache::get(svcCtx).registerTTLInfo(
coll->uuid(),
TTLCollectionCache::Info{
indexName, spec[IndexDescriptor::kExpireAfterSecondsFieldName].isNaN()});
}
});
}

View File

@ -205,13 +205,30 @@ Status IndexCatalogImpl::init(OperationContext* opCtx, Collection* collection) {
auto descriptor = std::make_unique<IndexDescriptor>(_getAccessMethodName(keyPattern), spec);
// TTL indexes with NaN 'expireAfterSeconds' cause problems in multiversion settings.
if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName)) {
if (spec[IndexDescriptor::kExpireAfterSecondsFieldName].isNaN()) {
LOGV2_OPTIONS(6852200,
{logv2::LogTag::kStartupWarnings},
"Found an existing TTL index with NaN 'expireAfterSeconds' in the "
"catalog.",
"ns"_attr = collection->ns(),
"uuid"_attr = collection->uuid(),
"index"_attr = indexName,
"spec"_attr = spec);
}
}
// TTL indexes are not compatible with capped collections.
// Note that TTL deletion is supported on capped clustered collections via bounded
// collection scan, which does not use an index.
if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName) &&
!collection->isCapped()) {
TTLCollectionCache::get(opCtx->getServiceContext())
.registerTTLInfo(collection->uuid(), indexName);
.registerTTLInfo(
collection->uuid(),
TTLCollectionCache::Info{
indexName, spec[IndexDescriptor::kExpireAfterSecondsFieldName].isNaN()});
}
bool ready = collection->isIndexReady(indexName);

View File

@ -71,6 +71,10 @@ namespace {
// specification.
MONGO_FAIL_POINT_DEFINE(skipIndexCreateFieldNameValidation);
// When the skipTTLIndexNaNExpireAfterSecondsValidation failpoint is enabled, validation for
// TTL index 'expireAfterSeconds' will be disabled.
MONGO_FAIL_POINT_DEFINE(skipTTLIndexNaNExpireAfterSecondsValidation);
static const std::set<StringData> allowedIdIndexFieldNames = {
IndexDescriptor::kCollationFieldName,
IndexDescriptor::kIndexNameFieldName,
@ -269,8 +273,8 @@ BSONObj removeUnknownFields(const NamespaceString& ns, const BSONObj& indexSpec)
BSONObj repairIndexSpec(const NamespaceString& ns,
const BSONObj& indexSpec,
const std::set<StringData>& allowedFieldNames) {
auto fixBoolIndexSpecFn = [&indexSpec, &ns](const BSONElement& indexSpecElem,
BSONObjBuilder* builder) {
auto fixIndexSpecFn = [&indexSpec, &ns](const BSONElement& indexSpecElem,
BSONObjBuilder* builder) {
StringData fieldName = indexSpecElem.fieldNameStringData();
if ((IndexDescriptor::kBackgroundFieldName == fieldName ||
IndexDescriptor::kUniqueFieldName == fieldName ||
@ -285,17 +289,28 @@ BSONObj repairIndexSpec(const NamespaceString& ns,
"fieldName"_attr = redact(fieldName),
"indexSpec"_attr = redact(indexSpec));
builder->appendBool(fieldName, true);
} else if (IndexDescriptor::kExpireAfterSecondsFieldName == fieldName &&
!(indexSpecElem.isNumber() && !indexSpecElem.isNaN())) {
LOGV2_WARNING(6835900,
"Fixing expire field from TTL index spec",
"namespace"_attr = redact(ns.toString()),
"fieldName"_attr = redact(fieldName),
"indexSpec"_attr = redact(indexSpec));
builder->appendNumber(fieldName,
durationCount<Seconds>(kExpireAfterSecondsForInactiveTTLIndex));
} else {
builder->append(indexSpecElem);
}
};
return buildRepairedIndexSpec(ns, indexSpec, allowedFieldNames, fixBoolIndexSpecFn);
return buildRepairedIndexSpec(ns, indexSpec, allowedFieldNames, fixIndexSpecFn);
}
StatusWith<BSONObj> validateIndexSpec(OperationContext* opCtx, const BSONObj& indexSpec) {
bool hasKeyPatternField = false;
bool hasIndexNameField = false;
bool hasNamespaceField = false;
bool isTTLIndexWithNaNExpireAfterSeconds = false;
bool hasVersionField = false;
bool hasCollationField = false;
bool hasWeightsField = false;
@ -554,6 +569,8 @@ StatusWith<BSONObj> validateIndexSpec(OperationContext* opCtx, const BSONObj& in
str::stream() << "The field '" << indexSpecElemFieldName
<< "' must be a number, but got "
<< typeName(indexSpecElem.type())};
} else if (IndexDescriptor::kExpireAfterSecondsFieldName == indexSpecElemFieldName) {
isTTLIndexWithNaNExpireAfterSeconds = indexSpecElem.isNaN();
} else {
// We can assume field name is valid at this point. Validation of fieldname is handled
// prior to this in validateIndexSpecFieldNames().
@ -625,6 +642,19 @@ StatusWith<BSONObj> validateIndexSpec(OperationContext* opCtx, const BSONObj& in
modifiedSpec = modifiedSpec.removeField(IndexDescriptor::kNamespaceFieldName);
}
if (isTTLIndexWithNaNExpireAfterSeconds &&
!skipTTLIndexNaNExpireAfterSecondsValidation.shouldFail()) {
// We create a new index specification with the 'expireAfterSeconds' field set as
// kExpireAfterSecondsForInactiveTTLIndex if the current value is NaN. A similar
// treatment is done in repairIndexSpec(). This rewrites the 'expireAfterSeconds'
// value to be compliant with the 'safeInt' IDL type for the listIndexes response.
BSONObjBuilder builder;
builder.appendNumber(IndexDescriptor::kExpireAfterSecondsFieldName,
durationCount<Seconds>(kExpireAfterSecondsForInactiveTTLIndex));
auto obj = builder.obj();
modifiedSpec = modifiedSpec.addField(obj.firstElement());
}
if (!hasVersionField) {
// We create a new index specification with the 'v' field set as 'defaultIndexVersion' if
// the field was omitted.
@ -785,7 +815,8 @@ StatusWith<BSONObj> validateIndexSpecCollation(OperationContext* opCtx,
return indexSpec;
}
Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds) {
Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds,
ValidateExpireAfterSecondsMode mode) {
if (expireAfterSeconds < 0) {
return {ErrorCodes::InvalidOptions,
str::stream() << "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName
@ -796,16 +827,31 @@ Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds) {
<< "TTL index '" << IndexDescriptor::kExpireAfterSecondsFieldName
<< "' option must be within an acceptable range, try a lower number";
// There are two cases where we can encounter an issue here.
// The first case is when we try to cast to millseconds from seconds, which could cause an
// overflow. The second case is where 'expireAfterSeconds' is larger than the current epoch
// time.
if (expireAfterSeconds > std::numeric_limits<std::int64_t>::max() / 1000) {
return {ErrorCodes::InvalidOptions, tooLargeErr};
}
auto expireAfterMillis = duration_cast<Milliseconds>(Seconds(expireAfterSeconds));
if (expireAfterMillis > Date_t::now().toDurationSinceEpoch()) {
return {ErrorCodes::InvalidOptions, tooLargeErr};
if (mode == ValidateExpireAfterSecondsMode::kSecondaryTTLIndex) {
// Relax epoch restriction on TTL indexes. This allows us to export and import existing
// TTL indexes with large values or NaN for the 'expireAfterSeconds' field.
// Additionally, the 'expireAfterSeconds' for TTL indexes is defined as safeInt (int32_t)
// in the IDL for listIndexes and collMod. See list_indexes.idl and coll_mod.idl.
if (expireAfterSeconds > std::numeric_limits<std::int32_t>::max()) {
return {ErrorCodes::InvalidOptions, tooLargeErr};
}
} else {
// Clustered collections with TTL.
// Note that 'expireAfterSeconds' is defined as safeInt64 in the IDL for the create and
// collMod commands. See create.idl and coll_mod.idl.
// There are two cases where we can encounter an issue here.
// The first case is when we try to cast to millseconds from seconds, which could cause an
// overflow. The second case is where 'expireAfterSeconds' is larger than the current epoch
// time. This isn't necessarily problematic for the general case, but for the specific case
// of time series collections, we cluster the collection by an OID value, where the
// timestamp portion is only a 32-bit unsigned integer offset of seconds since the epoch.
if (expireAfterSeconds > std::numeric_limits<std::int64_t>::max() / 1000) {
return {ErrorCodes::InvalidOptions, tooLargeErr};
}
auto expireAfterMillis = duration_cast<Milliseconds>(Seconds(expireAfterSeconds));
if (expireAfterMillis > Date_t::now().toDurationSinceEpoch()) {
return {ErrorCodes::InvalidOptions, tooLargeErr};
}
}
return Status::OK();
}
@ -829,7 +875,9 @@ Status validateIndexSpecTTL(const BSONObj& indexSpec) {
<< "'. Index spec: " << indexSpec};
}
if (auto status = validateExpireAfterSeconds(expireAfterSecondsElt.safeNumberLong());
if (auto status =
validateExpireAfterSeconds(expireAfterSecondsElt.safeNumberLong(),
ValidateExpireAfterSecondsMode::kSecondaryTTLIndex);
!status.isOK()) {
return {ErrorCodes::CannotCreateIndex,
str::stream() << status.reason() << ". Index spec: " << indexSpec};

View File

@ -43,6 +43,12 @@ class StatusWith;
namespace index_key_validate {
// TTL indexes with 'expireAfterSeconds' are repaired with this duration, which is chosen to be
// the largest possible value for the 'safeInt' type that can be returned in the listIndexes
// response.
constexpr auto kExpireAfterSecondsForInactiveTTLIndex =
Seconds(std::numeric_limits<int32_t>::max());
static std::set<StringData> allowedFieldNames = {
IndexDescriptor::k2dIndexBitsFieldName,
IndexDescriptor::k2dIndexMaxFieldName,
@ -122,9 +128,14 @@ StatusWith<BSONObj> validateIndexSpecCollation(OperationContext* opCtx,
const CollatorInterface* defaultCollator);
/**
* Validates the the 'expireAfterSeconds' value for a TTL index..
* Validates the the 'expireAfterSeconds' value for a TTL index or clustered collection.
*/
Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds);
enum class ValidateExpireAfterSecondsMode {
kSecondaryTTLIndex,
kClusteredTTLIndex,
};
Status validateExpireAfterSeconds(std::int64_t expireAfterSeconds,
ValidateExpireAfterSecondsMode mode);
/**
* Returns true if 'indexSpec' refers to a TTL index.

View File

@ -400,6 +400,15 @@ TEST(IndexKeyValidateTest, RemoveUnkownFieldsFromIndexSpecs) {
fromjson("{key: {a: 1}, name: 'index', safe: true, force: true}"))));
}
TEST(IndexKeyValidateTest, UpdateTTLIndexNaNExpireAfterSeconds) {
ASSERT(BSON("key" << BSON("a" << 1) << "name"
<< "index"
<< "expireAfterSeconds" << std::numeric_limits<int32_t>::max()
<< IndexDescriptor::kIndexVersionFieldName << IndexVersion::kV2)
.binaryEqual(unittest::assertGet(index_key_validate::validateIndexSpec(
nullptr, fromjson("{key: {a: 1}, name: 'index', expireAfterSeconds: NaN}")))));
}
TEST(IndexKeyValidateTest, RepairIndexSpecs) {
ASSERT(fromjson("{key: {a: 1}, name: 'index'}")
.binaryEqual(index_key_validate::repairIndexSpec(
@ -426,6 +435,20 @@ TEST(IndexKeyValidateTest, RepairIndexSpecs) {
NamespaceString("coll"),
fromjson("{key: {a: 1}, name: 'index', sparse: 'true', background: '1', safe: "
"true, force: true}"))));
ASSERT(BSON("key" << BSON("a" << 1) << "name"
<< "index"
<< "expireAfterSeconds" << std::numeric_limits<int32_t>::max())
.binaryEqual(index_key_validate::repairIndexSpec(
NamespaceString("coll"),
fromjson("{key: {a: 1}, name: 'index', expireAfterSeconds: NaN}"))));
ASSERT(BSON("key" << BSON("a" << 1) << "name"
<< "index"
<< "expireAfterSeconds" << std::numeric_limits<int32_t>::max())
.binaryEqual(index_key_validate::repairIndexSpec(
NamespaceString("coll"),
fromjson("{key: {a: 1}, name: 'index', expireAfterSeconds: '123'}"))));
}
TEST(IndexKeyValidateTest, GeoIndexSpecs) {

View File

@ -1116,6 +1116,17 @@ Status SortedDataIndexAccessMethod::_indexKeysOrWriteToSideTable(
*keysInsertedOut += inserted;
}
} else {
// Ensure that our snapshot is compatible with the index's minimum visibile snapshot.
const auto minVisibleTimestamp = _indexCatalogEntry->getMinimumVisibleSnapshot();
const auto readTimestamp =
opCtx->recoveryUnit()->getPointInTimeReadTimestamp(opCtx).value_or(
opCtx->recoveryUnit()->getCatalogConflictingTimestamp());
if (minVisibleTimestamp && !readTimestamp.isNull() &&
readTimestamp < *minVisibleTimestamp) {
throwWriteConflictException(
"Unable to read from a snapshot due to pending catalog changes.");
}
int64_t numInserted = 0;
status = insertKeysAndUpdateMultikeyPaths(
opCtx,
@ -1178,6 +1189,15 @@ void SortedDataIndexAccessMethod::_unindexKeysOrWriteToSideTable(
options.dupsAllowed = options.dupsAllowed || !_indexCatalogEntry->isReady(opCtx) ||
(checkRecordId == CheckRecordId::On);
// Ensure that our snapshot is compatible with the index's minimum visibile snapshot.
const auto minVisibleTimestamp = _indexCatalogEntry->getMinimumVisibleSnapshot();
const auto readTimestamp = opCtx->recoveryUnit()->getPointInTimeReadTimestamp(opCtx).value_or(
opCtx->recoveryUnit()->getCatalogConflictingTimestamp());
if (minVisibleTimestamp && !readTimestamp.isNull() && readTimestamp < *minVisibleTimestamp) {
throwWriteConflictException(
"Unable to read from a snapshot due to pending catalog changes.");
}
int64_t removed = 0;
Status status = removeKeys(opCtx, keys, options, &removed);

View File

@ -192,8 +192,9 @@ void removeIndexBuildEntryAfterCommitOrAbort(OperationContext* opCtx,
}
if (replCoord->getSettings().shouldRecoverFromOplogAsStandalone()) {
// TODO SERVER-60753: Remove this mixed-mode write.
opCtx->recoveryUnit()->allowUntimestampedWrite();
// Writes to the 'config.system.indexBuilds' collection are replicated and the index entry
// will be removed when the delete oplog entry is replayed at a later time.
return;
}
auto status = indexbuildentryhelpers::removeIndexBuildEntry(
@ -2702,7 +2703,11 @@ IndexBuildsCoordinator::CommitResult IndexBuildsCoordinator::_insertKeysFromSide
// TODO SERVER-67437 Once ReplIndexBuildState holds DatabaseName, use dbName directly for
// lock
DatabaseName dbName(boost::none, replState->dbName);
AutoGetDb autoDb(opCtx, dbName, MODE_IX);
// Skip the check for sharding's critical section check as it can only be acquired during a
// `movePrimary` or drop database operations. The only operation that would affect the index
// build is when the collection's data needs to get modified, but the only modification possible
// is to delete the entire collection, which will cause the index to be dropped.
Lock::DBLock dbLock(opCtx, dbName, MODE_IX);
// Unlock RSTL to avoid deadlocks with prepare conflicts and state transitions caused by waiting
// for a a strong collection lock. See SERVER-42621.

View File

@ -701,8 +701,10 @@ void OpObserverImpl::onInserts(OperationContext* opCtx,
// DOES need to be -- that will cause correctness issues). Additionally, if the user tried
// to insert measurements with dates outside the standard range, chances are they will do so
// again, and we will have only set the flag a little early.
invariant(opCtx->lockState()->isCollectionLockedForMode(nss, MODE_IX));
auto bucketsColl =
CollectionCatalog::get(opCtx)->lookupCollectionByNamespaceForRead(opCtx, nss);
tassert(6905201, "Could not find collection for write", bucketsColl);
auto timeSeriesOptions = bucketsColl->getTimeseriesOptions();
if (timeSeriesOptions.has_value()) {
if (auto currentSetting = bucketsColl->getRequiresTimeseriesExtendedRangeSupport();

View File

@ -123,6 +123,7 @@ env.Library(
'accumulator_rank.cpp',
'accumulator_std_dev.cpp',
'accumulator_sum.cpp',
'map_reduce_options.idl',
'window_function/window_bounds.cpp',
'window_function/window_function_covariance.cpp',
'window_function/window_function_count.cpp',
@ -142,6 +143,7 @@ env.Library(
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/exec/sort_executor',
'$BUILD_DIR/mongo/db/index/key_generator',
'$BUILD_DIR/mongo/idl/idl_parser',
],
)

View File

@ -32,6 +32,7 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/pipeline/accumulator_js_reduce.h"
#include "mongo/db/pipeline/make_js_function.h"
#include "mongo/db/pipeline/map_reduce_options_gen.h"
namespace mongo {
@ -119,6 +120,10 @@ void AccumulatorInternalJsReduce::processInternal(const Value& input, bool mergi
Value AccumulatorInternalJsReduce::getValue(bool toBeMerged) {
if (_values.size() < 1) {
return Value{};
} else if (mrSingleReduceOptimizationEnabled && _values.size() == 1) {
// This optimization existed in the old Pre-4.4 MapReduce implementation. If the flag is
// set, then we should replicate the optimization. See SERVER-68766 for more details.
return _values[0];
}
const auto keySize = _key.getApproximateSize();

View File

@ -38,6 +38,7 @@
#include "mongo/db/pipeline/process_interface/standalone_process_interface.h"
#include "mongo/db/service_context_d_test_fixture.h"
#include "mongo/dbtests/dbtests.h"
#include "mongo/idl/server_parameter_test_util.h"
#include "mongo/scripting/engine.h"
namespace mongo {
@ -197,6 +198,38 @@ TEST_F(MapReduceFixture, InternalJsReduceFailsWhenEvalContainsInvalidJavascript)
}
}
TEST_F(
MapReduceFixture,
InternalJsReduceFailsDependentOnDocumentCountWhenEvalIsInvalidJavascriptWithSingleReduceOpt) {
RAIIServerParameterControllerForTest flag("mrEnableSingleReduceOptimization", true);
std::string eval("INVALID_JAVASCRIPT");
// Multiple source documents should evaluate the passed in function and return an error with
// invalid javascript.
{
auto accum = AccumulatorInternalJsReduce::create(getExpCtx(), "INVALID_JAVASCRIPT");
auto input = Value(DOC("k" << Value(1) << "v" << Value(2)));
accum->process(input, false);
accum->process(input, false);
ASSERT_THROWS_CODE(accum->getValue(false), DBException, ErrorCodes::JSInterpreterFailure);
}
// Single source document. With the reduce optimization, we simply return this document rather
// than executing the JS engine at all, so no error is thrown.
{
auto accum = AccumulatorInternalJsReduce::create(getExpCtx(), "INVALID_JAVASCRIPT");
auto input = Value(DOC("k" << Value(1) << "v" << Value(2)));
auto expectedResult = Value(2);
accum->process(input, false);
Value result = accum->getValue(false);
ASSERT_VALUE_EQ(expectedResult, result);
ASSERT_EQUALS(expectedResult.getType(), result.getType());
}
}
TEST_F(MapReduceFixture, InternalJsReduceFailsIfArgumentNotDocument) {
auto argument = Value(2);
assertProcessFailsWithCode<AccumulatorInternalJsReduce>(

View File

@ -29,6 +29,8 @@
#include "mongo/db/pipeline/change_stream_rewrite_helpers.h"
#include <boost/algorithm/string/replace.hpp>
#include "mongo/db/matcher/expression_always_boolean.h"
#include "mongo/db/matcher/expression_expr.h"
#include "mongo/db/pipeline/document_source_change_stream.h"
@ -888,9 +890,12 @@ std::unique_ptr<MatchExpression> matchRewriteGenericNamespace(
}();
// Convert the MatchExpression $regex into a $regexMatch on the corresponding field.
// Backslashes must be escaped to ensure they retain their special behavior.
const auto regex =
boost::replace_all_copy(std::string(nsElem.regex()), R"(\)", R"(\\)");
const std::string exprRegexMatch = str::stream()
<< "{$regexMatch: {input: " << exprDbOrCollName << ", regex: '"
<< nsElem.regex() << "', options: '" << nsElem.regexFlags() << "'}}";
<< "{$regexMatch: {input: " << exprDbOrCollName << ", regex: '" << regex
<< "', options: '" << nsElem.regexFlags() << "'}}";
// Finally, wrap the regex in a $let which defines the '$$oplogField' variable.
const std::string exprRewrittenPredicate = str::stream()

View File

@ -656,6 +656,7 @@ DocumentSourceGraphLookUp::DocumentSourceGraphLookUp(
_variablesParseState(expCtx->variablesParseState.copyWith(_variables.useIdGenerator())) {
const auto& resolvedNamespace = pExpCtx->getResolvedNamespace(_from);
_fromExpCtx = pExpCtx->copyForSubPipeline(resolvedNamespace.ns, resolvedNamespace.uuid);
_fromExpCtx->inLookup = true;
// We append an additional BSONObj to '_fromPipeline' as a placeholder for the $match stage
// we'll eventually construct from the input document.

View File

@ -487,6 +487,10 @@ intrusive_ptr<DocumentSourceSort> DocumentSourceSort::parseBoundedSort(
BSONElement key = args["sortKey"];
uassert(6369904, "$_internalBoundedSort sortKey must be an object", key.type() == Object);
// Empty sort pattern is not allowed for the bounded sort.
uassert(6900501,
"$_internalBoundedSort stage must have at least one sort key",
!key.embeddedObject().isEmpty());
SortPattern pat{key.embeddedObject(), expCtx};
{

View File

@ -436,7 +436,7 @@ public:
// Tracks the depth of nested aggregation sub-pipelines. Used to enforce depth limits.
long long subPipelineDepth = 0;
// True if this 'ExpressionContext' object is for the inner side of a $lookup.
// True if this 'ExpressionContext' object is for the inner side of a $lookup or $graphLookup.
bool inLookup = false;
// If set, this will disallow use of features introduced in versions above the provided version.

View File

@ -24,15 +24,19 @@
# delete this exception statement from your version. If you delete this
# exception statement from all source files in the program, then also delete
# it in the license file.
#
global:
cpp_namespace: "mongo"
imports:
- "mongo/idl/basic_types.idl"
feature_flags:
featureFlagOIDCSpike:
description: "Feature flag to guard OIDC during spike implementation"
cpp_varname: gFeatureFlagOIDCSpike
server_parameters:
mrEnableSingleReduceOptimization:
description: >
In version 4.2 and before, MongoDB MapReduce will not call the reduce function
for a key that has only a single value. In version 4.4 and later, the reduce
function is still called in order to validate the JavaScript reduce function
even when there is only one value. This setting will re-enable the old optimization.
set_at: startup
cpp_vartype: bool
cpp_varname: mrSingleReduceOptimizationEnabled
default: false

View File

@ -50,11 +50,8 @@ public:
PerFunctionMemoryTracker() = delete;
void update(long long diff) {
tassert(5578603,
str::stream() << "Underflow on memory tracking, attempting to add " << diff
<< " but only " << _currentMemoryBytes << " available",
diff >= 0 || _currentMemoryBytes >= std::abs(diff));
set(_currentMemoryBytes + diff);
// TODO SERVER-61281: Check for memory underflow.
set(std::max(_currentMemoryBytes + diff, 0ll));
}
void set(long long total) {
@ -145,11 +142,8 @@ public:
* Updates total memory usage.
*/
void update(long long diff) {
tassert(5578602,
str::stream() << "Underflow on memory tracking, attempting to add " << diff
<< " but only " << _memoryUsageBytes << " available",
diff >= 0 || (int)_memoryUsageBytes >= -1 * diff);
set(_memoryUsageBytes + diff);
// TODO SERVER-61281: Check for memory underflow.
set(std::max(_memoryUsageBytes + diff, 0ll));
}
auto currentMemoryBytes() const {

View File

@ -99,9 +99,8 @@ TEST_F(MemoryUsageTrackerTest, UpdateUsageUpdatesGlobal) {
ASSERT_EQ(_tracker.maxMemoryBytes(), 150LL);
}
DEATH_TEST_F(MemoryUsageTrackerTest,
UpdateFunctionUsageToNegativeIsDisallowed,
"Underflow on memory tracking") {
// TODO SERVER-61281: Switch to 'DEATH_TEST_F' checking the underflow case.
TEST_F(MemoryUsageTrackerTest, UpdateFunctionUsageToNegativeIsDisallowed) {
_funcTracker.set(50LL);
ASSERT_EQ(_funcTracker.currentMemoryBytes(), 50LL);
ASSERT_EQ(_funcTracker.maxMemoryBytes(), 50LL);
@ -109,16 +108,19 @@ DEATH_TEST_F(MemoryUsageTrackerTest,
ASSERT_EQ(_tracker.maxMemoryBytes(), 50LL);
_funcTracker.update(-100);
ASSERT_EQ(_tracker.currentMemoryBytes(), 0LL);
ASSERT_EQ(_tracker.maxMemoryBytes(), 50LL);
}
DEATH_TEST_F(MemoryUsageTrackerTest,
UpdateMemUsageToNegativeIsDisallowed,
"Underflow on memory tracking") {
// TODO SERVER-61281: Switch to 'DEATH_TEST_F' checking the underflow case.
TEST_F(MemoryUsageTrackerTest, UpdateMemUsageToNegativeIsDisallowed) {
_tracker.set(50LL);
ASSERT_EQ(_tracker.currentMemoryBytes(), 50LL);
ASSERT_EQ(_tracker.maxMemoryBytes(), 50LL);
_tracker.update(-100);
ASSERT_EQ(_tracker.currentMemoryBytes(), 0LL);
ASSERT_EQ(_tracker.maxMemoryBytes(), 50LL);
}
} // namespace

View File

@ -31,6 +31,8 @@
#include "mongo/db/pipeline/document_source_mock.h"
#include "mongo/db/pipeline/sharded_agg_helpers.h"
#include "mongo/db/s/config/initial_split_policy.h"
#include "mongo/idl/server_parameter_test_util.h"
#include "mongo/logv2/log.h"
#include "mongo/s/query/sharded_agg_test_fixture.h"
#include "mongo/unittest/unittest.h"
@ -45,7 +47,6 @@ const ShardId primaryShardId = ShardId("0");
TEST_F(ReshardingSplitPolicyTest, ShardKeyWithNonDottedFieldAndIdIsNotProjectedSucceeds) {
auto shardKeyPattern = ShardKeyPattern(BSON("a" << 1));
auto pipeline =
Pipeline::parse(ReshardingSplitPolicy::createRawPipeline(
shardKeyPattern, 2 /* samplingRatio */, 1 /* numSplitPoints */),
@ -53,7 +54,6 @@ TEST_F(ReshardingSplitPolicyTest, ShardKeyWithNonDottedFieldAndIdIsNotProjectedS
auto mockSource =
DocumentSourceMock::createForTest({"{_id: 10, a: 15}", "{_id: 3, a: 5}"}, expCtx());
pipeline->addInitialSource(mockSource.get());
// We sample all of the documents since numSplitPoints(1) * samplingRatio (2) = 2 and the
// document source has 2 chunks. So we can assert on the returned values.
auto next = pipeline->getNext();
@ -90,7 +90,6 @@ TEST_F(ReshardingSplitPolicyTest, ShardKeyWithIdFieldIsProjectedSucceeds) {
TEST_F(ReshardingSplitPolicyTest, CompoundShardKeyWithNonDottedHashedFieldSucceeds) {
auto shardKeyPattern = ShardKeyPattern(BSON("a" << 1 << "b"
<< "hashed"));
auto pipeline =
Pipeline::parse(ReshardingSplitPolicy::createRawPipeline(
shardKeyPattern, 2 /* samplingRatio */, 1 /* numSplitPoints */),
@ -98,7 +97,6 @@ TEST_F(ReshardingSplitPolicyTest, CompoundShardKeyWithNonDottedHashedFieldSuccee
auto mockSource = DocumentSourceMock::createForTest(
{"{x: 1, b: 16, a: 15}", "{x: 2, b: 123, a: 5}"}, expCtx());
pipeline->addInitialSource(mockSource.get());
// We sample all of the documents since numSplitPoints(1) * samplingRatio (2) = 2 and the
// document source has 2 chunks. So we can assert on the returned values.
auto next = pipeline->getNext();
@ -126,9 +124,9 @@ TEST_F(ReshardingSplitPolicyTest, CompoundShardKeyWithDottedFieldSucceeds) {
// We sample all of the documents since numSplitPoints(1) * samplingRatio (2) = 2 and the
// document source has 2 chunks. So we can assert on the returned values.
auto next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("a" << BSON("b" << 10) << "c" << 5));
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("a.b" << 10 << "c" << 5));
next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("a" << BSON("b" << 20) << "c" << 1));
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("a.b" << 20 << "c" << 1));
ASSERT(!pipeline->getNext());
}
@ -148,10 +146,10 @@ TEST_F(ReshardingSplitPolicyTest, CompoundShardKeyWithDottedHashedFieldSucceeds)
// document source has 2 chunks. So we can assert on the returned values.
auto next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(),
BSON("a" << BSON("b" << 10 << "c" << -6548868637522515075LL) << "c" << 5));
BSON("a.b" << 10 << "c" << 5 << "a.c" << -6548868637522515075LL));
next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(),
BSON("a" << BSON("b" << 20 << "c" << 2598032665634823220LL) << "c" << 1));
BSON("a.b" << 20 << "c" << 1 << "a.c" << 2598032665634823220LL));
ASSERT(!pipeline->getNext());
}
@ -198,5 +196,78 @@ TEST_F(ReshardingSplitPolicyTest, SamplingSuceeds) {
}
}
TEST_F(ReshardingSplitPolicyTest, ShardKeyWithDottedPathAndIdIsNotProjectedSucceeds) {
auto shardKeyPattern = ShardKeyPattern(BSON("b" << 1));
auto pipeline =
Pipeline::parse(ReshardingSplitPolicy::createRawPipeline(
shardKeyPattern, 2 /* samplingRatio */, 1 /* numSplitPoints */),
expCtx());
auto mockSource = DocumentSourceMock::createForTest(
{"{_id: {a: 15}, b: 10}", "{_id: {a: 5}, b:1}"}, expCtx());
pipeline->addInitialSource(mockSource.get());
auto next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("b" << 1));
next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("b" << 10));
ASSERT(!pipeline->getNext());
}
TEST_F(ReshardingSplitPolicyTest, CompoundShardKeyWithDottedPathAndIdIsProjectedSucceeds) {
auto shardKeyPattern = ShardKeyPattern(BSON("_id.a" << 1 << "c" << 1));
auto pipeline =
Pipeline::parse(ReshardingSplitPolicy::createRawPipeline(
shardKeyPattern, 2 /* samplingRatio */, 1 /* numSplitPoints */),
expCtx());
auto mockSource = DocumentSourceMock::createForTest(
{"{_id: {a: 15}, c: 10}", "{_id: {a: 5}, c: 1}"}, expCtx());
pipeline->addInitialSource(mockSource.get());
auto next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("_id.a" << 5 << "c" << 1));
next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(), BSON("_id.a" << 15 << "c" << 10));
ASSERT(!pipeline->getNext());
}
TEST_F(ReshardingSplitPolicyTest, CompoundShardKeyWithDottedHashedPathSucceeds) {
auto shardKeyPattern = ShardKeyPattern(BSON("_id.a" << 1 << "b" << 1 << "_id.b"
<< "hashed"));
auto pipeline =
Pipeline::parse(ReshardingSplitPolicy::createRawPipeline(
shardKeyPattern, 2 /* samplingRatio */, 1 /* numSplitPoints */),
expCtx());
auto mockSource = DocumentSourceMock::createForTest(
{"{x: 10, _id: {a: 20, b: 16}, b: 1}", "{x: 3, _id: {a: 10, b: 123}, b: 5}"}, expCtx());
pipeline->addInitialSource(mockSource.get());
auto next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(),
BSON("_id.a" << 10 << "b" << 5 << "_id.b" << -6548868637522515075LL));
next = pipeline->getNext();
ASSERT_BSONOBJ_EQ(next.value().toBson(),
BSON("_id.a" << 20 << "b" << 1 << "_id.b" << 2598032665634823220LL));
ASSERT(!pipeline->getNext());
}
TEST_F(ReshardingSplitPolicyTest, ReshardingSucceedsWithLimitedMemoryForSortOperation) {
RAIIServerParameterControllerForTest sortMaxMemory{
"internalQueryMaxBlockingSortMemoryUsageBytes", 100};
auto shardKeyPattern = ShardKeyPattern(BSON("a" << 1));
const NamespaceString ns("reshard", "foo");
auto pipelineDocSource =
ReshardingSplitPolicy::makePipelineDocumentSource_forTest(operationContext(),
kTestAggregateNss,
shardKeyPattern,
3 /*numInitialChunks*/,
2 /*samplesPerChunk*/);
auto mockSource = DocumentSourceMock::createForTest(
{"{_id: 20, a: 4}", "{_id: 30, a: 3}", "{_id: 40, a: 2}", "{_id: 50, a: 1}"}, expCtx());
pipelineDocSource->getPipeline_forTest()->addInitialSource(mockSource.get());
auto next = pipelineDocSource->getNext();
ASSERT_BSONOBJ_EQ(BSON("a" << 2), next.value());
next = pipelineDocSource->getNext();
ASSERT_BSONOBJ_EQ(BSON("a" << 4), next.value());
ASSERT(!pipelineDocSource->getNext());
}
} // namespace
} // namespace mongo

View File

@ -257,15 +257,11 @@ void QueryPlannerIXSelect::getFields(const MatchExpression* node,
// Leaf nodes with a path and some array operators.
if (Indexability::nodeCanUseIndexOnOwnField(node)) {
out->insert(prefix + node->path().toString());
} else if (Indexability::arrayUsesIndexOnChildren(node)) {
} else if (Indexability::arrayUsesIndexOnChildren(node) && !node->path().empty()) {
// If the array uses an index on its children, it's something like
// {foo : {$elemMatch: {bar: 1}}}, in which case the predicate is really over foo.bar.
//
// When we have {foo: {$all: [{$elemMatch: {a: 1}}], the path of the embedded elemMatch
// is empty. We don't want to append a dot in that case as the field would be foo..a.
if (!node->path().empty()) {
prefix += node->path().toString() + ".";
}
// Note we skip empty path components since they are not allowed in index key patterns.
prefix += node->path().toString() + ".";
for (size_t i = 0; i < node->numChildren(); ++i) {
getFields(node->getChild(i), prefix, out);
@ -783,7 +779,8 @@ void QueryPlannerIXSelect::_rateIndices(MatchExpression* node,
childRt->path = rt->path;
node->getChild(0)->setTag(childRt);
}
} else if (Indexability::arrayUsesIndexOnChildren(node)) {
} else if (Indexability::arrayUsesIndexOnChildren(node) && !node->path().empty()) {
// Note we skip empty path components since they are not allowed in index key patterns.
const auto newPath = prefix + node->path().toString();
ElemMatchContext newContext;
// Note this StringData is unowned and references the string declared on the stack here.
@ -794,12 +791,7 @@ void QueryPlannerIXSelect::_rateIndices(MatchExpression* node,
// If the array uses an index on its children, it's something like
// {foo: {$elemMatch: {bar: 1}}}, in which case the predicate is really over foo.bar.
//
// When we have {foo: {$all: [{$elemMatch: {a: 1}}], the path of the embedded elemMatch
// is empty. We don't want to append a dot in that case as the field would be foo..a.
if (!node->path().empty()) {
prefix += node->path().toString() + ".";
}
prefix += node->path().toString() + ".";
for (size_t i = 0; i < node->numChildren(); ++i) {
_rateIndices(node->getChild(i), prefix, indices, collator, newContext);
}

View File

@ -2188,44 +2188,104 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> SlotBasedStageBuilder
namespace {
template <typename F>
struct FieldPathVisitor : public SelectiveConstExpressionVisitorBase {
struct FieldPathAndCondPreVisitor : public SelectiveConstExpressionVisitorBase {
// To avoid overloaded-virtual warnings.
using SelectiveConstExpressionVisitorBase::visit;
FieldPathVisitor(const F& fn) : _fn(fn) {}
FieldPathAndCondPreVisitor(const F& fn, int32_t& nestedCondLevel)
: _fn(fn), _nestedCondLevel(nestedCondLevel) {}
void visit(const ExpressionFieldPath* expr) final {
_fn(expr);
_fn(expr, _nestedCondLevel);
}
void visit(const ExpressionCond* expr) final {
++_nestedCondLevel;
}
void visit(const ExpressionSwitch* expr) final {
++_nestedCondLevel;
}
void visit(const ExpressionIfNull* expr) final {
++_nestedCondLevel;
}
void visit(const ExpressionAnd* expr) final {
++_nestedCondLevel;
}
void visit(const ExpressionOr* expr) final {
++_nestedCondLevel;
}
F _fn;
// Tracks the number of conditional expressions like $cond or $ifNull that are above us in the
// tree.
int32_t& _nestedCondLevel;
};
struct CondPostVisitor : public SelectiveConstExpressionVisitorBase {
// To avoid overloaded-virtual warnings.
using SelectiveConstExpressionVisitorBase::visit;
CondPostVisitor(int32_t& nestedCondLevel) : _nestedCondLevel(nestedCondLevel) {}
void visit(const ExpressionCond* expr) final {
--_nestedCondLevel;
}
void visit(const ExpressionSwitch* expr) final {
--_nestedCondLevel;
}
void visit(const ExpressionIfNull* expr) final {
--_nestedCondLevel;
}
void visit(const ExpressionAnd* expr) final {
--_nestedCondLevel;
}
void visit(const ExpressionOr* expr) final {
--_nestedCondLevel;
}
int32_t& _nestedCondLevel;
};
/**
* Walks through the 'expr' expression tree and whenever finds an 'ExpressionFieldPath', calls
* the 'fn' function. Type requirement for 'fn' is it must have a const 'ExpressionFieldPath'
* pointer parameter.
* pointer parameter and 'nestedCondLevel' parameter.
*/
template <typename F>
void walkAndActOnFieldPaths(Expression* expr, const F& fn) {
FieldPathVisitor<F> visitor(fn);
ExpressionWalker walker(&visitor, nullptr /*inVisitor*/, nullptr /*postVisitor*/);
int32_t nestedCondLevel = 0;
FieldPathAndCondPreVisitor<F> preVisitor(fn, nestedCondLevel);
CondPostVisitor postVisitor(nestedCondLevel);
ExpressionWalker walker(&preVisitor, nullptr /*inVisitor*/, &postVisitor);
expression_walker::walk(expr, &walker);
}
/**
* Checks whether all field paths in 'idExpr' and all accumulator expressions are top-level ones.
*/
bool checkAllFieldPathsAreTopLevel(const boost::intrusive_ptr<Expression>& idExpr,
const std::vector<AccumulationStatement>& accStmts) {
auto areAllTopLevelFields = true;
bool areAllFieldPathsOptimizable(const boost::intrusive_ptr<Expression>& idExpr,
const std::vector<AccumulationStatement>& accStmts) {
auto areFieldPathsOptimizable = true;
auto checkFieldPath = [&](const ExpressionFieldPath* fieldExpr) {
auto checkFieldPath = [&](const ExpressionFieldPath* fieldExpr, int32_t nestedCondLevel) {
// We optimize neither a field path for the top-level document itself (getPathLength() == 1)
// nor a field path that refers to a variable. We can optimize only top-level fields
// (getPathLength() == 2).
if (fieldExpr->getFieldPath().getPathLength() != 2 || fieldExpr->isVariableReference()) {
areAllTopLevelFields = false;
//
// The 'nestedCondLevel' being > 0 means that a field path is refered to below conditional
// expressions at the parent $group node, when we cannot optimize field path access and
// therefore, cannot avoid materialization.
if (nestedCondLevel > 0 || fieldExpr->getFieldPath().getPathLength() != 2 ||
fieldExpr->isVariableReference()) {
areFieldPathsOptimizable = false;
return;
}
};
@ -2238,7 +2298,7 @@ bool checkAllFieldPathsAreTopLevel(const boost::intrusive_ptr<Expression>& idExp
walkAndActOnFieldPaths(accStmt.expr.argument.get(), checkFieldPath);
}
return areAllTopLevelFields;
return areFieldPathsOptimizable;
}
/**
@ -2264,7 +2324,7 @@ EvalStage optimizeFieldPaths(StageBuilderState& state,
auto searchInChildOutputs = !optionalRootSlot.has_value();
auto retEvalStage = std::move(childEvalStage);
walkAndActOnFieldPaths(expr.get(), [&](const ExpressionFieldPath* fieldExpr) {
walkAndActOnFieldPaths(expr.get(), [&](const ExpressionFieldPath* fieldExpr, int32_t) {
// We optimize neither a field path for the top-level document itself nor a field path that
// refers to a variable instead of calling getField().
if (fieldExpr->getFieldPath().getPathLength() == 1 || fieldExpr->isVariableReference()) {
@ -2558,10 +2618,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> SlotBasedStageBuilder
const auto& accStmts = groupNode->accumulators;
auto childStageType = childNode->getType();
auto areAllTopLevelFields = checkAllFieldPathsAreTopLevel(idExpr, accStmts);
auto childReqs = reqs.copy();
if (childStageType == StageType::STAGE_GROUP && areAllTopLevelFields) {
if (childStageType == StageType::STAGE_GROUP && areAllFieldPathsOptimizable(idExpr, accStmts)) {
// Does not ask the GROUP child for the result slot to avoid unnecessary materialization if
// all fields are top-level fields. See the end of this function. For example, GROUP - GROUP
// - COLLSCAN case.

View File

@ -64,9 +64,11 @@ bool isQuerySbeCompatible(const CollectionPtr* collection,
const bool doesNotHaveElemMatchProject = !cq->getProj() || !cq->getProj()->containsElemMatch();
const bool isNotInnerSideOfLookup = !(expCtx && expCtx->inLookup);
return allExpressionsSupported && isNotCount && doesNotContainMetadataRequirements &&
isQueryNotAgainstTimeseriesCollection && isQueryNotAgainstClusteredCollection &&
doesNotSortOnMetaOrPathWithNumericComponents && isNotOplog && doesNotRequireMatchDetails &&
doesNotHaveElemMatchProject && isNotChangeCollection;
doesNotHaveElemMatchProject && isNotChangeCollection && isNotInnerSideOfLookup;
}
} // namespace mongo::sbe

View File

@ -1397,53 +1397,63 @@ void InitialSyncer::_lastOplogEntryFetcherCallbackForStopTimestamp(
std::shared_ptr<OnCompletionGuard> onCompletionGuard) {
OpTimeAndWallTime resultOpTimeAndWallTime = {OpTime(), Date_t()};
{
stdx::lock_guard<Latch> lock(_mutex);
auto status = _checkForShutdownAndConvertStatus_inlock(
result.getStatus(), "error fetching last oplog entry for stop timestamp");
if (_shouldRetryError(lock, status)) {
auto scheduleStatus =
(*_attemptExec)
->scheduleWork([this,
onCompletionGuard](executor::TaskExecutor::CallbackArgs args) {
// It is not valid to schedule the retry from within this callback,
// hence we schedule a lambda to schedule the retry.
stdx::lock_guard<Latch> lock(_mutex);
// Since the stopTimestamp is retrieved after we have done all the work of
// retrieving collection data, we handle retries within this class by
// retrying for 'initialSyncTransientErrorRetryPeriodSeconds' (default 24
// hours). This is the same retry strategy used when retrieving collection
// data, and avoids retrieving all the data and then throwing it away due to
// a transient network outage.
auto status = _scheduleLastOplogEntryFetcher_inlock(
[=](const StatusWith<mongo::Fetcher::QueryResponse>& status,
mongo::Fetcher::NextAction*,
mongo::BSONObjBuilder*) {
_lastOplogEntryFetcherCallbackForStopTimestamp(status,
onCompletionGuard);
},
kInitialSyncerHandlesRetries);
if (!status.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lock, status);
}
});
if (scheduleStatus.isOK())
{
stdx::lock_guard<Latch> lock(_mutex);
auto status = _checkForShutdownAndConvertStatus_inlock(
result.getStatus(), "error fetching last oplog entry for stop timestamp");
if (_shouldRetryError(lock, status)) {
auto scheduleStatus =
(*_attemptExec)
->scheduleWork(
[this, onCompletionGuard](executor::TaskExecutor::CallbackArgs args) {
// It is not valid to schedule the retry from within this callback,
// hence we schedule a lambda to schedule the retry.
stdx::lock_guard<Latch> lock(_mutex);
// Since the stopTimestamp is retrieved after we have done all the
// work of retrieving collection data, we handle retries within this
// class by retrying for
// 'initialSyncTransientErrorRetryPeriodSeconds' (default 24 hours).
// This is the same retry strategy used when retrieving collection
// data, and avoids retrieving all the data and then throwing it
// away due to a transient network outage.
auto status = _scheduleLastOplogEntryFetcher_inlock(
[=](const StatusWith<mongo::Fetcher::QueryResponse>& status,
mongo::Fetcher::NextAction*,
mongo::BSONObjBuilder*) {
_lastOplogEntryFetcherCallbackForStopTimestamp(
status, onCompletionGuard);
},
kInitialSyncerHandlesRetries);
if (!status.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(
lock, status);
}
});
if (scheduleStatus.isOK())
return;
// If scheduling failed, we're shutting down and cannot retry.
// So just continue with the original failed status.
}
if (!status.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lock, status);
return;
// If scheduling failed, we're shutting down and cannot retry.
// So just continue with the original failed status.
}
if (!status.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lock, status);
return;
}
auto&& optimeStatus = parseOpTimeAndWallTime(result);
if (!optimeStatus.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lock,
optimeStatus.getStatus());
return;
}
resultOpTimeAndWallTime = optimeStatus.getValue();
}
auto&& optimeStatus = parseOpTimeAndWallTime(result);
if (!optimeStatus.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lock,
optimeStatus.getStatus());
return;
}
resultOpTimeAndWallTime = optimeStatus.getValue();
// Release the _mutex to write to disk.
auto opCtx = makeOpCtx();
_replicationProcess->getConsistencyMarkers()->setMinValid(
opCtx.get(), resultOpTimeAndWallTime.opTime, true);
stdx::lock_guard<Latch> lock(_mutex);
_initialSyncState->stopTimestamp = resultOpTimeAndWallTime.opTime.getTimestamp();
// If the beginFetchingTimestamp is different from the stopTimestamp, it indicates that

View File

@ -110,12 +110,6 @@ ScopedCollectionFilter CollectionShardingRuntime::getOwnershipFilter(
// No operations should be calling getOwnershipFilter without a shard version
invariant(optReceivedShardVersion,
"getOwnershipFilter called by operation that doesn't specify shard version");
uassert(6279300,
"Request was received without an attached index version. This could indicate that "
"this request was sent by a router of an older version",
!feature_flags::gGlobalIndexesShardingCatalog.isEnabled(
serverGlobalParams.featureCompatibility) ||
optReceivedShardVersion->indexVersion());
}
auto metadata =
@ -148,12 +142,6 @@ ScopedCollectionDescription CollectionShardingRuntime::getCollectionDescription(
auto optMetadata = _getCurrentMetadataIfKnown(boost::none);
const auto receivedShardVersion{oss.getShardVersion(_nss)};
uassert(6279301,
"Request was received without an attached index version. This could indicate that this "
"request was sent by a router of an older version",
!feature_flags::gGlobalIndexesShardingCatalog.isEnabled(
serverGlobalParams.featureCompatibility) ||
!receivedShardVersion || receivedShardVersion->indexVersion());
uassert(
StaleConfigInfo(_nss,
receivedShardVersion ? (ChunkVersion)*receivedShardVersion
@ -368,13 +356,6 @@ CollectionShardingRuntime::_getMetadataWithVersionCheckAt(
// Assume that the received shard version was IGNORED if the current operation wasn't versioned
const auto& receivedShardVersion =
optReceivedShardVersion ? (ChunkVersion)*optReceivedShardVersion : ChunkVersion::IGNORED();
uassert(6279302,
"Request was received without an attached index version. This could indicate that this "
"request was sent by a router of an older version",
!feature_flags::gGlobalIndexesShardingCatalog.isEnabled(
serverGlobalParams.featureCompatibility) ||
receivedShardVersion == ChunkVersion::IGNORED() ||
optReceivedShardVersion->indexVersion());
auto csrLock = CSRLock::lockShared(opCtx, this);

View File

@ -33,12 +33,14 @@
#include "mongo/db/bson/dotted_path_support.h"
#include "mongo/db/catalog/collection_catalog.h"
#include "mongo/db/curop.h"
#include "mongo/db/pipeline/document_source.h"
#include "mongo/db/pipeline/lite_parsed_pipeline.h"
#include "mongo/db/pipeline/process_interface/shardsvr_process_interface.h"
#include "mongo/db/pipeline/sharded_agg_helpers.h"
#include "mongo/db/s/balancer/balancer_policy.h"
#include "mongo/db/s/sharding_state.h"
#include "mongo/db/vector_clock.h"
#include "mongo/logv2/log.h"
#include "mongo/s/balancer_configuration.h"
#include "mongo/s/catalog/type_shard.h"
#include "mongo/s/grid.h"
@ -52,6 +54,7 @@ namespace {
using ChunkDistributionMap = stdx::unordered_map<ShardId, size_t>;
using ZoneShardMap = StringMap<std::vector<ShardId>>;
using boost::intrusive_ptr;
std::vector<ShardId> getAllShardIdsSorted(OperationContext* opCtx) {
// Many tests assume that chunks will be placed on shards
@ -636,34 +639,29 @@ std::vector<BSONObj> ReshardingSplitPolicy::createRawPipeline(const ShardKeyPatt
std::vector<BSONObj> res;
const auto& shardKeyFields = shardKey.getKeyPatternFields();
BSONObjBuilder projectValBuilder;
BSONObjBuilder sortValBuilder;
using Doc = Document;
using Arr = std::vector<Value>;
using V = Value;
Arr arrayToObjectBuilder;
for (auto&& fieldRef : shardKeyFields) {
// If the shard key includes a hashed field and current fieldRef is the hashed field.
if (shardKey.isHashedPattern() &&
fieldRef->dottedField().compare(shardKey.getHashedField().fieldNameStringData()) == 0) {
projectValBuilder.append(fieldRef->dottedField(),
BSON("$toHashedIndexKey"
<< "$" + fieldRef->dottedField()));
arrayToObjectBuilder.emplace_back(
Doc{{"k", V{fieldRef->dottedField()}},
{"v", Doc{{"$toHashedIndexKey", V{"$" + fieldRef->dottedField()}}}}});
} else {
projectValBuilder.append(
str::stream() << fieldRef->dottedField(),
BSON("$ifNull" << BSON_ARRAY("$" + fieldRef->dottedField() << BSONNULL)));
arrayToObjectBuilder.emplace_back(Doc{
{"k", V{fieldRef->dottedField()}},
{"v", Doc{{"$ifNull", V{Arr{V{"$" + fieldRef->dottedField()}, V{BSONNULL}}}}}}});
}
sortValBuilder.append(fieldRef->dottedField().toString(), 1);
}
// Do not project _id if it's not part of the shard key.
if (!shardKey.hasId()) {
projectValBuilder.append("_id", 0);
}
res.push_back(BSON("$sample" << BSON("size" << numSplitPoints * samplesPerChunk)));
res.push_back(BSON("$project" << projectValBuilder.obj()));
res.push_back(BSON("$sort" << sortValBuilder.obj()));
res.push_back(
Doc{{"$replaceWith", Doc{{"$arrayToObject", Arr{V{arrayToObjectBuilder}}}}}}.toBson());
return res;
}
@ -786,26 +784,34 @@ void ReshardingSplitPolicy::_appendSplitPointsFromSample(BSONObjSet* splitPoints
while (nextKey && nRemaining > 0) {
// if key is hashed, nextKey values are already hashed
auto result = splitPoints->insert(
dotted_path_support::extractElementsBasedOnTemplate(*nextKey, shardKey.toBSON())
.getOwned());
auto result = splitPoints->insert(nextKey->getOwned());
if (result.second) {
nRemaining--;
}
nextKey = _samples->getNext();
}
}
std::unique_ptr<ReshardingSplitPolicy::SampleDocumentSource>
ReshardingSplitPolicy::makePipelineDocumentSource_forTest(OperationContext* opCtx,
const NamespaceString& ns,
const ShardKeyPattern& shardKey,
int numInitialChunks,
int samplesPerChunk) {
MakePipelineOptions opts;
opts.attachCursorSource = false;
return _makePipelineDocumentSource(
opCtx, ns, shardKey, numInitialChunks, samplesPerChunk, std::move(opts));
}
std::unique_ptr<ReshardingSplitPolicy::SampleDocumentSource>
ReshardingSplitPolicy::_makePipelineDocumentSource(OperationContext* opCtx,
const NamespaceString& ns,
const ShardKeyPattern& shardKey,
int numInitialChunks,
int samplesPerChunk) {
int samplesPerChunk,
MakePipelineOptions opts) {
auto rawPipeline = createRawPipeline(shardKey, numInitialChunks - 1, samplesPerChunk);
StringMap<ExpressionContext::ResolvedNamespace> resolvedNamespaces;
resolvedNamespaces[ns.coll()] = {ns, std::vector<BSONObj>{}};
@ -819,7 +825,7 @@ ReshardingSplitPolicy::_makePipelineDocumentSource(OperationContext* opCtx,
boost::none, /* explain */
false, /* fromMongos */
false, /* needsMerge */
false, /* allowDiskUse */
true, /* allowDiskUse */
true, /* bypassDocumentValidation */
false, /* isMapReduceCommand */
ns,
@ -829,8 +835,10 @@ ReshardingSplitPolicy::_makePipelineDocumentSource(OperationContext* opCtx,
std::move(resolvedNamespaces),
boost::none); /* collUUID */
return std::make_unique<PipelineDocumentSource>(Pipeline::makePipeline(rawPipeline, expCtx, {}),
samplesPerChunk - 1);
expCtx->tempDir = storageGlobalParams.dbpath + "/tmp";
return std::make_unique<PipelineDocumentSource>(
Pipeline::makePipeline(rawPipeline, expCtx, opts), samplesPerChunk - 1);
}
ReshardingSplitPolicy::PipelineDocumentSource::PipelineDocumentSource(

View File

@ -40,7 +40,6 @@
#include "mongo/s/catalog/type_tags.h"
#include "mongo/s/shard_key_pattern.h"
#include "mongo/util/string_map.h"
namespace mongo {
struct SplitPolicyParams {
@ -291,6 +290,7 @@ public:
public:
virtual ~SampleDocumentSource(){};
virtual boost::optional<BSONObj> getNext() = 0;
virtual Pipeline* getPipeline_forTest() = 0;
};
// Provides documents from a real Pipeline
@ -299,6 +299,9 @@ public:
PipelineDocumentSource() = delete;
PipelineDocumentSource(SampleDocumentPipeline pipeline, int skip);
boost::optional<BSONObj> getNext() override;
Pipeline* getPipeline_forTest() override {
return _pipeline.get();
}
private:
SampleDocumentPipeline _pipeline;
@ -334,13 +337,21 @@ public:
static constexpr int kDefaultSamplesPerChunk = 10;
static std::unique_ptr<SampleDocumentSource> makePipelineDocumentSource_forTest(
OperationContext* opCtx,
const NamespaceString& ns,
const ShardKeyPattern& shardKey,
int numInitialChunks,
int samplesPerChunk);
private:
static std::unique_ptr<SampleDocumentSource> _makePipelineDocumentSource(
OperationContext* opCtx,
const NamespaceString& ns,
const ShardKeyPattern& shardKey,
int numInitialChunks,
int samplesPerChunk);
int samplesPerChunk,
MakePipelineOptions opts = {});
/**
* Returns a set of split points to ensure that chunk boundaries will align with the zone

View File

@ -31,6 +31,7 @@
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/initial_split_policy.h"
#include "mongo/db/vector_clock.h"
#include "mongo/logv2/log.h"
#include "mongo/s/catalog/type_shard.h"
#include "mongo/s/catalog/type_tags.h"
#include "mongo/unittest/unittest.h"
@ -1725,6 +1726,10 @@ public:
return next;
}
Pipeline* getPipeline_forTest() override {
return nullptr;
}
private:
std::list<BSONObj> _toReturn;
};
@ -1763,9 +1768,9 @@ TEST_F(ReshardingInitSplitTest, NoZones) {
shardRegistry()->reload(operationContext());
std::list<BSONObj> mockSamples;
mockSamples.push_back(BSON("x" << 10 << "y" << 10));
mockSamples.push_back(BSON("x" << 10 << "y" << 20));
mockSamples.push_back(BSON("x" << 10 << "y" << 30));
mockSamples.push_back(BSON("y" << 10));
mockSamples.push_back(BSON("y" << 20));
mockSamples.push_back(BSON("y" << 30));
auto mockSampleSource = std::make_unique<MockPipelineSource>(std::move(mockSamples));
@ -1800,9 +1805,9 @@ TEST_F(ReshardingInitSplitTest, HashedShardKey) {
shardRegistry()->reload(operationContext());
std::list<BSONObj> mockSamples;
mockSamples.push_back(BSON("x" << 10 << "y" << 7766103514953448109LL));
mockSamples.push_back(BSON("x" << 10 << "y" << -9117533237618642180LL));
mockSamples.push_back(BSON("x" << 10 << "y" << -1196399207910989725LL));
mockSamples.push_back(BSON("y" << 7766103514953448109LL));
mockSamples.push_back(BSON("y" << -9117533237618642180LL));
mockSamples.push_back(BSON("y" << -1196399207910989725LL));
auto mockSampleSource = std::make_unique<MockPipelineSource>(std::move(mockSamples));
@ -1865,9 +1870,9 @@ TEST_F(ReshardingInitSplitTest, ZonesCoversEntireDomainButInsufficient) {
shardRegistry()->reload(operationContext());
std::list<BSONObj> mockSamples;
mockSamples.push_back(BSON("x" << 10 << "y" << 10));
mockSamples.push_back(BSON("x" << 10 << "y" << 20));
mockSamples.push_back(BSON("x" << 10 << "y" << 30));
mockSamples.push_back(BSON("y" << 10));
mockSamples.push_back(BSON("y" << 20));
mockSamples.push_back(BSON("y" << 30));
auto mockSampleSource = std::make_unique<MockPipelineSource>(std::move(mockSamples));
@ -1905,9 +1910,9 @@ TEST_F(ReshardingInitSplitTest, SamplesCoincidingWithZones) {
shardRegistry()->reload(operationContext());
std::list<BSONObj> mockSamples;
mockSamples.push_back(BSON("x" << 10 << "y" << 10));
mockSamples.push_back(BSON("x" << 10 << "y" << 20));
mockSamples.push_back(BSON("x" << 10 << "y" << 30));
mockSamples.push_back(BSON("y" << 10));
mockSamples.push_back(BSON("y" << 20));
mockSamples.push_back(BSON("y" << 30));
auto mockSampleSource = std::make_unique<MockPipelineSource>(std::move(mockSamples));

View File

@ -229,8 +229,9 @@ GlobalIndexCumulativeMetrics* GlobalIndexMetrics::getGlobalIndexCumulativeMetric
}
Milliseconds GlobalIndexMetrics::getRecipientHighEstimateRemainingTimeMillis() const {
return Milliseconds{0};
boost::optional<Milliseconds> GlobalIndexMetrics::getRecipientHighEstimateRemainingTimeMillis()
const {
return boost::none;
}
} // namespace mongo

View File

@ -212,7 +212,6 @@ public:
bool unique,
ServiceContext* serviceContext);
Milliseconds getRecipientHighEstimateRemainingTimeMillis() const;
template <typename T>
static auto initializeFrom(const T& document, ServiceContext* serviceContext) {
static_assert(isStateDocument<T>);
@ -240,6 +239,9 @@ public:
_stateHolder.onStateTransition(before, after);
}
protected:
boost::optional<Milliseconds> getRecipientHighEstimateRemainingTimeMillis() const override;
private:
GlobalIndexCumulativeMetrics* getGlobalIndexCumulativeMetrics();
std::string createOperationDescription() const noexcept override;

View File

@ -167,12 +167,20 @@ CoordinatorCommitMonitor::queryRemainingOperationTimeForRecipients() const {
uassertStatusOKWithContext(status, errorContext);
const auto remainingTime = extractOperationRemainingTime(shardResponse.data);
// A recipient shard does not report the remaining operation time when there is no data
// to copy and no oplog entry to apply.
if (remainingTime && remainingTime.value() < minRemainingTime) {
// If any recipient omits the "remainingMillis" field of the response then
// we cannot conclude that it is safe to begin the critical section.
// It is possible that the recipient just had a failover and
// was not able to restore its metrics before it replied to the
// _shardsvrReshardingOperationTime command.
if (!remainingTime) {
maxRemainingTime = Milliseconds::max();
continue;
}
if (remainingTime.value() < minRemainingTime) {
minRemainingTime = remainingTime.value();
}
if (remainingTime && remainingTime.value() > maxRemainingTime) {
if (remainingTime.value() > maxRemainingTime) {
maxRemainingTime = remainingTime.value();
}
}
@ -206,11 +214,19 @@ ExecutorFuture<void> CoordinatorCommitMonitor::_makeFuture() const {
"Encountered an error while querying recipients, will retry shortly",
"error"_attr = status);
return RemainingOperationTimes{Milliseconds(0), Milliseconds::max()};
// On error we definitely cannot begin the critical section. Therefore,
// return Milliseconds::max for remainingTimes.max (remainingTimes.max is used
// for determining whether the critical section should begin).
return RemainingOperationTimes{Milliseconds(-1), Milliseconds::max()};
})
.then([this, anchor = shared_from_this()](RemainingOperationTimes remainingTimes) {
_metrics->setCoordinatorHighEstimateRemainingTimeMillis(remainingTimes.max);
_metrics->setCoordinatorLowEstimateRemainingTimeMillis(remainingTimes.min);
// If remainingTimes.max (or remainingTimes.min) is Milliseconds::max, then use -1 so
// that the scale of the y-axis is still useful when looking at FTDC metrics.
auto clampIfMax = [](Milliseconds t) {
return t != Milliseconds::max() ? t : Milliseconds(-1);
};
_metrics->setCoordinatorHighEstimateRemainingTimeMillis(clampIfMax(remainingTimes.max));
_metrics->setCoordinatorLowEstimateRemainingTimeMillis(clampIfMax(remainingTimes.min));
// Check if all recipient shards are within the commit threshold.
if (remainingTimes.max <= _threshold)

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