Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
a445aa30
Commit
a445aa30
authored
Sep 26, 2013
by
antirez
Browse files
Cluster: master node now uses new protocol to vote.
parent
fb9b76fe
Changes
2
Show whitespace changes
Inline
Side-by-side
src/cluster.c
View file @
a445aa30
...
@@ -258,6 +258,7 @@ void clusterInit(void) {
...
@@ -258,6 +258,7 @@ void clusterInit(void) {
server.cluster->failover_auth_time = 0;
server.cluster->failover_auth_time = 0;
server.cluster->failover_auth_count = 0;
server.cluster->failover_auth_count = 0;
server.cluster->failover_auth_epoch = 0;
server.cluster->failover_auth_epoch = 0;
server.cluster->last_vote_epoch = 0;
memset(server.cluster->migrating_slots_to,0,
memset(server.cluster->migrating_slots_to,0,
sizeof(server.cluster->migrating_slots_to));
sizeof(server.cluster->migrating_slots_to));
memset(server.cluster->importing_slots_from,0,
memset(server.cluster->importing_slots_from,0,
...
@@ -396,6 +397,7 @@ clusterNode *createClusterNode(char *nodename, int flags) {
...
@@ -396,6 +397,7 @@ clusterNode *createClusterNode(char *nodename, int flags) {
memset(node->ip,0,sizeof(node->ip));
memset(node->ip,0,sizeof(node->ip));
node->port = 0;
node->port = 0;
node->fail_reports = listCreate();
node->fail_reports = listCreate();
node->voted_time = 0;
listSetFreeMethod(node->fail_reports,zfree);
listSetFreeMethod(node->fail_reports,zfree);
return node;
return node;
}
}
...
@@ -1178,15 +1180,18 @@ int clusterProcessPacket(clusterLink *link) {
...
@@ -1178,15 +1180,18 @@ int clusterProcessPacket(clusterLink *link) {
}
}
} else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST) {
} else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST) {
if (!sender) return 1; /* We don't know that node. */
if (!sender) return 1; /* We don't know that node. */
/* If we are not a master, ignore that message at all. */
if (!(server.cluster->myself->flags & REDIS_NODE_MASTER)) return 0;
clusterSendFailoverAuthIfNeeded(sender,hdr);
clusterSendFailoverAuthIfNeeded(sender,hdr);
} else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK) {
} else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK) {
if (!sender) return 1; /* We don't know that node. */
if (!sender) return 1; /* We don't know that node. */
/* If this is a master, increment the number of acknowledges
/* We consider this vote only if the sender if a master serving
* we received so far. */
* a non zero number of slots, with the currentEpoch that is equal
if (sender->flags & REDIS_NODE_MASTER)
* to our currentEpoch. */
if (sender->flags & REDIS_NODE_MASTER &&
sender->numslots > 0 &&
senderCurrentEpoch == server.cluster->currentEpoch)
{
server.cluster->failover_auth_count++;
server.cluster->failover_auth_count++;
}
} else {
} else {
redisLog(REDIS_WARNING,"Received unknown packet type: %d", type);
redisLog(REDIS_WARNING,"Received unknown packet type: %d", type);
}
}
...
@@ -1538,43 +1543,38 @@ void clusterSendFailoverAuth(clusterNode *node, uint64_t reqtime) {
...
@@ -1538,43 +1543,38 @@ void clusterSendFailoverAuth(clusterNode *node, uint64_t reqtime) {
clusterSendMessage(node->link,buf,totlen);
clusterSendMessage(node->link,buf,totlen);
}
}
/* If we believe 'node' is the "first slave" of it's master, reply with
/* Vote for the node asking for our vote if there are the conditions. */
* a FAILOVER_AUTH_GRANTED packet.
* The 'request' field points to the authorization request packet header, we
* need it in order to copy back the 'time' field in our reply.
*
* To be a first slave the sender must:
* 1) Be a slave.
* 2) Its master should be in FAIL state.
* 3) Ordering all the slaves IDs for its master by run-id, it should be the
* first (the smallest) among the ones not in FAIL / PFAIL state.
*/
void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {
void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {
char first[REDIS_CLUSTER_NAMELEN];
clusterNode *master = node->slaveof;
clusterNode *master = node->slaveof;
int j;
uint64_t requestEpoch = ntohu64(request->currentEpoch);
/* IF we are not a master serving at least 1 slot, we don't have the
* right to vote, as the cluster size in Redis Cluster is the number
* of masters serving at least one slot, and quorum is the cluster size + 1 */
if (!(server.cluster->myself->flags & REDIS_NODE_MASTER)) return;
if (server.cluster->myself->numslots == 0) return;
/* Request epoch must be >= our currentEpoch. */
if (requestEpoch < server.cluster->currentEpoch) return;
/* Node is a slave? Its master is down? */
/* I already voted for this epoch? Return ASAP. */
if (server.cluster->last_vote_epoch == server.cluster->currentEpoch) return;
/* Node must be a slave and its master down. */
if (!(node->flags & REDIS_NODE_SLAVE) ||
if (!(node->flags & REDIS_NODE_SLAVE) ||
master == NULL ||
master == NULL ||
!(master->flags & REDIS_NODE_FAIL)) return;
!(master->flags & REDIS_NODE_FAIL)) return;
/* Iterate all the master slaves to check what's the first one. */
/* We did not voted for a slave about this master for two
memset(first,0xff,sizeof(first));
* times the node timeout. This is not strictly needed for correctness
for (j = 0; j < master->numslaves; j++) {
* of the algorithm but makes the base case more linear. */
clusterNode *slave = master->slaves[j];
if (server.unixtime - node->slaveof->voted_time <
server.cluster_node_timeout * 2) return;
if (slave->flags & (REDIS_NODE_FAIL|REDIS_NODE_PFAIL)) continue;
if (memcmp(slave->name,first,sizeof(first)) < 0) {
memcpy(first,slave->name,sizeof(first));
}
}
/* Is 'node' the first slave? */
if (memcmp(node->name,first,sizeof(first)) != 0) return;
/* We can
send the packet
. */
/* We can
vote for this slave
. */
clusterSendFailoverAuth(node,request->time);
clusterSendFailoverAuth(node,request->time);
server.cluster->last_vote_epoch = server.cluster->currentEpoch;
node->slaveof->voted_time = server.unixtime;
}
}
/* This function is called if we are a slave node and our master serving
/* This function is called if we are a slave node and our master serving
...
@@ -1583,8 +1583,7 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {
...
@@ -1583,8 +1583,7 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {
* The gaol of this function is:
* The gaol of this function is:
* 1) To check if we are able to perform a failover, is our data updated?
* 1) To check if we are able to perform a failover, is our data updated?
* 2) Try to get elected by masters.
* 2) Try to get elected by masters.
* 3) Check if there is the majority of masters agreeing we should failover.
* 3) Perform the failover informing all the other nodes.
* 4) Perform the failover informing all the other nodes.
*/
*/
void clusterHandleSlaveFailover(void) {
void clusterHandleSlaveFailover(void) {
time_t data_age = server.unixtime - server.repl_down_since;
time_t data_age = server.unixtime - server.repl_down_since;
...
...
src/redis.h
View file @
a445aa30
...
@@ -628,6 +628,7 @@ struct clusterNode {
...
@@ -628,6 +628,7 @@ struct clusterNode {
time_t
ping_sent
;
/* Unix time we sent latest ping */
time_t
ping_sent
;
/* Unix time we sent latest ping */
time_t
pong_received
;
/* Unix time we received the pong */
time_t
pong_received
;
/* Unix time we received the pong */
time_t
fail_time
;
/* Unix time when FAIL flag was set */
time_t
fail_time
;
/* Unix time when FAIL flag was set */
time_t
voted_time
;
/* Last time we voted for a slave of this master */
char
ip
[
REDIS_IP_STR_LEN
];
/* Latest known IP address of this node */
char
ip
[
REDIS_IP_STR_LEN
];
/* Latest known IP address of this node */
int
port
;
/* Latest known port of this node */
int
port
;
/* Latest known port of this node */
clusterLink
*
link
;
/* TCP/IP link with this node */
clusterLink
*
link
;
/* TCP/IP link with this node */
...
@@ -650,6 +651,8 @@ typedef struct {
...
@@ -650,6 +651,8 @@ typedef struct {
int
failover_auth_count
;
/* Number of votes received so far. */
int
failover_auth_count
;
/* Number of votes received so far. */
int
failover_auth_sent
;
/* True if we already asked for votes. */
int
failover_auth_sent
;
/* True if we already asked for votes. */
uint64_t
failover_auth_epoch
;
/* Epoch of the current election. */
uint64_t
failover_auth_epoch
;
/* Epoch of the current election. */
/* The followign fields are uesd by masters to take state on elections. */
uint64_t
last_vote_epoch
;
/* Epoch of the last vote granted. */
}
clusterState
;
}
clusterState
;
/* Redis cluster messages header */
/* Redis cluster messages header */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment