mongo/jstests/sharding/shard_router_handle_staleco...

85 lines
3.7 KiB
JavaScript

/**
* Tests that mongos can detect stale routing information before checking for UUID mismatches and
* redirect the request to the appropriate shard.
*
* @tags: [requires_sharding]
*/
import {withRetryOnTransientTxnError} from "jstests/libs/auto_retry_transaction_in_sharding.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
const st = new ShardingTest({shards: 2, mongos: 2});
const dbName = "db";
function checkCommand(cmd, collName, withinTransaction) {
let session;
const withRetryIfWithinTransaction = function (func) {
if (withinTransaction) {
withRetryOnTransientTxnError(func, () => {
if (session) {
session.abortTransaction();
}
session = null;
});
} else {
func();
}
};
withRetryIfWithinTransaction(() => {
const db = st.getDB(dbName);
const coll = db[collName];
coll.drop();
// Create a sharded collection and move it to the secondary shard.
assert.commandWorked(st.s0.adminCommand({shardCollection: coll.getFullName(), key: {a: 1}}));
const nonPrimaryShard = st.getOther(st.getPrimaryShard(dbName)).name;
assert.commandWorked(
st.s0.adminCommand({moveChunk: `${dbName}.${collName}`, find: {a: 0}, to: nonPrimaryShard}),
);
// We now proceed to insert one document on each mongos connection. This will register cache
// information about where to route the requests to that particular shard key.
let i = 0;
st.forEachMongos((mongos) => {
mongos.getDB(dbName)[collName].insert({a: 0, x: i++});
});
if (withinTransaction) {
session = st.s1.getDB(dbName).getMongo().startSession();
session.startTransaction({readConcern: {level: "snapshot"}});
}
// Drop and recreate the collection on the primary shard. Now the collection resides on the
// primary shard rather than the secondary. Note that we are only doing this in one mongos
// so that the other one has stale information.
const sDb = st.s0.getDB(dbName);
assert.commandWorked(sDb.runCommand({drop: coll.getName()}));
assert.commandWorked(sDb.adminCommand({shardCollection: coll.getFullName(), key: {a: 1}}));
const newUuid = sDb.getCollectionInfos({name: coll.getName()})[0].info.uuid;
// Proceed to make a request on the other mongos for the new collection. We expect this
// request to get sent to the wrong shard as the router is stale. mongos should detect this
// and retry the request with the correct shard. No exception should be passed to the user
// in this case.
if (withinTransaction) {
const sessionColl = session.getDatabase(dbName).getCollection(collName);
assert.commandWorked(sessionColl.runCommand(Object.extend(cmd, {collectionUUID: newUuid})));
session.commitTransaction();
} else {
assert.commandWorked(
st.s1.getDB(dbName)[collName].runCommand(Object.extend(cmd, {collectionUUID: newUuid})),
);
}
});
}
let collName = jsTestName() + "_find";
checkCommand({find: collName, filter: {}}, collName, false);
checkCommand({find: collName, filter: {}}, collName, true);
collName = jsTestName() + "_insert";
checkCommand({insert: collName, documents: [{x: 1}]}, collName, false);
checkCommand({insert: collName, documents: [{x: 1}]}, collName, true);
collName = jsTestName() + "_agg";
checkCommand({aggregate: collName, pipeline: [{$match: {x: 1}}], cursor: {batchSize: 10}}, collName, false);
checkCommand({aggregate: collName, pipeline: [{$match: {x: 1}}], cursor: {batchSize: 10}}, collName, true);
st.stop();