redis-cli: safer cluster fix with unreachalbe masters.

This commit is contained in:
antirez 2020-04-29 16:57:06 +02:00
parent 7c29c9eec1
commit 551fed3169

View File

@ -123,6 +123,7 @@
#define CLUSTER_MANAGER_CMD_FLAG_COPY 1 << 7 #define CLUSTER_MANAGER_CMD_FLAG_COPY 1 << 7
#define CLUSTER_MANAGER_CMD_FLAG_COLOR 1 << 8 #define CLUSTER_MANAGER_CMD_FLAG_COLOR 1 << 8
#define CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS 1 << 9 #define CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS 1 << 9
#define CLUSTER_MANAGER_CMD_FLAG_FIX_WITH_UNREACHABLE_MASTERS 1 << 10
#define CLUSTER_MANAGER_OPT_GETFRIENDS 1 << 0 #define CLUSTER_MANAGER_OPT_GETFRIENDS 1 << 0
#define CLUSTER_MANAGER_OPT_COLD 1 << 1 #define CLUSTER_MANAGER_OPT_COLD 1 << 1
@ -1599,6 +1600,9 @@ static int parseOptions(int argc, char **argv) {
} else if (!strcmp(argv[i],"--cluster-search-multiple-owners")) { } else if (!strcmp(argv[i],"--cluster-search-multiple-owners")) {
config.cluster_manager_command.flags |= config.cluster_manager_command.flags |=
CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS; CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS;
} else if (!strcmp(argv[i],"--cluster-fix-with-unreachable-masters")) {
config.cluster_manager_command.flags |=
CLUSTER_MANAGER_CMD_FLAG_FIX_WITH_UNREACHABLE_MASTERS;
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
} else if (!strcmp(argv[i],"--tls")) { } else if (!strcmp(argv[i],"--tls")) {
config.tls = 1; config.tls = 1;
@ -2146,6 +2150,7 @@ static int evalMode(int argc, char **argv) {
static struct clusterManager { static struct clusterManager {
list *nodes; /* List of nodes in the configuration. */ list *nodes; /* List of nodes in the configuration. */
list *errors; list *errors;
int unreachable_masters; /* Masters we are not able to reach. */
} cluster_manager; } cluster_manager;
/* Used by clusterManagerFixSlotsCoverage */ /* Used by clusterManagerFixSlotsCoverage */
@ -2288,7 +2293,7 @@ clusterManagerCommandDef clusterManagerCommands[] = {
"search-multiple-owners"}, "search-multiple-owners"},
{"info", clusterManagerCommandInfo, -1, "host:port", NULL}, {"info", clusterManagerCommandInfo, -1, "host:port", NULL},
{"fix", clusterManagerCommandFix, -1, "host:port", {"fix", clusterManagerCommandFix, -1, "host:port",
"search-multiple-owners"}, "search-multiple-owners,fix-with-unreachable-masters"},
{"reshard", clusterManagerCommandReshard, -1, "host:port", {"reshard", clusterManagerCommandReshard, -1, "host:port",
"from <arg>,to <arg>,slots <arg>,yes,timeout <arg>,pipeline <arg>," "from <arg>,to <arg>,slots <arg>,yes,timeout <arg>,pipeline <arg>,"
"replace"}, "replace"},
@ -4013,7 +4018,9 @@ static int clusterManagerLoadInfoFromNode(clusterManagerNode *node, int opts) {
if (friend->flags & (CLUSTER_MANAGER_FLAG_NOADDR | if (friend->flags & (CLUSTER_MANAGER_FLAG_NOADDR |
CLUSTER_MANAGER_FLAG_DISCONNECT | CLUSTER_MANAGER_FLAG_DISCONNECT |
CLUSTER_MANAGER_FLAG_FAIL)) CLUSTER_MANAGER_FLAG_FAIL))
{
goto invalid_friend; goto invalid_friend;
}
listAddNodeTail(cluster_manager.nodes, friend); listAddNodeTail(cluster_manager.nodes, friend);
} else { } else {
clusterManagerLogErr("[ERR] Unable to load info for " clusterManagerLogErr("[ERR] Unable to load info for "
@ -4023,6 +4030,8 @@ static int clusterManagerLoadInfoFromNode(clusterManagerNode *node, int opts) {
} }
continue; continue;
invalid_friend: invalid_friend:
if (!(friend->flags & CLUSTER_MANAGER_FLAG_SLAVE))
cluster_manager.unreachable_masters++;
freeClusterManagerNode(friend); freeClusterManagerNode(friend);
} }
listRelease(node->friends); listRelease(node->friends);
@ -4396,6 +4405,14 @@ static clusterManagerNode *clusterManagerNodeMasterRandom() {
} }
static int clusterManagerFixSlotsCoverage(char *all_slots) { static int clusterManagerFixSlotsCoverage(char *all_slots) {
int force_fix = config.cluster_manager_command.flags &
CLUSTER_MANAGER_CMD_FLAG_FIX_WITH_UNREACHABLE_MASTERS;
if (cluster_manager.unreachable_masters > 0 && !force_fix) {
clusterManagerLogWarn("*** Fixing slots coverage with %d unreachable masters is dangerous: redis-cli will assume that slots about masters that are not reachable are not covered, and will try to reassign them to the reachable nodes. This can cause data loss and is rarely what you want to do. If you really want to proceed use the --cluster-fix-with-unreachable-masters option.\n", cluster_manager.unreachable_masters);
exit(1);
}
int i, fixed = 0; int i, fixed = 0;
list *none = NULL, *single = NULL, *multi = NULL; list *none = NULL, *single = NULL, *multi = NULL;
clusterManagerLogInfo(">>> Fixing slots coverage...\n"); clusterManagerLogInfo(">>> Fixing slots coverage...\n");
@ -4585,6 +4602,14 @@ cleanup:
* more nodes. This function fixes this condition by migrating keys where * more nodes. This function fixes this condition by migrating keys where
* it seems more sensible. */ * it seems more sensible. */
static int clusterManagerFixOpenSlot(int slot) { static int clusterManagerFixOpenSlot(int slot) {
int force_fix = config.cluster_manager_command.flags &
CLUSTER_MANAGER_CMD_FLAG_FIX_WITH_UNREACHABLE_MASTERS;
if (cluster_manager.unreachable_masters > 0 && !force_fix) {
clusterManagerLogWarn("*** Fixing open slots with %d unreachable masters is dangerous: redis-cli will assume that slots about masters that are not reachable are not covered, and will try to reassign them to the reachable nodes. This can cause data loss and is rarely what you want to do. If you really want to proceed use the --cluster-fix-with-unreachable-masters option.\n", cluster_manager.unreachable_masters);
exit(1);
}
clusterManagerLogInfo(">>> Fixing open slot %d\n", slot); clusterManagerLogInfo(">>> Fixing open slot %d\n", slot);
/* Try to obtain the current slot owner, according to the current /* Try to obtain the current slot owner, according to the current
* nodes configuration. */ * nodes configuration. */