summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js
diff options
context:
space:
mode:
authorAnton Korshunov <anton.korshunov@mongodb.com>2021-06-01 12:22:25 +0100
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-03 08:02:19 +0000
commit1aa41b5625ae0ac2e757f3638585e20d7d81e7ca (patch)
tree76ca00b164415dc1d3d1243179906bfa50255808 /jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js
parentdcd9f60e591acffeedabb5fa368f407a035473b2 (diff)
downloadmongo-1aa41b5625ae0ac2e757f3638585e20d7d81e7ca.tar.gz
SERVER-57317 Fix optimized oplog scans in SBE to correctly handle $_resumeAfter queries
Diffstat (limited to 'jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js')
-rw-r--r--jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js152
1 files changed, 152 insertions, 0 deletions
diff --git a/jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js b/jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js
new file mode 100644
index 00000000000..e62fa2ff094
--- /dev/null
+++ b/jstests/noPassthrough/oplog_scan_optimizations_do_not_conflict.js
@@ -0,0 +1,152 @@
+/**
+ * Test that optimized collection scan on the oplog collection can be applied and executed
+ * successfully.
+ * @tags: [
+ * requires_replication,
+ * ]
+ */
+(function() {
+"use strict";
+
+const rst = new ReplSetTest({nodes: 2});
+rst.startSet();
+rst.initiate();
+
+const db = rst.getPrimary().getDB("oplog_scan_optimizations");
+const localDb = rst.getPrimary().getDB("local");
+const collName = "oplog_scan_optimizations";
+const oplogCollName = "oplog.rs";
+const coll = db[collName];
+const oplogColl = localDb[oplogCollName];
+
+coll.drop();
+
+// Insert several document so that we can use a cursor to fetch them in multiple batches.
+const testData = [{_id: 0, a: 1}, {_id: 1, a: 2}, {_id: 2, a: 3}];
+assert.commandWorked(coll.insert(testData));
+
+// Run the initial query and request to return a resume token. We will also request to return a
+// recordId for the document as it will
+// be used as a $_resumeAfter token later.
+let res = assert.commandWorked(localDb.runCommand({
+ find: oplogCollName,
+ filter: {op: "i", "o.a": {$gte: 1}},
+ hint: {$natural: 1},
+ batchSize: 1,
+ showRecordId: true,
+ $_requestResumeToken: true
+}));
+assert.eq(1, res.cursor.firstBatch.length);
+assert(res.cursor.firstBatch[0].hasOwnProperty("$recordId"));
+assert.hasFields(res.cursor, ["postBatchResumeToken"]);
+
+const firstResumeToken = res.cursor.postBatchResumeToken;
+const firstOplogBatch = res.cursor.firstBatch;
+
+res = assert.commandWorked(
+ localDb.runCommand({getMore: res.cursor.id, collection: oplogCollName, batchSize: 1}));
+assert.eq(1, res.cursor.nextBatch.length);
+assert(res.cursor.nextBatch[0].hasOwnProperty("$recordId"));
+assert.hasFields(res.cursor, ["postBatchResumeToken"]);
+
+const secondResumeToken = res.cursor.postBatchResumeToken;
+const secondOplogBatch = res.cursor.nextBatch;
+
+// Kill the cursor before attempting to resume.
+assert.commandWorked(localDb.runCommand({killCursors: oplogCollName, cursors: [res.cursor.id]}));
+
+// Try to resume the query from the saved resume token. This fails because '$_resumeAfter' expects a
+// '$recordId' resume token, not a 'ts' resume token. This is appropriate since resuming on the
+// oplog should occur by timestamp, not by record id.
+assert.commandFailedWithCode(localDb.runCommand({
+ find: oplogCollName,
+ filter: {ts: {$gte: firstResumeToken.ts}},
+ hint: {$natural: 1},
+ batchSize: 1,
+ $_requestResumeToken: true,
+ $_resumeAfter: firstResumeToken
+}),
+ ErrorCodes.BadValue);
+
+// Now try to resume using a '$recordId' resume token, which doesn't make a ton of sense, but is
+// still allowed.
+res = assert.commandWorked(localDb.runCommand({
+ find: oplogCollName,
+ filter: {ts: {$gte: firstResumeToken.ts}},
+ hint: {$natural: 1},
+ batchSize: 1,
+ showRecordId: true,
+ $_requestResumeToken: true,
+ $_resumeAfter: {$recordId: firstOplogBatch[0].$recordId}
+}));
+assert.eq(1, res.cursor.firstBatch.length);
+assert.eq(secondOplogBatch[0], res.cursor.firstBatch[0]);
+
+// Kill the cursor before attempting to resume.
+assert.commandWorked(localDb.runCommand({killCursors: oplogCollName, cursors: [res.cursor.id]}));
+
+res = assert.commandWorked(localDb.runCommand({
+ find: oplogCollName,
+ filter: {ts: {$lte: secondResumeToken.ts}},
+ hint: {$natural: 1},
+ batchSize: 1,
+ showRecordId: true,
+ $_requestResumeToken: true,
+ $_resumeAfter: {$recordId: firstOplogBatch[0].$recordId}
+}));
+assert.eq(1, res.cursor.firstBatch.length);
+assert.eq(secondOplogBatch[0], res.cursor.firstBatch[0]);
+
+// Kill the cursor before attempting to resume.
+assert.commandWorked(localDb.runCommand({killCursors: oplogCollName, cursors: [res.cursor.id]}));
+
+res = assert.commandWorked(localDb.runCommand({
+ find: oplogCollName,
+ filter: {ts: {$eq: secondResumeToken.ts}},
+ hint: {$natural: 1},
+ batchSize: 1,
+ showRecordId: true,
+ $_requestResumeToken: true,
+ $_resumeAfter: {$recordId: firstOplogBatch[0].$recordId}
+}));
+assert.eq(1, res.cursor.firstBatch.length);
+assert.eq(secondOplogBatch[0], res.cursor.firstBatch[0]);
+
+// Kill the cursor before attempting to resume.
+assert.commandWorked(localDb.runCommand({killCursors: oplogCollName, cursors: [res.cursor.id]}));
+
+res = assert.commandWorked(localDb.runCommand({
+ find: oplogCollName,
+ filter: {ts: {$gt: firstResumeToken.ts, $lte: secondResumeToken.ts}},
+ hint: {$natural: 1},
+ batchSize: 1,
+ showRecordId: true,
+ $_requestResumeToken: true,
+ $_resumeAfter: {$recordId: firstOplogBatch[0].$recordId}
+}));
+assert.eq(1, res.cursor.firstBatch.length);
+assert.eq(secondOplogBatch[0], res.cursor.firstBatch[0]);
+
+// Kill the cursor before attempting to resume.
+assert.commandWorked(localDb.runCommand({killCursors: oplogCollName, cursors: [res.cursor.id]}));
+
+// Try to resume the query from a non-existent recordId and check that it fails to position the
+// cursor to the record specified in the resume token.
+assert.commandFailedWithCode(localDb.runCommand({
+ find: oplogCollName,
+ hint: {$natural: 1},
+ batchSize: 1,
+ $_requestResumeToken: true,
+ $_resumeAfter: {$recordId: NumberLong("50")}
+}),
+ ErrorCodes.KeyNotFound);
+
+// When we have a predicate on a 'ts' field of the oplog collection, we can build an optimized
+// collection scan. Make sure we can run such optimized scans and get the result.
+assert.eq(oplogColl.find({ts: {$gte: firstResumeToken.ts}}).itcount(), 3);
+assert.eq(oplogColl.find({ts: {$gt: firstResumeToken.ts}}).itcount(), 2);
+assert.gt(oplogColl.find({ts: {$lte: firstResumeToken.ts}}).itcount(), 1);
+assert.gt(oplogColl.find({ts: {$lt: firstResumeToken.ts}}).itcount(), 1);
+
+rst.stopSet();
+})();