(function() {
|
"use strict";
|
|
const dbName = "test";
|
const collName = "foo";
|
const ns = dbName + "." + collName;
|
|
const st = new ShardingTest({shards: 2, config: 1});
|
|
// Shard a collection with chunks [minKey, 0), [0, maxKey) on shard0 and shard1, respectively.
|
|
assert.commandWorked(st.s.adminCommand({enableSharding: dbName}));
|
st.ensurePrimaryShard(dbName, st.shard0.shardName);
|
|
assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {skey: 1}}));
|
assert.commandWorked(st.s.adminCommand({split: ns, middle: {skey: 0}}));
|
assert.commandWorked(
|
st.s.adminCommand({moveChunk: ns, find: {skey: 5}, to: st.shard1.shardName}));
|
|
// Create a unique compound index prefixed on the shard key and insert two orphans with the same
|
// shard key but different values for the second field in the index.
|
|
const mongosColl = st.s.getDB(dbName)[collName];
|
assert.commandWorked(mongosColl.createIndex({skey: 1, uniqueField: 1}, {unique: true}));
|
|
assert.writeOK(mongosColl.insert({_id: 1, skey: -5, uniqueField: 0}));
|
|
const orphanColl = st.rs1.getPrimary().getDB(dbName)[collName];
|
assert.writeOK(orphanColl.insert({_id: 1, skey: -5, uniqueField: 0}));
|
assert.writeOK(orphanColl.insert({_id: 2, skey: -5, uniqueField: 1}));
|
|
// Start a transaction and send an update without the shard key that will be broadcast to all
|
// shards. The write will fail against an orphan because it would violate the unique index,
|
// which will abort the entire transaction. Outside a transaction, this write would succeed with
|
// a writeError.
|
|
const session = st.s.startSession();
|
session.startTransaction();
|
assert.commandFailedWithCode(session.getDatabase(dbName).runCommand({
|
update: collName,
|
updates: [{q: {uniqueField: 0}, u: {$set: {uniqueField: 1}}, multi: true}]
|
}),
|
ErrorCodes.DuplicateKey);
|
|
// The non-orphan was not updated.
|
assert.sameMembers(mongosColl.find().toArray(), [{_id: 1, skey: -5, uniqueField: 0}]);
|
|
// Repeat the previous update outside a transaction and the command instead updates the
|
// non-orphan with a writeError.
|
|
assert.commandWorkedIgnoringWriteErrors(mongosColl.getDB().runCommand({
|
update: collName,
|
updates: [{q: {uniqueField: 0}, u: {$set: {uniqueField: 1}}, multi: true}]
|
}));
|
|
// The non-orphan was updated.
|
assert.sameMembers(mongosColl.find().toArray(), [{_id: 1, skey: -5, uniqueField: 1}]);
|
|
st.stop();
|
})();
|