CLUSTER RESET implemented.
The new command is able to reset a cluster node so that it starts again as a fresh node. By default the command performs a soft reset (the same as calling it as CLUSTER RESET SOFT), and the following steps are performed: 1) All slots are set as unassigned. 2) The list of known nodes is flushed. 3) Node is set as master if it is a slave. When an hard reset is performed with CLUSTER RESET HARD the following additional operations are performed: 4) A new Node ID is created at random. 5) Epochs are set to 0. CLUSTER RESET is useful both when the sysadmin wants to reconfigure a node with a different role (for example turning a slave into a master) and for testing purposes. It also may play a role in automatically provisioned Redis Clusters, since it allows to reset a node back to the initial state in order to be reconfigured.
This commit is contained in:
parent
8b9d5ecbd1
commit
796f4ae9f7
@ -70,6 +70,8 @@ void clusterDoBeforeSleep(int flags);
|
|||||||
void clusterSendUpdate(clusterLink *link, clusterNode *node);
|
void clusterSendUpdate(clusterLink *link, clusterNode *node);
|
||||||
void resetManualFailover(void);
|
void resetManualFailover(void);
|
||||||
void clusterCloseAllSlots(void);
|
void clusterCloseAllSlots(void);
|
||||||
|
void clusterSetNodeAsMaster(clusterNode *n);
|
||||||
|
void clusterDelNode(clusterNode *delnode);
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* Initialization
|
* Initialization
|
||||||
@ -462,6 +464,65 @@ void clusterInit(void) {
|
|||||||
resetManualFailover();
|
resetManualFailover();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset a node performing a soft or hard reset:
|
||||||
|
*
|
||||||
|
* 1) All other nodes are forget.
|
||||||
|
* 2) All the assigned / open slots are released.
|
||||||
|
* 3) If the node is a slave, it turns into a master.
|
||||||
|
* 5) Only for hard reset: a new Node ID is generated.
|
||||||
|
* 6) Only for hard reset: currentEpoch and configEpoch are set to 0.
|
||||||
|
* 7) The new configuration is saved and the cluster state updated. */
|
||||||
|
void clusterReset(int hard) {
|
||||||
|
dictIterator *di;
|
||||||
|
dictEntry *de;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* Turn into master. */
|
||||||
|
if (nodeIsSlave(myself)) {
|
||||||
|
clusterSetNodeAsMaster(myself);
|
||||||
|
replicationUnsetMaster();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close slots, reset manual failover state. */
|
||||||
|
clusterCloseAllSlots();
|
||||||
|
resetManualFailover();
|
||||||
|
|
||||||
|
/* Unassign all the slots. */
|
||||||
|
for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) clusterDelSlot(j);
|
||||||
|
|
||||||
|
/* Forget all the nodes, but myself. */
|
||||||
|
di = dictGetSafeIterator(server.cluster->nodes);
|
||||||
|
while((de = dictNext(di)) != NULL) {
|
||||||
|
clusterNode *node = dictGetVal(de);
|
||||||
|
|
||||||
|
if (node == myself) continue;
|
||||||
|
clusterDelNode(node);
|
||||||
|
}
|
||||||
|
dictReleaseIterator(di);
|
||||||
|
|
||||||
|
/* Hard reset only: set epochs to 0, change node ID. */
|
||||||
|
if (hard) {
|
||||||
|
sds oldname;
|
||||||
|
|
||||||
|
server.cluster->currentEpoch = 0;
|
||||||
|
server.cluster->lastVoteEpoch = 0;
|
||||||
|
myself->configEpoch = 0;
|
||||||
|
|
||||||
|
/* To change the Node ID we need to remove the old name from the
|
||||||
|
* nodes table, change the ID, and re-add back with new name. */
|
||||||
|
oldname = sdsnewlen(myself->name, REDIS_CLUSTER_NAMELEN);
|
||||||
|
dictDelete(server.cluster->nodes,oldname);
|
||||||
|
sdsfree(oldname);
|
||||||
|
getRandomHexChars(myself->name, REDIS_CLUSTER_NAMELEN);
|
||||||
|
clusterAddNode(myself);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure to persist the new config and update the state. */
|
||||||
|
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|
|
||||||
|
CLUSTER_TODO_UPDATE_STATE|
|
||||||
|
CLUSTER_TODO_FSYNC_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* CLUSTER communication link
|
* CLUSTER communication link
|
||||||
* -------------------------------------------------------------------------- */
|
* -------------------------------------------------------------------------- */
|
||||||
@ -3728,6 +3789,33 @@ void clusterCommand(redisClient *c) {
|
|||||||
CLUSTER_TODO_SAVE_CONFIG);
|
CLUSTER_TODO_SAVE_CONFIG);
|
||||||
addReply(c,shared.ok);
|
addReply(c,shared.ok);
|
||||||
}
|
}
|
||||||
|
} else if (!strcasecmp(c->argv[1]->ptr,"reset") &&
|
||||||
|
(c->argc == 2 || c->argc == 3))
|
||||||
|
{
|
||||||
|
/* CLUSTER RESET [SOFT|HARD] */
|
||||||
|
int hard = 0;
|
||||||
|
|
||||||
|
/* Parse soft/hard argument. Default is soft. */
|
||||||
|
if (c->argc == 3) {
|
||||||
|
if (!strcasecmp(c->argv[2]->ptr,"hard")) {
|
||||||
|
hard = 1;
|
||||||
|
} else if (!strcasecmp(c->argv[2]->ptr,"hard")) {
|
||||||
|
hard = 0;
|
||||||
|
} else {
|
||||||
|
addReply(c,shared.syntaxerr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slaves can be reset while containing data, but not master nodes
|
||||||
|
* that must be empty. */
|
||||||
|
if (nodeIsMaster(myself) && dictSize(c->db->dict) != 0) {
|
||||||
|
addReplyError(c,"CLUSTER RESET can't be called with "
|
||||||
|
"master nodes containing keys");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clusterReset(hard);
|
||||||
|
addReply(c,shared.ok);
|
||||||
} else {
|
} else {
|
||||||
addReplyError(c,"Wrong CLUSTER subcommand or number of arguments");
|
addReplyError(c,"Wrong CLUSTER subcommand or number of arguments");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user