0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

SERVER-39227 Don't throw StaleConfig from command response in DBClientBase when connected to mongos

This commit is contained in:
Jack Mulrow 2019-02-05 13:07:04 -05:00
parent e2251dbc97
commit ee79572485
2 changed files with 72 additions and 3 deletions

View File

@ -0,0 +1,63 @@
// Verifies mongos returns StaleConfig if it exhausts its allowed stale version retry attempts,
// using the command read and write modes.
//
// @tags: [requires_sharding]
(function() {
"use strict";
const dbName = "test";
const collName = "foo";
const ns = dbName + '.' + collName;
const st = new ShardingTest({shards: 2, config: 1});
const testDB = st.s.getDB(dbName);
// Only testing the command read and write modes.
assert(testDB.getMongo().readMode() === "commands");
assert(testDB.getMongo().writeMode() === "commands");
// Shard a collection with the only chunk on shard0.
assert.commandWorked(st.s.adminCommand({enableSharding: dbName}));
st.ensurePrimaryShard(dbName, st.shard0.shardName);
assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {_id: 1}}));
const sourcePrimary = st.rs0.getPrimary();
const recipientPrimary = st.rs1.getPrimary();
// Disable the best-effort recipient metadata refresh after migrations and move the chunk
// between shards so the recipient shard, shard1, is stale.
assert.commandWorked(sourcePrimary.adminCommand(
{configureFailPoint: "doNotRefreshRecipientAfterCommit", mode: "alwaysOn"}));
assert.commandWorked(
st.s.adminCommand({moveChunk: ns, find: {_id: 0}, to: st.shard1.shardName}));
// Disable metadata refreshes on the recipient shard so it will indefinitely return StaleConfig.
assert.commandWorked(recipientPrimary.adminCommand(
{configureFailPoint: "skipShardFilteringMetadataRefresh", mode: "alwaysOn"}));
// Test various read and write commands that are sent with shard versions and thus can return
// StaleConfig. Batch writes, i.e. insert/update/delete, return batch responses with ok:1 and
// NoProgressMade write errors when retries are exhausted, so they are excluded.
const kCommands = [
{aggregate: collName, pipeline: [], cursor: {}},
{count: collName},
{distinct: collName, query: {}, key: "_id"},
{find: collName},
{findAndModify: collName, query: {_id: 0}, update: {$set: {x: 1}}},
];
kCommands.forEach((cmd) => {
// The recipient shard should return StaleConfig until mongos exhausts its retries and
// returns the final StaleConfig to the client.
assert.commandFailedWithCode(testDB.runCommand(cmd),
ErrorCodes.StaleConfig,
"expected to fail with StaleConfig, cmd: " + tojson(cmd));
});
assert.commandWorked(sourcePrimary.adminCommand(
{configureFailPoint: "doNotRefreshRecipientAfterCommit", mode: "off"}));
assert.commandWorked(recipientPrimary.adminCommand(
{configureFailPoint: "skipShardFilteringMetadataRefresh", mode: "off"}));
st.stop();
})();

View File

@ -156,9 +156,15 @@ rpc::UniqueReply DBClientBase::parseCommandReplyMessage(const std::string& host,
uassertStatusOK(_metadataReader(opCtx, commandReply->getCommandReply(), host));
}
auto status = getStatusFromCommandResult(commandReply->getCommandReply());
if (status == ErrorCodes::StaleConfig) {
uassertStatusOK(status.withContext("stale config in runCommand"));
// StaleConfig is thrown because clients acting as routers handle the exception at a higher
// level. Routing clients only expect StaleConfig from shards, so the exception should not be
// thrown when connected to a mongos, which allows StaleConfig to be returned to clients that
// connect to a mongos with DBClient, e.g. the shell.
if (!isMongos()) {
auto status = getStatusFromCommandResult(commandReply->getCommandReply());
if (status == ErrorCodes::StaleConfig) {
uassertStatusOK(status.withContext("stale config in runCommand"));
}
}
return rpc::UniqueReply(replyMsg, std::move(commandReply));