diff --git a/src/cluster.c b/src/cluster.c index 2cd98cd021c..a1a36a5b3fe 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -48,6 +48,7 @@ clusterNode *myself = NULL; clusterNode *createClusterNode(char *nodename, int flags); void clusterAddNode(clusterNode *node); +void setClusterNodeName(clusterNode *node); void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask); void clusterReadHandler(connection *conn); void clusterSendPing(clusterLink *link, int type); @@ -212,13 +213,17 @@ int clusterLoadConfig(char *filename) { n = createClusterNode(argv[0],0); clusterAddNode(n); } + + /*Human readable name*/ + memcpy(n->human_readable_name, argv[1], strlen(argv[1]) + 1); + /* Address and port */ - if ((p = strrchr(argv[1],':')) == NULL) { + if ((p = strrchr(argv[2],':')) == NULL) { sdsfreesplitres(argv,argc); goto fmterr; } *p = '\0'; - memcpy(n->ip,argv[1],strlen(argv[1])+1); + memcpy(n->ip,argv[2],strlen(argv[2])+1); char *port = p+1; char *busp = strchr(port,'@'); if (busp) { @@ -230,12 +235,11 @@ int clusterLoadConfig(char *filename) { * In this case we set it to the default offset of 10000 from the * base port. */ n->cport = busp ? atoi(busp) : n->port + CLUSTER_PORT_INCR; - /* The plaintext port for client in a TLS cluster (n->pport) is not * stored in nodes.conf. It is received later over the bus protocol. */ /* Parse flags */ - p = s = argv[2]; + p = s = argv[3]; while(p) { p = strchr(s,','); if (p) *p = '\0'; @@ -268,25 +272,28 @@ int clusterLoadConfig(char *filename) { /* Get master if any. Set the master and populate master's * slave list. */ - if (argv[3][0] != '-') { - master = clusterLookupNode(argv[3]); + if (argv[4][0] != '-') { + master = clusterLookupNode(argv[4]); if (!master) { - master = createClusterNode(argv[3],0); + master = createClusterNode(argv[4],0); clusterAddNode(master); } n->slaveof = master; clusterNodeAddSlave(master,n); } + /* Custom nodename */ + n->has_human_readable_name = atoi(argv[5]); + /* Set ping sent / pong received timestamps */ - if (atoi(argv[4])) n->ping_sent = mstime(); - if (atoi(argv[5])) n->pong_received = mstime(); + if (atoi(argv[6])) n->ping_sent = mstime(); + if (atoi(argv[7])) n->pong_received = mstime(); /* Set configEpoch for this node. */ - n->configEpoch = strtoull(argv[6],NULL,10); + n->configEpoch = strtoull(argv[8],NULL,10); /* Populate hash slots served by this instance. */ - for (j = 8; j < argc; j++) { + for (j = 10; j < argc; j++) { int start, stop; if (argv[j][0] == '[') { @@ -340,7 +347,7 @@ int clusterLoadConfig(char *filename) { zfree(line); fclose(fp); - serverLog(LL_NOTICE,"Node configuration loaded, I'm %.40s", myself->name); + serverLog(LL_NOTICE,"Node configuration loaded, I'm %.40s %s", myself->name, myself->human_readable_name); /* Something that should never happen: currentEpoch smaller than * the max epoch found in the nodes configuration. However we handle this @@ -348,6 +355,7 @@ int clusterLoadConfig(char *filename) { if (clusterGetMaxEpoch() > server.cluster->currentEpoch) { server.cluster->currentEpoch = clusterGetMaxEpoch(); } + return C_OK; fmterr: @@ -380,6 +388,7 @@ int clusterSaveConfig(int do_fsync) { /* Get the nodes description and concatenate our "vars" directive to * save currentEpoch and lastVoteEpoch. */ + ci = clusterGenNodesDescription(CLUSTER_NODE_HANDSHAKE, 0); ci = sdscatprintf(ci,"vars currentEpoch %llu lastVoteEpoch %llu\n", (unsigned long long) server.cluster->currentEpoch, @@ -557,8 +566,8 @@ void clusterInit(void) { * by the createClusterNode() function. */ myself = server.cluster->myself = createClusterNode(NULL,CLUSTER_NODE_MYSELF|CLUSTER_NODE_MASTER); - serverLog(LL_NOTICE,"No cluster configuration found, I'm %.40s", - myself->name); + serverLog(LL_NOTICE,"No cluster configuration found, I'm %.40s %s", + myself->name, myself->human_readable_name); clusterAddNode(myself); saveconf = 1; } @@ -659,7 +668,7 @@ void clusterReset(int hard) { sdsfree(oldname); getRandomHexChars(myself->name, CLUSTER_NAMELEN); clusterAddNode(myself); - serverLog(LL_NOTICE,"Node hard reset, now I'm %.40s", myself->name); + serverLog(LL_NOTICE,"Node hard reset, now I'm %.40s %s", myself->name, myself->human_readable_name); } /* Make sure to persist the new config and update the state. */ @@ -819,6 +828,25 @@ unsigned int keyHashSlot(char *key, int keylen) { * CLUSTER node API * -------------------------------------------------------------------------- */ +/* Assign a human readable name to nodes for clusters*/ +void setClusterNodeName(clusterNode *node) { + if (node->has_human_readable_name == 1) + return; + char ip[NET_IP_STR_LEN]; + strcpy(ip,node->ip); + sprintf(node->human_readable_name, "%s_%u", ip,(unsigned int)node->port); +} + +/* Manually assign a human readable name to nodes for clusters*/ +int setManualClusterNodeName(clusterNode *node, char * newname) { + if (newname == NULL) + return 0; + memcpy(node->human_readable_name, newname, strlen(newname) + 1); + node->has_human_readable_name = 1; + clusterSaveConfig(1); + return 1; +} + /* Create a new cluster node, with the specified flags. * If "nodename" is NULL this is considered a first handshake and a random * node name is assigned to this node (it will be fixed later when we'll @@ -839,6 +867,7 @@ clusterNode *createClusterNode(char *nodename, int flags) { memset(node->slots,0,sizeof(node->slots)); node->slots_info = NULL; node->numslots = 0; + node->has_human_readable_name = 0; node->numslaves = 0; node->slaves = NULL; node->slaveof = NULL; @@ -847,6 +876,7 @@ clusterNode *createClusterNode(char *nodename, int flags) { node->fail_time = 0; node->link = NULL; memset(node->ip,0,sizeof(node->ip)); + memset(node->human_readable_name,0,sizeof(node->human_readable_name)); node->port = 0; node->cport = 0; node->pport = 0; @@ -1076,7 +1106,20 @@ clusterNode *clusterLookupNode(const char *name) { de = dictFind(server.cluster->nodes,s); sdsfree(s); - if (de == NULL) return NULL; + if (de == NULL) { + /* Check if any node has the same human readable name*/ + dictIterator *di; + dictEntry *de2; + + di = dictGetSafeIterator(server.cluster->nodes); + while((de2 = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de2); + if (strcmp(node->human_readable_name,name ) == 0) + return node; + } + dictReleaseIterator(di); + return NULL; + } return dictGetVal(de); } @@ -1090,6 +1133,7 @@ void clusterRenameNode(clusterNode *node, char *newname) { serverLog(LL_DEBUG,"Renaming node %.40s into %.40s", node->name, newname); + retval = dictDelete(server.cluster->nodes, s); sdsfree(s); serverAssert(retval == DICT_OK); @@ -1223,9 +1267,9 @@ void clusterHandleConfigEpochCollision(clusterNode *sender) { myself->configEpoch = server.cluster->currentEpoch; clusterSaveConfigOrDie(1); serverLog(LL_VERBOSE, - "WARNING: configEpoch collision with node %.40s." + "WARNING: configEpoch collision with node %.40s %s." " configEpoch set to %llu", - sender->name, + sender->name, sender->human_readable_name, (unsigned long long) myself->configEpoch); } @@ -1341,7 +1385,7 @@ void markNodeAsFailingIfNeeded(clusterNode *node) { if (failures < needed_quorum) return; /* No weak agreement from masters. */ serverLog(LL_NOTICE, - "Marking node %.40s as failing (quorum reached).", node->name); + "Marking node %.40s %s as failing (quorum reached).", node->name, node ->human_readable_name); /* Mark the node as failing. */ node->flags &= ~CLUSTER_NODE_PFAIL; @@ -1369,8 +1413,8 @@ void clearNodeFailureIfNeeded(clusterNode *node) { * node again. */ if (nodeIsSlave(node) || node->numslots == 0) { serverLog(LL_NOTICE, - "Clear FAIL state for node %.40s: %s is reachable again.", - node->name, + "Clear FAIL state for node %.40s %s: %s is reachable again.", + node->name, node->human_readable_name, nodeIsSlave(node) ? "replica" : "master without slots"); node->flags &= ~CLUSTER_NODE_FAIL; clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); @@ -1385,8 +1429,8 @@ void clearNodeFailureIfNeeded(clusterNode *node) { (server.cluster_node_timeout * CLUSTER_FAIL_UNDO_TIME_MULT)) { serverLog(LL_NOTICE, - "Clear FAIL state for node %.40s: is reachable again and nobody is serving its slots after some time.", - node->name); + "Clear FAIL state for node %.40s %s: is reachable again and nobody is serving its slots after some time.", + node->name, node->human_readable_name); node->flags &= ~CLUSTER_NODE_FAIL; clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); } @@ -1468,6 +1512,7 @@ int clusterStartHandshake(char *ip, int port, int cport) { memcpy(n->ip,norm_ip,sizeof(n->ip)); n->port = port; n->cport = cport; + setClusterNodeName(n); clusterAddNode(n); return 1; } @@ -1506,15 +1551,15 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) { if (flags & (CLUSTER_NODE_FAIL|CLUSTER_NODE_PFAIL)) { if (clusterNodeAddFailureReport(node,sender)) { serverLog(LL_VERBOSE, - "Node %.40s reported node %.40s as not reachable.", - sender->name, node->name); + "Node %.40s %s reported node %.40s %s as not reachable.", + sender->name, sender->human_readable_name, node->name, node->human_readable_name); } markNodeAsFailingIfNeeded(node); } else { if (clusterNodeDelFailureReport(node,sender)) { serverLog(LL_VERBOSE, - "Node %.40s reported node %.40s is back online.", - sender->name, node->name); + "Node %.40s %s reported node %.40s %s is back online.", + sender->name, sender->human_readable_name, node->name, node->human_readable_name); } } } @@ -1559,6 +1604,10 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) { node->pport = ntohs(g->pport); node->cport = ntohs(g->cport); node->flags &= ~CLUSTER_NODE_NOADDR; + if (hdr->has_human_readable_name) + setManualClusterNodeName(node, hdr->human_readable_name); + else + setClusterNodeName(node); } } else { /* If it's not in NOADDR state and we don't have it, we @@ -1580,6 +1629,10 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) { node->port = ntohs(g->port); node->pport = ntohs(g->pport); node->cport = ntohs(g->cport); + if (hdr->has_human_readable_name) + setManualClusterNodeName(node, hdr->human_readable_name); + else + setClusterNodeName(node); clusterAddNode(node); } } @@ -1638,10 +1691,14 @@ int nodeUpdateAddressIfNeeded(clusterNode *node, clusterLink *link, node->port = port; node->pport = pport; node->cport = cport; + if (hdr->has_human_readable_name) + setManualClusterNodeName(node, hdr->human_readable_name); + else + setClusterNodeName(node); if (node->link) freeClusterLink(node->link); node->flags &= ~CLUSTER_NODE_NOADDR; - serverLog(LL_WARNING,"Address updated for node %.40s, now %s:%d", - node->name, node->ip, node->port); + serverLog(LL_WARNING,"Address updated for node %.40s %s, now %s:%d", + node->name, node->human_readable_name, node->ip, node->port); /* Check if this is our master and we have to change the * replication target as well. */ @@ -1770,7 +1827,7 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc sender_slots == migrated_our_slots)) { serverLog(LL_WARNING, "Configuration change detected. Reconfiguring myself " - "as a replica of %.40s", sender->name); + "as a replica of %.40s %s", sender->name, sender->human_readable_name); clusterSetMaster(sender); clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| CLUSTER_TODO_UPDATE_STATE| @@ -1928,12 +1985,17 @@ int clusterProcessPacket(clusterLink *link) { strcmp(ip,myself->ip)) { memcpy(myself->ip,ip,NET_IP_STR_LEN); + setClusterNodeName(myself); serverLog(LL_WARNING,"IP address for this node updated to %s", myself->ip); clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); } } + if (sender && strcmp(sender->human_readable_name,hdr->human_readable_name) != 0) { + strncpy(sender->human_readable_name, hdr->human_readable_name, CLUSTER_HUMAN_NAMELEN); + } + /* Add this node if it is new for us and the msg type is MEET. * In this stage we don't try to add the node with the right * flags, slaveof pointer, and so forth, as this details will be @@ -1973,8 +2035,15 @@ int clusterProcessPacket(clusterLink *link) { * IP/port of the node with the new one. */ if (sender) { serverLog(LL_VERBOSE, - "Handshake: we already know node %.40s, " - "updating the address if needed.", sender->name); + "Handshake: we already know node %.40s %s, " + "updating the address if needed.", sender->name, sender->human_readable_name); + + if (hdr->has_human_readable_name) { + setManualClusterNodeName(sender, hdr->human_readable_name); + } + else + setClusterNodeName(sender); + if (nodeUpdateAddressIfNeeded(sender,link,hdr)) { clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| @@ -1989,8 +2058,8 @@ int clusterProcessPacket(clusterLink *link) { /* First thing to do is replacing the random name with the * right node name if this was a handshake stage. */ clusterRenameNode(link->node, hdr->sender); - serverLog(LL_DEBUG,"Handshake with node %.40s completed.", - link->node->name); + serverLog(LL_DEBUG,"Handshake with node %.40s %s completed.", + link->node->name, link->node->human_readable_name); link->node->flags &= ~CLUSTER_NODE_HANDSHAKE; link->node->flags |= flags&(CLUSTER_NODE_MASTER|CLUSTER_NODE_SLAVE); clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); @@ -2000,10 +2069,11 @@ int clusterProcessPacket(clusterLink *link) { /* If the reply has a non matching node ID we * disconnect this node and set it as not having an associated * address. */ - serverLog(LL_DEBUG,"PONG contains mismatching sender ID. About node %.40s added %d ms ago, having flags %d", - link->node->name, + serverLog(LL_DEBUG,"PONG contains mismatching sender ID. About node %.40s %s added %d ms ago, having flags %d", + link->node->name, link->node->human_readable_name, (int)(now-(link->node->ctime)), link->node->flags); + link->node->flags |= CLUSTER_NODE_NOADDR; link->node->ip[0] = '\0'; link->node->port = 0; @@ -2147,9 +2217,10 @@ int clusterProcessPacket(clusterLink *link) { senderConfigEpoch) { serverLog(LL_VERBOSE, - "Node %.40s has old slots configuration, sending " - "an UPDATE message about %.40s", - sender->name, server.cluster->slots[j]->name); + "Node %.40s %s has old slots configuration, sending " + "an UPDATE message about %.40s %s", + sender->name, sender->human_readable_name, + server.cluster->slots[j]->name, server.cluster->slots[j]->human_readable_name); clusterSendUpdate(sender->link, server.cluster->slots[j]); @@ -2243,8 +2314,8 @@ int clusterProcessPacket(clusterLink *link) { server.cluster->mf_end = now + CLUSTER_MF_TIMEOUT; server.cluster->mf_slave = sender; pauseClients(now+(CLUSTER_MF_TIMEOUT*CLUSTER_MF_PAUSE_MULT),CLIENT_PAUSE_WRITE); - serverLog(LL_WARNING,"Manual failover requested by replica %.40s.", - sender->name); + serverLog(LL_WARNING,"Manual failover requested by replica %.40s %s.", + sender->name, sender->human_readable_name); /* We need to send a ping message to the replica, as it would carry * `server.cluster->mf_master_offset`, which means the master paused clients * at offset `server.cluster->mf_master_offset`, so that the replica would @@ -2326,8 +2397,8 @@ void clusterLinkConnectHandler(connection *conn) { /* Check if connection succeeded */ if (connGetState(conn) != CONN_STATE_CONNECTED) { - serverLog(LL_VERBOSE, "Connection with Node %.40s at %s:%d failed: %s", - node->name, node->ip, node->cport, + serverLog(LL_VERBOSE, "Connection with Node %.40s %s at %s:%d failed: %s", + node->name, node->human_readable_name, node->ip, node->cport, connGetLastError(conn)); freeClusterLink(link); return; @@ -2358,8 +2429,8 @@ void clusterLinkConnectHandler(connection *conn) { * normal PING packets. */ node->flags &= ~CLUSTER_NODE_MEET; - serverLog(LL_DEBUG,"Connecting with Node %.40s at %s:%d", - node->name, node->ip, node->cport); + serverLog(LL_DEBUG,"Connecting with Node %.40s %s at %s:%d", + node->name, node->human_readable_name, node->ip, node->cport); } /* Read data. Try to read the first field of the header first to check the @@ -2499,6 +2570,8 @@ void clusterBuildMessageHdr(clusterMsg *hdr, int type) { hdr->sig[3] = 'b'; hdr->type = htons(type); memcpy(hdr->sender,myself->name,CLUSTER_NAMELEN); + strncpy(hdr->human_readable_name,myself->human_readable_name,CLUSTER_HUMAN_NAMELEN); + hdr->has_human_readable_name = myself->has_human_readable_name; /* If cluster-announce-ip option is enabled, force the receivers of our * packets to use the specified address for this node. Otherwise if the @@ -2523,6 +2596,7 @@ void clusterBuildMessageHdr(clusterMsg *hdr, int type) { hdr->flags = htons(myself->flags); hdr->state = server.cluster->state; + /* Set the currentEpoch and configEpochs. */ hdr->currentEpoch = htonu64(server.cluster->currentEpoch); hdr->configEpoch = htonu64(master->configEpoch); @@ -2577,6 +2651,7 @@ void clusterSetGossipEntry(clusterMsg *hdr, int i, clusterNode *n) { gossip->cport = htons(n->cport); gossip->flags = htons(n->flags); gossip->pport = htons(n->pport); + gossip->has_human_readable_name = n->has_human_readable_name; gossip->notused1 = 0; } @@ -2642,6 +2717,7 @@ void clusterSendPing(clusterLink *link, int type) { /* Populate the header. */ if (link->node && type == CLUSTERMSG_TYPE_PING) link->node->ping_sent = mstime(); + clusterBuildMessageHdr(hdr,type); /* Populate the gossip fields */ @@ -2960,8 +3036,8 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { * request, if the request epoch was greater. */ if (requestCurrentEpoch < server.cluster->currentEpoch) { serverLog(LL_WARNING, - "Failover auth denied to %.40s: reqEpoch (%llu) < curEpoch(%llu)", - node->name, + "Failover auth denied to %.40s %s: reqEpoch (%llu) < curEpoch(%llu)", + node->name, node->human_readable_name, (unsigned long long) requestCurrentEpoch, (unsigned long long) server.cluster->currentEpoch); return; @@ -2970,8 +3046,8 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { /* I already voted for this epoch? Return ASAP. */ if (server.cluster->lastVoteEpoch == server.cluster->currentEpoch) { serverLog(LL_WARNING, - "Failover auth denied to %.40s: already voted for epoch %llu", - node->name, + "Failover auth denied to %.40s %s: already voted for epoch %llu", + node->name, node->human_readable_name, (unsigned long long) server.cluster->currentEpoch); return; } @@ -2984,16 +3060,16 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { { if (nodeIsMaster(node)) { serverLog(LL_WARNING, - "Failover auth denied to %.40s: it is a master node", - node->name); + "Failover auth denied to %.40s %s: it is a master node", + node->name, node->human_readable_name); } else if (master == NULL) { serverLog(LL_WARNING, - "Failover auth denied to %.40s: I don't know its master", - node->name); + "Failover auth denied to %.40s %s: I don't know its master", + node->name, node->human_readable_name); } else if (!nodeFailed(master)) { serverLog(LL_WARNING, - "Failover auth denied to %.40s: its master is up", - node->name); + "Failover auth denied to %.40s %s: its master is up", + node->name, node->human_readable_name); } return; } @@ -3004,9 +3080,9 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { if (mstime() - node->slaveof->voted_time < server.cluster_node_timeout * 2) { serverLog(LL_WARNING, - "Failover auth denied to %.40s: " + "Failover auth denied to %.40s %s: " "can't vote about this master before %lld milliseconds", - node->name, + node->name, node->human_readable_name, (long long) ((server.cluster_node_timeout*2)- (mstime() - node->slaveof->voted_time))); return; @@ -3026,9 +3102,9 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { * is served by a master with a greater configEpoch than the one claimed * by the slave requesting our vote. Refuse to vote for this slave. */ serverLog(LL_WARNING, - "Failover auth denied to %.40s: " + "Failover auth denied to %.40s %s: " "slot %d epoch (%llu) > reqEpoch (%llu)", - node->name, j, + node->name, node->human_readable_name, j, (unsigned long long) server.cluster->slots[j]->configEpoch, (unsigned long long) requestConfigEpoch); return; @@ -3039,8 +3115,8 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { node->slaveof->voted_time = mstime(); clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|CLUSTER_TODO_FSYNC_CONFIG); clusterSendFailoverAuth(node); - serverLog(LL_WARNING, "Failover auth granted to %.40s for epoch %llu", - node->name, (unsigned long long) server.cluster->currentEpoch); + serverLog(LL_WARNING, "Failover auth granted to %.40s %s for epoch %llu", + node->name, node->human_readable_name, (unsigned long long) server.cluster->currentEpoch); } /* This function returns the "rank" of this instance, a slave, in the context @@ -3268,7 +3344,7 @@ void clusterHandleSlaveFailover(void) { if (server.cluster->mf_end) { server.cluster->failover_auth_time = mstime(); server.cluster->failover_auth_rank = 0; - clusterDoBeforeSleep(CLUSTER_TODO_HANDLE_FAILOVER); + clusterDoBeforeSleep(CLUSTER_TODO_HANDLE_FAILOVER); } serverLog(LL_WARNING, "Start of election delayed for %lld milliseconds " @@ -3457,8 +3533,8 @@ void clusterHandleSlaveMigration(int max_slaves) { (mstime()-target->orphaned_time) > CLUSTER_SLAVE_MIGRATION_DELAY && !(server.cluster_module_flags & CLUSTER_MODULE_FLAG_NO_FAILOVER)) { - serverLog(LL_WARNING,"Migrating to orphaned master %.40s", - target->name); + serverLog(LL_WARNING,"Migrating to orphaned master %.40s %s", + target->name, target->human_readable_name); clusterSetMaster(target); } } @@ -3685,7 +3761,7 @@ void clusterCron(void) { } } if (min_pong_node) { - serverLog(LL_DEBUG,"Pinging node %.40s", min_pong_node->name); + serverLog(LL_DEBUG,"Pinging node %.40s %s", min_pong_node->name, min_pong_node->human_readable_name); clusterSendPing(min_pong_node->link, CLUSTERMSG_TYPE_PING); } } @@ -3785,8 +3861,8 @@ void clusterCron(void) { /* Timeout reached. Set the node as possibly failing if it is * not already in this state. */ if (!(node->flags & (CLUSTER_NODE_PFAIL|CLUSTER_NODE_FAIL))) { - serverLog(LL_DEBUG,"*** NODE %.40s possibly failing", - node->name); + serverLog(LL_DEBUG,"*** NODE %.40s %s possibly failing", + node->name, node->human_readable_name); node->flags |= CLUSTER_NODE_PFAIL; update_state = 1; } @@ -3818,7 +3894,7 @@ void clusterCron(void) { * a migration if there is no master with at least *two* working * slaves. */ if (orphaned_masters && max_slaves >= 2 && this_slaves == max_slaves && - server.cluster_allow_replica_migration) + server.cluster_allow_replica_migration) clusterHandleSlaveMigration(max_slaves); } @@ -4242,7 +4318,14 @@ sds clusterGenNodeDescription(clusterNode *node, int use_pport) { int port = use_pport && node->pport ? node->pport : node->port; /* Node coordinates */ - ci = sdscatlen(sdsempty(),node->name,CLUSTER_NAMELEN); + ci = sdscatlen(sdsempty(),node->name,CLUSTER_NAMELEN); + + /* Human readable name of node */ + if (node->human_readable_name[0] == '\0') + ci = sdscatfmt(ci," -",node->human_readable_name); + else + ci = sdscatfmt(ci," %s",node->human_readable_name); + ci = sdscatfmt(ci," %s:%i@%i ", node->ip, port, @@ -4258,6 +4341,9 @@ sds clusterGenNodeDescription(clusterNode *node, int use_pport) { else ci = sdscatlen(ci,"-",1); + /* Adding has human readable name */ + ci = sdscatfmt(ci," %i",node->has_human_readable_name); + unsigned long long nodeEpoch = node->configEpoch; if (nodeIsSlave(node) && node->slaveof) { nodeEpoch = node->slaveof->configEpoch; @@ -4581,9 +4667,13 @@ void clusterCommand(client *c) { " Connect nodes into a working cluster.", "MYID", " Return the node id.", +"MYNAME", +" Return the human readable node name.", +"SETNAME ", +" Sets the human-readable node name.", "NODES", " Return cluster configuration seen by node. Output format:", -" ...", +" ...", "REPLICATE ", " Configure current node as replica to .", "RESET [HARD|SOFT]", @@ -4642,6 +4732,18 @@ NULL } else if (!strcasecmp(c->argv[1]->ptr,"myid") && c->argc == 2) { /* CLUSTER MYID */ addReplyBulkCBuffer(c,myself->name, CLUSTER_NAMELEN); + } else if (!strcasecmp(c->argv[1]->ptr,"myname") && c->argc == 2) { + /* CLUSTER MYNAME */ + if (myself->human_readable_name[0] != '\0') + addReplyBulkCBuffer(c,myself->human_readable_name, strlen(myself->human_readable_name)); + else + addReplyError(c,"Node is not assigned name yet."); + } else if (!strcasecmp(c->argv[1]->ptr,"setname") && c->argc == 3) { + /* CLUSTER SETNAME */ + if (setManualClusterNodeName(myself,c->argv[2]->ptr)) + addReply(c,shared.ok); + else + addReplyError(c,"Error setting the name of the node."); } else if (!strcasecmp(c->argv[1]->ptr,"slots") && c->argc == 2) { /* CLUSTER SLOTS */ clusterReplyMultiBulkSlots(c); diff --git a/src/cluster.h b/src/cluster.h index f9781477561..14832a653cd 100644 --- a/src/cluster.h +++ b/src/cluster.h @@ -6,9 +6,10 @@ *----------------------------------------------------------------------------*/ #define CLUSTER_SLOTS 16384 -#define CLUSTER_OK 0 /* Everything looks ok */ -#define CLUSTER_FAIL 1 /* The cluster can't work */ -#define CLUSTER_NAMELEN 40 /* sha1 hex length */ +#define CLUSTER_OK 0 /* Everything looks ok */ +#define CLUSTER_FAIL 1 /* The cluster can't work */ +#define CLUSTER_NAMELEN 40 /* sha1 hex length */ +#define CLUSTER_HUMAN_NAMELEN 64 /* Max length of human readable node name */ #define CLUSTER_PORT_INCR 10000 /* Cluster port = baseport + PORT_INCR */ /* The following defines are amount of time, sometimes expressed as @@ -113,6 +114,7 @@ typedef struct clusterNodeFailReport { typedef struct clusterNode { mstime_t ctime; /* Node object creation time. */ char name[CLUSTER_NAMELEN]; /* Node name, hex string, sha1-size */ + char human_readable_name[CLUSTER_HUMAN_NAMELEN]; /* Human readable name for node */ int flags; /* CLUSTER_NODE_... */ uint64_t configEpoch; /* Last configEpoch observed for this node */ unsigned char slots[CLUSTER_SLOTS/8]; /* slots handled by this node */ @@ -139,6 +141,7 @@ typedef struct clusterNode { int cport; /* Latest known cluster port of this node. */ clusterLink *link; /* TCP/IP link with this node */ list *fail_reports; /* List of nodes signaling this as failing */ + int has_human_readable_name; /* Indicates whether custom nodename is used */ } clusterNode; /* State for the Slot to Key API, for a single slot. The keys in the same slot @@ -206,12 +209,14 @@ typedef struct { char nodename[CLUSTER_NAMELEN]; uint32_t ping_sent; uint32_t pong_received; - char ip[NET_IP_STR_LEN]; /* IP address last time it was seen */ - uint16_t port; /* base port last time it was seen */ - uint16_t cport; /* cluster port last time it was seen */ - uint16_t flags; /* node->flags copy */ - uint16_t pport; /* plaintext-port, when base port is TLS */ + char ip[NET_IP_STR_LEN]; /* IP address last time it was seen */ + char human_readable_name[CLUSTER_HUMAN_NAMELEN]; /* Human readable name for node */ + uint16_t port; /* base port last time it was seen */ + uint16_t cport; /* cluster port last time it was seen */ + uint16_t flags; /* node->flags copy */ + uint16_t pport; /* plaintext-port, when base port is TLS */ uint16_t notused1; + int has_human_readable_name; /* Indicates whether custom nodename is used */ } clusterMsgDataGossip; typedef struct { @@ -284,13 +289,15 @@ typedef struct { unsigned char myslots[CLUSTER_SLOTS/8]; char slaveof[CLUSTER_NAMELEN]; char myip[NET_IP_STR_LEN]; /* Sender IP, if not all zeroed. */ - char notused1[32]; /* 32 bytes reserved for future usage. */ + char human_readable_name[CLUSTER_HUMAN_NAMELEN]; /* Human readable name assigned to the sender */ + char notused1[32]; /* 32 bytes reserved for future usage. */ uint16_t pport; /* Sender TCP plaintext port, if base port is TLS */ uint16_t cport; /* Sender TCP cluster bus port */ uint16_t flags; /* Sender node flags */ unsigned char state; /* Cluster state from the POV of the sender */ unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */ union clusterMsgData data; + int has_human_readable_name; /* Indicates whether custom nodename is used */ } clusterMsg; #define CLUSTERMSG_MIN_LEN (sizeof(clusterMsg)-sizeof(union clusterMsgData)) diff --git a/src/redis-cli.c b/src/redis-cli.c index 060f3ef667f..e3a4419199e 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -4006,8 +4006,10 @@ static int clusterManagerNodeLoadInfo(clusterManagerNode *node, int opts, lines = p + 1; char *name = NULL, *addr = NULL, *flags = NULL, *master_id = NULL, *ping_sent = NULL, *ping_recv = NULL, *config_epoch = NULL, - *link_status = NULL; + *link_status = NULL, *human_readable_name = NULL, *has_human_readable_name = NULL; UNUSED(link_status); + UNUSED(human_readable_name); + UNUSED(has_human_readable_name); int i = 0; while ((p = strchr(line, ' ')) != NULL) { *p = '\0'; @@ -4015,15 +4017,17 @@ static int clusterManagerNodeLoadInfo(clusterManagerNode *node, int opts, line = p + 1; switch(i++){ case 0: name = token; break; - case 1: addr = token; break; - case 2: flags = token; break; - case 3: master_id = token; break; - case 4: ping_sent = token; break; - case 5: ping_recv = token; break; - case 6: config_epoch = token; break; - case 7: link_status = token; break; + case 1: human_readable_name = token; break; + case 2: addr = token; break; + case 3: flags = token; break; + case 4: master_id = token; break; + case 5: has_human_readable_name = token; break; + case 6: ping_sent = token; break; + case 7: ping_recv = token; break; + case 8: config_epoch = token; break; + case 9: link_status = token; break; } - if (i == 8) break; // Slots + if (i == 10) break; // Slots } if (!flags) { success = 0; @@ -4035,7 +4039,7 @@ static int clusterManagerNodeLoadInfo(clusterManagerNode *node, int opts, node->flags |= CLUSTER_MANAGER_FLAG_MYSELF; currentNode = node; clusterManagerNodeResetSlots(node); - if (i == 8) { + if (i == 10) { int remaining = strlen(line); while (remaining > 0) { p = strchr(line, ' '); diff --git a/src/server.c b/src/server.c index 5f76b96123d..b02e3202304 100644 --- a/src/server.c +++ b/src/server.c @@ -597,6 +597,12 @@ struct redisCommand clusterSubcommands[] = { {"myid",clusterCommand,2, "ok-stale random"}, + {"myname",clusterCommand,2, + "ok-stale random"}, + + {"setname",clusterCommand,3, + "ok-stale random"}, + {"nodes",clusterCommand,2, "ok-stale random"}, diff --git a/tests/cluster/cluster.tcl b/tests/cluster/cluster.tcl index e9578928242..91bff65e624 100644 --- a/tests/cluster/cluster.tcl +++ b/tests/cluster/cluster.tcl @@ -18,14 +18,16 @@ proc get_cluster_nodes id { set args [split $l] set node [dict create \ id [lindex $args 0] \ - addr [lindex $args 1] \ - flags [split [lindex $args 2] ,] \ - slaveof [lindex $args 3] \ - ping_sent [lindex $args 4] \ - pong_recv [lindex $args 5] \ - config_epoch [lindex $args 6] \ - linkstate [lindex $args 7] \ - slots [lrange $args 8 end] \ + name [lindex $args 1] \ + addr [lindex $args 2] \ + flags [split [lindex $args 3] ,] \ + slaveof [lindex $args 4] \ + customName [lindex $args 5] \ + ping_sent [lindex $args 6] \ + pong_recv [lindex $args 7] \ + config_epoch [lindex $args 8] \ + linkstate [lindex $args 9] \ + slots [lrange $args 10 end] \ ] lappend nodes $node } diff --git a/tests/support/cluster.tcl b/tests/support/cluster.tcl index df4b7f3d031..25e809ffc49 100644 --- a/tests/support/cluster.tcl +++ b/tests/support/cluster.tcl @@ -102,8 +102,8 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { set line [string trim $line] if {$line eq {}} continue set args [split $line " "] - lassign $args nodeid addr flags slaveof pingsent pongrecv configepoch linkstate - set slots [lrange $args 8 end] + lassign $args nodeid name addr flags slaveof customname pingsent pongrecv configepoch linkstate + set slots [lrange $args 10 end] set addr [lindex [split $addr @] 0] if {$addr eq {:0}} { set addr $start_host:$start_port @@ -118,11 +118,13 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { # Build this node description as an hash. set node [dict create \ id $nodeid \ + name $name \ addr $addr \ host $host \ port $port \ flags $flags \ slaveof $slaveof \ + customname $customname \ slots $slots \ link $link \ ]