SERVER-125916 SERVER-104976 Remove the repairShardedCollectionChunksHistory command (#53105)
GitOrigin-RevId: 5d1fc8602e0ad82e094d1a94c249473978309cde
This commit is contained in:
parent
13c8d307d8
commit
c73dc85799
@ -98,7 +98,6 @@ resmoke_suite_test(
|
||||
name = "no_passthrough",
|
||||
srcs = [
|
||||
"//jstests/noPassthrough/ddl:set_allow_migrations.js",
|
||||
"//jstests/noPassthrough/global_catalog:repair_sharded_collection_history.js",
|
||||
"//jstests/noPassthrough/global_catalog:reset_placement_history.js",
|
||||
"//jstests/noPassthrough/versioning_protocol:_flush_cache_update_commands.js",
|
||||
"//jstests/noPassthrough/versioning_protocol:flush_router_config.js",
|
||||
|
||||
@ -252,10 +252,6 @@ const internalCommandsMap = {
|
||||
testname: "_configsvrRemoveTags",
|
||||
command: {_configsvrRemoveTags: "test"},
|
||||
},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {
|
||||
testname: "_configsvrRepairShardedCollectionChunksHistory",
|
||||
command: {_configsvrRepairShardedCollectionChunksHistory: ns},
|
||||
},
|
||||
_configsvrResetPlacementHistory: {
|
||||
testname: "_configsvrResetPlacementHistory",
|
||||
command: {_configsvrResetPlacementHistory: ns},
|
||||
|
||||
@ -292,7 +292,6 @@ const skippedAuthTestingCommands = [
|
||||
"reapLogicalSessionCacheNow",
|
||||
"recreateRangeDeletionTasks",
|
||||
"releaseMemory",
|
||||
"repairShardedCollectionChunksHistory",
|
||||
"replicateSearchIndexCommand",
|
||||
"replSetAbortPrimaryCatchUp",
|
||||
"replSetRequestVotes",
|
||||
|
||||
@ -118,7 +118,6 @@ let viewsCommandTests = {
|
||||
_configsvrRemoveShard: {skip: isAnInternalCommand},
|
||||
_configsvrRemoveShardFromZone: {skip: isAnInternalCommand},
|
||||
_configsvrRemoveTags: {skip: isAnInternalCommand},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
|
||||
_configsvrResetPlacementHistory: {skip: isAnInternalCommand},
|
||||
_configsvrReshardCollection: {skip: isAnInternalCommand},
|
||||
_configsvrRunRestore: {skip: isAnInternalCommand},
|
||||
@ -665,13 +664,6 @@ let viewsCommandTests = {
|
||||
skipSharded: true,
|
||||
},
|
||||
],
|
||||
repairShardedCollectionChunksHistory: {
|
||||
command: {repairShardedCollectionChunksHistory: "test.view"},
|
||||
skipStandalone: true,
|
||||
isAdminCommand: true,
|
||||
expectFailure: true,
|
||||
expectedErrorCode: ErrorCodes.ConflictingOperationInProgress,
|
||||
},
|
||||
replicateSearchIndexCommand: {skip: isAnInternalCommand},
|
||||
replSetAbortPrimaryCatchUp: {skip: isUnrelated},
|
||||
replSetFreeze: {skip: isUnrelated},
|
||||
|
||||
@ -113,7 +113,6 @@ const wcCommandsTests = {
|
||||
_configsvrRemoveShardFromZone: {skip: "internal command"},
|
||||
_configsvrRemoveTags: {skip: "internal command"},
|
||||
_configsvrRenameCollection: {skip: "internal command"},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: "internal command"},
|
||||
_configsvrResetPlacementHistory: {skip: "internal command"},
|
||||
_configsvrReshardCollection: {skip: "internal command"},
|
||||
_configsvrRunRestore: {skip: "internal command"},
|
||||
@ -2242,7 +2241,6 @@ const wcCommandsTests = {
|
||||
admin: true,
|
||||
},
|
||||
},
|
||||
repairShardedCollectionChunksHistory: {skip: "does not accept write concern"},
|
||||
replicateSearchIndexCommand: {skip: "internal command for testing only"},
|
||||
replSetAbortPrimaryCatchUp: {skip: "does not accept write concern"},
|
||||
replSetFreeze: {skip: "does not accept write concern"},
|
||||
@ -3337,7 +3335,6 @@ const wcTimeseriesCommandsTests = {
|
||||
_configsvrRemoveShardFromZone: {skip: "internal command"},
|
||||
_configsvrRemoveTags: {skip: "internal command"},
|
||||
_configsvrRenameCollection: {skip: "internal command"},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: "internal command"},
|
||||
_configsvrResetPlacementHistory: {skip: "internal command"},
|
||||
_configsvrReshardCollection: {skip: "internal command"},
|
||||
_configsvrRunRestore: {skip: "internal command"},
|
||||
@ -4326,7 +4323,6 @@ const wcTimeseriesCommandsTests = {
|
||||
removeShardFromZone: {skip: "does not accept write concern"},
|
||||
// TODO SERVER-125423: add test coverage now that viewless timeseries are enabled.
|
||||
renameCollection: {skip: "not supported on timeseries views"},
|
||||
repairShardedCollectionChunksHistory: {skip: "does not accept write concern"},
|
||||
replicateSearchIndexCommand: {skip: "internal command for testing only"},
|
||||
replSetAbortPrimaryCatchUp: {skip: "does not accept write concern"},
|
||||
replSetFreeze: {skip: "does not accept write concern"},
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
import {ShardingTest} from "jstests/libs/shardingtest.js";
|
||||
|
||||
let st = new ShardingTest({
|
||||
shards: 1,
|
||||
});
|
||||
|
||||
let shardPrimary = st.rs0.getPrimary();
|
||||
let shardPrimaryConfigDB = shardPrimary.getDB("config");
|
||||
|
||||
let testDB = st.s.getDB("test1");
|
||||
|
||||
// Create a sharded collection with primary shard 0.
|
||||
assert.commandWorked(st.s.adminCommand({enableSharding: testDB.getName(), primaryShard: st.shard0.shardName}));
|
||||
assert.commandWorked(st.s.adminCommand({shardCollection: testDB.foo.getFullName(), key: {a: 1}}));
|
||||
assert.commandWorked(st.s.adminCommand({split: testDB.foo.getFullName(), middle: {a: 0}}));
|
||||
assert.commandWorked(st.s.adminCommand({split: testDB.foo.getFullName(), middle: {a: -1000}}));
|
||||
assert.commandWorked(st.s.adminCommand({split: testDB.foo.getFullName(), middle: {a: +1000}}));
|
||||
|
||||
assert.writeOK(st.s.getDB("test1").foo.insert({_id: "id1", a: 1}));
|
||||
assert.neq(null, st.s.getDB("test1").foo.findOne({_id: "id1", a: 1}));
|
||||
|
||||
assert.writeOK(st.s.getDB("test1").foo.insert({_id: "id2", a: -1}));
|
||||
assert.neq(null, st.s.getDB("test1").foo.findOne({_id: "id2", a: -1}));
|
||||
|
||||
const collection = st.s.getDB("config").getCollection("collections").findOne({_id: "test1.foo"});
|
||||
|
||||
// Manually clear the 'historyIsAt40' field from the config server and the history entries from
|
||||
// the shards' cache collections in order to simulate a wrong upgrade due to SERVER-62065
|
||||
assert.writeOK(
|
||||
st.s.getDB("config").chunks.update({uuid: collection.uuid}, {"$unset": {historyIsAt40: ""}}, {multi: true}),
|
||||
);
|
||||
assert.writeOK(
|
||||
shardPrimaryConfigDB.getCollection("cache.chunks.test1.foo").update({}, {"$unset": {history: ""}}, {multi: true}),
|
||||
);
|
||||
|
||||
assert.commandWorked(st.s.adminCommand({repairShardedCollectionChunksHistory: "test1.foo"}));
|
||||
|
||||
// Make sure chunks for test1.foo were given history after repair
|
||||
let chunks = st.s.getDB("config").getCollection("chunks").find({uuid: collection.uuid}).toArray();
|
||||
assert.eq(chunks.length, 4);
|
||||
chunks.forEach((chunk) => {
|
||||
assert.neq(null, chunk);
|
||||
assert(chunk.hasOwnProperty("history"), "test1.foo does not have a history after repair");
|
||||
assert(chunk.hasOwnProperty("historyIsAt40"), "test1.foo does not have a historyIsAt40 after repair");
|
||||
});
|
||||
chunks = shardPrimaryConfigDB.getCollection("cache.chunks.test1.foo").find().toArray();
|
||||
assert.eq(chunks.length, 4);
|
||||
chunks.forEach((chunk) => {
|
||||
assert.neq(null, chunk);
|
||||
assert(chunk.hasOwnProperty("history"), "test1.foo does not have a history on the shard after repair");
|
||||
});
|
||||
|
||||
st.stop();
|
||||
@ -288,7 +288,6 @@ const allCommands = {
|
||||
command: {renameCollection: fullNs, to: dbName + ".renamedColl"},
|
||||
isAdminCommand: true,
|
||||
},
|
||||
repairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
|
||||
replicateSearchIndexCommand: {skip: isAnInternalCommand},
|
||||
replSetGetStatus: {skip: "mongos does not run replset commands"},
|
||||
resetPlacementHistory: {command: {resetPlacementHistory: 1}, isAdminCommand: true},
|
||||
|
||||
@ -64,7 +64,6 @@ const allCommands = {
|
||||
_configsvrRemoveShard: {skip: isAnInternalCommand},
|
||||
_configsvrRemoveShardFromZone: {skip: isAnInternalCommand},
|
||||
_configsvrRemoveTags: {skip: isAnInternalCommand},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
|
||||
_configsvrResetPlacementHistory: {skip: isAnInternalCommand},
|
||||
_configsvrReshardCollection: {skip: isAnInternalCommand},
|
||||
_configsvrRunRestore: {skip: isAnInternalCommand},
|
||||
@ -1337,7 +1336,6 @@ const allCommands = {
|
||||
assert.commandWorked(conn.getDB(dbName).runCommand({drop: collName + "2"}));
|
||||
},
|
||||
},
|
||||
repairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
|
||||
replicateSearchIndexCommand: {skip: isAnInternalCommand},
|
||||
replSetAbortPrimaryCatchUp: {
|
||||
// This will be tested in FCV upgrade/downgrade passthroughs through the replsets directory.
|
||||
|
||||
@ -55,7 +55,6 @@ const allCommands = {
|
||||
_configsvrRemoveShard: {skip: isPrimaryOnly},
|
||||
_configsvrRemoveShardFromZone: {skip: isPrimaryOnly},
|
||||
_configsvrRemoveTags: {skip: isPrimaryOnly},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: isPrimaryOnly},
|
||||
_configsvrResetPlacementHistory: {skip: isPrimaryOnly},
|
||||
_configsvrReshardCollection: {skip: isPrimaryOnly},
|
||||
_configsvrRunRestore: {skip: isPrimaryOnly},
|
||||
@ -405,7 +404,6 @@ const allCommands = {
|
||||
reIndex: {skip: isNotAUserDataRead},
|
||||
releaseMemory: {skip: isNotAUserDataRead},
|
||||
renameCollection: {skip: isPrimaryOnly},
|
||||
repairShardedCollectionChunksHistory: {skip: isPrimaryOnly},
|
||||
replSetAbortPrimaryCatchUp: {skip: isNotAUserDataRead},
|
||||
replSetFreeze: {skip: isNotAUserDataRead},
|
||||
replSetGetConfig: {skip: isNotAUserDataRead},
|
||||
|
||||
@ -59,7 +59,6 @@ const allCommands = {
|
||||
_configsvrRemoveShard: {skip: isAnInternalCommand},
|
||||
_configsvrRemoveShardFromZone: {skip: isAnInternalCommand},
|
||||
_configsvrRemoveTags: {skip: isAnInternalCommand},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
|
||||
_configsvrResetPlacementHistory: {skip: isAnInternalCommand},
|
||||
_configsvrReshardCollection: {skip: isAnInternalCommand},
|
||||
_configsvrRunRestore: {skip: isAnInternalCommand},
|
||||
@ -1045,7 +1044,6 @@ const allCommands = {
|
||||
assert.commandWorked(mongoS.getDB(dbName).runCommand({drop: collName}));
|
||||
},
|
||||
},
|
||||
repairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
|
||||
replicateSearchIndexCommand: {skip: isAnInternalCommand},
|
||||
replSetAbortPrimaryCatchUp: {skip: "tested in direct_shard_connection_auth_rs_commands.js"},
|
||||
replSetFreeze: {skip: "tested in direct_shard_connection_auth_rs_commands.js"},
|
||||
|
||||
@ -873,7 +873,6 @@ const allTestCases = {
|
||||
},
|
||||
},
|
||||
},
|
||||
repairShardedCollectionChunksHistory: {skip: "always targets the config server"},
|
||||
replicateSearchIndexCommand: {skip: "internal command for testing only"},
|
||||
replSetGetStatus: {skip: "not supported in mongos"},
|
||||
resetPlacementHistory: {skip: "always targets the config server"},
|
||||
@ -1031,7 +1030,6 @@ const allTestCases = {
|
||||
_configsvrRemoveShard: {skip: "TODO"},
|
||||
_configsvrRemoveShardFromZone: {skip: "TODO"},
|
||||
_configsvrRemoveTags: {skip: "TODO"},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: "TODO"},
|
||||
_configsvrResetPlacementHistory: {skip: "TODO"},
|
||||
_configsvrReshardCollection: {skip: "TODO"},
|
||||
_configsvrRunRestore: {skip: "TODO"},
|
||||
|
||||
@ -8,6 +8,7 @@ export const commandsRemovedFromMongodSinceLastLTS = [
|
||||
"_shardsvrCommitToShardLocalCatalog", // Removed in 8.2
|
||||
"stageDebug",
|
||||
"_configsvrRemoveShardCommit",
|
||||
"_configsvrRepairShardedCollectionChunksHistory", // Removed in 9.0
|
||||
"_configsvrAddShardCoordinator",
|
||||
"_shardsvrChangePrimary", // Removed in 9.0
|
||||
"_shardsvrCommitIndexParticipant",
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
export const commandsRemovedFromMongosSinceLastLTS = [
|
||||
"_getAuditConfigGeneration", // Removed in 8.1
|
||||
"changePrimary", // Removed in 9.0
|
||||
"repairShardedCollectionChunksHistory", // Removed in 9.0
|
||||
"startRecordingTraffic",
|
||||
"stopRecordingTraffic",
|
||||
"cleanupReshardCollection",
|
||||
|
||||
@ -333,21 +333,6 @@ export let MongosAPIParametersUtil = (function () {
|
||||
{commandName: "oidcListKeys", skip: "TODO(SERVER-108802)", conditional: true},
|
||||
{commandName: "oidcRefreshKeys", skip: "TODO(SERVER-108802)", conditional: true},
|
||||
{commandName: "removeQuerySettings", skip: "TODO(SERVER-108802)"},
|
||||
{
|
||||
commandName: "repairShardedCollectionChunksHistory",
|
||||
run: {
|
||||
inAPIVersion1: false,
|
||||
configServerCommandName: "_configsvrRepairShardedCollectionChunksHistory",
|
||||
runsAgainstAdminDb: true,
|
||||
permittedInTxn: false,
|
||||
permittedOnShardedCollection: true,
|
||||
setUp: () => {
|
||||
assert.commandWorked(st.s.adminCommand({enableSharding: "db", primaryShard: st.shard0.shardName}));
|
||||
assert.commandWorked(st.s.adminCommand({shardCollection: "db.collection", key: {_id: 1}}));
|
||||
},
|
||||
command: () => ({repairShardedCollectionChunksHistory: "db.collection"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
commandName: "resetPlacementHistory",
|
||||
// The command is expected to fail when the featureFlagChangeStreamPreciseShardTargeting is disabled.
|
||||
|
||||
@ -113,7 +113,6 @@ let testCases = {
|
||||
_configsvrRemoveShardFromZone: {skip: "internal command"},
|
||||
_configsvrRemoveTags: {skip: "internal command"},
|
||||
_configsvrRenameCollection: {skip: "internal command"},
|
||||
_configsvrRepairShardedCollectionChunksHistory: {skip: "internal command"},
|
||||
_configsvrResetPlacementHistory: {skip: "internal command"},
|
||||
_configsvrReshardCollection: {skip: "internal command"},
|
||||
_configsvrRunRestore: {skip: "internal command"},
|
||||
@ -712,7 +711,6 @@ let testCases = {
|
||||
checkReadConcern: false,
|
||||
checkWriteConcern: true,
|
||||
},
|
||||
repairShardedCollectionChunksHistory: {skip: "does not accept read or write concern"},
|
||||
replicateSearchIndexCommand: {skip: "internal command"},
|
||||
replSetAbortPrimaryCatchUp: {skip: "does not accept read or write concern"},
|
||||
replSetFreeze: {skip: "does not accept read or write concern"},
|
||||
|
||||
@ -340,7 +340,6 @@ let testCases = {
|
||||
removeShard: {skip: "primary only"},
|
||||
removeShardFromZone: {skip: "primary only"},
|
||||
renameCollection: {skip: "primary only"},
|
||||
repairShardedCollectionChunksHistory: {skip: "does not return user data"},
|
||||
replicateSearchIndexCommand: {skip: "internal command for testing only"},
|
||||
replSetAbortPrimaryCatchUp: {skip: "does not return user data"},
|
||||
replSetFreeze: {skip: "does not return user data"},
|
||||
|
||||
@ -441,7 +441,6 @@ let testCases = {
|
||||
removeShard: {skip: "primary only"},
|
||||
removeShardFromZone: {skip: "primary only"},
|
||||
renameCollection: {skip: "primary only"},
|
||||
repairShardedCollectionChunksHistory: {skip: "does not return user data"},
|
||||
replicateSearchIndexCommand: {skip: "internal command"},
|
||||
replSetAbortPrimaryCatchUp: {skip: "does not return user data"},
|
||||
replSetFreeze: {skip: "does not return user data"},
|
||||
|
||||
@ -356,7 +356,6 @@ let testCases = {
|
||||
removeShard: {skip: "primary only"},
|
||||
removeShardFromZone: {skip: "primary only"},
|
||||
renameCollection: {skip: "primary only"},
|
||||
repairShardedCollectionChunksHistory: {skip: "does not return user data"},
|
||||
replicateSearchIndexCommand: {skip: "for testing only"},
|
||||
replSetAbortPrimaryCatchUp: {skip: "does not return user data"},
|
||||
replSetFreeze: {skip: "does not return user data"},
|
||||
|
||||
@ -416,15 +416,6 @@ idl_generator(
|
||||
],
|
||||
)
|
||||
|
||||
idl_generator(
|
||||
name = "repair_sharded_collection_chunks_history_gen",
|
||||
src = "repair_sharded_collection_chunks_history.idl",
|
||||
deps = [
|
||||
"//src/mongo/db:basic_types_gen",
|
||||
"//src/mongo/idl:generic_argument_gen",
|
||||
],
|
||||
)
|
||||
|
||||
idl_generator(
|
||||
name = "upgrade_downgrade_viewless_timeseries_gen",
|
||||
src = "upgrade_downgrade_viewless_timeseries.idl",
|
||||
|
||||
@ -1,131 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2021-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/base/error_codes.h"
|
||||
#include "mongo/base/status.h"
|
||||
#include "mongo/base/string_data.h"
|
||||
#include "mongo/bson/bsonelement.h"
|
||||
#include "mongo/bson/bsonmisc.h"
|
||||
#include "mongo/bson/bsonobj.h"
|
||||
#include "mongo/bson/bsonobjbuilder.h"
|
||||
#include "mongo/client/read_preference.h"
|
||||
#include "mongo/db/auth/action_type.h"
|
||||
#include "mongo/db/auth/authorization_session.h"
|
||||
#include "mongo/db/auth/resource_pattern.h"
|
||||
#include "mongo/db/commands.h"
|
||||
#include "mongo/db/database_name.h"
|
||||
#include "mongo/db/global_catalog/ddl/repair_sharded_collection_chunks_history_gen.h"
|
||||
#include "mongo/db/namespace_string.h"
|
||||
#include "mongo/db/operation_context.h"
|
||||
#include "mongo/db/service_context.h"
|
||||
#include "mongo/db/sharding_environment/client/shard.h"
|
||||
#include "mongo/db/sharding_environment/grid.h"
|
||||
#include "mongo/db/topology/shard_registry.h"
|
||||
#include "mongo/util/assert_util.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding
|
||||
|
||||
|
||||
namespace mongo {
|
||||
namespace {
|
||||
|
||||
class RepairShardedCollectionChunksHistoryCommand
|
||||
: public TypedCommand<RepairShardedCollectionChunksHistoryCommand> {
|
||||
public:
|
||||
using Request = RepairShardedCollectionChunksHistory;
|
||||
|
||||
class Invocation final : public InvocationBase {
|
||||
public:
|
||||
using InvocationBase::InvocationBase;
|
||||
|
||||
void typedRun(OperationContext* opCtx) {
|
||||
|
||||
BSONObjBuilder cmdBuilder;
|
||||
ConfigsvrRepairShardedCollectionChunksHistory cmd(ns());
|
||||
cmd.setForce(request().getForce());
|
||||
cmd.setDbName(DatabaseName::kAdmin);
|
||||
cmd.serialize(&cmdBuilder);
|
||||
|
||||
auto configShard = Grid::get(opCtx)->shardRegistry()->getConfigShard();
|
||||
auto cmdResponse = uassertStatusOK(
|
||||
configShard->runCommand(opCtx,
|
||||
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
|
||||
DatabaseName::kAdmin,
|
||||
CommandHelpers::appendMajorityWriteConcern(
|
||||
cmdBuilder.obj(), opCtx->getWriteConcern()),
|
||||
Shard::RetryPolicy::kIdempotent));
|
||||
uassertStatusOK(cmdResponse.commandStatus);
|
||||
}
|
||||
|
||||
private:
|
||||
NamespaceString ns() const override {
|
||||
return request().getCommandParameter();
|
||||
}
|
||||
|
||||
bool supportsWriteConcern() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The command intentionally uses the permission control of split/mergeChunks since it only
|
||||
// modifies the contents of chunk entries and increments the collection/shard placement
|
||||
// versions without causing any data placement changes
|
||||
void doCheckAuthorization(OperationContext* opCtx) const override {
|
||||
uassert(ErrorCodes::Unauthorized,
|
||||
"Unauthorized",
|
||||
AuthorizationSession::get(opCtx->getClient())
|
||||
->isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns()),
|
||||
ActionType::splitChunk));
|
||||
}
|
||||
};
|
||||
|
||||
AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
|
||||
return AllowedOnSecondary::kAlways;
|
||||
}
|
||||
|
||||
bool adminOnly() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string help() const override {
|
||||
return "Administrative command to repair the effects of SERVER-62065. If the collection "
|
||||
"has been upgraded through a cluster comprised of binaries which do not contain "
|
||||
"this command, the chunks cache collections on the shards will miss history "
|
||||
"entries. This command will correct that and will mark such collections as "
|
||||
"correctly repaired, so that a subsequent invocation will not cause any changes to "
|
||||
"the routing information. In rare cases where the history entries are missing due "
|
||||
"to corrupted restore, the 'force:true' parameter can be passed which will force "
|
||||
"all history entries to be re-added.";
|
||||
}
|
||||
};
|
||||
MONGO_REGISTER_COMMAND(RepairShardedCollectionChunksHistoryCommand).forRouter();
|
||||
|
||||
} // namespace
|
||||
} // namespace mongo
|
||||
@ -1,137 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2021-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
|
||||
#include "mongo/base/error_codes.h"
|
||||
#include "mongo/base/status.h"
|
||||
#include "mongo/base/string_data.h"
|
||||
#include "mongo/bson/bsonelement.h"
|
||||
#include "mongo/bson/bsonobj.h"
|
||||
#include "mongo/bson/bsonobjbuilder.h"
|
||||
#include "mongo/db/auth/action_type.h"
|
||||
#include "mongo/db/auth/authorization_session.h"
|
||||
#include "mongo/db/auth/resource_pattern.h"
|
||||
#include "mongo/db/commands.h"
|
||||
#include "mongo/db/database_name.h"
|
||||
#include "mongo/db/global_catalog/ddl/repair_sharded_collection_chunks_history_gen.h"
|
||||
#include "mongo/db/global_catalog/ddl/sharding_catalog_manager.h"
|
||||
#include "mongo/db/logical_time.h"
|
||||
#include "mongo/db/namespace_string.h"
|
||||
#include "mongo/db/namespace_string_util.h"
|
||||
#include "mongo/db/operation_context.h"
|
||||
#include "mongo/db/repl/read_concern_args.h"
|
||||
#include "mongo/db/repl/read_concern_level.h"
|
||||
#include "mongo/db/router_role/routing_cache/catalog_cache.h"
|
||||
#include "mongo/db/router_role/routing_cache/routing_information_cache.h"
|
||||
#include "mongo/db/server_options.h"
|
||||
#include "mongo/db/service_context.h"
|
||||
#include "mongo/db/topology/cluster_role.h"
|
||||
#include "mongo/db/topology/vector_clock/vector_clock.h"
|
||||
#include "mongo/util/assert_util.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/move/utility_core.hpp>
|
||||
|
||||
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
|
||||
|
||||
|
||||
namespace mongo {
|
||||
namespace {
|
||||
|
||||
class ConfigSvrRepairShardedCollectionChunksHistoryCommand
|
||||
: public TypedCommand<ConfigSvrRepairShardedCollectionChunksHistoryCommand> {
|
||||
public:
|
||||
using Request = ConfigsvrRepairShardedCollectionChunksHistory;
|
||||
|
||||
class Invocation final : public InvocationBase {
|
||||
public:
|
||||
using InvocationBase::InvocationBase;
|
||||
|
||||
void typedRun(OperationContext* opCtx) {
|
||||
|
||||
uassert(
|
||||
ErrorCodes::IllegalOperation,
|
||||
"_configsvrRepairShardedCollectionChunksHistory can only be run on config servers",
|
||||
serverGlobalParams.clusterRole.has(ClusterRole::ConfigServer));
|
||||
|
||||
// Set the operation context read concern level to local for reads into the config
|
||||
// database.
|
||||
repl::ReadConcernArgs::get(opCtx) =
|
||||
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern);
|
||||
|
||||
CommandHelpers::uassertCommandRunWithMajority(
|
||||
ConfigsvrRepairShardedCollectionChunksHistory::kCommandName,
|
||||
opCtx->getWriteConcern());
|
||||
|
||||
auto currentTime = VectorClock::get(opCtx)->getTime();
|
||||
auto validAfter = currentTime.configTime().asTimestamp();
|
||||
|
||||
ShardingCatalogManager::get(opCtx)->upgradeChunksHistory(
|
||||
opCtx, ns(), request().getForce(), validAfter);
|
||||
|
||||
RoutingInformationCache::get(opCtx)->invalidateCollectionEntry_LINEARIZABLE(ns());
|
||||
}
|
||||
|
||||
private:
|
||||
NamespaceString ns() const override {
|
||||
return request().getCommandParameter();
|
||||
}
|
||||
|
||||
bool supportsWriteConcern() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void doCheckAuthorization(OperationContext* opCtx) const override {
|
||||
uassert(ErrorCodes::Unauthorized,
|
||||
"Unauthorized",
|
||||
AuthorizationSession::get(opCtx->getClient())
|
||||
->isAuthorizedForActionsOnResource(
|
||||
ResourcePattern::forClusterResource(request().getDbName().tenantId()),
|
||||
ActionType::internal));
|
||||
}
|
||||
};
|
||||
|
||||
AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
|
||||
return AllowedOnSecondary::kNever;
|
||||
}
|
||||
|
||||
bool adminOnly() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string help() const override {
|
||||
return "Internal command, which is exported by the sharding config server. Do not call "
|
||||
"directly.";
|
||||
}
|
||||
};
|
||||
MONGO_REGISTER_COMMAND(ConfigSvrRepairShardedCollectionChunksHistoryCommand).forShard();
|
||||
|
||||
} // namespace
|
||||
} // namespace mongo
|
||||
@ -1,60 +0,0 @@
|
||||
# Copyright (C) 2024-present MongoDB, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the Server Side Public License, version 1,
|
||||
# as published by MongoDB, Inc.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# Server Side Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the Server Side Public License
|
||||
# along with this program. If not, see
|
||||
# <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
#
|
||||
# As a special exception, the copyright holders give permission to link the
|
||||
# code of portions of this program with the OpenSSL library under certain
|
||||
# conditions as described in each individual source file and distribute
|
||||
# linked combinations including the program with the OpenSSL library. You
|
||||
# must comply with the Server Side Public License in all respects for
|
||||
# all of the code used other than as permitted herein. If you modify file(s)
|
||||
# with this exception, you may extend this exception to your version of the
|
||||
# file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
# delete this exception statement from your version. If you delete this
|
||||
# exception statement from all source files in the program, then also delete
|
||||
# it in the license file.
|
||||
#
|
||||
|
||||
global:
|
||||
mod_visibility: private
|
||||
cpp_namespace: "mongo"
|
||||
|
||||
imports:
|
||||
- "mongo/db/basic_types.idl"
|
||||
|
||||
commands:
|
||||
repairShardedCollectionChunksHistory:
|
||||
command_name: repairShardedCollectionChunksHistory
|
||||
description: "The repairShardedCollectionChunksHistory command on mongos to repair a sharded collection's chunk history due to the effects of SERVER-62065, with an option to forcefully re-add all history entries if needed."
|
||||
namespace: type
|
||||
type: namespacestring
|
||||
api_version: ""
|
||||
strict: false
|
||||
fields:
|
||||
force:
|
||||
description: "If true, chunks that were repaired earlier by repairShardedCollectionChunksHistory are re-repaired. If false, chunks that were repaired earlier are skipped."
|
||||
type: optionalBool
|
||||
|
||||
_configsvrRepairShardedCollectionChunksHistory:
|
||||
command_name: _configsvrRepairShardedCollectionChunksHistory
|
||||
cpp_name: ConfigsvrRepairShardedCollectionChunksHistory
|
||||
description: "The internal _configsvrRepairShardedCollectionChunksHistory command to repair a sharded collection's chunk history."
|
||||
namespace: type
|
||||
type: namespacestring
|
||||
api_version: ""
|
||||
strict: false
|
||||
fields:
|
||||
force:
|
||||
description: "If true, chunks that were repaired earlier by repairShardedCollectionChunksHistory are re-repaired. If false, chunks that were repaired earlier are skipped."
|
||||
type: optionalBool
|
||||
@ -662,18 +662,6 @@ public:
|
||||
*/
|
||||
static void clearForTests(ServiceContext* serviceContext);
|
||||
|
||||
//
|
||||
// Upgrade/downgrade
|
||||
//
|
||||
|
||||
/**
|
||||
* Upgrade the chunk metadata to include the history field.
|
||||
*/
|
||||
void upgradeChunksHistory(OperationContext* opCtx,
|
||||
const NamespaceString& nss,
|
||||
bool force,
|
||||
const Timestamp& validAfter);
|
||||
|
||||
/**
|
||||
* Returns a catalog client that will always run commands locally. Can only be used on a
|
||||
* config server node.
|
||||
|
||||
@ -1813,135 +1813,6 @@ StatusWith<ChunkType> ShardingCatalogManager::_findChunkOnConfig(OperationContex
|
||||
return ChunkType::parseFromConfigBSON(origChunks.front(), epoch, timestamp);
|
||||
}
|
||||
|
||||
void ShardingCatalogManager::upgradeChunksHistory(OperationContext* opCtx,
|
||||
const NamespaceString& nss,
|
||||
bool force,
|
||||
const Timestamp& validAfter) {
|
||||
const auto shardRegistry = Grid::get(opCtx)->shardRegistry();
|
||||
|
||||
// Mark opCtx as interruptible to ensure that all reads and writes to the metadata collections
|
||||
// under the exclusive _kChunkOpLock happen on the same term.
|
||||
opCtx->setAlwaysInterruptAtStepDownOrUp_UNSAFE();
|
||||
|
||||
// Take _kChunkOpLock in exclusive mode to prevent concurrent chunk splits, merges, and
|
||||
// migrations.
|
||||
Lock::ExclusiveLock lk(opCtx, _kChunkOpLock);
|
||||
|
||||
const auto [coll, collPlacementVersion] =
|
||||
uassertStatusOK(getCollectionAndVersion(opCtx, _localConfigShard.get(), nss));
|
||||
|
||||
if (force) {
|
||||
LOGV2(620650,
|
||||
"Resetting the 'historyIsAt40' field for all chunks in collection {namespace} in "
|
||||
"order to force all chunks' history to get recreated",
|
||||
logAttrs(nss));
|
||||
|
||||
BatchedCommandRequest request([collUuid = coll.getUuid()] {
|
||||
write_ops::UpdateCommandRequest updateOp(NamespaceString::kConfigsvrChunksNamespace);
|
||||
updateOp.setUpdates({[&] {
|
||||
write_ops::UpdateOpEntry entry;
|
||||
entry.setQ(BSON(ChunkType::collectionUUID() << collUuid));
|
||||
entry.setU(write_ops::UpdateModification::parseFromClassicUpdate(
|
||||
BSON("$unset" << BSON(ChunkType::historyIsAt40() << ""))));
|
||||
entry.setUpsert(false);
|
||||
entry.setMulti(true);
|
||||
return entry;
|
||||
}()});
|
||||
return updateOp;
|
||||
}());
|
||||
|
||||
auto response = _localConfigShard->runBatchWriteCommand(
|
||||
opCtx,
|
||||
Milliseconds(defaultConfigCommandTimeoutMS.load()),
|
||||
request,
|
||||
ShardingCatalogClient::writeConcernLocalHavingUpstreamWaiter(),
|
||||
Shard::RetryPolicy::kIdempotent);
|
||||
uassertStatusOK(response.toStatus());
|
||||
|
||||
uassert(ErrorCodes::Error(5760502),
|
||||
str::stream() << "No chunks found for collection " << nss.toStringForErrorMsg(),
|
||||
response.getN() > 0);
|
||||
}
|
||||
|
||||
// Find the chunk history
|
||||
const auto allChunksVector = [&, collUuid = coll.getUuid()] {
|
||||
auto findChunksResponse = uassertStatusOK(_localConfigShard->exhaustiveFindOnConfig(
|
||||
opCtx,
|
||||
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
|
||||
repl::ReadConcernLevel::kLocalReadConcern,
|
||||
NamespaceString::kConfigsvrChunksNamespace,
|
||||
BSON(ChunkType::collectionUUID() << collUuid),
|
||||
BSONObj(),
|
||||
boost::none));
|
||||
uassert(ErrorCodes::Error(5760503),
|
||||
str::stream() << "No chunks found for collection " << nss.toStringForErrorMsg(),
|
||||
!findChunksResponse.docs.empty());
|
||||
return std::move(findChunksResponse.docs);
|
||||
}();
|
||||
|
||||
// Bump the major version in order to be guaranteed to trigger refresh on every shard
|
||||
ChunkVersion newCollectionPlacementVersion(
|
||||
{collPlacementVersion.epoch(), collPlacementVersion.getTimestamp()},
|
||||
{collPlacementVersion.majorVersion() + 1, 0});
|
||||
std::set<ShardId> shardsOwningChunks;
|
||||
for (const auto& chunk : allChunksVector) {
|
||||
auto upgradeChunk = uassertStatusOK(ChunkType::parseFromConfigBSON(
|
||||
chunk, collPlacementVersion.epoch(), collPlacementVersion.getTimestamp()));
|
||||
shardsOwningChunks.emplace(upgradeChunk.getShard());
|
||||
bool historyIsAt40 = chunk[ChunkType::historyIsAt40()].booleanSafe();
|
||||
if (historyIsAt40) {
|
||||
uassert(
|
||||
ErrorCodes::Error(5760504),
|
||||
str::stream() << "Chunk " << upgradeChunk.getName() << " in collection "
|
||||
<< nss.toStringForErrorMsg()
|
||||
<< " indicates that it has been upgraded to version 4.0, but is "
|
||||
"missing the history field. This indicates a corrupted routing "
|
||||
"table and requires a manual intervention to be fixed.",
|
||||
!upgradeChunk.getHistory().empty());
|
||||
continue;
|
||||
}
|
||||
|
||||
upgradeChunk.setVersion(newCollectionPlacementVersion);
|
||||
newCollectionPlacementVersion.incMinor();
|
||||
|
||||
// Construct the fresh history.
|
||||
upgradeChunk.setOnCurrentShardSince(validAfter);
|
||||
upgradeChunk.setHistory(
|
||||
{ChunkHistory{*upgradeChunk.getOnCurrentShardSince(), upgradeChunk.getShard()}});
|
||||
|
||||
// Set the 'historyIsAt40' field so that it gets skipped if the command is re-run
|
||||
BSONObjBuilder chunkObjBuilder(upgradeChunk.toConfigBSON());
|
||||
chunkObjBuilder.appendBool(ChunkType::historyIsAt40(), true);
|
||||
|
||||
// Run the update
|
||||
uassertStatusOK(_localCatalogClient->updateConfigDocument(
|
||||
opCtx,
|
||||
NamespaceString::kConfigsvrChunksNamespace,
|
||||
BSON(ChunkType::name(upgradeChunk.getName())),
|
||||
chunkObjBuilder.obj(),
|
||||
false,
|
||||
ShardingCatalogClient::writeConcernLocalHavingUpstreamWaiter()));
|
||||
}
|
||||
|
||||
// Wait for the writes to become majority committed so that the subsequent shard refreshes can
|
||||
// see them
|
||||
const auto clientOpTime = repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp();
|
||||
WriteConcernResult unusedWCResult;
|
||||
uassertStatusOK(waitForWriteConcern(
|
||||
opCtx, clientOpTime, defaultMajorityWriteConcernDoNotUse(), &unusedWCResult));
|
||||
|
||||
for (const auto& shardId : shardsOwningChunks) {
|
||||
auto shard = uassertStatusOK(shardRegistry->getShard(opCtx, shardId));
|
||||
uassertStatusOK(Shard::CommandResponse::getEffectiveStatus(shard->runCommand(
|
||||
opCtx,
|
||||
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
|
||||
DatabaseName::kAdmin,
|
||||
BSON("_flushRoutingTableCacheUpdates"
|
||||
<< NamespaceStringUtil::serialize(nss, SerializationContext::stateDefault())),
|
||||
Shard::RetryPolicy::kIdempotent)));
|
||||
}
|
||||
}
|
||||
|
||||
void ShardingCatalogManager::clearJumboFlag(OperationContext* opCtx,
|
||||
const NamespaceString& nss,
|
||||
const OID& collectionEpoch,
|
||||
|
||||
@ -582,7 +582,6 @@ mongo_cc_library(
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_merge_chunks_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_remove_chunks_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_remove_shard_from_zone_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_repair_sharded_collection_chunks_history_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_reset_placement_history_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_run_restore_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:configsvr_run_restore_gen",
|
||||
|
||||
@ -289,7 +289,6 @@ mongo_cc_library(
|
||||
"//src/mongo/db/global_catalog/ddl:move_primary_gen",
|
||||
"//src/mongo/db/global_catalog/ddl:placement_history_commands_gen",
|
||||
"//src/mongo/db/global_catalog/ddl:remove_shard_from_zone_request_type.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:repair_sharded_collection_chunks_history_gen",
|
||||
"//src/mongo/db/global_catalog/ddl:set_allow_migrations_gen",
|
||||
"//src/mongo/db/global_catalog/ddl:sharded_ddl_commands_gen",
|
||||
"//src/mongo/db/global_catalog/ddl:shardsvr_join_ddl_coordinators_request_gen",
|
||||
|
||||
@ -126,7 +126,6 @@ mongo_cc_library(
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_recreate_range_deletion_tasks_command.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_refine_collection_shard_key_cmd.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_rename_collection_cmd.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_repair_sharded_collection_chunks_history_cmd.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_reset_placement_history_cmd.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_set_allow_migrations_cmd.cpp",
|
||||
"//src/mongo/db/global_catalog/ddl:cluster_shard_collection_cmd.cpp",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user