diff options
Diffstat (limited to 'jstests/noPassthrough/upsert_duplicate_key_retry.js')
-rw-r--r-- | jstests/noPassthrough/upsert_duplicate_key_retry.js | 152 |
1 files changed, 75 insertions, 77 deletions
diff --git a/jstests/noPassthrough/upsert_duplicate_key_retry.js b/jstests/noPassthrough/upsert_duplicate_key_retry.js index 5841f5a7eb0..c2015642b0e 100644 --- a/jstests/noPassthrough/upsert_duplicate_key_retry.js +++ b/jstests/noPassthrough/upsert_duplicate_key_retry.js @@ -10,81 +10,79 @@ */ (function() { - "use strict"; - - const rst = new ReplSetTest({nodes: 1}); - rst.startSet(); - rst.initiate(); - - const testDB = rst.getPrimary().getDB("test"); - const adminDB = testDB.getSiblingDB("admin"); - const collName = "upsert_duplicate_key_retry"; - const testColl = testDB.getCollection(collName); - - testDB.runCommand({drop: collName}); - - // Queries current operations until 'count' matching operations are found. - function awaitMatchingCurrentOpCount(message, count) { - assert.soon(() => { - const currentOp = - adminDB.aggregate([{$currentOp: {}}, {$match: {msg: message}}]).toArray(); - return (currentOp.length === count); - }); - } - - function performUpsert() { - // This function is called from startParallelShell(), so closed-over variables will not be - // available. We must re-obtain the value of 'testColl' in the function body. - const testColl = db.getMongo().getDB("test").getCollection("upsert_duplicate_key_retry"); - assert.commandWorked(testColl.update({x: 3}, {$inc: {y: 1}}, {upsert: true})); - } - - assert.commandWorked(testColl.createIndex({x: 1}, {unique: true})); - - // Will hang upsert operations just prior to performing an insert. - assert.commandWorked(testDB.adminCommand( - {configureFailPoint: "hangBeforeUpsertPerformsInsert", mode: "alwaysOn"})); - - const awaitUpdate1 = startParallelShell(performUpsert, rst.ports[0]); - const awaitUpdate2 = startParallelShell(performUpsert, rst.ports[0]); - - awaitMatchingCurrentOpCount("hangBeforeUpsertPerformsInsert", 2); - - assert.commandWorked( - testDB.adminCommand({configureFailPoint: "hangBeforeUpsertPerformsInsert", mode: "off"})); - - awaitUpdate1(); - awaitUpdate2(); - - const cursor = testColl.find({}, {_id: 0}); - assert.eq(cursor.next(), {x: 3, y: 2}); - assert(!cursor.hasNext(), cursor.toArray()); - - // Confirm that oplog entries exist for both insert and update operation. - const oplogColl = testDB.getSiblingDB("local").getCollection("oplog.rs"); - assert.eq(1, oplogColl.find({"op": "i", "ns": "test.upsert_duplicate_key_retry"}).itcount()); - assert.eq(1, oplogColl.find({"op": "u", "ns": "test.upsert_duplicate_key_retry"}).itcount()); - - // - // Confirm DuplicateKey error for cases that should not be retried. - // - assert.commandWorked(testDB.runCommand({drop: collName})); - assert.commandWorked(testColl.createIndex({x: 1}, {unique: true})); - - // DuplicateKey error on replacement-style upsert, where the unique index key value to be - // written does not match the value of the query predicate. - assert.commandWorked(testColl.createIndex({x: 1}, {unique: true})); - assert.commandWorked(testColl.insert({_id: 1, 'a': 12345})); - assert.commandFailedWithCode(testColl.update({x: 3}, {}, {upsert: true}), - ErrorCodes.DuplicateKey); - - // DuplicateKey error on update-style upsert, where the unique index key value to be written - // does not match the value of the query predicate. - assert.commandWorked(testColl.remove({})); - assert.commandWorked(testColl.insert({x: 3})); - assert.commandWorked(testColl.insert({x: 4})); - assert.commandFailedWithCode(testColl.update({x: 3}, {$inc: {x: 1}}, {upsert: true}), - ErrorCodes.DuplicateKey); - - rst.stopSet(); +"use strict"; + +const rst = new ReplSetTest({nodes: 1}); +rst.startSet(); +rst.initiate(); + +const testDB = rst.getPrimary().getDB("test"); +const adminDB = testDB.getSiblingDB("admin"); +const collName = "upsert_duplicate_key_retry"; +const testColl = testDB.getCollection(collName); + +testDB.runCommand({drop: collName}); + +// Queries current operations until 'count' matching operations are found. +function awaitMatchingCurrentOpCount(message, count) { + assert.soon(() => { + const currentOp = adminDB.aggregate([{$currentOp: {}}, {$match: {msg: message}}]).toArray(); + return (currentOp.length === count); + }); +} + +function performUpsert() { + // This function is called from startParallelShell(), so closed-over variables will not be + // available. We must re-obtain the value of 'testColl' in the function body. + const testColl = db.getMongo().getDB("test").getCollection("upsert_duplicate_key_retry"); + assert.commandWorked(testColl.update({x: 3}, {$inc: {y: 1}}, {upsert: true})); +} + +assert.commandWorked(testColl.createIndex({x: 1}, {unique: true})); + +// Will hang upsert operations just prior to performing an insert. +assert.commandWorked( + testDB.adminCommand({configureFailPoint: "hangBeforeUpsertPerformsInsert", mode: "alwaysOn"})); + +const awaitUpdate1 = startParallelShell(performUpsert, rst.ports[0]); +const awaitUpdate2 = startParallelShell(performUpsert, rst.ports[0]); + +awaitMatchingCurrentOpCount("hangBeforeUpsertPerformsInsert", 2); + +assert.commandWorked( + testDB.adminCommand({configureFailPoint: "hangBeforeUpsertPerformsInsert", mode: "off"})); + +awaitUpdate1(); +awaitUpdate2(); + +const cursor = testColl.find({}, {_id: 0}); +assert.eq(cursor.next(), {x: 3, y: 2}); +assert(!cursor.hasNext(), cursor.toArray()); + +// Confirm that oplog entries exist for both insert and update operation. +const oplogColl = testDB.getSiblingDB("local").getCollection("oplog.rs"); +assert.eq(1, oplogColl.find({"op": "i", "ns": "test.upsert_duplicate_key_retry"}).itcount()); +assert.eq(1, oplogColl.find({"op": "u", "ns": "test.upsert_duplicate_key_retry"}).itcount()); + +// +// Confirm DuplicateKey error for cases that should not be retried. +// +assert.commandWorked(testDB.runCommand({drop: collName})); +assert.commandWorked(testColl.createIndex({x: 1}, {unique: true})); + +// DuplicateKey error on replacement-style upsert, where the unique index key value to be +// written does not match the value of the query predicate. +assert.commandWorked(testColl.createIndex({x: 1}, {unique: true})); +assert.commandWorked(testColl.insert({_id: 1, 'a': 12345})); +assert.commandFailedWithCode(testColl.update({x: 3}, {}, {upsert: true}), ErrorCodes.DuplicateKey); + +// DuplicateKey error on update-style upsert, where the unique index key value to be written +// does not match the value of the query predicate. +assert.commandWorked(testColl.remove({})); +assert.commandWorked(testColl.insert({x: 3})); +assert.commandWorked(testColl.insert({x: 4})); +assert.commandFailedWithCode(testColl.update({x: 3}, {$inc: {x: 1}}, {upsert: true}), + ErrorCodes.DuplicateKey); + +rst.stopSet(); })(); |