summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavi Vetriselvan <pavithra.vetriselvan@mongodb.com>2021-04-21 10:42:44 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-26 16:50:11 +0000
commit13bc7749febf4cdd860e28d7df72fd82b10ec1a5 (patch)
tree0c0b8f5c64fc38ca813218c4568e7add13d63fda
parentc13c5887dd1b01314145bc731efedb1db8a5642a (diff)
downloadmongo-13bc7749febf4cdd860e28d7df72fd82b10ec1a5.tar.gz
SERVER-55359 pre/post image ops after startFetchingDonorOpTime should be filtered out of oplog buffer
(cherry picked from commit 9457ca34a5e157698602e620042c6c8037023375)
-rw-r--r--buildscripts/resmokeconfig/suites/tenant_migration_kill_primary_jscore_passthrough.yml3
-rw-r--r--buildscripts/resmokeconfig/suites/tenant_migration_stepdown_jscore_passthrough.yml3
-rw-r--r--buildscripts/resmokeconfig/suites/tenant_migration_terminate_primary_jscore_passthrough.yml3
-rw-r--r--jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js17
-rw-r--r--jstests/replsets/tenant_migration_retryable_write_retry.js46
-rw-r--r--src/mongo/db/repl/tenant_migration_util.cpp70
6 files changed, 101 insertions, 41 deletions
diff --git a/buildscripts/resmokeconfig/suites/tenant_migration_kill_primary_jscore_passthrough.yml b/buildscripts/resmokeconfig/suites/tenant_migration_kill_primary_jscore_passthrough.yml
index 39e9f112e13..37072afb156 100644
--- a/buildscripts/resmokeconfig/suites/tenant_migration_kill_primary_jscore_passthrough.yml
+++ b/buildscripts/resmokeconfig/suites/tenant_migration_kill_primary_jscore_passthrough.yml
@@ -120,9 +120,6 @@ selector:
# Blacklists specific to this suite
#
- # TODO (SERVER-55359): Docs in tenant migration oplog buffer collection might not be ordered by
- # timestamp.
- - jstests/core/*find_and_modify*.js
- jstests/core/api_version_parameters.js
- jstests/core/benchrun_pipeline_updates.js
- jstests/core/bypass_doc_validation.js
diff --git a/buildscripts/resmokeconfig/suites/tenant_migration_stepdown_jscore_passthrough.yml b/buildscripts/resmokeconfig/suites/tenant_migration_stepdown_jscore_passthrough.yml
index 2cc25669001..a6c9a598184 100644
--- a/buildscripts/resmokeconfig/suites/tenant_migration_stepdown_jscore_passthrough.yml
+++ b/buildscripts/resmokeconfig/suites/tenant_migration_stepdown_jscore_passthrough.yml
@@ -120,9 +120,6 @@ selector:
# Blacklists specific to this suite
#
- # TODO (SERVER-55359): Docs in tenant migration oplog buffer collection might not be ordered by
- # timestamp.
- - jstests/core/*find_and_modify*.js
- jstests/core/api_version_parameters.js
- jstests/core/benchrun_pipeline_updates.js
- jstests/core/bypass_doc_validation.js
diff --git a/buildscripts/resmokeconfig/suites/tenant_migration_terminate_primary_jscore_passthrough.yml b/buildscripts/resmokeconfig/suites/tenant_migration_terminate_primary_jscore_passthrough.yml
index 668cb84c2db..08702a8cbbc 100644
--- a/buildscripts/resmokeconfig/suites/tenant_migration_terminate_primary_jscore_passthrough.yml
+++ b/buildscripts/resmokeconfig/suites/tenant_migration_terminate_primary_jscore_passthrough.yml
@@ -120,9 +120,6 @@ selector:
# Blacklists specific to this suite
#
- # TODO (SERVER-55359): Docs in tenant migration oplog buffer collection might not be ordered by
- # timestamp.
- - jstests/core/*find_and_modify*.js
- jstests/core/api_version_parameters.js
- jstests/core/benchrun_pipeline_updates.js
- jstests/core/bypass_doc_validation.js
diff --git a/jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js b/jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js
index 9d32c1b1f60..98ac4e63c62 100644
--- a/jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js
+++ b/jstests/replsets/tenant_migration_recipient_fetches_retryable_writes_oplog_entries.js
@@ -139,7 +139,21 @@ batchInsertWorker.join();
// `lastWriteOpTime` is after `startFetchingDonorOpTime`. The corresponding oplog entries should
// not be added to the oplog buffer.
assert.commandWorked(
- tenantCollection3.insert({_id: "retryableWrite4"}, {writeConcern: {w: "majority"}}));
+ tenantCollection3.insert({_id: "retryableWrite4", count: 0}, {writeConcern: {w: "majority"}}));
+
+// Test that when a post image op's `postImageOpTime` is after `startFetchingDonorOpTime`, it gets
+// filtered out.
+tenantCollection3.findAndModify({
+ query: {_id: "retryableWrite4"},
+ update: {$inc: {count: 1}},
+ new: true,
+ writeConcern: {w: "majority"}
+});
+
+// Test that when a pre image op's `preImageOpTime` is after `startFetchingDonorOpTime`, it gets
+// filtered out.
+tenantCollection3.findAndModify(
+ {query: {_id: "retryableWrite4"}, remove: true, writeConcern: {w: "majority"}});
fpAfterRetrievingStartOpTime.off();
fpAfterRetrievingRetryableWrites.wait();
@@ -160,6 +174,7 @@ assert.eq(1, recipientOplogBuffer.find({"entry.o._id": "bulkRetryableWrite0"}).i
// Ensure the retryable write oplog entries that should not be in `kOplogBufferNS` are in fact not.
assert.eq(0, recipientOplogBuffer.find({"entry.o._id": "retryableWrite1"}).itcount());
assert.eq(0, recipientOplogBuffer.find({"entry.o._id": "retryableWrite4"}).itcount());
+assert.eq(0, recipientOplogBuffer.find({"entry.o2._id": "retryableWrite4"}).itcount());
assert.eq(0, recipientOplogBuffer.find({"entry.o._id": "bulkRetryableWrite1"}).itcount());
fpAfterRetrievingRetryableWrites.off();
diff --git a/jstests/replsets/tenant_migration_retryable_write_retry.js b/jstests/replsets/tenant_migration_retryable_write_retry.js
index 9559ab57dc6..0bd659a2d6c 100644
--- a/jstests/replsets/tenant_migration_retryable_write_retry.js
+++ b/jstests/replsets/tenant_migration_retryable_write_retry.js
@@ -224,6 +224,20 @@ assert.commandWorked(donorPrimary.getDB(kDbName).runCommand({
writeConcern: {w: "majority"}
}));
+const lsid8 = {
+ id: UUID()
+};
+const sessionTag8 = "retryable findAndModify update after migration";
+assert.commandWorked(donorPrimary.getDB(kDbName).runCommand({
+ findAndModify: kCollName,
+ query: {x: 7},
+ update: {$set: {tag: sessionTag8}},
+ new: true,
+ txnNumber: NumberLong(0),
+ lsid: lsid8,
+ writeConcern: {w: "majority"}
+}));
+
// The aggregation pipeline will return an array of retryable writes oplog entries (pre-image/
// post-image oplog entries included) with "ts" < "startFetchingTimestamp" and sorted in ascending
// order of "ts".
@@ -261,20 +275,40 @@ const aggRes = donorPrimary.getDB("config").runCommand({
// single-element 'lastOps' array field with a single 'lastOp' field.
{$addFields: {lastOp: {$first: "$lastOps"}}},
{$unset: "lastOps"},
- // Fetch preImage oplog entry for findAndModify from the oplog view.
+ // Fetch the preImage oplog entry for findAndModify from the oplog view only if it occurred
+ // before `startFetchingTimestamp`.
{$lookup: {
from: {db: "local", coll: "system.tenantMigration.oplogView"},
- localField: "lastOp.preImageOpTime.ts",
- foreignField: "ts",
+ let: { preimage_ts: "$lastOp.preImageOpTime.ts"},
+ pipeline: [{
+ $match: {
+ $expr: {
+ $and: [
+ {$eq: [ "$ts", "$$preimage_ts"]},
+ {$lt: ["$ts", startFetchingTimestamp]}
+ ]
+ }
+ }
+ }],
// This array is expected to contain exactly one element if the 'preImageOpTime'
// field is not null.
as: "preImageOps"
}},
- // Fetch postImage oplog entry for findAndModify from the oplog view.
+ // Fetch the postImage oplog entry for findAndModify from the oplog view only if it occurred
+ // before `startFetchingTimestamp`.
{$lookup: {
from: {db: "local", coll: "system.tenantMigration.oplogView"},
- localField: "lastOp.postImageOpTime.ts",
- foreignField: "ts",
+ let: { postimage_ts: "$lastOp.postImageOpTime.ts"},
+ pipeline: [{
+ $match: {
+ $expr: {
+ $and: [
+ {$eq: [ "$ts", "$$postimage_ts"]},
+ {$lt: ["$ts", startFetchingTimestamp]}
+ ]
+ }
+ }
+ }],
// This array is expected to contain exactly one element if the 'postImageOpTime'
// field is not null.
as: "postImageOps"
diff --git a/src/mongo/db/repl/tenant_migration_util.cpp b/src/mongo/db/repl/tenant_migration_util.cpp
index 9989cf4cb9d..860fc442eea 100644
--- a/src/mongo/db/repl/tenant_migration_util.cpp
+++ b/src/mongo/db/repl/tenant_migration_util.cpp
@@ -249,31 +249,51 @@ createRetryableWritesOplogFetchingPipelineForTenantMigrations(
// 5. Remove `lastOps` in favor of `lastOp`.
stages.emplace_back(DocumentSourceProject::createUnset(FieldPath("lastOps"), expCtx));
- // 6. Fetch preImage oplog entry for `findAndModify` from the oplog view. `preImageOps` is not
- // expected to contain exactly one element if the `preImageOpTime` field is not null.
- stages.emplace_back(DocumentSourceLookUp::createFromBson(
- Doc{{"$lookup",
- Doc{{"from", Doc{{"db", "local"_sd}, {"coll", "system.tenantMigration.oplogView"_sd}}},
- {"localField", "lastOp.preImageOpTime.ts"_sd},
- {"foreignField", "ts"_sd},
- {"as", "preImageOps"_sd}}}}
- .toBson()
- .firstElement(),
- expCtx));
-
-
- // 7. Fetch postImage oplog entry for `findAndModify` from the oplog view. `postImageOps` is not
- // expected to contain exactly one element if the `postImageOpTime` field is not null.
- stages.emplace_back(DocumentSourceLookUp::createFromBson(
- Doc{{"$lookup",
- Doc{{"from", Doc{{"db", "local"_sd}, {"coll", "system.tenantMigration.oplogView"_sd}}},
- {"localField", "lastOp.postImageOpTime.ts"_sd},
- {"foreignField", "ts"_sd},
- {"as", "postImageOps"_sd}}}}
- .toBson()
- .firstElement(),
- expCtx));
+ // 6. Fetch preImage oplog entry for `findAndModify` from the oplog view. `preImageOps` is
+ // expected to contain exactly one element if the `preImageOpTime` field is not null and is
+ // earlier than `startFetchingTimestamp`.
+ stages.emplace_back(DocumentSourceLookUp::createFromBson(fromjson("{\
+ $lookup: {\
+ from: {db: 'local', coll: 'system.tenantMigration.oplogView'},\
+ let: { preimage_ts: '$lastOp.preImageOpTime.ts'},\
+ pipeline: [{\
+ $match: {\
+ $expr: {\
+ $and: [\
+ {$eq: ['$ts', '$$preimage_ts']},\
+ {$lt: ['$ts', " + startFetchingTimestamp.toString() +
+ "]}\
+ ]\
+ }\
+ }\
+ }],\
+ as: 'preImageOps'\
+ }}")
+ .firstElement(),
+ expCtx));
+ // 7. Fetch postImage oplog entry for `findAndModify` from the oplog view. `postImageOps` is
+ // expected to contain exactly one element if the `postImageOpTime` field is not null and is
+ // earlier than `startFetchingTimestamp`.
+ stages.emplace_back(DocumentSourceLookUp::createFromBson(fromjson("{\
+ $lookup: {\
+ from: {db: 'local', coll: 'system.tenantMigration.oplogView'},\
+ let: { postimage_ts: '$lastOp.postImageOpTime.ts'},\
+ pipeline: [{\
+ $match: {\
+ $expr: {\
+ $and: [\
+ {$eq: ['$ts', '$$postimage_ts']},\
+ {$lt: ['$ts', " + startFetchingTimestamp.toString() +
+ "]}\
+ ]\
+ }\
+ }\
+ }],\
+ as: 'postImageOps'\
+ }}")
+ .firstElement(),
+ expCtx));
// 8. Fetch oplog entries in each chain from the oplog view.
stages.emplace_back(DocumentSourceGraphLookUp::createFromBson(
@@ -288,7 +308,7 @@ createRetryableWritesOplogFetchingPipelineForTenantMigrations(
.firstElement(),
expCtx));
- // 9. Filter out all oplog entries from the `history` arrary that occur after
+ // 9. Filter out all oplog entries from the `history` array that occur after
// `startFetchingTimestamp`. Since the oplog fetching and application stages will already
// capture entries after `startFetchingTimestamp`, we only need the earlier part of the oplog
// chain.