diff options
author | Pavi Vetriselvan <pavithra.vetriselvan@mongodb.com> | 2021-04-21 10:42:44 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-26 16:50:11 +0000 |
commit | 13bc7749febf4cdd860e28d7df72fd82b10ec1a5 (patch) | |
tree | 0c0b8f5c64fc38ca813218c4568e7add13d63fda | |
parent | c13c5887dd1b01314145bc731efedb1db8a5642a (diff) | |
download | mongo-13bc7749febf4cdd860e28d7df72fd82b10ec1a5.tar.gz |
SERVER-55359 pre/post image ops after startFetchingDonorOpTime should be filtered out of oplog buffer
(cherry picked from commit 9457ca34a5e157698602e620042c6c8037023375)
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. |