1 /* Redis Sentinel implementation 2 * 3 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * * Neither the name of Redis nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without 16 * specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "redis.h" 32 #include "hiredis.h" 33 #include "async.h" 34 35 #include <ctype.h> 36 #include <arpa/inet.h> 37 #include <sys/socket.h> 38 #include <sys/wait.h> 39 #include <fcntl.h> 40 41 extern char **environ; 42 43 #define REDIS_SENTINEL_PORT 26379 44 45 /* ======================== Sentinel global state =========================== */ 46 47 /* Address object, used to describe an ip:port pair. */ 48 typedef struct sentinelAddr { 49 char *ip; 50 int port; 51 } sentinelAddr; 52 53 /* A Sentinel Redis Instance object is monitoring. */ 54 #define SRI_MASTER (1<<0) 55 #define SRI_SLAVE (1<<1) 56 #define SRI_SENTINEL (1<<2) 57 #define SRI_DISCONNECTED (1<<3) 58 #define SRI_S_DOWN (1<<4) /* Subjectively down (no quorum). */ 59 #define SRI_O_DOWN (1<<5) /* Objectively down (confirmed by others). */ 60 #define SRI_MASTER_DOWN (1<<6) /* A Sentinel with this flag set thinks that 61 its master is down. */ 62 #define SRI_FAILOVER_IN_PROGRESS (1<<7) /* Failover is in progress for 63 this master. */ 64 #define SRI_PROMOTED (1<<8) /* Slave selected for promotion. */ 65 #define SRI_RECONF_SENT (1<<9) /* SLAVEOF <newmaster> sent. */ 66 #define SRI_RECONF_INPROG (1<<10) /* Slave synchronization in progress. */ 67 #define SRI_RECONF_DONE (1<<11) /* Slave synchronized with new master. */ 68 #define SRI_FORCE_FAILOVER (1<<12) /* Force failover with master up. */ 69 #define SRI_SCRIPT_KILL_SENT (1<<13) /* SCRIPT KILL already sent on -BUSY */ 70 71 /* Note: times are in milliseconds. */ 72 #define SENTINEL_INFO_PERIOD 10000 73 #define SENTINEL_PING_PERIOD 1000 74 #define SENTINEL_ASK_PERIOD 1000 75 #define SENTINEL_PUBLISH_PERIOD 2000 76 #define SENTINEL_DEFAULT_DOWN_AFTER 30000 77 #define SENTINEL_HELLO_CHANNEL "__sentinel__:hello" 78 #define SENTINEL_TILT_TRIGGER 2000 79 #define SENTINEL_TILT_PERIOD (SENTINEL_PING_PERIOD*30) 80 #define SENTINEL_DEFAULT_SLAVE_PRIORITY 100 81 #define SENTINEL_SLAVE_RECONF_TIMEOUT 10000 82 #define SENTINEL_DEFAULT_PARALLEL_SYNCS 1 83 #define SENTINEL_MIN_LINK_RECONNECT_PERIOD 15000 84 #define SENTINEL_DEFAULT_FAILOVER_TIMEOUT (60*3*1000) 85 #define SENTINEL_MAX_PENDING_COMMANDS 100 86 #define SENTINEL_ELECTION_TIMEOUT 10000 87 #define SENTINEL_MAX_DESYNC 1000 88 89 /* Failover machine different states. */ 90 #define SENTINEL_FAILOVER_STATE_NONE 0 /* No failover in progress. */ 91 #define SENTINEL_FAILOVER_STATE_WAIT_START 1 /* Wait for failover_start_time*/ 92 #define SENTINEL_FAILOVER_STATE_SELECT_SLAVE 2 /* Select slave to promote */ 93 #define SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE 3 /* Slave -> Master */ 94 #define SENTINEL_FAILOVER_STATE_WAIT_PROMOTION 4 /* Wait slave to change role */ 95 #define SENTINEL_FAILOVER_STATE_RECONF_SLAVES 5 /* SLAVEOF newmaster */ 96 #define SENTINEL_FAILOVER_STATE_UPDATE_CONFIG 6 /* Monitor promoted slave. */ 97 98 #define SENTINEL_MASTER_LINK_STATUS_UP 0 99 #define SENTINEL_MASTER_LINK_STATUS_DOWN 1 100 101 /* Generic flags that can be used with different functions. 102 * They use higher bits to avoid colliding with the function specific 103 * flags. */ 104 #define SENTINEL_NO_FLAGS 0 105 #define SENTINEL_GENERATE_EVENT (1<<16) 106 #define SENTINEL_LEADER (1<<17) 107 #define SENTINEL_OBSERVER (1<<18) 108 109 /* Script execution flags and limits. */ 110 #define SENTINEL_SCRIPT_NONE 0 111 #define SENTINEL_SCRIPT_RUNNING 1 112 #define SENTINEL_SCRIPT_MAX_QUEUE 256 113 #define SENTINEL_SCRIPT_MAX_RUNNING 16 114 #define SENTINEL_SCRIPT_MAX_RUNTIME 60000 /* 60 seconds max exec time. */ 115 #define SENTINEL_SCRIPT_MAX_RETRY 10 116 #define SENTINEL_SCRIPT_RETRY_DELAY 30000 /* 30 seconds between retries. */ 117 118 typedef struct sentinelRedisInstance { 119 int flags; /* See SRI_... defines */ 120 char *name; /* Master name from the point of view of this sentinel. */ 121 char *runid; /* run ID of this instance. */ 122 uint64_t config_epoch; /* Configuration epoch. */ 123 sentinelAddr *addr; /* Master host. */ 124 redisAsyncContext *cc; /* Hiredis context for commands. */ 125 redisAsyncContext *pc; /* Hiredis context for Pub / Sub. */ 126 int pending_commands; /* Number of commands sent waiting for a reply. */ 127 mstime_t cc_conn_time; /* cc connection time. */ 128 mstime_t pc_conn_time; /* pc connection time. */ 129 mstime_t pc_last_activity; /* Last time we received any message. */ 130 mstime_t last_avail_time; /* Last time the instance replied to ping with 131 a reply we consider valid. */ 132 mstime_t last_ping_time; /* Last time a pending ping was sent in the 133 context of the current command connection 134 with the instance. 0 if still not sent or 135 if pong already received. */ 136 mstime_t last_pong_time; /* Last time the instance replied to ping, 137 whatever the reply was. That's used to check 138 if the link is idle and must be reconnected. */ 139 mstime_t last_pub_time; /* Last time we sent hello via Pub/Sub. */ 140 mstime_t last_hello_time; /* Only used if SRI_SENTINEL is set. Last time 141 we received a hello from this Sentinel 142 via Pub/Sub. */ 143 mstime_t last_master_down_reply_time; /* Time of last reply to 144 SENTINEL is-master-down command. */ 145 mstime_t s_down_since_time; /* Subjectively down since time. */ 146 mstime_t o_down_since_time; /* Objectively down since time. */ 147 mstime_t down_after_period; /* Consider it down after that period. */ 148 mstime_t info_refresh; /* Time at which we received INFO output from it. */ 149 150 /* Role and the first time we observed it. 151 * This is useful in order to delay replacing what the instance reports 152 * with our own configuration. We need to always wait some time in order 153 * to give a chance to the leader to report the new configuration before 154 * we do silly things. */ 155 int role_reported; 156 mstime_t role_reported_time; 157 mstime_t slave_conf_change_time; /* Last time slave master addr changed. */ 158 159 /* Master specific. */ 160 dict *sentinels; /* Other sentinels monitoring the same master. */ 161 dict *slaves; /* Slaves for this master instance. */ 162 unsigned int quorum;/* Number of sentinels that need to agree on failure. */ 163 int parallel_syncs; /* How many slaves to reconfigure at same time. */ 164 char *auth_pass; /* Password to use for AUTH against master & slaves. */ 165 166 /* Slave specific. */ 167 mstime_t master_link_down_time; /* Slave replication link down time. */ 168 int slave_priority; /* Slave priority according to its INFO output. */ 169 mstime_t slave_reconf_sent_time; /* Time at which we sent SLAVE OF <new> */ 170 struct sentinelRedisInstance *master; /* Master instance if it's slave. */ 171 char *slave_master_host; /* Master host as reported by INFO */ 172 int slave_master_port; /* Master port as reported by INFO */ 173 int slave_master_link_status; /* Master link status as reported by INFO */ 174 unsigned long long slave_repl_offset; /* Slave replication offset. */ 175 /* Failover */ 176 char *leader; /* If this is a master instance, this is the runid of 177 the Sentinel that should perform the failover. If 178 this is a Sentinel, this is the runid of the Sentinel 179 that this Sentinel voted as leader. */ 180 uint64_t leader_epoch; /* Epoch of the 'leader' field. */ 181 uint64_t failover_epoch; /* Epoch of the currently started failover. */ 182 int failover_state; /* See SENTINEL_FAILOVER_STATE_* defines. */ 183 mstime_t failover_state_change_time; 184 mstime_t failover_start_time; /* Last failover attempt start time. */ 185 mstime_t failover_timeout; /* Max time to refresh failover state. */ 186 mstime_t failover_delay_logged; /* For what failover_start_time value we 187 logged the failover delay. */ 188 struct sentinelRedisInstance *promoted_slave; /* Promoted slave instance. */ 189 /* Scripts executed to notify admin or reconfigure clients: when they 190 * are set to NULL no script is executed. */ 191 char *notification_script; 192 char *client_reconfig_script; 193 sds info; /* cached INFO output */ 194 } sentinelRedisInstance; 195 196 /* Main state. */ 197 struct sentinelState { 198 uint64_t current_epoch; /* Current epoch. */ 199 dict *masters; /* Dictionary of master sentinelRedisInstances. 200 Key is the instance name, value is the 201 sentinelRedisInstance structure pointer. */ 202 int tilt; /* Are we in TILT mode? */ 203 int running_scripts; /* Number of scripts in execution right now. */ 204 mstime_t tilt_start_time; /* When TITL started. */ 205 mstime_t previous_time; /* Last time we ran the time handler. */ 206 list *scripts_queue; /* Queue of user scripts to execute. */ 207 char *announce_ip; /* IP addr that is gossiped to other sentinels if 208 not NULL. */ 209 int announce_port; /* Port that is gossiped to other sentinels if 210 non zero. */ 211 } sentinel; 212 213 /* A script execution job. */ 214 typedef struct sentinelScriptJob { 215 int flags; /* Script job flags: SENTINEL_SCRIPT_* */ 216 int retry_num; /* Number of times we tried to execute it. */ 217 char **argv; /* Arguments to call the script. */ 218 mstime_t start_time; /* Script execution time if the script is running, 219 otherwise 0 if we are allowed to retry the 220 execution at any time. If the script is not 221 running and it's not 0, it means: do not run 222 before the specified time. */ 223 pid_t pid; /* Script execution pid. */ 224 } sentinelScriptJob; 225 226 /* ======================= hiredis ae.c adapters ============================= 227 * Note: this implementation is taken from hiredis/adapters/ae.h, however 228 * we have our modified copy for Sentinel in order to use our allocator 229 * and to have full control over how the adapter works. */ 230 231 typedef struct redisAeEvents { 232 redisAsyncContext *context; 233 aeEventLoop *loop; 234 int fd; 235 int reading, writing; 236 } redisAeEvents; 237 238 static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 239 ((void)el); ((void)fd); ((void)mask); 240 241 redisAeEvents *e = (redisAeEvents*)privdata; 242 redisAsyncHandleRead(e->context); 243 } 244 245 static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 246 ((void)el); ((void)fd); ((void)mask); 247 248 redisAeEvents *e = (redisAeEvents*)privdata; 249 redisAsyncHandleWrite(e->context); 250 } 251 252 static void redisAeAddRead(void *privdata) { 253 redisAeEvents *e = (redisAeEvents*)privdata; 254 aeEventLoop *loop = e->loop; 255 if (!e->reading) { 256 e->reading = 1; 257 aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); 258 } 259 } 260 261 static void redisAeDelRead(void *privdata) { 262 redisAeEvents *e = (redisAeEvents*)privdata; 263 aeEventLoop *loop = e->loop; 264 if (e->reading) { 265 e->reading = 0; 266 aeDeleteFileEvent(loop,e->fd,AE_READABLE); 267 } 268 } 269 270 static void redisAeAddWrite(void *privdata) { 271 redisAeEvents *e = (redisAeEvents*)privdata; 272 aeEventLoop *loop = e->loop; 273 if (!e->writing) { 274 e->writing = 1; 275 aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); 276 } 277 } 278 279 static void redisAeDelWrite(void *privdata) { 280 redisAeEvents *e = (redisAeEvents*)privdata; 281 aeEventLoop *loop = e->loop; 282 if (e->writing) { 283 e->writing = 0; 284 aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); 285 } 286 } 287 288 static void redisAeCleanup(void *privdata) { 289 redisAeEvents *e = (redisAeEvents*)privdata; 290 redisAeDelRead(privdata); 291 redisAeDelWrite(privdata); 292 zfree(e); 293 } 294 295 static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { 296 redisContext *c = &(ac->c); 297 redisAeEvents *e; 298 299 /* Nothing should be attached when something is already attached */ 300 if (ac->ev.data != NULL) 301 return REDIS_ERR; 302 303 /* Create container for context and r/w events */ 304 e = (redisAeEvents*)zmalloc(sizeof(*e)); 305 e->context = ac; 306 e->loop = loop; 307 e->fd = c->fd; 308 e->reading = e->writing = 0; 309 310 /* Register functions to start/stop listening for events */ 311 ac->ev.addRead = redisAeAddRead; 312 ac->ev.delRead = redisAeDelRead; 313 ac->ev.addWrite = redisAeAddWrite; 314 ac->ev.delWrite = redisAeDelWrite; 315 ac->ev.cleanup = redisAeCleanup; 316 ac->ev.data = e; 317 318 return REDIS_OK; 319 } 320 321 /* ============================= Prototypes ================================= */ 322 323 void sentinelLinkEstablishedCallback(const redisAsyncContext *c, int status); 324 void sentinelDisconnectCallback(const redisAsyncContext *c, int status); 325 void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privdata); 326 sentinelRedisInstance *sentinelGetMasterByName(char *name); 327 char *sentinelGetSubjectiveLeader(sentinelRedisInstance *master); 328 char *sentinelGetObjectiveLeader(sentinelRedisInstance *master); 329 int yesnotoi(char *s); 330 void sentinelDisconnectInstanceFromContext(const redisAsyncContext *c); 331 void sentinelKillLink(sentinelRedisInstance *ri, redisAsyncContext *c); 332 const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance *ri); 333 void sentinelAbortFailover(sentinelRedisInstance *ri); 334 void sentinelEvent(int level, char *type, sentinelRedisInstance *ri, const char *fmt, ...); 335 sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master); 336 void sentinelScheduleScriptExecution(char *path, ...); 337 void sentinelStartFailover(sentinelRedisInstance *master); 338 void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata); 339 int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port); 340 char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch); 341 void sentinelFlushConfig(void); 342 void sentinelGenerateInitialMonitorEvents(void); 343 int sentinelSendPing(sentinelRedisInstance *ri); 344 int sentinelForceHelloUpdateForMaster(sentinelRedisInstance *master); 345 346 /* ========================= Dictionary types =============================== */ 347 348 unsigned int dictSdsHash(const void *key); 349 int dictSdsKeyCompare(void *privdata, const void *key1, const void *key2); 350 void releaseSentinelRedisInstance(sentinelRedisInstance *ri); 351 352 void dictInstancesValDestructor (void *privdata, void *obj) { 353 REDIS_NOTUSED(privdata); 354 releaseSentinelRedisInstance(obj); 355 } 356 357 /* Instance name (sds) -> instance (sentinelRedisInstance pointer) 358 * 359 * also used for: sentinelRedisInstance->sentinels dictionary that maps 360 * sentinels ip:port to last seen time in Pub/Sub hello message. */ 361 dictType instancesDictType = { 362 dictSdsHash, /* hash function */ 363 NULL, /* key dup */ 364 NULL, /* val dup */ 365 dictSdsKeyCompare, /* key compare */ 366 NULL, /* key destructor */ 367 dictInstancesValDestructor /* val destructor */ 368 }; 369 370 /* Instance runid (sds) -> votes (long casted to void*) 371 * 372 * This is useful into sentinelGetObjectiveLeader() function in order to 373 * count the votes and understand who is the leader. */ 374 dictType leaderVotesDictType = { 375 dictSdsHash, /* hash function */ 376 NULL, /* key dup */ 377 NULL, /* val dup */ 378 dictSdsKeyCompare, /* key compare */ 379 NULL, /* key destructor */ 380 NULL /* val destructor */ 381 }; 382 383 /* =========================== Initialization =============================== */ 384 385 void sentinelCommand(redisClient *c); 386 void sentinelInfoCommand(redisClient *c); 387 void sentinelSetCommand(redisClient *c); 388 void sentinelPublishCommand(redisClient *c); 389 void sentinelRoleCommand(redisClient *c); 390 391 struct redisCommand sentinelcmds[] = { 392 {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0}, 393 {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0}, 394 {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0}, 395 {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, 396 {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0}, 397 {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, 398 {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0}, 399 {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0}, 400 {"role",sentinelRoleCommand,1,"l",0,NULL,0,0,0,0,0}, 401 {"client",clientCommand,-2,"rs",0,NULL,0,0,0,0,0}, 402 {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0} 403 }; 404 405 /* This function overwrites a few normal Redis config default with Sentinel 406 * specific defaults. */ 407 void initSentinelConfig(void) { 408 server.port = REDIS_SENTINEL_PORT; 409 } 410 411 /* Perform the Sentinel mode initialization. */ 412 void initSentinel(void) { 413 unsigned int j; 414 415 /* Remove usual Redis commands from the command table, then just add 416 * the SENTINEL command. */ 417 dictEmpty(server.commands,NULL); 418 for (j = 0; j < sizeof(sentinelcmds)/sizeof(sentinelcmds[0]); j++) { 419 int retval; 420 struct redisCommand *cmd = sentinelcmds+j; 421 422 retval = dictAdd(server.commands, sdsnew(cmd->name), cmd); 423 redisAssert(retval == DICT_OK); 424 } 425 426 /* Initialize various data structures. */ 427 sentinel.current_epoch = 0; 428 sentinel.masters = dictCreate(&instancesDictType,NULL); 429 sentinel.tilt = 0; 430 sentinel.tilt_start_time = 0; 431 sentinel.previous_time = mstime(); 432 sentinel.running_scripts = 0; 433 sentinel.scripts_queue = listCreate(); 434 sentinel.announce_ip = NULL; 435 sentinel.announce_port = 0; 436 } 437 438 /* This function gets called when the server is in Sentinel mode, started, 439 * loaded the configuration, and is ready for normal operations. */ 440 void sentinelIsRunning(void) { 441 redisLog(REDIS_WARNING,"Sentinel runid is %s", server.runid); 442 443 if (server.configfile == NULL) { 444 redisLog(REDIS_WARNING, 445 "Sentinel started without a config file. Exiting..."); 446 exit(1); 447 } else if (access(server.configfile,W_OK) == -1) { 448 redisLog(REDIS_WARNING, 449 "Sentinel config file %s is not writable: %s. Exiting...", 450 server.configfile,strerror(errno)); 451 exit(1); 452 } 453 454 /* We want to generate a +monitor event for every configured master 455 * at startup. */ 456 sentinelGenerateInitialMonitorEvents(); 457 } 458 459 /* ============================== sentinelAddr ============================== */ 460 461 /* Create a sentinelAddr object and return it on success. 462 * On error NULL is returned and errno is set to: 463 * ENOENT: Can't resolve the hostname. 464 * EINVAL: Invalid port number. 465 */ 466 sentinelAddr *createSentinelAddr(char *hostname, int port) { 467 char ip[REDIS_IP_STR_LEN]; 468 sentinelAddr *sa; 469 470 if (port <= 0 || port > 65535) { 471 errno = EINVAL; 472 return NULL; 473 } 474 if (anetResolve(NULL,hostname,ip,sizeof(ip)) == ANET_ERR) { 475 errno = ENOENT; 476 return NULL; 477 } 478 sa = zmalloc(sizeof(*sa)); 479 sa->ip = sdsnew(ip); 480 sa->port = port; 481 return sa; 482 } 483 484 /* Return a duplicate of the source address. */ 485 sentinelAddr *dupSentinelAddr(sentinelAddr *src) { 486 sentinelAddr *sa; 487 488 sa = zmalloc(sizeof(*sa)); 489 sa->ip = sdsnew(src->ip); 490 sa->port = src->port; 491 return sa; 492 } 493 494 /* Free a Sentinel address. Can't fail. */ 495 void releaseSentinelAddr(sentinelAddr *sa) { 496 sdsfree(sa->ip); 497 zfree(sa); 498 } 499 500 /* Return non-zero if two addresses are equal. */ 501 int sentinelAddrIsEqual(sentinelAddr *a, sentinelAddr *b) { 502 return a->port == b->port && !strcasecmp(a->ip,b->ip); 503 } 504 505 /* =========================== Events notification ========================== */ 506 507 /* Send an event to log, pub/sub, user notification script. 508 * 509 * 'level' is the log level for logging. Only REDIS_WARNING events will trigger 510 * the execution of the user notification script. 511 * 512 * 'type' is the message type, also used as a pub/sub channel name. 513 * 514 * 'ri', is the redis instance target of this event if applicable, and is 515 * used to obtain the path of the notification script to execute. 516 * 517 * The remaining arguments are printf-alike. 518 * If the format specifier starts with the two characters "%@" then ri is 519 * not NULL, and the message is prefixed with an instance identifier in the 520 * following format: 521 * 522 * <instance type> <instance name> <ip> <port> 523 * 524 * If the instance type is not master, than the additional string is 525 * added to specify the originating master: 526 * 527 * @ <master name> <master ip> <master port> 528 * 529 * Any other specifier after "%@" is processed by printf itself. 530 */ 531 void sentinelEvent(int level, char *type, sentinelRedisInstance *ri, 532 const char *fmt, ...) { 533 va_list ap; 534 char msg[REDIS_MAX_LOGMSG_LEN]; 535 robj *channel, *payload; 536 537 /* Handle %@ */ 538 if (fmt[0] == '%' && fmt[1] == '@') { 539 sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? 540 NULL : ri->master; 541 542 if (master) { 543 snprintf(msg, sizeof(msg), "%s %s %s %d @ %s %s %d", 544 sentinelRedisInstanceTypeStr(ri), 545 ri->name, ri->addr->ip, ri->addr->port, 546 master->name, master->addr->ip, master->addr->port); 547 } else { 548 snprintf(msg, sizeof(msg), "%s %s %s %d", 549 sentinelRedisInstanceTypeStr(ri), 550 ri->name, ri->addr->ip, ri->addr->port); 551 } 552 fmt += 2; 553 } else { 554 msg[0] = '\0'; 555 } 556 557 /* Use vsprintf for the rest of the formatting if any. */ 558 if (fmt[0] != '\0') { 559 va_start(ap, fmt); 560 vsnprintf(msg+strlen(msg), sizeof(msg)-strlen(msg), fmt, ap); 561 va_end(ap); 562 } 563 564 /* Log the message if the log level allows it to be logged. */ 565 if (level >= server.verbosity) 566 redisLog(level,"%s %s",type,msg); 567 568 /* Publish the message via Pub/Sub if it's not a debugging one. */ 569 if (level != REDIS_DEBUG) { 570 channel = createStringObject(type,strlen(type)); 571 payload = createStringObject(msg,strlen(msg)); 572 pubsubPublishMessage(channel,payload); 573 decrRefCount(channel); 574 decrRefCount(payload); 575 } 576 577 /* Call the notification script if applicable. */ 578 if (level == REDIS_WARNING && ri != NULL) { 579 sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? 580 ri : ri->master; 581 if (master && master->notification_script) { 582 sentinelScheduleScriptExecution(master->notification_script, 583 type,msg,NULL); 584 } 585 } 586 } 587 588 /* This function is called only at startup and is used to generate a 589 * +monitor event for every configured master. The same events are also 590 * generated when a master to monitor is added at runtime via the 591 * SENTINEL MONITOR command. */ 592 void sentinelGenerateInitialMonitorEvents(void) { 593 dictIterator *di; 594 dictEntry *de; 595 596 di = dictGetIterator(sentinel.masters); 597 while((de = dictNext(di)) != NULL) { 598 sentinelRedisInstance *ri = dictGetVal(de); 599 sentinelEvent(REDIS_WARNING,"+monitor",ri,"%@ quorum %d",ri->quorum); 600 } 601 dictReleaseIterator(di); 602 } 603 604 /* ============================ script execution ============================ */ 605 606 /* Release a script job structure and all the associated data. */ 607 void sentinelReleaseScriptJob(sentinelScriptJob *sj) { 608 int j = 0; 609 610 while(sj->argv[j]) sdsfree(sj->argv[j++]); 611 zfree(sj->argv); 612 zfree(sj); 613 } 614 615 #define SENTINEL_SCRIPT_MAX_ARGS 16 616 void sentinelScheduleScriptExecution(char *path, ...) { 617 va_list ap; 618 char *argv[SENTINEL_SCRIPT_MAX_ARGS+1]; 619 int argc = 1; 620 sentinelScriptJob *sj; 621 622 va_start(ap, path); 623 while(argc < SENTINEL_SCRIPT_MAX_ARGS) { 624 argv[argc] = va_arg(ap,char*); 625 if (!argv[argc]) break; 626 argv[argc] = sdsnew(argv[argc]); /* Copy the string. */ 627 argc++; 628 } 629 va_end(ap); 630 argv[0] = sdsnew(path); 631 632 sj = zmalloc(sizeof(*sj)); 633 sj->flags = SENTINEL_SCRIPT_NONE; 634 sj->retry_num = 0; 635 sj->argv = zmalloc(sizeof(char*)*(argc+1)); 636 sj->start_time = 0; 637 sj->pid = 0; 638 memcpy(sj->argv,argv,sizeof(char*)*(argc+1)); 639 640 listAddNodeTail(sentinel.scripts_queue,sj); 641 642 /* Remove the oldest non running script if we already hit the limit. */ 643 if (listLength(sentinel.scripts_queue) > SENTINEL_SCRIPT_MAX_QUEUE) { 644 listNode *ln; 645 listIter li; 646 647 listRewind(sentinel.scripts_queue,&li); 648 while ((ln = listNext(&li)) != NULL) { 649 sj = ln->value; 650 651 if (sj->flags & SENTINEL_SCRIPT_RUNNING) continue; 652 /* The first node is the oldest as we add on tail. */ 653 listDelNode(sentinel.scripts_queue,ln); 654 sentinelReleaseScriptJob(sj); 655 break; 656 } 657 redisAssert(listLength(sentinel.scripts_queue) <= 658 SENTINEL_SCRIPT_MAX_QUEUE); 659 } 660 } 661 662 /* Lookup a script in the scripts queue via pid, and returns the list node 663 * (so that we can easily remove it from the queue if needed). */ 664 listNode *sentinelGetScriptListNodeByPid(pid_t pid) { 665 listNode *ln; 666 listIter li; 667 668 listRewind(sentinel.scripts_queue,&li); 669 while ((ln = listNext(&li)) != NULL) { 670 sentinelScriptJob *sj = ln->value; 671 672 if ((sj->flags & SENTINEL_SCRIPT_RUNNING) && sj->pid == pid) 673 return ln; 674 } 675 return NULL; 676 } 677 678 /* Run pending scripts if we are not already at max number of running 679 * scripts. */ 680 void sentinelRunPendingScripts(void) { 681 listNode *ln; 682 listIter li; 683 mstime_t now = mstime(); 684 685 /* Find jobs that are not running and run them, from the top to the 686 * tail of the queue, so we run older jobs first. */ 687 listRewind(sentinel.scripts_queue,&li); 688 while (sentinel.running_scripts < SENTINEL_SCRIPT_MAX_RUNNING && 689 (ln = listNext(&li)) != NULL) 690 { 691 sentinelScriptJob *sj = ln->value; 692 pid_t pid; 693 694 /* Skip if already running. */ 695 if (sj->flags & SENTINEL_SCRIPT_RUNNING) continue; 696 697 /* Skip if it's a retry, but not enough time has elapsed. */ 698 if (sj->start_time && sj->start_time > now) continue; 699 700 sj->flags |= SENTINEL_SCRIPT_RUNNING; 701 sj->start_time = mstime(); 702 sj->retry_num++; 703 pid = fork(); 704 705 if (pid == -1) { 706 /* Parent (fork error). 707 * We report fork errors as signal 99, in order to unify the 708 * reporting with other kind of errors. */ 709 sentinelEvent(REDIS_WARNING,"-script-error",NULL, 710 "%s %d %d", sj->argv[0], 99, 0); 711 sj->flags &= ~SENTINEL_SCRIPT_RUNNING; 712 sj->pid = 0; 713 } else if (pid == 0) { 714 /* Child */ 715 execve(sj->argv[0],sj->argv,environ); 716 /* If we are here an error occurred. */ 717 _exit(2); /* Don't retry execution. */ 718 } else { 719 sentinel.running_scripts++; 720 sj->pid = pid; 721 sentinelEvent(REDIS_DEBUG,"+script-child",NULL,"%ld",(long)pid); 722 } 723 } 724 } 725 726 /* How much to delay the execution of a script that we need to retry after 727 * an error? 728 * 729 * We double the retry delay for every further retry we do. So for instance 730 * if RETRY_DELAY is set to 30 seconds and the max number of retries is 10 731 * starting from the second attempt to execute the script the delays are: 732 * 30 sec, 60 sec, 2 min, 4 min, 8 min, 16 min, 32 min, 64 min, 128 min. */ 733 mstime_t sentinelScriptRetryDelay(int retry_num) { 734 mstime_t delay = SENTINEL_SCRIPT_RETRY_DELAY; 735 736 while (retry_num-- > 1) delay *= 2; 737 return delay; 738 } 739 740 /* Check for scripts that terminated, and remove them from the queue if the 741 * script terminated successfully. If instead the script was terminated by 742 * a signal, or returned exit code "1", it is scheduled to run again if 743 * the max number of retries did not already elapsed. */ 744 void sentinelCollectTerminatedScripts(void) { 745 int statloc; 746 pid_t pid; 747 748 while ((pid = wait3(&statloc,WNOHANG,NULL)) > 0) { 749 int exitcode = WEXITSTATUS(statloc); 750 int bysignal = 0; 751 listNode *ln; 752 sentinelScriptJob *sj; 753 754 if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc); 755 sentinelEvent(REDIS_DEBUG,"-script-child",NULL,"%ld %d %d", 756 (long)pid, exitcode, bysignal); 757 758 ln = sentinelGetScriptListNodeByPid(pid); 759 if (ln == NULL) { 760 redisLog(REDIS_WARNING,"wait3() returned a pid (%ld) we can't find in our scripts execution queue!", (long)pid); 761 continue; 762 } 763 sj = ln->value; 764 765 /* If the script was terminated by a signal or returns an 766 * exit code of "1" (that means: please retry), we reschedule it 767 * if the max number of retries is not already reached. */ 768 if ((bysignal || exitcode == 1) && 769 sj->retry_num != SENTINEL_SCRIPT_MAX_RETRY) 770 { 771 sj->flags &= ~SENTINEL_SCRIPT_RUNNING; 772 sj->pid = 0; 773 sj->start_time = mstime() + 774 sentinelScriptRetryDelay(sj->retry_num); 775 } else { 776 /* Otherwise let's remove the script, but log the event if the 777 * execution did not terminated in the best of the ways. */ 778 if (bysignal || exitcode != 0) { 779 sentinelEvent(REDIS_WARNING,"-script-error",NULL, 780 "%s %d %d", sj->argv[0], bysignal, exitcode); 781 } 782 listDelNode(sentinel.scripts_queue,ln); 783 sentinelReleaseScriptJob(sj); 784 sentinel.running_scripts--; 785 } 786 } 787 } 788 789 /* Kill scripts in timeout, they'll be collected by the 790 * sentinelCollectTerminatedScripts() function. */ 791 void sentinelKillTimedoutScripts(void) { 792 listNode *ln; 793 listIter li; 794 mstime_t now = mstime(); 795 796 listRewind(sentinel.scripts_queue,&li); 797 while ((ln = listNext(&li)) != NULL) { 798 sentinelScriptJob *sj = ln->value; 799 800 if (sj->flags & SENTINEL_SCRIPT_RUNNING && 801 (now - sj->start_time) > SENTINEL_SCRIPT_MAX_RUNTIME) 802 { 803 sentinelEvent(REDIS_WARNING,"-script-timeout",NULL,"%s %ld", 804 sj->argv[0], (long)sj->pid); 805 kill(sj->pid,SIGKILL); 806 } 807 } 808 } 809 810 /* Implements SENTINEL PENDING-SCRIPTS command. */ 811 void sentinelPendingScriptsCommand(redisClient *c) { 812 listNode *ln; 813 listIter li; 814 815 addReplyMultiBulkLen(c,listLength(sentinel.scripts_queue)); 816 listRewind(sentinel.scripts_queue,&li); 817 while ((ln = listNext(&li)) != NULL) { 818 sentinelScriptJob *sj = ln->value; 819 int j = 0; 820 821 addReplyMultiBulkLen(c,10); 822 823 addReplyBulkCString(c,"argv"); 824 while (sj->argv[j]) j++; 825 addReplyMultiBulkLen(c,j); 826 j = 0; 827 while (sj->argv[j]) addReplyBulkCString(c,sj->argv[j++]); 828 829 addReplyBulkCString(c,"flags"); 830 addReplyBulkCString(c, 831 (sj->flags & SENTINEL_SCRIPT_RUNNING) ? "running" : "scheduled"); 832 833 addReplyBulkCString(c,"pid"); 834 addReplyBulkLongLong(c,sj->pid); 835 836 if (sj->flags & SENTINEL_SCRIPT_RUNNING) { 837 addReplyBulkCString(c,"run-time"); 838 addReplyBulkLongLong(c,mstime() - sj->start_time); 839 } else { 840 mstime_t delay = sj->start_time ? (sj->start_time-mstime()) : 0; 841 if (delay < 0) delay = 0; 842 addReplyBulkCString(c,"run-delay"); 843 addReplyBulkLongLong(c,delay); 844 } 845 846 addReplyBulkCString(c,"retry-num"); 847 addReplyBulkLongLong(c,sj->retry_num); 848 } 849 } 850 851 /* This function calls, if any, the client reconfiguration script with the 852 * following parameters: 853 * 854 * <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> 855 * 856 * It is called every time a failover is performed. 857 * 858 * <state> is currently always "failover". 859 * <role> is either "leader" or "observer". 860 * 861 * from/to fields are respectively master -> promoted slave addresses for 862 * "start" and "end". */ 863 void sentinelCallClientReconfScript(sentinelRedisInstance *master, int role, char *state, sentinelAddr *from, sentinelAddr *to) { 864 char fromport[32], toport[32]; 865 866 if (master->client_reconfig_script == NULL) return; 867 ll2string(fromport,sizeof(fromport),from->port); 868 ll2string(toport,sizeof(toport),to->port); 869 sentinelScheduleScriptExecution(master->client_reconfig_script, 870 master->name, 871 (role == SENTINEL_LEADER) ? "leader" : "observer", 872 state, from->ip, fromport, to->ip, toport, NULL); 873 } 874 875 /* ========================== sentinelRedisInstance ========================= */ 876 877 /* Create a redis instance, the following fields must be populated by the 878 * caller if needed: 879 * runid: set to NULL but will be populated once INFO output is received. 880 * info_refresh: is set to 0 to mean that we never received INFO so far. 881 * 882 * If SRI_MASTER is set into initial flags the instance is added to 883 * sentinel.masters table. 884 * 885 * if SRI_SLAVE or SRI_SENTINEL is set then 'master' must be not NULL and the 886 * instance is added into master->slaves or master->sentinels table. 887 * 888 * If the instance is a slave or sentinel, the name parameter is ignored and 889 * is created automatically as hostname:port. 890 * 891 * The function fails if hostname can't be resolved or port is out of range. 892 * When this happens NULL is returned and errno is set accordingly to the 893 * createSentinelAddr() function. 894 * 895 * The function may also fail and return NULL with errno set to EBUSY if 896 * a master or slave with the same name already exists. */ 897 sentinelRedisInstance *createSentinelRedisInstance(char *name, int flags, char *hostname, int port, int quorum, sentinelRedisInstance *master) { 898 sentinelRedisInstance *ri; 899 sentinelAddr *addr; 900 dict *table = NULL; 901 char slavename[REDIS_PEER_ID_LEN], *sdsname; 902 903 redisAssert(flags & (SRI_MASTER|SRI_SLAVE|SRI_SENTINEL)); 904 redisAssert((flags & SRI_MASTER) || master != NULL); 905 906 /* Check address validity. */ 907 addr = createSentinelAddr(hostname,port); 908 if (addr == NULL) return NULL; 909 910 /* For slaves and sentinel we use ip:port as name. */ 911 if (flags & (SRI_SLAVE|SRI_SENTINEL)) { 912 anetFormatAddr(slavename, sizeof(slavename), hostname, port); 913 name = slavename; 914 } 915 916 /* Make sure the entry is not duplicated. This may happen when the same 917 * name for a master is used multiple times inside the configuration or 918 * if we try to add multiple times a slave or sentinel with same ip/port 919 * to a master. */ 920 if (flags & SRI_MASTER) table = sentinel.masters; 921 else if (flags & SRI_SLAVE) table = master->slaves; 922 else if (flags & SRI_SENTINEL) table = master->sentinels; 923 sdsname = sdsnew(name); 924 if (dictFind(table,sdsname)) { 925 sdsfree(sdsname); 926 errno = EBUSY; 927 return NULL; 928 } 929 930 /* Create the instance object. */ 931 ri = zmalloc(sizeof(*ri)); 932 /* Note that all the instances are started in the disconnected state, 933 * the event loop will take care of connecting them. */ 934 ri->flags = flags | SRI_DISCONNECTED; 935 ri->name = sdsname; 936 ri->runid = NULL; 937 ri->config_epoch = 0; 938 ri->addr = addr; 939 ri->cc = NULL; 940 ri->pc = NULL; 941 ri->pending_commands = 0; 942 ri->cc_conn_time = 0; 943 ri->pc_conn_time = 0; 944 ri->pc_last_activity = 0; 945 /* We set the last_ping_time to "now" even if we actually don't have yet 946 * a connection with the node, nor we sent a ping. 947 * This is useful to detect a timeout in case we'll not be able to connect 948 * with the node at all. */ 949 ri->last_ping_time = mstime(); 950 ri->last_avail_time = mstime(); 951 ri->last_pong_time = mstime(); 952 ri->last_pub_time = mstime(); 953 ri->last_hello_time = mstime(); 954 ri->last_master_down_reply_time = mstime(); 955 ri->s_down_since_time = 0; 956 ri->o_down_since_time = 0; 957 ri->down_after_period = master ? master->down_after_period : 958 SENTINEL_DEFAULT_DOWN_AFTER; 959 ri->master_link_down_time = 0; 960 ri->auth_pass = NULL; 961 ri->slave_priority = SENTINEL_DEFAULT_SLAVE_PRIORITY; 962 ri->slave_reconf_sent_time = 0; 963 ri->slave_master_host = NULL; 964 ri->slave_master_port = 0; 965 ri->slave_master_link_status = SENTINEL_MASTER_LINK_STATUS_DOWN; 966 ri->slave_repl_offset = 0; 967 ri->sentinels = dictCreate(&instancesDictType,NULL); 968 ri->quorum = quorum; 969 ri->parallel_syncs = SENTINEL_DEFAULT_PARALLEL_SYNCS; 970 ri->master = master; 971 ri->slaves = dictCreate(&instancesDictType,NULL); 972 ri->info_refresh = 0; 973 974 /* Failover state. */ 975 ri->leader = NULL; 976 ri->leader_epoch = 0; 977 ri->failover_epoch = 0; 978 ri->failover_state = SENTINEL_FAILOVER_STATE_NONE; 979 ri->failover_state_change_time = 0; 980 ri->failover_start_time = 0; 981 ri->failover_timeout = SENTINEL_DEFAULT_FAILOVER_TIMEOUT; 982 ri->failover_delay_logged = 0; 983 ri->promoted_slave = NULL; 984 ri->notification_script = NULL; 985 ri->client_reconfig_script = NULL; 986 ri->info = NULL; 987 988 /* Role */ 989 ri->role_reported = ri->flags & (SRI_MASTER|SRI_SLAVE); 990 ri->role_reported_time = mstime(); 991 ri->slave_conf_change_time = mstime(); 992 993 /* Add into the right table. */ 994 dictAdd(table, ri->name, ri); 995 return ri; 996 } 997 998 /* Release this instance and all its slaves, sentinels, hiredis connections. 999 * This function does not take care of unlinking the instance from the main 1000 * masters table (if it is a master) or from its master sentinels/slaves table 1001 * if it is a slave or sentinel. */ 1002 void releaseSentinelRedisInstance(sentinelRedisInstance *ri) { 1003 /* Release all its slaves or sentinels if any. */ 1004 dictRelease(ri->sentinels); 1005 dictRelease(ri->slaves); 1006 1007 /* Release hiredis connections. */ 1008 if (ri->cc) sentinelKillLink(ri,ri->cc); 1009 if (ri->pc) sentinelKillLink(ri,ri->pc); 1010 1011 /* Free other resources. */ 1012 sdsfree(ri->name); 1013 sdsfree(ri->runid); 1014 sdsfree(ri->notification_script); 1015 sdsfree(ri->client_reconfig_script); 1016 sdsfree(ri->slave_master_host); 1017 sdsfree(ri->leader); 1018 sdsfree(ri->auth_pass); 1019 sdsfree(ri->info); 1020 releaseSentinelAddr(ri->addr); 1021 1022 /* Clear state into the master if needed. */ 1023 if ((ri->flags & SRI_SLAVE) && (ri->flags & SRI_PROMOTED) && ri->master) 1024 ri->master->promoted_slave = NULL; 1025 1026 zfree(ri); 1027 } 1028 1029 /* Lookup a slave in a master Redis instance, by ip and port. */ 1030 sentinelRedisInstance *sentinelRedisInstanceLookupSlave( 1031 sentinelRedisInstance *ri, char *ip, int port) 1032 { 1033 sds key; 1034 sentinelRedisInstance *slave; 1035 char buf[REDIS_PEER_ID_LEN]; 1036 1037 redisAssert(ri->flags & SRI_MASTER); 1038 anetFormatAddr(buf,sizeof(buf),ip,port); 1039 key = sdsnew(buf); 1040 slave = dictFetchValue(ri->slaves,key); 1041 sdsfree(key); 1042 return slave; 1043 } 1044 1045 /* Return the name of the type of the instance as a string. */ 1046 const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance *ri) { 1047 if (ri->flags & SRI_MASTER) return "master"; 1048 else if (ri->flags & SRI_SLAVE) return "slave"; 1049 else if (ri->flags & SRI_SENTINEL) return "sentinel"; 1050 else return "unknown"; 1051 } 1052 1053 /* This function removes all the instances found in the dictionary of 1054 * sentinels in the specified 'master', having either: 1055 * 1056 * 1) The same ip/port as specified. 1057 * 2) The same runid. 1058 * 1059 * "1" and "2" don't need to verify at the same time, just one is enough. 1060 * If "runid" is NULL it is not checked. 1061 * Similarly if "ip" is NULL it is not checked. 1062 * 1063 * This function is useful because every time we add a new Sentinel into 1064 * a master's Sentinels dictionary, we want to be very sure about not 1065 * having duplicated instances for any reason. This is important because 1066 * other sentinels are needed to reach ODOWN quorum, and later to get 1067 * voted for a given configuration epoch in order to perform the failover. 1068 * 1069 * The function returns the number of Sentinels removed. */ 1070 int removeMatchingSentinelsFromMaster(sentinelRedisInstance *master, char *ip, int port, char *runid) { 1071 dictIterator *di; 1072 dictEntry *de; 1073 int removed = 0; 1074 1075 di = dictGetSafeIterator(master->sentinels); 1076 while((de = dictNext(di)) != NULL) { 1077 sentinelRedisInstance *ri = dictGetVal(de); 1078 1079 if ((ri->runid && runid && strcmp(ri->runid,runid) == 0) || 1080 (ip && strcmp(ri->addr->ip,ip) == 0 && port == ri->addr->port)) 1081 { 1082 dictDelete(master->sentinels,ri->name); 1083 removed++; 1084 } 1085 } 1086 dictReleaseIterator(di); 1087 return removed; 1088 } 1089 1090 /* Search an instance with the same runid, ip and port into a dictionary 1091 * of instances. Return NULL if not found, otherwise return the instance 1092 * pointer. 1093 * 1094 * runid or ip can be NULL. In such a case the search is performed only 1095 * by the non-NULL field. */ 1096 sentinelRedisInstance *getSentinelRedisInstanceByAddrAndRunID(dict *instances, char *ip, int port, char *runid) { 1097 dictIterator *di; 1098 dictEntry *de; 1099 sentinelRedisInstance *instance = NULL; 1100 1101 redisAssert(ip || runid); /* User must pass at least one search param. */ 1102 di = dictGetIterator(instances); 1103 while((de = dictNext(di)) != NULL) { 1104 sentinelRedisInstance *ri = dictGetVal(de); 1105 1106 if (runid && !ri->runid) continue; 1107 if ((runid == NULL || strcmp(ri->runid, runid) == 0) && 1108 (ip == NULL || (strcmp(ri->addr->ip, ip) == 0 && 1109 ri->addr->port == port))) 1110 { 1111 instance = ri; 1112 break; 1113 } 1114 } 1115 dictReleaseIterator(di); 1116 return instance; 1117 } 1118 1119 /* Master lookup by name */ 1120 sentinelRedisInstance *sentinelGetMasterByName(char *name) { 1121 sentinelRedisInstance *ri; 1122 sds sdsname = sdsnew(name); 1123 1124 ri = dictFetchValue(sentinel.masters,sdsname); 1125 sdsfree(sdsname); 1126 return ri; 1127 } 1128 1129 /* Add the specified flags to all the instances in the specified dictionary. */ 1130 void sentinelAddFlagsToDictOfRedisInstances(dict *instances, int flags) { 1131 dictIterator *di; 1132 dictEntry *de; 1133 1134 di = dictGetIterator(instances); 1135 while((de = dictNext(di)) != NULL) { 1136 sentinelRedisInstance *ri = dictGetVal(de); 1137 ri->flags |= flags; 1138 } 1139 dictReleaseIterator(di); 1140 } 1141 1142 /* Remove the specified flags to all the instances in the specified 1143 * dictionary. */ 1144 void sentinelDelFlagsToDictOfRedisInstances(dict *instances, int flags) { 1145 dictIterator *di; 1146 dictEntry *de; 1147 1148 di = dictGetIterator(instances); 1149 while((de = dictNext(di)) != NULL) { 1150 sentinelRedisInstance *ri = dictGetVal(de); 1151 ri->flags &= ~flags; 1152 } 1153 dictReleaseIterator(di); 1154 } 1155 1156 /* Reset the state of a monitored master: 1157 * 1) Remove all slaves. 1158 * 2) Remove all sentinels. 1159 * 3) Remove most of the flags resulting from runtime operations. 1160 * 4) Reset timers to their default value. 1161 * 5) In the process of doing this undo the failover if in progress. 1162 * 6) Disconnect the connections with the master (will reconnect automatically). 1163 */ 1164 1165 #define SENTINEL_RESET_NO_SENTINELS (1<<0) 1166 void sentinelResetMaster(sentinelRedisInstance *ri, int flags) { 1167 redisAssert(ri->flags & SRI_MASTER); 1168 dictRelease(ri->slaves); 1169 ri->slaves = dictCreate(&instancesDictType,NULL); 1170 if (!(flags & SENTINEL_RESET_NO_SENTINELS)) { 1171 dictRelease(ri->sentinels); 1172 ri->sentinels = dictCreate(&instancesDictType,NULL); 1173 } 1174 if (ri->cc) sentinelKillLink(ri,ri->cc); 1175 if (ri->pc) sentinelKillLink(ri,ri->pc); 1176 ri->flags &= SRI_MASTER|SRI_DISCONNECTED; 1177 if (ri->leader) { 1178 sdsfree(ri->leader); 1179 ri->leader = NULL; 1180 } 1181 ri->failover_state = SENTINEL_FAILOVER_STATE_NONE; 1182 ri->failover_state_change_time = 0; 1183 ri->failover_start_time = 0; 1184 ri->promoted_slave = NULL; 1185 sdsfree(ri->runid); 1186 sdsfree(ri->slave_master_host); 1187 ri->runid = NULL; 1188 ri->slave_master_host = NULL; 1189 ri->last_ping_time = mstime(); 1190 ri->last_avail_time = mstime(); 1191 ri->last_pong_time = mstime(); 1192 ri->role_reported_time = mstime(); 1193 ri->role_reported = SRI_MASTER; 1194 if (flags & SENTINEL_GENERATE_EVENT) 1195 sentinelEvent(REDIS_WARNING,"+reset-master",ri,"%@"); 1196 } 1197 1198 /* Call sentinelResetMaster() on every master with a name matching the specified 1199 * pattern. */ 1200 int sentinelResetMastersByPattern(char *pattern, int flags) { 1201 dictIterator *di; 1202 dictEntry *de; 1203 int reset = 0; 1204 1205 di = dictGetIterator(sentinel.masters); 1206 while((de = dictNext(di)) != NULL) { 1207 sentinelRedisInstance *ri = dictGetVal(de); 1208 1209 if (ri->name) { 1210 if (stringmatch(pattern,ri->name,0)) { 1211 sentinelResetMaster(ri,flags); 1212 reset++; 1213 } 1214 } 1215 } 1216 dictReleaseIterator(di); 1217 return reset; 1218 } 1219 1220 /* Reset the specified master with sentinelResetMaster(), and also change 1221 * the ip:port address, but take the name of the instance unmodified. 1222 * 1223 * This is used to handle the +switch-master event. 1224 * 1225 * The function returns REDIS_ERR if the address can't be resolved for some 1226 * reason. Otherwise REDIS_OK is returned. */ 1227 int sentinelResetMasterAndChangeAddress(sentinelRedisInstance *master, char *ip, int port) { 1228 sentinelAddr *oldaddr, *newaddr; 1229 sentinelAddr **slaves = NULL; 1230 int numslaves = 0, j; 1231 dictIterator *di; 1232 dictEntry *de; 1233 1234 newaddr = createSentinelAddr(ip,port); 1235 if (newaddr == NULL) return REDIS_ERR; 1236 1237 /* Make a list of slaves to add back after the reset. 1238 * Don't include the one having the address we are switching to. */ 1239 di = dictGetIterator(master->slaves); 1240 while((de = dictNext(di)) != NULL) { 1241 sentinelRedisInstance *slave = dictGetVal(de); 1242 1243 if (sentinelAddrIsEqual(slave->addr,newaddr)) continue; 1244 slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1)); 1245 slaves[numslaves++] = createSentinelAddr(slave->addr->ip, 1246 slave->addr->port); 1247 } 1248 dictReleaseIterator(di); 1249 1250 /* If we are switching to a different address, include the old address 1251 * as a slave as well, so that we'll be able to sense / reconfigure 1252 * the old master. */ 1253 if (!sentinelAddrIsEqual(newaddr,master->addr)) { 1254 slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1)); 1255 slaves[numslaves++] = createSentinelAddr(master->addr->ip, 1256 master->addr->port); 1257 } 1258 1259 /* Reset and switch address. */ 1260 sentinelResetMaster(master,SENTINEL_RESET_NO_SENTINELS); 1261 oldaddr = master->addr; 1262 master->addr = newaddr; 1263 master->o_down_since_time = 0; 1264 master->s_down_since_time = 0; 1265 1266 /* Add slaves back. */ 1267 for (j = 0; j < numslaves; j++) { 1268 sentinelRedisInstance *slave; 1269 1270 slave = createSentinelRedisInstance(NULL,SRI_SLAVE,slaves[j]->ip, 1271 slaves[j]->port, master->quorum, master); 1272 releaseSentinelAddr(slaves[j]); 1273 if (slave) { 1274 sentinelEvent(REDIS_NOTICE,"+slave",slave,"%@"); 1275 sentinelFlushConfig(); 1276 } 1277 } 1278 zfree(slaves); 1279 1280 /* Release the old address at the end so we are safe even if the function 1281 * gets the master->addr->ip and master->addr->port as arguments. */ 1282 releaseSentinelAddr(oldaddr); 1283 sentinelFlushConfig(); 1284 return REDIS_OK; 1285 } 1286 1287 /* Return non-zero if there was no SDOWN or ODOWN error associated to this 1288 * instance in the latest 'ms' milliseconds. */ 1289 int sentinelRedisInstanceNoDownFor(sentinelRedisInstance *ri, mstime_t ms) { 1290 mstime_t most_recent; 1291 1292 most_recent = ri->s_down_since_time; 1293 if (ri->o_down_since_time > most_recent) 1294 most_recent = ri->o_down_since_time; 1295 return most_recent == 0 || (mstime() - most_recent) > ms; 1296 } 1297 1298 /* Return the current master address, that is, its address or the address 1299 * of the promoted slave if already operational. */ 1300 sentinelAddr *sentinelGetCurrentMasterAddress(sentinelRedisInstance *master) { 1301 /* If we are failing over the master, and the state is already 1302 * SENTINEL_FAILOVER_STATE_RECONF_SLAVES or greater, it means that we 1303 * already have the new configuration epoch in the master, and the 1304 * slave acknowledged the configuration switch. Advertise the new 1305 * address. */ 1306 if ((master->flags & SRI_FAILOVER_IN_PROGRESS) && 1307 master->promoted_slave && 1308 master->failover_state >= SENTINEL_FAILOVER_STATE_RECONF_SLAVES) 1309 { 1310 return master->promoted_slave->addr; 1311 } else { 1312 return master->addr; 1313 } 1314 } 1315 1316 /* This function sets the down_after_period field value in 'master' to all 1317 * the slaves and sentinel instances connected to this master. */ 1318 void sentinelPropagateDownAfterPeriod(sentinelRedisInstance *master) { 1319 dictIterator *di; 1320 dictEntry *de; 1321 int j; 1322 dict *d[] = {master->slaves, master->sentinels, NULL}; 1323 1324 for (j = 0; d[j]; j++) { 1325 di = dictGetIterator(d[j]); 1326 while((de = dictNext(di)) != NULL) { 1327 sentinelRedisInstance *ri = dictGetVal(de); 1328 ri->down_after_period = master->down_after_period; 1329 } 1330 dictReleaseIterator(di); 1331 } 1332 } 1333 1334 /* ============================ Config handling ============================= */ 1335 char *sentinelHandleConfiguration(char **argv, int argc) { 1336 sentinelRedisInstance *ri; 1337 1338 if (!strcasecmp(argv[0],"monitor") && argc == 5) { 1339 /* monitor <name> <host> <port> <quorum> */ 1340 int quorum = atoi(argv[4]); 1341 1342 if (quorum <= 0) return "Quorum must be 1 or greater."; 1343 if (createSentinelRedisInstance(argv[1],SRI_MASTER,argv[2], 1344 atoi(argv[3]),quorum,NULL) == NULL) 1345 { 1346 switch(errno) { 1347 case EBUSY: return "Duplicated master name."; 1348 case ENOENT: return "Can't resolve master instance hostname."; 1349 case EINVAL: return "Invalid port number"; 1350 } 1351 } 1352 } else if (!strcasecmp(argv[0],"down-after-milliseconds") && argc == 3) { 1353 /* down-after-milliseconds <name> <milliseconds> */ 1354 ri = sentinelGetMasterByName(argv[1]); 1355 if (!ri) return "No such master with specified name."; 1356 ri->down_after_period = atoi(argv[2]); 1357 if (ri->down_after_period <= 0) 1358 return "negative or zero time parameter."; 1359 sentinelPropagateDownAfterPeriod(ri); 1360 } else if (!strcasecmp(argv[0],"failover-timeout") && argc == 3) { 1361 /* failover-timeout <name> <milliseconds> */ 1362 ri = sentinelGetMasterByName(argv[1]); 1363 if (!ri) return "No such master with specified name."; 1364 ri->failover_timeout = atoi(argv[2]); 1365 if (ri->failover_timeout <= 0) 1366 return "negative or zero time parameter."; 1367 } else if (!strcasecmp(argv[0],"parallel-syncs") && argc == 3) { 1368 /* parallel-syncs <name> <milliseconds> */ 1369 ri = sentinelGetMasterByName(argv[1]); 1370 if (!ri) return "No such master with specified name."; 1371 ri->parallel_syncs = atoi(argv[2]); 1372 } else if (!strcasecmp(argv[0],"notification-script") && argc == 3) { 1373 /* notification-script <name> <path> */ 1374 ri = sentinelGetMasterByName(argv[1]); 1375 if (!ri) return "No such master with specified name."; 1376 if (access(argv[2],X_OK) == -1) 1377 return "Notification script seems non existing or non executable."; 1378 ri->notification_script = sdsnew(argv[2]); 1379 } else if (!strcasecmp(argv[0],"client-reconfig-script") && argc == 3) { 1380 /* client-reconfig-script <name> <path> */ 1381 ri = sentinelGetMasterByName(argv[1]); 1382 if (!ri) return "No such master with specified name."; 1383 if (access(argv[2],X_OK) == -1) 1384 return "Client reconfiguration script seems non existing or " 1385 "non executable."; 1386 ri->client_reconfig_script = sdsnew(argv[2]); 1387 } else if (!strcasecmp(argv[0],"auth-pass") && argc == 3) { 1388 /* auth-pass <name> <password> */ 1389 ri = sentinelGetMasterByName(argv[1]); 1390 if (!ri) return "No such master with specified name."; 1391 ri->auth_pass = sdsnew(argv[2]); 1392 } else if (!strcasecmp(argv[0],"current-epoch") && argc == 2) { 1393 /* current-epoch <epoch> */ 1394 unsigned long long current_epoch = strtoull(argv[1],NULL,10); 1395 if (current_epoch > sentinel.current_epoch) 1396 sentinel.current_epoch = current_epoch; 1397 } else if (!strcasecmp(argv[0],"config-epoch") && argc == 3) { 1398 /* config-epoch <name> <epoch> */ 1399 ri = sentinelGetMasterByName(argv[1]); 1400 if (!ri) return "No such master with specified name."; 1401 ri->config_epoch = strtoull(argv[2],NULL,10); 1402 /* The following update of current_epoch is not really useful as 1403 * now the current epoch is persisted on the config file, but 1404 * we leave this check here for redundancy. */ 1405 if (ri->config_epoch > sentinel.current_epoch) 1406 sentinel.current_epoch = ri->config_epoch; 1407 } else if (!strcasecmp(argv[0],"leader-epoch") && argc == 3) { 1408 /* leader-epoch <name> <epoch> */ 1409 ri = sentinelGetMasterByName(argv[1]); 1410 if (!ri) return "No such master with specified name."; 1411 ri->leader_epoch = strtoull(argv[2],NULL,10); 1412 } else if (!strcasecmp(argv[0],"known-slave") && argc == 4) { 1413 sentinelRedisInstance *slave; 1414 1415 /* known-slave <name> <ip> <port> */ 1416 ri = sentinelGetMasterByName(argv[1]); 1417 if (!ri) return "No such master with specified name."; 1418 if ((slave = createSentinelRedisInstance(NULL,SRI_SLAVE,argv[2], 1419 atoi(argv[3]), ri->quorum, ri)) == NULL) 1420 { 1421 return "Wrong hostname or port for slave."; 1422 } 1423 } else if (!strcasecmp(argv[0],"known-sentinel") && 1424 (argc == 4 || argc == 5)) { 1425 sentinelRedisInstance *si; 1426 1427 /* known-sentinel <name> <ip> <port> [runid] */ 1428 ri = sentinelGetMasterByName(argv[1]); 1429 if (!ri) return "No such master with specified name."; 1430 if ((si = createSentinelRedisInstance(NULL,SRI_SENTINEL,argv[2], 1431 atoi(argv[3]), ri->quorum, ri)) == NULL) 1432 { 1433 return "Wrong hostname or port for sentinel."; 1434 } 1435 if (argc == 5) si->runid = sdsnew(argv[4]); 1436 } else if (!strcasecmp(argv[0],"announce-ip") && argc == 2) { 1437 /* announce-ip <ip-address> */ 1438 if (strlen(argv[1])) 1439 sentinel.announce_ip = sdsnew(argv[1]); 1440 } else if (!strcasecmp(argv[0],"announce-port") && argc == 2) { 1441 /* announce-port <port> */ 1442 sentinel.announce_port = atoi(argv[1]); 1443 } else { 1444 return "Unrecognized sentinel configuration statement."; 1445 } 1446 return NULL; 1447 } 1448 1449 /* Implements CONFIG REWRITE for "sentinel" option. 1450 * This is used not just to rewrite the configuration given by the user 1451 * (the configured masters) but also in order to retain the state of 1452 * Sentinel across restarts: config epoch of masters, associated slaves 1453 * and sentinel instances, and so forth. */ 1454 void rewriteConfigSentinelOption(struct rewriteConfigState *state) { 1455 dictIterator *di, *di2; 1456 dictEntry *de; 1457 sds line; 1458 1459 /* For every master emit a "sentinel monitor" config entry. */ 1460 di = dictGetIterator(sentinel.masters); 1461 while((de = dictNext(di)) != NULL) { 1462 sentinelRedisInstance *master, *ri; 1463 sentinelAddr *master_addr; 1464 1465 /* sentinel monitor */ 1466 master = dictGetVal(de); 1467 master_addr = sentinelGetCurrentMasterAddress(master); 1468 line = sdscatprintf(sdsempty(),"sentinel monitor %s %s %d %d", 1469 master->name, master_addr->ip, master_addr->port, 1470 master->quorum); 1471 rewriteConfigRewriteLine(state,"sentinel",line,1); 1472 1473 /* sentinel down-after-milliseconds */ 1474 if (master->down_after_period != SENTINEL_DEFAULT_DOWN_AFTER) { 1475 line = sdscatprintf(sdsempty(), 1476 "sentinel down-after-milliseconds %s %ld", 1477 master->name, (long) master->down_after_period); 1478 rewriteConfigRewriteLine(state,"sentinel",line,1); 1479 } 1480 1481 /* sentinel failover-timeout */ 1482 if (master->failover_timeout != SENTINEL_DEFAULT_FAILOVER_TIMEOUT) { 1483 line = sdscatprintf(sdsempty(), 1484 "sentinel failover-timeout %s %ld", 1485 master->name, (long) master->failover_timeout); 1486 rewriteConfigRewriteLine(state,"sentinel",line,1); 1487 } 1488 1489 /* sentinel parallel-syncs */ 1490 if (master->parallel_syncs != SENTINEL_DEFAULT_PARALLEL_SYNCS) { 1491 line = sdscatprintf(sdsempty(), 1492 "sentinel parallel-syncs %s %d", 1493 master->name, master->parallel_syncs); 1494 rewriteConfigRewriteLine(state,"sentinel",line,1); 1495 } 1496 1497 /* sentinel notification-script */ 1498 if (master->notification_script) { 1499 line = sdscatprintf(sdsempty(), 1500 "sentinel notification-script %s %s", 1501 master->name, master->notification_script); 1502 rewriteConfigRewriteLine(state,"sentinel",line,1); 1503 } 1504 1505 /* sentinel client-reconfig-script */ 1506 if (master->client_reconfig_script) { 1507 line = sdscatprintf(sdsempty(), 1508 "sentinel client-reconfig-script %s %s", 1509 master->name, master->client_reconfig_script); 1510 rewriteConfigRewriteLine(state,"sentinel",line,1); 1511 } 1512 1513 /* sentinel auth-pass */ 1514 if (master->auth_pass) { 1515 line = sdscatprintf(sdsempty(), 1516 "sentinel auth-pass %s %s", 1517 master->name, master->auth_pass); 1518 rewriteConfigRewriteLine(state,"sentinel",line,1); 1519 } 1520 1521 /* sentinel config-epoch */ 1522 line = sdscatprintf(sdsempty(), 1523 "sentinel config-epoch %s %llu", 1524 master->name, (unsigned long long) master->config_epoch); 1525 rewriteConfigRewriteLine(state,"sentinel",line,1); 1526 1527 /* sentinel leader-epoch */ 1528 line = sdscatprintf(sdsempty(), 1529 "sentinel leader-epoch %s %llu", 1530 master->name, (unsigned long long) master->leader_epoch); 1531 rewriteConfigRewriteLine(state,"sentinel",line,1); 1532 1533 /* sentinel known-slave */ 1534 di2 = dictGetIterator(master->slaves); 1535 while((de = dictNext(di2)) != NULL) { 1536 sentinelAddr *slave_addr; 1537 1538 ri = dictGetVal(de); 1539 slave_addr = ri->addr; 1540 1541 /* If master_addr (obtained using sentinelGetCurrentMasterAddress() 1542 * so it may be the address of the promoted slave) is equal to this 1543 * slave's address, a failover is in progress and the slave was 1544 * already successfully promoted. So as the address of this slave 1545 * we use the old master address instead. */ 1546 if (sentinelAddrIsEqual(slave_addr,master_addr)) 1547 slave_addr = master->addr; 1548 line = sdscatprintf(sdsempty(), 1549 "sentinel known-slave %s %s %d", 1550 master->name, ri->addr->ip, ri->addr->port); 1551 rewriteConfigRewriteLine(state,"sentinel",line,1); 1552 } 1553 dictReleaseIterator(di2); 1554 1555 /* sentinel known-sentinel */ 1556 di2 = dictGetIterator(master->sentinels); 1557 while((de = dictNext(di2)) != NULL) { 1558 ri = dictGetVal(de); 1559 line = sdscatprintf(sdsempty(), 1560 "sentinel known-sentinel %s %s %d%s%s", 1561 master->name, ri->addr->ip, ri->addr->port, 1562 ri->runid ? " " : "", 1563 ri->runid ? ri->runid : ""); 1564 rewriteConfigRewriteLine(state,"sentinel",line,1); 1565 } 1566 dictReleaseIterator(di2); 1567 } 1568 1569 /* sentinel current-epoch is a global state valid for all the masters. */ 1570 line = sdscatprintf(sdsempty(), 1571 "sentinel current-epoch %llu", (unsigned long long) sentinel.current_epoch); 1572 rewriteConfigRewriteLine(state,"sentinel",line,1); 1573 1574 /* sentinel announce-ip. */ 1575 if (sentinel.announce_ip) { 1576 line = sdsnew("sentinel announce-ip "); 1577 line = sdscatrepr(line, sentinel.announce_ip, sdslen(sentinel.announce_ip)); 1578 rewriteConfigRewriteLine(state,"sentinel",line,1); 1579 } 1580 1581 /* sentinel announce-port. */ 1582 if (sentinel.announce_port) { 1583 line = sdscatprintf(sdsempty(),"sentinel announce-port %d", 1584 sentinel.announce_port); 1585 rewriteConfigRewriteLine(state,"sentinel",line,1); 1586 } 1587 1588 dictReleaseIterator(di); 1589 } 1590 1591 /* This function uses the config rewriting Redis engine in order to persist 1592 * the state of the Sentinel in the current configuration file. 1593 * 1594 * Before returning the function calls fsync() against the generated 1595 * configuration file to make sure changes are committed to disk. 1596 * 1597 * On failure the function logs a warning on the Redis log. */ 1598 void sentinelFlushConfig(void) { 1599 int fd = -1; 1600 int saved_hz = server.hz; 1601 int rewrite_status; 1602 1603 server.hz = REDIS_DEFAULT_HZ; 1604 rewrite_status = rewriteConfig(server.configfile); 1605 server.hz = saved_hz; 1606 1607 if (rewrite_status == -1) goto werr; 1608 if ((fd = open(server.configfile,O_RDONLY)) == -1) goto werr; 1609 if (fsync(fd) == -1) goto werr; 1610 if (close(fd) == EOF) goto werr; 1611 return; 1612 1613 werr: 1614 if (fd != -1) close(fd); 1615 redisLog(REDIS_WARNING,"WARNING: Sentinel was not able to save the new configuration on disk!!!: %s", strerror(errno)); 1616 } 1617 1618 /* ====================== hiredis connection handling ======================= */ 1619 1620 /* Completely disconnect a hiredis link from an instance. */ 1621 void sentinelKillLink(sentinelRedisInstance *ri, redisAsyncContext *c) { 1622 if (ri->cc == c) { 1623 ri->cc = NULL; 1624 ri->pending_commands = 0; 1625 } 1626 if (ri->pc == c) ri->pc = NULL; 1627 c->data = NULL; 1628 ri->flags |= SRI_DISCONNECTED; 1629 redisAsyncFree(c); 1630 } 1631 1632 /* This function takes a hiredis context that is in an error condition 1633 * and make sure to mark the instance as disconnected performing the 1634 * cleanup needed. 1635 * 1636 * Note: we don't free the hiredis context as hiredis will do it for us 1637 * for async connections. */ 1638 void sentinelDisconnectInstanceFromContext(const redisAsyncContext *c) { 1639 sentinelRedisInstance *ri = c->data; 1640 int pubsub; 1641 1642 if (ri == NULL) return; /* The instance no longer exists. */ 1643 1644 pubsub = (ri->pc == c); 1645 sentinelEvent(REDIS_DEBUG, pubsub ? "-pubsub-link" : "-cmd-link", ri, 1646 "%@ #%s", c->errstr); 1647 if (pubsub) 1648 ri->pc = NULL; 1649 else 1650 ri->cc = NULL; 1651 ri->flags |= SRI_DISCONNECTED; 1652 } 1653 1654 void sentinelLinkEstablishedCallback(const redisAsyncContext *c, int status) { 1655 if (status != REDIS_OK) { 1656 sentinelDisconnectInstanceFromContext(c); 1657 } else { 1658 sentinelRedisInstance *ri = c->data; 1659 int pubsub = (ri->pc == c); 1660 1661 sentinelEvent(REDIS_DEBUG, pubsub ? "+pubsub-link" : "+cmd-link", ri, 1662 "%@"); 1663 } 1664 } 1665 1666 void sentinelDisconnectCallback(const redisAsyncContext *c, int status) { 1667 REDIS_NOTUSED(status); 1668 sentinelDisconnectInstanceFromContext(c); 1669 } 1670 1671 /* Send the AUTH command with the specified master password if needed. 1672 * Note that for slaves the password set for the master is used. 1673 * 1674 * We don't check at all if the command was successfully transmitted 1675 * to the instance as if it fails Sentinel will detect the instance down, 1676 * will disconnect and reconnect the link and so forth. */ 1677 void sentinelSendAuthIfNeeded(sentinelRedisInstance *ri, redisAsyncContext *c) { 1678 char *auth_pass = (ri->flags & SRI_MASTER) ? ri->auth_pass : 1679 ri->master->auth_pass; 1680 1681 if (auth_pass) { 1682 if (redisAsyncCommand(c, sentinelDiscardReplyCallback, NULL, "AUTH %s", 1683 auth_pass) == REDIS_OK) ri->pending_commands++; 1684 } 1685 } 1686 1687 /* Use CLIENT SETNAME to name the connection in the Redis instance as 1688 * sentinel-<first_8_chars_of_runid>-<connection_type> 1689 * The connection type is "cmd" or "pubsub" as specified by 'type'. 1690 * 1691 * This makes it possible to list all the sentinel instances connected 1692 * to a Redis servewr with CLIENT LIST, grepping for a specific name format. */ 1693 void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char *type) { 1694 char name[64]; 1695 1696 snprintf(name,sizeof(name),"sentinel-%.8s-%s",server.runid,type); 1697 if (redisAsyncCommand(c, sentinelDiscardReplyCallback, NULL, 1698 "CLIENT SETNAME %s", name) == REDIS_OK) 1699 { 1700 ri->pending_commands++; 1701 } 1702 } 1703 1704 /* Create the async connections for the specified instance if the instance 1705 * is disconnected. Note that the SRI_DISCONNECTED flag is set even if just 1706 * one of the two links (commands and pub/sub) is missing. */ 1707 void sentinelReconnectInstance(sentinelRedisInstance *ri) { 1708 if (!(ri->flags & SRI_DISCONNECTED)) return; 1709 1710 /* Commands connection. */ 1711 if (ri->cc == NULL) { 1712 ri->cc = redisAsyncConnectBind(ri->addr->ip,ri->addr->port,REDIS_BIND_ADDR); 1713 if (ri->cc->err) { 1714 sentinelEvent(REDIS_DEBUG,"-cmd-link-reconnection",ri,"%@ #%s", 1715 ri->cc->errstr); 1716 sentinelKillLink(ri,ri->cc); 1717 } else { 1718 ri->cc_conn_time = mstime(); 1719 ri->cc->data = ri; 1720 redisAeAttach(server.el,ri->cc); 1721 redisAsyncSetConnectCallback(ri->cc, 1722 sentinelLinkEstablishedCallback); 1723 redisAsyncSetDisconnectCallback(ri->cc, 1724 sentinelDisconnectCallback); 1725 sentinelSendAuthIfNeeded(ri,ri->cc); 1726 sentinelSetClientName(ri,ri->cc,"cmd"); 1727 1728 /* Send a PING ASAP when reconnecting. */ 1729 sentinelSendPing(ri); 1730 } 1731 } 1732 /* Pub / Sub */ 1733 if ((ri->flags & (SRI_MASTER|SRI_SLAVE)) && ri->pc == NULL) { 1734 ri->pc = redisAsyncConnectBind(ri->addr->ip,ri->addr->port,REDIS_BIND_ADDR); 1735 if (ri->pc->err) { 1736 sentinelEvent(REDIS_DEBUG,"-pubsub-link-reconnection",ri,"%@ #%s", 1737 ri->pc->errstr); 1738 sentinelKillLink(ri,ri->pc); 1739 } else { 1740 int retval; 1741 1742 ri->pc_conn_time = mstime(); 1743 ri->pc->data = ri; 1744 redisAeAttach(server.el,ri->pc); 1745 redisAsyncSetConnectCallback(ri->pc, 1746 sentinelLinkEstablishedCallback); 1747 redisAsyncSetDisconnectCallback(ri->pc, 1748 sentinelDisconnectCallback); 1749 sentinelSendAuthIfNeeded(ri,ri->pc); 1750 sentinelSetClientName(ri,ri->pc,"pubsub"); 1751 /* Now we subscribe to the Sentinels "Hello" channel. */ 1752 retval = redisAsyncCommand(ri->pc, 1753 sentinelReceiveHelloMessages, NULL, "SUBSCRIBE %s", 1754 SENTINEL_HELLO_CHANNEL); 1755 if (retval != REDIS_OK) { 1756 /* If we can't subscribe, the Pub/Sub connection is useless 1757 * and we can simply disconnect it and try again. */ 1758 sentinelKillLink(ri,ri->pc); 1759 return; 1760 } 1761 } 1762 } 1763 /* Clear the DISCONNECTED flags only if we have both the connections 1764 * (or just the commands connection if this is a sentinel instance). */ 1765 if (ri->cc && (ri->flags & SRI_SENTINEL || ri->pc)) 1766 ri->flags &= ~SRI_DISCONNECTED; 1767 } 1768 1769 /* ======================== Redis instances pinging ======================== */ 1770 1771 /* Return true if master looks "sane", that is: 1772 * 1) It is actually a master in the current configuration. 1773 * 2) It reports itself as a master. 1774 * 3) It is not SDOWN or ODOWN. 1775 * 4) We obtained last INFO no more than two times the INFO period time ago. */ 1776 int sentinelMasterLooksSane(sentinelRedisInstance *master) { 1777 return 1778 master->flags & SRI_MASTER && 1779 master->role_reported == SRI_MASTER && 1780 (master->flags & (SRI_S_DOWN|SRI_O_DOWN)) == 0 && 1781 (mstime() - master->info_refresh) < SENTINEL_INFO_PERIOD*2; 1782 } 1783 1784 /* Process the INFO output from masters. */ 1785 void sentinelRefreshInstanceInfo(sentinelRedisInstance *ri, const char *info) { 1786 sds *lines; 1787 int numlines, j; 1788 int role = 0; 1789 1790 /* cache full INFO output for instance */ 1791 sdsfree(ri->info); 1792 ri->info = sdsnew(info); 1793 1794 /* The following fields must be reset to a given value in the case they 1795 * are not found at all in the INFO output. */ 1796 ri->master_link_down_time = 0; 1797 1798 /* Process line by line. */ 1799 lines = sdssplitlen(info,strlen(info),"\r\n",2,&numlines); 1800 for (j = 0; j < numlines; j++) { 1801 sentinelRedisInstance *slave; 1802 sds l = lines[j]; 1803 1804 /* run_id:<40 hex chars>*/ 1805 if (sdslen(l) >= 47 && !memcmp(l,"run_id:",7)) { 1806 if (ri->runid == NULL) { 1807 ri->runid = sdsnewlen(l+7,40); 1808 } else { 1809 if (strncmp(ri->runid,l+7,40) != 0) { 1810 sentinelEvent(REDIS_NOTICE,"+reboot",ri,"%@"); 1811 sdsfree(ri->runid); 1812 ri->runid = sdsnewlen(l+7,40); 1813 } 1814 } 1815 } 1816 1817 /* old versions: slave0:<ip>,<port>,<state> 1818 * new versions: slave0:ip=127.0.0.1,port=9999,... */ 1819 if ((ri->flags & SRI_MASTER) && 1820 sdslen(l) >= 7 && 1821 !memcmp(l,"slave",5) && isdigit(l[5])) 1822 { 1823 char *ip, *port, *end; 1824 1825 if (strstr(l,"ip=") == NULL) { 1826 /* Old format. */ 1827 ip = strchr(l,':'); if (!ip) continue; 1828 ip++; /* Now ip points to start of ip address. */ 1829 port = strchr(ip,','); if (!port) continue; 1830 *port = '\0'; /* nul term for easy access. */ 1831 port++; /* Now port points to start of port number. */ 1832 end = strchr(port,','); if (!end) continue; 1833 *end = '\0'; /* nul term for easy access. */ 1834 } else { 1835 /* New format. */ 1836 ip = strstr(l,"ip="); if (!ip) continue; 1837 ip += 3; /* Now ip points to start of ip address. */ 1838 port = strstr(l,"port="); if (!port) continue; 1839 port += 5; /* Now port points to start of port number. */ 1840 /* Nul term both fields for easy access. */ 1841 end = strchr(ip,','); if (end) *end = '\0'; 1842 end = strchr(port,','); if (end) *end = '\0'; 1843 } 1844 1845 /* Check if we already have this slave into our table, 1846 * otherwise add it. */ 1847 if (sentinelRedisInstanceLookupSlave(ri,ip,atoi(port)) == NULL) { 1848 if ((slave = createSentinelRedisInstance(NULL,SRI_SLAVE,ip, 1849 atoi(port), ri->quorum, ri)) != NULL) 1850 { 1851 sentinelEvent(REDIS_NOTICE,"+slave",slave,"%@"); 1852 } 1853 } 1854 } 1855 1856 /* master_link_down_since_seconds:<seconds> */ 1857 if (sdslen(l) >= 32 && 1858 !memcmp(l,"master_link_down_since_seconds",30)) 1859 { 1860 ri->master_link_down_time = strtoll(l+31,NULL,10)*1000; 1861 } 1862 1863 /* role:<role> */ 1864 if (!memcmp(l,"role:master",11)) role = SRI_MASTER; 1865 else if (!memcmp(l,"role:slave",10)) role = SRI_SLAVE; 1866 1867 if (role == SRI_SLAVE) { 1868 /* master_host:<host> */ 1869 if (sdslen(l) >= 12 && !memcmp(l,"master_host:",12)) { 1870 if (ri->slave_master_host == NULL || 1871 strcasecmp(l+12,ri->slave_master_host)) 1872 { 1873 sdsfree(ri->slave_master_host); 1874 ri->slave_master_host = sdsnew(l+12); 1875 ri->slave_conf_change_time = mstime(); 1876 } 1877 } 1878 1879 /* master_port:<port> */ 1880 if (sdslen(l) >= 12 && !memcmp(l,"master_port:",12)) { 1881 int slave_master_port = atoi(l+12); 1882 1883 if (ri->slave_master_port != slave_master_port) { 1884 ri->slave_master_port = slave_master_port; 1885 ri->slave_conf_change_time = mstime(); 1886 } 1887 } 1888 1889 /* master_link_status:<status> */ 1890 if (sdslen(l) >= 19 && !memcmp(l,"master_link_status:",19)) { 1891 ri->slave_master_link_status = 1892 (strcasecmp(l+19,"up") == 0) ? 1893 SENTINEL_MASTER_LINK_STATUS_UP : 1894 SENTINEL_MASTER_LINK_STATUS_DOWN; 1895 } 1896 1897 /* slave_priority:<priority> */ 1898 if (sdslen(l) >= 15 && !memcmp(l,"slave_priority:",15)) 1899 ri->slave_priority = atoi(l+15); 1900 1901 /* slave_repl_offset:<offset> */ 1902 if (sdslen(l) >= 18 && !memcmp(l,"slave_repl_offset:",18)) 1903 ri->slave_repl_offset = strtoull(l+18,NULL,10); 1904 } 1905 } 1906 ri->info_refresh = mstime(); 1907 sdsfreesplitres(lines,numlines); 1908 1909 /* ---------------------------- Acting half ----------------------------- 1910 * Some things will not happen if sentinel.tilt is true, but some will 1911 * still be processed. */ 1912 1913 /* Remember when the role changed. */ 1914 if (role != ri->role_reported) { 1915 ri->role_reported_time = mstime(); 1916 ri->role_reported = role; 1917 if (role == SRI_SLAVE) ri->slave_conf_change_time = mstime(); 1918 /* Log the event with +role-change if the new role is coherent or 1919 * with -role-change if there is a mismatch with the current config. */ 1920 sentinelEvent(REDIS_VERBOSE, 1921 ((ri->flags & (SRI_MASTER|SRI_SLAVE)) == role) ? 1922 "+role-change" : "-role-change", 1923 ri, "%@ new reported role is %s", 1924 role == SRI_MASTER ? "master" : "slave", 1925 ri->flags & SRI_MASTER ? "master" : "slave"); 1926 } 1927 1928 /* None of the following conditions are processed when in tilt mode, so 1929 * return asap. */ 1930 if (sentinel.tilt) return; 1931 1932 /* Handle master -> slave role switch. */ 1933 if ((ri->flags & SRI_MASTER) && role == SRI_SLAVE) { 1934 /* Nothing to do, but masters claiming to be slaves are 1935 * considered to be unreachable by Sentinel, so eventually 1936 * a failover will be triggered. */ 1937 } 1938 1939 /* Handle slave -> master role switch. */ 1940 if ((ri->flags & SRI_SLAVE) && role == SRI_MASTER) { 1941 /* If this is a promoted slave we can change state to the 1942 * failover state machine. */ 1943 if ((ri->flags & SRI_PROMOTED) && 1944 (ri->master->flags & SRI_FAILOVER_IN_PROGRESS) && 1945 (ri->master->failover_state == 1946 SENTINEL_FAILOVER_STATE_WAIT_PROMOTION)) 1947 { 1948 /* Now that we are sure the slave was reconfigured as a master 1949 * set the master configuration epoch to the epoch we won the 1950 * election to perform this failover. This will force the other 1951 * Sentinels to update their config (assuming there is not 1952 * a newer one already available). */ 1953 ri->master->config_epoch = ri->master->failover_epoch; 1954 ri->master->failover_state = SENTINEL_FAILOVER_STATE_RECONF_SLAVES; 1955 ri->master->failover_state_change_time = mstime(); 1956 sentinelFlushConfig(); 1957 sentinelEvent(REDIS_WARNING,"+promoted-slave",ri,"%@"); 1958 sentinelEvent(REDIS_WARNING,"+failover-state-reconf-slaves", 1959 ri->master,"%@"); 1960 sentinelCallClientReconfScript(ri->master,SENTINEL_LEADER, 1961 "start",ri->master->addr,ri->addr); 1962 sentinelForceHelloUpdateForMaster(ri->master); 1963 } else { 1964 /* A slave turned into a master. We want to force our view and 1965 * reconfigure as slave. Wait some time after the change before 1966 * going forward, to receive new configs if any. */ 1967 mstime_t wait_time = SENTINEL_PUBLISH_PERIOD*4; 1968 1969 if (!(ri->flags & SRI_PROMOTED) && 1970 sentinelMasterLooksSane(ri->master) && 1971 sentinelRedisInstanceNoDownFor(ri,wait_time) && 1972 mstime() - ri->role_reported_time > wait_time) 1973 { 1974 int retval = sentinelSendSlaveOf(ri, 1975 ri->master->addr->ip, 1976 ri->master->addr->port); 1977 if (retval == REDIS_OK) 1978 sentinelEvent(REDIS_NOTICE,"+convert-to-slave",ri,"%@"); 1979 } 1980 } 1981 } 1982 1983 /* Handle slaves replicating to a different master address. */ 1984 if ((ri->flags & SRI_SLAVE) && 1985 role == SRI_SLAVE && 1986 (ri->slave_master_port != ri->master->addr->port || 1987 strcasecmp(ri->slave_master_host,ri->master->addr->ip))) 1988 { 1989 mstime_t wait_time = ri->master->failover_timeout; 1990 1991 /* Make sure the master is sane before reconfiguring this instance 1992 * into a slave. */ 1993 if (sentinelMasterLooksSane(ri->master) && 1994 sentinelRedisInstanceNoDownFor(ri,wait_time) && 1995 mstime() - ri->slave_conf_change_time > wait_time) 1996 { 1997 int retval = sentinelSendSlaveOf(ri, 1998 ri->master->addr->ip, 1999 ri->master->addr->port); 2000 if (retval == REDIS_OK) 2001 sentinelEvent(REDIS_NOTICE,"+fix-slave-config",ri,"%@"); 2002 } 2003 } 2004 2005 /* Detect if the slave that is in the process of being reconfigured 2006 * changed state. */ 2007 if ((ri->flags & SRI_SLAVE) && role == SRI_SLAVE && 2008 (ri->flags & (SRI_RECONF_SENT|SRI_RECONF_INPROG))) 2009 { 2010 /* SRI_RECONF_SENT -> SRI_RECONF_INPROG. */ 2011 if ((ri->flags & SRI_RECONF_SENT) && 2012 ri->slave_master_host && 2013 strcmp(ri->slave_master_host, 2014 ri->master->promoted_slave->addr->ip) == 0 && 2015 ri->slave_master_port == ri->master->promoted_slave->addr->port) 2016 { 2017 ri->flags &= ~SRI_RECONF_SENT; 2018 ri->flags |= SRI_RECONF_INPROG; 2019 sentinelEvent(REDIS_NOTICE,"+slave-reconf-inprog",ri,"%@"); 2020 } 2021 2022 /* SRI_RECONF_INPROG -> SRI_RECONF_DONE */ 2023 if ((ri->flags & SRI_RECONF_INPROG) && 2024 ri->slave_master_link_status == SENTINEL_MASTER_LINK_STATUS_UP) 2025 { 2026 ri->flags &= ~SRI_RECONF_INPROG; 2027 ri->flags |= SRI_RECONF_DONE; 2028 sentinelEvent(REDIS_NOTICE,"+slave-reconf-done",ri,"%@"); 2029 } 2030 } 2031 } 2032 2033 void sentinelInfoReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2034 sentinelRedisInstance *ri = c->data; 2035 redisReply *r; 2036 REDIS_NOTUSED(privdata); 2037 2038 if (ri) ri->pending_commands--; 2039 if (!reply || !ri) return; 2040 r = reply; 2041 2042 if (r->type == REDIS_REPLY_STRING) { 2043 sentinelRefreshInstanceInfo(ri,r->str); 2044 } 2045 } 2046 2047 /* Just discard the reply. We use this when we are not monitoring the return 2048 * value of the command but its effects directly. */ 2049 void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2050 sentinelRedisInstance *ri = c->data; 2051 REDIS_NOTUSED(reply); 2052 REDIS_NOTUSED(privdata); 2053 2054 if (ri) ri->pending_commands--; 2055 } 2056 2057 void sentinelPingReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2058 sentinelRedisInstance *ri = c->data; 2059 redisReply *r; 2060 REDIS_NOTUSED(privdata); 2061 2062 if (ri) ri->pending_commands--; 2063 if (!reply || !ri) return; 2064 r = reply; 2065 2066 if (r->type == REDIS_REPLY_STATUS || 2067 r->type == REDIS_REPLY_ERROR) { 2068 /* Update the "instance available" field only if this is an 2069 * acceptable reply. */ 2070 if (strncmp(r->str,"PONG",4) == 0 || 2071 strncmp(r->str,"LOADING",7) == 0 || 2072 strncmp(r->str,"MASTERDOWN",10) == 0) 2073 { 2074 ri->last_avail_time = mstime(); 2075 ri->last_ping_time = 0; /* Flag the pong as received. */ 2076 } else { 2077 /* Send a SCRIPT KILL command if the instance appears to be 2078 * down because of a busy script. */ 2079 if (strncmp(r->str,"BUSY",4) == 0 && 2080 (ri->flags & SRI_S_DOWN) && 2081 !(ri->flags & SRI_SCRIPT_KILL_SENT)) 2082 { 2083 if (redisAsyncCommand(ri->cc, 2084 sentinelDiscardReplyCallback, NULL, 2085 "SCRIPT KILL") == REDIS_OK) 2086 ri->pending_commands++; 2087 ri->flags |= SRI_SCRIPT_KILL_SENT; 2088 } 2089 } 2090 } 2091 ri->last_pong_time = mstime(); 2092 } 2093 2094 /* This is called when we get the reply about the PUBLISH command we send 2095 * to the master to advertise this sentinel. */ 2096 void sentinelPublishReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2097 sentinelRedisInstance *ri = c->data; 2098 redisReply *r; 2099 REDIS_NOTUSED(privdata); 2100 2101 if (ri) ri->pending_commands--; 2102 if (!reply || !ri) return; 2103 r = reply; 2104 2105 /* Only update pub_time if we actually published our message. Otherwise 2106 * we'll retry again in 100 milliseconds. */ 2107 if (r->type != REDIS_REPLY_ERROR) 2108 ri->last_pub_time = mstime(); 2109 } 2110 2111 /* Process an hello message received via Pub/Sub in master or slave instance, 2112 * or sent directly to this sentinel via the (fake) PUBLISH command of Sentinel. 2113 * 2114 * If the master name specified in the message is not known, the message is 2115 * discarded. */ 2116 void sentinelProcessHelloMessage(char *hello, int hello_len) { 2117 /* Format is composed of 8 tokens: 2118 * 0=ip,1=port,2=runid,3=current_epoch,4=master_name, 2119 * 5=master_ip,6=master_port,7=master_config_epoch. */ 2120 int numtokens, port, removed, master_port; 2121 uint64_t current_epoch, master_config_epoch; 2122 char **token = sdssplitlen(hello, hello_len, ",", 1, &numtokens); 2123 sentinelRedisInstance *si, *master; 2124 2125 if (numtokens == 8) { 2126 /* Obtain a reference to the master this hello message is about */ 2127 master = sentinelGetMasterByName(token[4]); 2128 if (!master) goto cleanup; /* Unknown master, skip the message. */ 2129 2130 /* First, try to see if we already have this sentinel. */ 2131 port = atoi(token[1]); 2132 master_port = atoi(token[6]); 2133 si = getSentinelRedisInstanceByAddrAndRunID( 2134 master->sentinels,token[0],port,token[2]); 2135 current_epoch = strtoull(token[3],NULL,10); 2136 master_config_epoch = strtoull(token[7],NULL,10); 2137 2138 if (!si) { 2139 /* If not, remove all the sentinels that have the same runid 2140 * OR the same ip/port, because it's either a restart or a 2141 * network topology change. */ 2142 removed = removeMatchingSentinelsFromMaster(master,token[0],port, 2143 token[2]); 2144 if (removed) { 2145 sentinelEvent(REDIS_NOTICE,"-dup-sentinel",master, 2146 "%@ #duplicate of %s:%d or %s", 2147 token[0],port,token[2]); 2148 } 2149 2150 /* Add the new sentinel. */ 2151 si = createSentinelRedisInstance(NULL,SRI_SENTINEL, 2152 token[0],port,master->quorum,master); 2153 if (si) { 2154 sentinelEvent(REDIS_NOTICE,"+sentinel",si,"%@"); 2155 /* The runid is NULL after a new instance creation and 2156 * for Sentinels we don't have a later chance to fill it, 2157 * so do it now. */ 2158 si->runid = sdsnew(token[2]); 2159 sentinelFlushConfig(); 2160 } 2161 } 2162 2163 /* Update local current_epoch if received current_epoch is greater.*/ 2164 if (current_epoch > sentinel.current_epoch) { 2165 sentinel.current_epoch = current_epoch; 2166 sentinelFlushConfig(); 2167 sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu", 2168 (unsigned long long) sentinel.current_epoch); 2169 } 2170 2171 /* Update master info if received configuration is newer. */ 2172 if (master->config_epoch < master_config_epoch) { 2173 master->config_epoch = master_config_epoch; 2174 if (master_port != master->addr->port || 2175 strcmp(master->addr->ip, token[5])) 2176 { 2177 sentinelAddr *old_addr; 2178 2179 sentinelEvent(REDIS_WARNING,"+config-update-from",si,"%@"); 2180 sentinelEvent(REDIS_WARNING,"+switch-master", 2181 master,"%s %s %d %s %d", 2182 master->name, 2183 master->addr->ip, master->addr->port, 2184 token[5], master_port); 2185 2186 old_addr = dupSentinelAddr(master->addr); 2187 sentinelResetMasterAndChangeAddress(master, token[5], master_port); 2188 sentinelCallClientReconfScript(master, 2189 SENTINEL_OBSERVER,"start", 2190 old_addr,master->addr); 2191 releaseSentinelAddr(old_addr); 2192 } 2193 } 2194 2195 /* Update the state of the Sentinel. */ 2196 if (si) si->last_hello_time = mstime(); 2197 } 2198 2199 cleanup: 2200 sdsfreesplitres(token,numtokens); 2201 } 2202 2203 2204 /* This is our Pub/Sub callback for the Hello channel. It's useful in order 2205 * to discover other sentinels attached at the same master. */ 2206 void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privdata) { 2207 sentinelRedisInstance *ri = c->data; 2208 redisReply *r; 2209 REDIS_NOTUSED(privdata); 2210 2211 if (!reply || !ri) return; 2212 r = reply; 2213 2214 /* Update the last activity in the pubsub channel. Note that since we 2215 * receive our messages as well this timestamp can be used to detect 2216 * if the link is probably disconnected even if it seems otherwise. */ 2217 ri->pc_last_activity = mstime(); 2218 2219 /* Sanity check in the reply we expect, so that the code that follows 2220 * can avoid to check for details. */ 2221 if (r->type != REDIS_REPLY_ARRAY || 2222 r->elements != 3 || 2223 r->element[0]->type != REDIS_REPLY_STRING || 2224 r->element[1]->type != REDIS_REPLY_STRING || 2225 r->element[2]->type != REDIS_REPLY_STRING || 2226 strcmp(r->element[0]->str,"message") != 0) return; 2227 2228 /* We are not interested in meeting ourselves */ 2229 if (strstr(r->element[2]->str,server.runid) != NULL) return; 2230 2231 sentinelProcessHelloMessage(r->element[2]->str, r->element[2]->len); 2232 } 2233 2234 /* Send an "Hello" message via Pub/Sub to the specified 'ri' Redis 2235 * instance in order to broadcast the current configuraiton for this 2236 * master, and to advertise the existence of this Sentinel at the same time. 2237 * 2238 * The message has the following format: 2239 * 2240 * sentinel_ip,sentinel_port,sentinel_runid,current_epoch, 2241 * master_name,master_ip,master_port,master_config_epoch. 2242 * 2243 * Returns REDIS_OK if the PUBLISH was queued correctly, otherwise 2244 * REDIS_ERR is returned. */ 2245 int sentinelSendHello(sentinelRedisInstance *ri) { 2246 char ip[REDIS_IP_STR_LEN]; 2247 char payload[REDIS_IP_STR_LEN+1024]; 2248 int retval; 2249 char *announce_ip; 2250 int announce_port; 2251 sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? ri : ri->master; 2252 sentinelAddr *master_addr = sentinelGetCurrentMasterAddress(master); 2253 2254 if (ri->flags & SRI_DISCONNECTED) return REDIS_ERR; 2255 2256 /* Use the specified announce address if specified, otherwise try to 2257 * obtain our own IP address. */ 2258 if (sentinel.announce_ip) { 2259 announce_ip = sentinel.announce_ip; 2260 } else { 2261 if (anetSockName(ri->cc->c.fd,ip,sizeof(ip),NULL) == -1) 2262 return REDIS_ERR; 2263 announce_ip = ip; 2264 } 2265 announce_port = sentinel.announce_port ? 2266 sentinel.announce_port : server.port; 2267 2268 /* Format and send the Hello message. */ 2269 snprintf(payload,sizeof(payload), 2270 "%s,%d,%s,%llu," /* Info about this sentinel. */ 2271 "%s,%s,%d,%llu", /* Info about current master. */ 2272 announce_ip, announce_port, server.runid, 2273 (unsigned long long) sentinel.current_epoch, 2274 /* --- */ 2275 master->name,master_addr->ip,master_addr->port, 2276 (unsigned long long) master->config_epoch); 2277 retval = redisAsyncCommand(ri->cc, 2278 sentinelPublishReplyCallback, NULL, "PUBLISH %s %s", 2279 SENTINEL_HELLO_CHANNEL,payload); 2280 if (retval != REDIS_OK) return REDIS_ERR; 2281 ri->pending_commands++; 2282 return REDIS_OK; 2283 } 2284 2285 /* Reset last_pub_time in all the instances in the specified dictionary 2286 * in order to force the delivery of an Hello update ASAP. */ 2287 void sentinelForceHelloUpdateDictOfRedisInstances(dict *instances) { 2288 dictIterator *di; 2289 dictEntry *de; 2290 2291 di = dictGetSafeIterator(instances); 2292 while((de = dictNext(di)) != NULL) { 2293 sentinelRedisInstance *ri = dictGetVal(de); 2294 if (ri->last_pub_time >= (SENTINEL_PUBLISH_PERIOD+1)) 2295 ri->last_pub_time -= (SENTINEL_PUBLISH_PERIOD+1); 2296 } 2297 dictReleaseIterator(di); 2298 } 2299 2300 /* This function forces the delivery of an "Hello" message (see 2301 * sentinelSendHello() top comment for further information) to all the Redis 2302 * and Sentinel instances related to the specified 'master'. 2303 * 2304 * It is technically not needed since we send an update to every instance 2305 * with a period of SENTINEL_PUBLISH_PERIOD milliseconds, however when a 2306 * Sentinel upgrades a configuration it is a good idea to deliever an update 2307 * to the other Sentinels ASAP. */ 2308 int sentinelForceHelloUpdateForMaster(sentinelRedisInstance *master) { 2309 if (!(master->flags & SRI_MASTER)) return REDIS_ERR; 2310 if (master->last_pub_time >= (SENTINEL_PUBLISH_PERIOD+1)) 2311 master->last_pub_time -= (SENTINEL_PUBLISH_PERIOD+1); 2312 sentinelForceHelloUpdateDictOfRedisInstances(master->sentinels); 2313 sentinelForceHelloUpdateDictOfRedisInstances(master->slaves); 2314 return REDIS_OK; 2315 } 2316 2317 /* Send a PING to the specified instance and refresh the last_ping_time 2318 * if it is zero (that is, if we received a pong for the previous ping). 2319 * 2320 * On error zero is returned, and we can't consider the PING command 2321 * queued in the connection. */ 2322 int sentinelSendPing(sentinelRedisInstance *ri) { 2323 int retval = redisAsyncCommand(ri->cc, 2324 sentinelPingReplyCallback, NULL, "PING"); 2325 if (retval == REDIS_OK) { 2326 ri->pending_commands++; 2327 /* We update the ping time only if we received the pong for 2328 * the previous ping, otherwise we are technically waiting 2329 * since the first ping that did not received a reply. */ 2330 if (ri->last_ping_time == 0) ri->last_ping_time = mstime(); 2331 return 1; 2332 } else { 2333 return 0; 2334 } 2335 } 2336 2337 /* Send periodic PING, INFO, and PUBLISH to the Hello channel to 2338 * the specified master or slave instance. */ 2339 void sentinelSendPeriodicCommands(sentinelRedisInstance *ri) { 2340 mstime_t now = mstime(); 2341 mstime_t info_period, ping_period; 2342 int retval; 2343 2344 /* Return ASAP if we have already a PING or INFO already pending, or 2345 * in the case the instance is not properly connected. */ 2346 if (ri->flags & SRI_DISCONNECTED) return; 2347 2348 /* For INFO, PING, PUBLISH that are not critical commands to send we 2349 * also have a limit of SENTINEL_MAX_PENDING_COMMANDS. We don't 2350 * want to use a lot of memory just because a link is not working 2351 * properly (note that anyway there is a redundant protection about this, 2352 * that is, the link will be disconnected and reconnected if a long 2353 * timeout condition is detected. */ 2354 if (ri->pending_commands >= SENTINEL_MAX_PENDING_COMMANDS) return; 2355 2356 /* If this is a slave of a master in O_DOWN condition we start sending 2357 * it INFO every second, instead of the usual SENTINEL_INFO_PERIOD 2358 * period. In this state we want to closely monitor slaves in case they 2359 * are turned into masters by another Sentinel, or by the sysadmin. */ 2360 if ((ri->flags & SRI_SLAVE) && 2361 (ri->master->flags & (SRI_O_DOWN|SRI_FAILOVER_IN_PROGRESS))) { 2362 info_period = 1000; 2363 } else { 2364 info_period = SENTINEL_INFO_PERIOD; 2365 } 2366 2367 /* We ping instances every time the last received pong is older than 2368 * the configured 'down-after-milliseconds' time, but every second 2369 * anyway if 'down-after-milliseconds' is greater than 1 second. */ 2370 ping_period = ri->down_after_period; 2371 if (ping_period > SENTINEL_PING_PERIOD) ping_period = SENTINEL_PING_PERIOD; 2372 2373 if ((ri->flags & SRI_SENTINEL) == 0 && 2374 (ri->info_refresh == 0 || 2375 (now - ri->info_refresh) > info_period)) 2376 { 2377 /* Send INFO to masters and slaves, not sentinels. */ 2378 retval = redisAsyncCommand(ri->cc, 2379 sentinelInfoReplyCallback, NULL, "INFO"); 2380 if (retval == REDIS_OK) ri->pending_commands++; 2381 } else if ((now - ri->last_pong_time) > ping_period) { 2382 /* Send PING to all the three kinds of instances. */ 2383 sentinelSendPing(ri); 2384 } else if ((now - ri->last_pub_time) > SENTINEL_PUBLISH_PERIOD) { 2385 /* PUBLISH hello messages to all the three kinds of instances. */ 2386 sentinelSendHello(ri); 2387 } 2388 } 2389 2390 /* =========================== SENTINEL command ============================= */ 2391 2392 const char *sentinelFailoverStateStr(int state) { 2393 switch(state) { 2394 case SENTINEL_FAILOVER_STATE_NONE: return "none"; 2395 case SENTINEL_FAILOVER_STATE_WAIT_START: return "wait_start"; 2396 case SENTINEL_FAILOVER_STATE_SELECT_SLAVE: return "select_slave"; 2397 case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE: return "send_slaveof_noone"; 2398 case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION: return "wait_promotion"; 2399 case SENTINEL_FAILOVER_STATE_RECONF_SLAVES: return "reconf_slaves"; 2400 case SENTINEL_FAILOVER_STATE_UPDATE_CONFIG: return "update_config"; 2401 default: return "unknown"; 2402 } 2403 } 2404 2405 /* Redis instance to Redis protocol representation. */ 2406 void addReplySentinelRedisInstance(redisClient *c, sentinelRedisInstance *ri) { 2407 char *flags = sdsempty(); 2408 void *mbl; 2409 int fields = 0; 2410 2411 mbl = addDeferredMultiBulkLength(c); 2412 2413 addReplyBulkCString(c,"name"); 2414 addReplyBulkCString(c,ri->name); 2415 fields++; 2416 2417 addReplyBulkCString(c,"ip"); 2418 addReplyBulkCString(c,ri->addr->ip); 2419 fields++; 2420 2421 addReplyBulkCString(c,"port"); 2422 addReplyBulkLongLong(c,ri->addr->port); 2423 fields++; 2424 2425 addReplyBulkCString(c,"runid"); 2426 addReplyBulkCString(c,ri->runid ? ri->runid : ""); 2427 fields++; 2428 2429 addReplyBulkCString(c,"flags"); 2430 if (ri->flags & SRI_S_DOWN) flags = sdscat(flags,"s_down,"); 2431 if (ri->flags & SRI_O_DOWN) flags = sdscat(flags,"o_down,"); 2432 if (ri->flags & SRI_MASTER) flags = sdscat(flags,"master,"); 2433 if (ri->flags & SRI_SLAVE) flags = sdscat(flags,"slave,"); 2434 if (ri->flags & SRI_SENTINEL) flags = sdscat(flags,"sentinel,"); 2435 if (ri->flags & SRI_DISCONNECTED) flags = sdscat(flags,"disconnected,"); 2436 if (ri->flags & SRI_MASTER_DOWN) flags = sdscat(flags,"master_down,"); 2437 if (ri->flags & SRI_FAILOVER_IN_PROGRESS) 2438 flags = sdscat(flags,"failover_in_progress,"); 2439 if (ri->flags & SRI_PROMOTED) flags = sdscat(flags,"promoted,"); 2440 if (ri->flags & SRI_RECONF_SENT) flags = sdscat(flags,"reconf_sent,"); 2441 if (ri->flags & SRI_RECONF_INPROG) flags = sdscat(flags,"reconf_inprog,"); 2442 if (ri->flags & SRI_RECONF_DONE) flags = sdscat(flags,"reconf_done,"); 2443 2444 if (sdslen(flags) != 0) sdsrange(flags,0,-2); /* remove last "," */ 2445 addReplyBulkCString(c,flags); 2446 sdsfree(flags); 2447 fields++; 2448 2449 addReplyBulkCString(c,"pending-commands"); 2450 addReplyBulkLongLong(c,ri->pending_commands); 2451 fields++; 2452 2453 if (ri->flags & SRI_FAILOVER_IN_PROGRESS) { 2454 addReplyBulkCString(c,"failover-state"); 2455 addReplyBulkCString(c,(char*)sentinelFailoverStateStr(ri->failover_state)); 2456 fields++; 2457 } 2458 2459 addReplyBulkCString(c,"last-ping-sent"); 2460 addReplyBulkLongLong(c, 2461 ri->last_ping_time ? (mstime() - ri->last_ping_time) : 0); 2462 fields++; 2463 2464 addReplyBulkCString(c,"last-ok-ping-reply"); 2465 addReplyBulkLongLong(c,mstime() - ri->last_avail_time); 2466 fields++; 2467 2468 addReplyBulkCString(c,"last-ping-reply"); 2469 addReplyBulkLongLong(c,mstime() - ri->last_pong_time); 2470 fields++; 2471 2472 if (ri->flags & SRI_S_DOWN) { 2473 addReplyBulkCString(c,"s-down-time"); 2474 addReplyBulkLongLong(c,mstime()-ri->s_down_since_time); 2475 fields++; 2476 } 2477 2478 if (ri->flags & SRI_O_DOWN) { 2479 addReplyBulkCString(c,"o-down-time"); 2480 addReplyBulkLongLong(c,mstime()-ri->o_down_since_time); 2481 fields++; 2482 } 2483 2484 addReplyBulkCString(c,"down-after-milliseconds"); 2485 addReplyBulkLongLong(c,ri->down_after_period); 2486 fields++; 2487 2488 /* Masters and Slaves */ 2489 if (ri->flags & (SRI_MASTER|SRI_SLAVE)) { 2490 addReplyBulkCString(c,"info-refresh"); 2491 addReplyBulkLongLong(c,mstime() - ri->info_refresh); 2492 fields++; 2493 2494 addReplyBulkCString(c,"role-reported"); 2495 addReplyBulkCString(c, (ri->role_reported == SRI_MASTER) ? "master" : 2496 "slave"); 2497 fields++; 2498 2499 addReplyBulkCString(c,"role-reported-time"); 2500 addReplyBulkLongLong(c,mstime() - ri->role_reported_time); 2501 fields++; 2502 } 2503 2504 /* Only masters */ 2505 if (ri->flags & SRI_MASTER) { 2506 addReplyBulkCString(c,"config-epoch"); 2507 addReplyBulkLongLong(c,ri->config_epoch); 2508 fields++; 2509 2510 addReplyBulkCString(c,"num-slaves"); 2511 addReplyBulkLongLong(c,dictSize(ri->slaves)); 2512 fields++; 2513 2514 addReplyBulkCString(c,"num-other-sentinels"); 2515 addReplyBulkLongLong(c,dictSize(ri->sentinels)); 2516 fields++; 2517 2518 addReplyBulkCString(c,"quorum"); 2519 addReplyBulkLongLong(c,ri->quorum); 2520 fields++; 2521 2522 addReplyBulkCString(c,"failover-timeout"); 2523 addReplyBulkLongLong(c,ri->failover_timeout); 2524 fields++; 2525 2526 addReplyBulkCString(c,"parallel-syncs"); 2527 addReplyBulkLongLong(c,ri->parallel_syncs); 2528 fields++; 2529 2530 if (ri->notification_script) { 2531 addReplyBulkCString(c,"notification-script"); 2532 addReplyBulkCString(c,ri->notification_script); 2533 fields++; 2534 } 2535 2536 if (ri->client_reconfig_script) { 2537 addReplyBulkCString(c,"client-reconfig-script"); 2538 addReplyBulkCString(c,ri->client_reconfig_script); 2539 fields++; 2540 } 2541 } 2542 2543 /* Only slaves */ 2544 if (ri->flags & SRI_SLAVE) { 2545 addReplyBulkCString(c,"master-link-down-time"); 2546 addReplyBulkLongLong(c,ri->master_link_down_time); 2547 fields++; 2548 2549 addReplyBulkCString(c,"master-link-status"); 2550 addReplyBulkCString(c, 2551 (ri->slave_master_link_status == SENTINEL_MASTER_LINK_STATUS_UP) ? 2552 "ok" : "err"); 2553 fields++; 2554 2555 addReplyBulkCString(c,"master-host"); 2556 addReplyBulkCString(c, 2557 ri->slave_master_host ? ri->slave_master_host : "?"); 2558 fields++; 2559 2560 addReplyBulkCString(c,"master-port"); 2561 addReplyBulkLongLong(c,ri->slave_master_port); 2562 fields++; 2563 2564 addReplyBulkCString(c,"slave-priority"); 2565 addReplyBulkLongLong(c,ri->slave_priority); 2566 fields++; 2567 2568 addReplyBulkCString(c,"slave-repl-offset"); 2569 addReplyBulkLongLong(c,ri->slave_repl_offset); 2570 fields++; 2571 } 2572 2573 /* Only sentinels */ 2574 if (ri->flags & SRI_SENTINEL) { 2575 addReplyBulkCString(c,"last-hello-message"); 2576 addReplyBulkLongLong(c,mstime() - ri->last_hello_time); 2577 fields++; 2578 2579 addReplyBulkCString(c,"voted-leader"); 2580 addReplyBulkCString(c,ri->leader ? ri->leader : "?"); 2581 fields++; 2582 2583 addReplyBulkCString(c,"voted-leader-epoch"); 2584 addReplyBulkLongLong(c,ri->leader_epoch); 2585 fields++; 2586 } 2587 2588 setDeferredMultiBulkLength(c,mbl,fields*2); 2589 } 2590 2591 /* Output a number of instances contained inside a dictionary as 2592 * Redis protocol. */ 2593 void addReplyDictOfRedisInstances(redisClient *c, dict *instances) { 2594 dictIterator *di; 2595 dictEntry *de; 2596 2597 di = dictGetIterator(instances); 2598 addReplyMultiBulkLen(c,dictSize(instances)); 2599 while((de = dictNext(di)) != NULL) { 2600 sentinelRedisInstance *ri = dictGetVal(de); 2601 2602 addReplySentinelRedisInstance(c,ri); 2603 } 2604 dictReleaseIterator(di); 2605 } 2606 2607 /* Lookup the named master into sentinel.masters. 2608 * If the master is not found reply to the client with an error and returns 2609 * NULL. */ 2610 sentinelRedisInstance *sentinelGetMasterByNameOrReplyError(redisClient *c, 2611 robj *name) 2612 { 2613 sentinelRedisInstance *ri; 2614 2615 ri = dictFetchValue(sentinel.masters,name->ptr); 2616 if (!ri) { 2617 addReplyError(c,"No such master with that name"); 2618 return NULL; 2619 } 2620 return ri; 2621 } 2622 2623 void sentinelCommand(redisClient *c) { 2624 if (!strcasecmp(c->argv[1]->ptr,"masters")) { 2625 /* SENTINEL MASTERS */ 2626 if (c->argc != 2) goto numargserr; 2627 addReplyDictOfRedisInstances(c,sentinel.masters); 2628 } else if (!strcasecmp(c->argv[1]->ptr,"master")) { 2629 /* SENTINEL MASTER <name> */ 2630 sentinelRedisInstance *ri; 2631 2632 if (c->argc != 3) goto numargserr; 2633 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) 2634 == NULL) return; 2635 addReplySentinelRedisInstance(c,ri); 2636 } else if (!strcasecmp(c->argv[1]->ptr,"slaves")) { 2637 /* SENTINEL SLAVES <master-name> */ 2638 sentinelRedisInstance *ri; 2639 2640 if (c->argc != 3) goto numargserr; 2641 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL) 2642 return; 2643 addReplyDictOfRedisInstances(c,ri->slaves); 2644 } else if (!strcasecmp(c->argv[1]->ptr,"sentinels")) { 2645 /* SENTINEL SENTINELS <master-name> */ 2646 sentinelRedisInstance *ri; 2647 2648 if (c->argc != 3) goto numargserr; 2649 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL) 2650 return; 2651 addReplyDictOfRedisInstances(c,ri->sentinels); 2652 } else if (!strcasecmp(c->argv[1]->ptr,"is-master-down-by-addr")) { 2653 /* SENTINEL IS-MASTER-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid>*/ 2654 sentinelRedisInstance *ri; 2655 long long req_epoch; 2656 uint64_t leader_epoch = 0; 2657 char *leader = NULL; 2658 long port; 2659 int isdown = 0; 2660 2661 if (c->argc != 6) goto numargserr; 2662 if (getLongFromObjectOrReply(c,c->argv[3],&port,NULL) != REDIS_OK || 2663 getLongLongFromObjectOrReply(c,c->argv[4],&req_epoch,NULL) 2664 != REDIS_OK) 2665 return; 2666 ri = getSentinelRedisInstanceByAddrAndRunID(sentinel.masters, 2667 c->argv[2]->ptr,port,NULL); 2668 2669 /* It exists? Is actually a master? Is subjectively down? It's down. 2670 * Note: if we are in tilt mode we always reply with "0". */ 2671 if (!sentinel.tilt && ri && (ri->flags & SRI_S_DOWN) && 2672 (ri->flags & SRI_MASTER)) 2673 isdown = 1; 2674 2675 /* Vote for the master (or fetch the previous vote) if the request 2676 * includes a runid, otherwise the sender is not seeking for a vote. */ 2677 if (ri && ri->flags & SRI_MASTER && strcasecmp(c->argv[5]->ptr,"*")) { 2678 leader = sentinelVoteLeader(ri,(uint64_t)req_epoch, 2679 c->argv[5]->ptr, 2680 &leader_epoch); 2681 } 2682 2683 /* Reply with a three-elements multi-bulk reply: 2684 * down state, leader, vote epoch. */ 2685 addReplyMultiBulkLen(c,3); 2686 addReply(c, isdown ? shared.cone : shared.czero); 2687 addReplyBulkCString(c, leader ? leader : "*"); 2688 addReplyLongLong(c, (long long)leader_epoch); 2689 if (leader) sdsfree(leader); 2690 } else if (!strcasecmp(c->argv[1]->ptr,"reset")) { 2691 /* SENTINEL RESET <pattern> */ 2692 if (c->argc != 3) goto numargserr; 2693 addReplyLongLong(c,sentinelResetMastersByPattern(c->argv[2]->ptr,SENTINEL_GENERATE_EVENT)); 2694 } else if (!strcasecmp(c->argv[1]->ptr,"get-master-addr-by-name")) { 2695 /* SENTINEL GET-MASTER-ADDR-BY-NAME <master-name> */ 2696 sentinelRedisInstance *ri; 2697 2698 if (c->argc != 3) goto numargserr; 2699 ri = sentinelGetMasterByName(c->argv[2]->ptr); 2700 if (ri == NULL) { 2701 addReply(c,shared.nullmultibulk); 2702 } else { 2703 sentinelAddr *addr = sentinelGetCurrentMasterAddress(ri); 2704 2705 addReplyMultiBulkLen(c,2); 2706 addReplyBulkCString(c,addr->ip); 2707 addReplyBulkLongLong(c,addr->port); 2708 } 2709 } else if (!strcasecmp(c->argv[1]->ptr,"failover")) { 2710 /* SENTINEL FAILOVER <master-name> */ 2711 sentinelRedisInstance *ri; 2712 2713 if (c->argc != 3) goto numargserr; 2714 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL) 2715 return; 2716 if (ri->flags & SRI_FAILOVER_IN_PROGRESS) { 2717 addReplySds(c,sdsnew("-INPROG Failover already in progress\r\n")); 2718 return; 2719 } 2720 if (sentinelSelectSlave(ri) == NULL) { 2721 addReplySds(c,sdsnew("-NOGOODSLAVE No suitable slave to promote\r\n")); 2722 return; 2723 } 2724 redisLog(REDIS_WARNING,"Executing user requested FAILOVER of '%s'", 2725 ri->name); 2726 sentinelStartFailover(ri); 2727 ri->flags |= SRI_FORCE_FAILOVER; 2728 addReply(c,shared.ok); 2729 } else if (!strcasecmp(c->argv[1]->ptr,"pending-scripts")) { 2730 /* SENTINEL PENDING-SCRIPTS */ 2731 2732 if (c->argc != 2) goto numargserr; 2733 sentinelPendingScriptsCommand(c); 2734 } else if (!strcasecmp(c->argv[1]->ptr,"monitor")) { 2735 /* SENTINEL MONITOR <name> <ip> <port> <quorum> */ 2736 sentinelRedisInstance *ri; 2737 long quorum, port; 2738 char ip[REDIS_IP_STR_LEN]; 2739 2740 if (c->argc != 6) goto numargserr; 2741 if (getLongFromObjectOrReply(c,c->argv[5],&quorum,"Invalid quorum") 2742 != REDIS_OK) return; 2743 if (getLongFromObjectOrReply(c,c->argv[4],&port,"Invalid port") 2744 != REDIS_OK) return; 2745 2746 if (quorum <= 0) { 2747 addReplyError(c, "Quorum must be 1 or greater."); 2748 return; 2749 } 2750 2751 /* Make sure the IP field is actually a valid IP before passing it 2752 * to createSentinelRedisInstance(), otherwise we may trigger a 2753 * DNS lookup at runtime. */ 2754 if (anetResolveIP(NULL,c->argv[3]->ptr,ip,sizeof(ip)) == ANET_ERR) { 2755 addReplyError(c,"Invalid IP address specified"); 2756 return; 2757 } 2758 2759 /* Parameters are valid. Try to create the master instance. */ 2760 ri = createSentinelRedisInstance(c->argv[2]->ptr,SRI_MASTER, 2761 c->argv[3]->ptr,port,quorum,NULL); 2762 if (ri == NULL) { 2763 switch(errno) { 2764 case EBUSY: 2765 addReplyError(c,"Duplicated master name"); 2766 break; 2767 case EINVAL: 2768 addReplyError(c,"Invalid port number"); 2769 break; 2770 default: 2771 addReplyError(c,"Unspecified error adding the instance"); 2772 break; 2773 } 2774 } else { 2775 sentinelFlushConfig(); 2776 sentinelEvent(REDIS_WARNING,"+monitor",ri,"%@ quorum %d",ri->quorum); 2777 addReply(c,shared.ok); 2778 } 2779 } else if (!strcasecmp(c->argv[1]->ptr,"remove")) { 2780 /* SENTINEL REMOVE <name> */ 2781 sentinelRedisInstance *ri; 2782 2783 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) 2784 == NULL) return; 2785 sentinelEvent(REDIS_WARNING,"-monitor",ri,"%@"); 2786 dictDelete(sentinel.masters,c->argv[2]->ptr); 2787 sentinelFlushConfig(); 2788 addReply(c,shared.ok); 2789 } else if (!strcasecmp(c->argv[1]->ptr,"set")) { 2790 if (c->argc < 3 || c->argc % 2 == 0) goto numargserr; 2791 sentinelSetCommand(c); 2792 } else if (!strcasecmp(c->argv[1]->ptr,"info-cache")) { 2793 if (c->argc < 2) goto numargserr; 2794 mstime_t now = mstime(); 2795 2796 /* Create an ad-hoc dictionary type so that we can iterate 2797 * a dictionary composed of just the master groups the user 2798 * requested. */ 2799 dictType copy_keeper = instancesDictType; 2800 copy_keeper.valDestructor = NULL; 2801 dict *masters_local = sentinel.masters; 2802 if (c->argc > 2) { 2803 masters_local = dictCreate(©_keeper, NULL); 2804 2805 for (int i = 2; i < c->argc; i++) { 2806 sentinelRedisInstance *ri; 2807 ri = sentinelGetMasterByName(c->argv[i]->ptr); 2808 if (!ri) continue; /* ignore non-existing names */ 2809 dictAdd(masters_local, ri->name, ri); 2810 } 2811 } 2812 2813 /* Reply format: 2814 * 1.) master name 2815 * 2.) 1.) info from master 2816 * 2.) info from replica 2817 * ... 2818 * 3.) other master name 2819 * ... 2820 */ 2821 addReplyMultiBulkLen(c,dictSize(masters_local) * 2); 2822 2823 dictIterator *di; 2824 dictEntry *de; 2825 di = dictGetIterator(masters_local); 2826 while ((de = dictNext(di)) != NULL) { 2827 sentinelRedisInstance *ri = dictGetVal(de); 2828 addReplyBulkCBuffer(c,ri->name,strlen(ri->name)); 2829 addReplyMultiBulkLen(c,dictSize(ri->slaves) + 1); /* +1 for self */ 2830 addReplyMultiBulkLen(c,2); 2831 addReplyLongLong(c, now - ri->info_refresh); 2832 if (ri->info) 2833 addReplyBulkCBuffer(c,ri->info,sdslen(ri->info)); 2834 else 2835 addReply(c,shared.nullbulk); 2836 2837 dictIterator *sdi; 2838 dictEntry *sde; 2839 sdi = dictGetIterator(ri->slaves); 2840 while ((sde = dictNext(sdi)) != NULL) { 2841 sentinelRedisInstance *sri = dictGetVal(sde); 2842 addReplyMultiBulkLen(c,2); 2843 addReplyLongLong(c, now - sri->info_refresh); 2844 if (sri->info) 2845 addReplyBulkCBuffer(c,sri->info,sdslen(sri->info)); 2846 else 2847 addReply(c,shared.nullbulk); 2848 } 2849 dictReleaseIterator(sdi); 2850 } 2851 dictReleaseIterator(di); 2852 if (masters_local != sentinel.masters) dictRelease(masters_local); 2853 } else { 2854 addReplyErrorFormat(c,"Unknown sentinel subcommand '%s'", 2855 (char*)c->argv[1]->ptr); 2856 } 2857 return; 2858 2859 numargserr: 2860 addReplyErrorFormat(c,"Wrong number of arguments for 'sentinel %s'", 2861 (char*)c->argv[1]->ptr); 2862 } 2863 2864 /* SENTINEL INFO [section] */ 2865 void sentinelInfoCommand(redisClient *c) { 2866 if (c->argc > 2) { 2867 addReply(c,shared.syntaxerr); 2868 return; 2869 } 2870 2871 int defsections = 0, allsections = 0; 2872 char *section = c->argc == 2 ? c->argv[1]->ptr : NULL; 2873 if (section) { 2874 allsections = !strcasecmp(section,"all"); 2875 defsections = !strcasecmp(section,"default"); 2876 } else { 2877 defsections = 1; 2878 } 2879 2880 int sections = 0; 2881 sds info = sdsempty(); 2882 if (defsections || allsections || !strcasecmp(section,"server")) { 2883 if (sections++) info = sdscat(info,"\r\n"); 2884 sds serversection = genRedisInfoString("server"); 2885 info = sdscatlen(info,serversection,sdslen(serversection)); 2886 sdsfree(serversection); 2887 } 2888 2889 if (defsections || allsections || !strcasecmp(section,"sentinel")) { 2890 dictIterator *di; 2891 dictEntry *de; 2892 int master_id = 0; 2893 2894 if (sections++) info = sdscat(info,"\r\n"); 2895 info = sdscatprintf(info, 2896 "# Sentinel\r\n" 2897 "sentinel_masters:%lu\r\n" 2898 "sentinel_tilt:%d\r\n" 2899 "sentinel_running_scripts:%d\r\n" 2900 "sentinel_scripts_queue_length:%ld\r\n", 2901 dictSize(sentinel.masters), 2902 sentinel.tilt, 2903 sentinel.running_scripts, 2904 listLength(sentinel.scripts_queue)); 2905 2906 di = dictGetIterator(sentinel.masters); 2907 while((de = dictNext(di)) != NULL) { 2908 sentinelRedisInstance *ri = dictGetVal(de); 2909 char *status = "ok"; 2910 2911 if (ri->flags & SRI_O_DOWN) status = "odown"; 2912 else if (ri->flags & SRI_S_DOWN) status = "sdown"; 2913 info = sdscatprintf(info, 2914 "master%d:name=%s,status=%s,address=%s:%d," 2915 "slaves=%lu,sentinels=%lu\r\n", 2916 master_id++, ri->name, status, 2917 ri->addr->ip, ri->addr->port, 2918 dictSize(ri->slaves), 2919 dictSize(ri->sentinels)+1); 2920 } 2921 dictReleaseIterator(di); 2922 } 2923 2924 addReplyBulkSds(c, info); 2925 } 2926 2927 /* Implements Sentinel verison of the ROLE command. The output is 2928 * "sentinel" and the list of currently monitored master names. */ 2929 void sentinelRoleCommand(redisClient *c) { 2930 dictIterator *di; 2931 dictEntry *de; 2932 2933 addReplyMultiBulkLen(c,2); 2934 addReplyBulkCBuffer(c,"sentinel",8); 2935 addReplyMultiBulkLen(c,dictSize(sentinel.masters)); 2936 2937 di = dictGetIterator(sentinel.masters); 2938 while((de = dictNext(di)) != NULL) { 2939 sentinelRedisInstance *ri = dictGetVal(de); 2940 2941 addReplyBulkCString(c,ri->name); 2942 } 2943 dictReleaseIterator(di); 2944 } 2945 2946 /* SENTINEL SET <mastername> [<option> <value> ...] */ 2947 void sentinelSetCommand(redisClient *c) { 2948 sentinelRedisInstance *ri; 2949 int j, changes = 0; 2950 char *option, *value; 2951 2952 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) 2953 == NULL) return; 2954 2955 /* Process option - value pairs. */ 2956 for (j = 3; j < c->argc; j += 2) { 2957 option = c->argv[j]->ptr; 2958 value = c->argv[j+1]->ptr; 2959 robj *o = c->argv[j+1]; 2960 long long ll; 2961 2962 if (!strcasecmp(option,"down-after-milliseconds")) { 2963 /* down-after-millisecodns <milliseconds> */ 2964 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2965 goto badfmt; 2966 ri->down_after_period = ll; 2967 sentinelPropagateDownAfterPeriod(ri); 2968 changes++; 2969 } else if (!strcasecmp(option,"failover-timeout")) { 2970 /* failover-timeout <milliseconds> */ 2971 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2972 goto badfmt; 2973 ri->failover_timeout = ll; 2974 changes++; 2975 } else if (!strcasecmp(option,"parallel-syncs")) { 2976 /* parallel-syncs <milliseconds> */ 2977 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2978 goto badfmt; 2979 ri->parallel_syncs = ll; 2980 changes++; 2981 } else if (!strcasecmp(option,"notification-script")) { 2982 /* notification-script <path> */ 2983 if (strlen(value) && access(value,X_OK) == -1) { 2984 addReplyError(c, 2985 "Notification script seems non existing or non executable"); 2986 if (changes) sentinelFlushConfig(); 2987 return; 2988 } 2989 sdsfree(ri->notification_script); 2990 ri->notification_script = strlen(value) ? sdsnew(value) : NULL; 2991 changes++; 2992 } else if (!strcasecmp(option,"client-reconfig-script")) { 2993 /* client-reconfig-script <path> */ 2994 if (strlen(value) && access(value,X_OK) == -1) { 2995 addReplyError(c, 2996 "Client reconfiguration script seems non existing or " 2997 "non executable"); 2998 if (changes) sentinelFlushConfig(); 2999 return; 3000 } 3001 sdsfree(ri->client_reconfig_script); 3002 ri->client_reconfig_script = strlen(value) ? sdsnew(value) : NULL; 3003 changes++; 3004 } else if (!strcasecmp(option,"auth-pass")) { 3005 /* auth-pass <password> */ 3006 sdsfree(ri->auth_pass); 3007 ri->auth_pass = strlen(value) ? sdsnew(value) : NULL; 3008 changes++; 3009 } else if (!strcasecmp(option,"quorum")) { 3010 /* quorum <count> */ 3011 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 3012 goto badfmt; 3013 ri->quorum = ll; 3014 changes++; 3015 } else { 3016 addReplyErrorFormat(c,"Unknown option '%s' for SENTINEL SET", 3017 option); 3018 if (changes) sentinelFlushConfig(); 3019 return; 3020 } 3021 sentinelEvent(REDIS_WARNING,"+set",ri,"%@ %s %s",option,value); 3022 } 3023 3024 if (changes) sentinelFlushConfig(); 3025 addReply(c,shared.ok); 3026 return; 3027 3028 badfmt: /* Bad format errors */ 3029 if (changes) sentinelFlushConfig(); 3030 addReplyErrorFormat(c,"Invalid argument '%s' for SENTINEL SET '%s'", 3031 value, option); 3032 } 3033 3034 /* Our fake PUBLISH command: it is actually useful only to receive hello messages 3035 * from the other sentinel instances, and publishing to a channel other than 3036 * SENTINEL_HELLO_CHANNEL is forbidden. 3037 * 3038 * Because we have a Sentinel PUBLISH, the code to send hello messages is the same 3039 * for all the three kind of instances: masters, slaves, sentinels. */ 3040 void sentinelPublishCommand(redisClient *c) { 3041 if (strcmp(c->argv[1]->ptr,SENTINEL_HELLO_CHANNEL)) { 3042 addReplyError(c, "Only HELLO messages are accepted by Sentinel instances."); 3043 return; 3044 } 3045 sentinelProcessHelloMessage(c->argv[2]->ptr,sdslen(c->argv[2]->ptr)); 3046 addReplyLongLong(c,1); 3047 } 3048 3049 /* ===================== SENTINEL availability checks ======================= */ 3050 3051 /* Is this instance down from our point of view? */ 3052 void sentinelCheckSubjectivelyDown(sentinelRedisInstance *ri) { 3053 mstime_t elapsed = 0; 3054 3055 if (ri->last_ping_time) 3056 elapsed = mstime() - ri->last_ping_time; 3057 3058 /* Check if we are in need for a reconnection of one of the 3059 * links, because we are detecting low activity. 3060 * 3061 * 1) Check if the command link seems connected, was connected not less 3062 * than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have a 3063 * pending ping for more than half the timeout. */ 3064 if (ri->cc && 3065 (mstime() - ri->cc_conn_time) > SENTINEL_MIN_LINK_RECONNECT_PERIOD && 3066 ri->last_ping_time != 0 && /* Ther is a pending ping... */ 3067 /* The pending ping is delayed, and we did not received 3068 * error replies as well. */ 3069 (mstime() - ri->last_ping_time) > (ri->down_after_period/2) && 3070 (mstime() - ri->last_pong_time) > (ri->down_after_period/2)) 3071 { 3072 sentinelKillLink(ri,ri->cc); 3073 } 3074 3075 /* 2) Check if the pubsub link seems connected, was connected not less 3076 * than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have no 3077 * activity in the Pub/Sub channel for more than 3078 * SENTINEL_PUBLISH_PERIOD * 3. 3079 */ 3080 if (ri->pc && 3081 (mstime() - ri->pc_conn_time) > SENTINEL_MIN_LINK_RECONNECT_PERIOD && 3082 (mstime() - ri->pc_last_activity) > (SENTINEL_PUBLISH_PERIOD*3)) 3083 { 3084 sentinelKillLink(ri,ri->pc); 3085 } 3086 3087 /* Update the SDOWN flag. We believe the instance is SDOWN if: 3088 * 3089 * 1) It is not replying. 3090 * 2) We believe it is a master, it reports to be a slave for enough time 3091 * to meet the down_after_period, plus enough time to get two times 3092 * INFO report from the instance. */ 3093 if (elapsed > ri->down_after_period || 3094 (ri->flags & SRI_MASTER && 3095 ri->role_reported == SRI_SLAVE && 3096 mstime() - ri->role_reported_time > 3097 (ri->down_after_period+SENTINEL_INFO_PERIOD*2))) 3098 { 3099 /* Is subjectively down */ 3100 if ((ri->flags & SRI_S_DOWN) == 0) { 3101 sentinelEvent(REDIS_WARNING,"+sdown",ri,"%@"); 3102 ri->s_down_since_time = mstime(); 3103 ri->flags |= SRI_S_DOWN; 3104 } 3105 } else { 3106 /* Is subjectively up */ 3107 if (ri->flags & SRI_S_DOWN) { 3108 sentinelEvent(REDIS_WARNING,"-sdown",ri,"%@"); 3109 ri->flags &= ~(SRI_S_DOWN|SRI_SCRIPT_KILL_SENT); 3110 } 3111 } 3112 } 3113 3114 /* Is this instance down according to the configured quorum? 3115 * 3116 * Note that ODOWN is a weak quorum, it only means that enough Sentinels 3117 * reported in a given time range that the instance was not reachable. 3118 * However messages can be delayed so there are no strong guarantees about 3119 * N instances agreeing at the same time about the down state. */ 3120 void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) { 3121 dictIterator *di; 3122 dictEntry *de; 3123 unsigned int quorum = 0, odown = 0; 3124 3125 if (master->flags & SRI_S_DOWN) { 3126 /* Is down for enough sentinels? */ 3127 quorum = 1; /* the current sentinel. */ 3128 /* Count all the other sentinels. */ 3129 di = dictGetIterator(master->sentinels); 3130 while((de = dictNext(di)) != NULL) { 3131 sentinelRedisInstance *ri = dictGetVal(de); 3132 3133 if (ri->flags & SRI_MASTER_DOWN) quorum++; 3134 } 3135 dictReleaseIterator(di); 3136 if (quorum >= master->quorum) odown = 1; 3137 } 3138 3139 /* Set the flag accordingly to the outcome. */ 3140 if (odown) { 3141 if ((master->flags & SRI_O_DOWN) == 0) { 3142 sentinelEvent(REDIS_WARNING,"+odown",master,"%@ #quorum %d/%d", 3143 quorum, master->quorum); 3144 master->flags |= SRI_O_DOWN; 3145 master->o_down_since_time = mstime(); 3146 } 3147 } else { 3148 if (master->flags & SRI_O_DOWN) { 3149 sentinelEvent(REDIS_WARNING,"-odown",master,"%@"); 3150 master->flags &= ~SRI_O_DOWN; 3151 } 3152 } 3153 } 3154 3155 /* Receive the SENTINEL is-master-down-by-addr reply, see the 3156 * sentinelAskMasterStateToOtherSentinels() function for more information. */ 3157 void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *privdata) { 3158 sentinelRedisInstance *ri = c->data; 3159 redisReply *r; 3160 REDIS_NOTUSED(privdata); 3161 3162 if (ri) ri->pending_commands--; 3163 if (!reply || !ri) return; 3164 r = reply; 3165 3166 /* Ignore every error or unexpected reply. 3167 * Note that if the command returns an error for any reason we'll 3168 * end clearing the SRI_MASTER_DOWN flag for timeout anyway. */ 3169 if (r->type == REDIS_REPLY_ARRAY && r->elements == 3 && 3170 r->element[0]->type == REDIS_REPLY_INTEGER && 3171 r->element[1]->type == REDIS_REPLY_STRING && 3172 r->element[2]->type == REDIS_REPLY_INTEGER) 3173 { 3174 ri->last_master_down_reply_time = mstime(); 3175 if (r->element[0]->integer == 1) { 3176 ri->flags |= SRI_MASTER_DOWN; 3177 } else { 3178 ri->flags &= ~SRI_MASTER_DOWN; 3179 } 3180 if (strcmp(r->element[1]->str,"*")) { 3181 /* If the runid in the reply is not "*" the Sentinel actually 3182 * replied with a vote. */ 3183 sdsfree(ri->leader); 3184 if ((long long)ri->leader_epoch != r->element[2]->integer) 3185 redisLog(REDIS_WARNING, 3186 "%s voted for %s %llu", ri->name, 3187 r->element[1]->str, 3188 (unsigned long long) r->element[2]->integer); 3189 ri->leader = sdsnew(r->element[1]->str); 3190 ri->leader_epoch = r->element[2]->integer; 3191 } 3192 } 3193 } 3194 3195 /* If we think the master is down, we start sending 3196 * SENTINEL IS-MASTER-DOWN-BY-ADDR requests to other sentinels 3197 * in order to get the replies that allow to reach the quorum 3198 * needed to mark the master in ODOWN state and trigger a failover. */ 3199 #define SENTINEL_ASK_FORCED (1<<0) 3200 void sentinelAskMasterStateToOtherSentinels(sentinelRedisInstance *master, int flags) { 3201 dictIterator *di; 3202 dictEntry *de; 3203 3204 di = dictGetIterator(master->sentinels); 3205 while((de = dictNext(di)) != NULL) { 3206 sentinelRedisInstance *ri = dictGetVal(de); 3207 mstime_t elapsed = mstime() - ri->last_master_down_reply_time; 3208 char port[32]; 3209 int retval; 3210 3211 /* If the master state from other sentinel is too old, we clear it. */ 3212 if (elapsed > SENTINEL_ASK_PERIOD*5) { 3213 ri->flags &= ~SRI_MASTER_DOWN; 3214 sdsfree(ri->leader); 3215 ri->leader = NULL; 3216 } 3217 3218 /* Only ask if master is down to other sentinels if: 3219 * 3220 * 1) We believe it is down, or there is a failover in progress. 3221 * 2) Sentinel is connected. 3222 * 3) We did not received the info within SENTINEL_ASK_PERIOD ms. */ 3223 if ((master->flags & SRI_S_DOWN) == 0) continue; 3224 if (ri->flags & SRI_DISCONNECTED) continue; 3225 if (!(flags & SENTINEL_ASK_FORCED) && 3226 mstime() - ri->last_master_down_reply_time < SENTINEL_ASK_PERIOD) 3227 continue; 3228 3229 /* Ask */ 3230 ll2string(port,sizeof(port),master->addr->port); 3231 retval = redisAsyncCommand(ri->cc, 3232 sentinelReceiveIsMasterDownReply, NULL, 3233 "SENTINEL is-master-down-by-addr %s %s %llu %s", 3234 master->addr->ip, port, 3235 sentinel.current_epoch, 3236 (master->failover_state > SENTINEL_FAILOVER_STATE_NONE) ? 3237 server.runid : "*"); 3238 if (retval == REDIS_OK) ri->pending_commands++; 3239 } 3240 dictReleaseIterator(di); 3241 } 3242 3243 /* =============================== FAILOVER ================================= */ 3244 3245 /* Vote for the sentinel with 'req_runid' or return the old vote if already 3246 * voted for the specifed 'req_epoch' or one greater. 3247 * 3248 * If a vote is not available returns NULL, otherwise return the Sentinel 3249 * runid and populate the leader_epoch with the epoch of the vote. */ 3250 char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch) { 3251 if (req_epoch > sentinel.current_epoch) { 3252 sentinel.current_epoch = req_epoch; 3253 sentinelFlushConfig(); 3254 sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu", 3255 (unsigned long long) sentinel.current_epoch); 3256 } 3257 3258 if (master->leader_epoch < req_epoch && sentinel.current_epoch <= req_epoch) 3259 { 3260 sdsfree(master->leader); 3261 master->leader = sdsnew(req_runid); 3262 master->leader_epoch = sentinel.current_epoch; 3263 sentinelFlushConfig(); 3264 sentinelEvent(REDIS_WARNING,"+vote-for-leader",master,"%s %llu", 3265 master->leader, (unsigned long long) master->leader_epoch); 3266 /* If we did not voted for ourselves, set the master failover start 3267 * time to now, in order to force a delay before we can start a 3268 * failover for the same master. */ 3269 if (strcasecmp(master->leader,server.runid)) 3270 master->failover_start_time = mstime()+rand()%SENTINEL_MAX_DESYNC; 3271 } 3272 3273 *leader_epoch = master->leader_epoch; 3274 return master->leader ? sdsnew(master->leader) : NULL; 3275 } 3276 3277 struct sentinelLeader { 3278 char *runid; 3279 unsigned long votes; 3280 }; 3281 3282 /* Helper function for sentinelGetLeader, increment the counter 3283 * relative to the specified runid. */ 3284 int sentinelLeaderIncr(dict *counters, char *runid) { 3285 dictEntry *de = dictFind(counters,runid); 3286 uint64_t oldval; 3287 3288 if (de) { 3289 oldval = dictGetUnsignedIntegerVal(de); 3290 dictSetUnsignedIntegerVal(de,oldval+1); 3291 return oldval+1; 3292 } else { 3293 de = dictAddRaw(counters,runid); 3294 redisAssert(de != NULL); 3295 dictSetUnsignedIntegerVal(de,1); 3296 return 1; 3297 } 3298 } 3299 3300 /* Scan all the Sentinels attached to this master to check if there 3301 * is a leader for the specified epoch. 3302 * 3303 * To be a leader for a given epoch, we should have the majority of 3304 * the Sentinels we know (ever seen since the last SENTINEL RESET) that 3305 * reported the same instance as leader for the same epoch. */ 3306 char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) { 3307 dict *counters; 3308 dictIterator *di; 3309 dictEntry *de; 3310 unsigned int voters = 0, voters_quorum; 3311 char *myvote; 3312 char *winner = NULL; 3313 uint64_t leader_epoch; 3314 uint64_t max_votes = 0; 3315 3316 redisAssert(master->flags & (SRI_O_DOWN|SRI_FAILOVER_IN_PROGRESS)); 3317 counters = dictCreate(&leaderVotesDictType,NULL); 3318 3319 voters = dictSize(master->sentinels)+1; /* All the other sentinels and me. */ 3320 3321 /* Count other sentinels votes */ 3322 di = dictGetIterator(master->sentinels); 3323 while((de = dictNext(di)) != NULL) { 3324 sentinelRedisInstance *ri = dictGetVal(de); 3325 if (ri->leader != NULL && ri->leader_epoch == sentinel.current_epoch) 3326 sentinelLeaderIncr(counters,ri->leader); 3327 } 3328 dictReleaseIterator(di); 3329 3330 /* Check what's the winner. For the winner to win, it needs two conditions: 3331 * 1) Absolute majority between voters (50% + 1). 3332 * 2) And anyway at least master->quorum votes. */ 3333 di = dictGetIterator(counters); 3334 while((de = dictNext(di)) != NULL) { 3335 uint64_t votes = dictGetUnsignedIntegerVal(de); 3336 3337 if (votes > max_votes) { 3338 max_votes = votes; 3339 winner = dictGetKey(de); 3340 } 3341 } 3342 dictReleaseIterator(di); 3343 3344 /* Count this Sentinel vote: 3345 * if this Sentinel did not voted yet, either vote for the most 3346 * common voted sentinel, or for itself if no vote exists at all. */ 3347 if (winner) 3348 myvote = sentinelVoteLeader(master,epoch,winner,&leader_epoch); 3349 else 3350 myvote = sentinelVoteLeader(master,epoch,server.runid,&leader_epoch); 3351 3352 if (myvote && leader_epoch == epoch) { 3353 uint64_t votes = sentinelLeaderIncr(counters,myvote); 3354 3355 if (votes > max_votes) { 3356 max_votes = votes; 3357 winner = myvote; 3358 } 3359 } 3360 3361 voters_quorum = voters/2+1; 3362 if (winner && (max_votes < voters_quorum || max_votes < master->quorum)) 3363 winner = NULL; 3364 3365 winner = winner ? sdsnew(winner) : NULL; 3366 sdsfree(myvote); 3367 dictRelease(counters); 3368 return winner; 3369 } 3370 3371 /* Send SLAVEOF to the specified instance, always followed by a 3372 * CONFIG REWRITE command in order to store the new configuration on disk 3373 * when possible (that is, if the Redis instance is recent enough to support 3374 * config rewriting, and if the server was started with a configuration file). 3375 * 3376 * If Host is NULL the function sends "SLAVEOF NO ONE". 3377 * 3378 * The command returns REDIS_OK if the SLAVEOF command was accepted for 3379 * (later) delivery otherwise REDIS_ERR. The command replies are just 3380 * discarded. */ 3381 int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port) { 3382 char portstr[32]; 3383 int retval; 3384 3385 ll2string(portstr,sizeof(portstr),port); 3386 3387 /* If host is NULL we send SLAVEOF NO ONE that will turn the instance 3388 * into a master. */ 3389 if (host == NULL) { 3390 host = "NO"; 3391 memcpy(portstr,"ONE",4); 3392 } 3393 3394 /* In order to send SLAVEOF in a safe way, we send a transaction performing 3395 * the following tasks: 3396 * 1) Reconfigure the instance according to the specified host/port params. 3397 * 2) Rewrite the configuraiton. 3398 * 3) Disconnect all clients (but this one sending the commnad) in order 3399 * to trigger the ask-master-on-reconnection protocol for connected 3400 * clients. 3401 * 3402 * Note that we don't check the replies returned by commands, since we 3403 * will observe instead the effects in the next INFO output. */ 3404 retval = redisAsyncCommand(ri->cc, 3405 sentinelDiscardReplyCallback, NULL, "MULTI"); 3406 if (retval == REDIS_ERR) return retval; 3407 ri->pending_commands++; 3408 3409 retval = redisAsyncCommand(ri->cc, 3410 sentinelDiscardReplyCallback, NULL, "SLAVEOF %s %s", host, portstr); 3411 if (retval == REDIS_ERR) return retval; 3412 ri->pending_commands++; 3413 3414 retval = redisAsyncCommand(ri->cc, 3415 sentinelDiscardReplyCallback, NULL, "CONFIG REWRITE"); 3416 if (retval == REDIS_ERR) return retval; 3417 ri->pending_commands++; 3418 3419 /* CLIENT KILL TYPE <type> is only supported starting from Redis 2.8.12, 3420 * however sending it to an instance not understanding this command is not 3421 * an issue because CLIENT is variadic command, so Redis will not 3422 * recognized as a syntax error, and the transaction will not fail (but 3423 * only the unsupported command will fail). */ 3424 retval = redisAsyncCommand(ri->cc, 3425 sentinelDiscardReplyCallback, NULL, "CLIENT KILL TYPE normal"); 3426 if (retval == REDIS_ERR) return retval; 3427 ri->pending_commands++; 3428 3429 retval = redisAsyncCommand(ri->cc, 3430 sentinelDiscardReplyCallback, NULL, "EXEC"); 3431 if (retval == REDIS_ERR) return retval; 3432 ri->pending_commands++; 3433 3434 return REDIS_OK; 3435 } 3436 3437 /* Setup the master state to start a failover. */ 3438 void sentinelStartFailover(sentinelRedisInstance *master) { 3439 redisAssert(master->flags & SRI_MASTER); 3440 3441 master->failover_state = SENTINEL_FAILOVER_STATE_WAIT_START; 3442 master->flags |= SRI_FAILOVER_IN_PROGRESS; 3443 master->failover_epoch = ++sentinel.current_epoch; 3444 sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu", 3445 (unsigned long long) sentinel.current_epoch); 3446 sentinelEvent(REDIS_WARNING,"+try-failover",master,"%@"); 3447 master->failover_start_time = mstime()+rand()%SENTINEL_MAX_DESYNC; 3448 master->failover_state_change_time = mstime(); 3449 } 3450 3451 /* This function checks if there are the conditions to start the failover, 3452 * that is: 3453 * 3454 * 1) Master must be in ODOWN condition. 3455 * 2) No failover already in progress. 3456 * 3) No failover already attempted recently. 3457 * 3458 * We still don't know if we'll win the election so it is possible that we 3459 * start the failover but that we'll not be able to act. 3460 * 3461 * Return non-zero if a failover was started. */ 3462 int sentinelStartFailoverIfNeeded(sentinelRedisInstance *master) { 3463 /* We can't failover if the master is not in O_DOWN state. */ 3464 if (!(master->flags & SRI_O_DOWN)) return 0; 3465 3466 /* Failover already in progress? */ 3467 if (master->flags & SRI_FAILOVER_IN_PROGRESS) return 0; 3468 3469 /* Last failover attempt started too little time ago? */ 3470 if (mstime() - master->failover_start_time < 3471 master->failover_timeout*2) 3472 { 3473 if (master->failover_delay_logged != master->failover_start_time) { 3474 time_t clock = (master->failover_start_time + 3475 master->failover_timeout*2) / 1000; 3476 char ctimebuf[26]; 3477 3478 ctime_r(&clock,ctimebuf); 3479 ctimebuf[24] = '\0'; /* Remove newline. */ 3480 master->failover_delay_logged = master->failover_start_time; 3481 redisLog(REDIS_WARNING, 3482 "Next failover delay: I will not start a failover before %s", 3483 ctimebuf); 3484 } 3485 return 0; 3486 } 3487 3488 sentinelStartFailover(master); 3489 return 1; 3490 } 3491 3492 /* Select a suitable slave to promote. The current algorithm only uses 3493 * the following parameters: 3494 * 3495 * 1) None of the following conditions: S_DOWN, O_DOWN, DISCONNECTED. 3496 * 2) Last time the slave replied to ping no more than 5 times the PING period. 3497 * 3) info_refresh not older than 3 times the INFO refresh period. 3498 * 4) master_link_down_time no more than: 3499 * (now - master->s_down_since_time) + (master->down_after_period * 10). 3500 * Basically since the master is down from our POV, the slave reports 3501 * to be disconnected no more than 10 times the configured down-after-period. 3502 * This is pretty much black magic but the idea is, the master was not 3503 * available so the slave may be lagging, but not over a certain time. 3504 * Anyway we'll select the best slave according to replication offset. 3505 * 5) Slave priority can't be zero, otherwise the slave is discarded. 3506 * 3507 * Among all the slaves matching the above conditions we select the slave 3508 * with, in order of sorting key: 3509 * 3510 * - lower slave_priority. 3511 * - bigger processed replication offset. 3512 * - lexicographically smaller runid. 3513 * 3514 * Basically if runid is the same, the slave that processed more commands 3515 * from the master is selected. 3516 * 3517 * The function returns the pointer to the selected slave, otherwise 3518 * NULL if no suitable slave was found. 3519 */ 3520 3521 /* Helper for sentinelSelectSlave(). This is used by qsort() in order to 3522 * sort suitable slaves in a "better first" order, to take the first of 3523 * the list. */ 3524 int compareSlavesForPromotion(const void *a, const void *b) { 3525 sentinelRedisInstance **sa = (sentinelRedisInstance **)a, 3526 **sb = (sentinelRedisInstance **)b; 3527 char *sa_runid, *sb_runid; 3528 3529 if ((*sa)->slave_priority != (*sb)->slave_priority) 3530 return (*sa)->slave_priority - (*sb)->slave_priority; 3531 3532 /* If priority is the same, select the slave with greater replication 3533 * offset (processed more data frmo the master). */ 3534 if ((*sa)->slave_repl_offset > (*sb)->slave_repl_offset) { 3535 return -1; /* a < b */ 3536 } else if ((*sa)->slave_repl_offset < (*sb)->slave_repl_offset) { 3537 return 1; /* b > a */ 3538 } 3539 3540 /* If the replication offset is the same select the slave with that has 3541 * the lexicographically smaller runid. Note that we try to handle runid 3542 * == NULL as there are old Redis versions that don't publish runid in 3543 * INFO. A NULL runid is considered bigger than any other runid. */ 3544 sa_runid = (*sa)->runid; 3545 sb_runid = (*sb)->runid; 3546 if (sa_runid == NULL && sb_runid == NULL) return 0; 3547 else if (sa_runid == NULL) return 1; /* a > b */ 3548 else if (sb_runid == NULL) return -1; /* a < b */ 3549 return strcasecmp(sa_runid, sb_runid); 3550 } 3551 3552 sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) { 3553 sentinelRedisInstance **instance = 3554 zmalloc(sizeof(instance[0])*dictSize(master->slaves)); 3555 sentinelRedisInstance *selected = NULL; 3556 int instances = 0; 3557 dictIterator *di; 3558 dictEntry *de; 3559 mstime_t max_master_down_time = 0; 3560 3561 if (master->flags & SRI_S_DOWN) 3562 max_master_down_time += mstime() - master->s_down_since_time; 3563 max_master_down_time += master->down_after_period * 10; 3564 3565 di = dictGetIterator(master->slaves); 3566 while((de = dictNext(di)) != NULL) { 3567 sentinelRedisInstance *slave = dictGetVal(de); 3568 mstime_t info_validity_time; 3569 3570 if (slave->flags & (SRI_S_DOWN|SRI_O_DOWN|SRI_DISCONNECTED)) continue; 3571 if (mstime() - slave->last_avail_time > SENTINEL_PING_PERIOD*5) continue; 3572 if (slave->slave_priority == 0) continue; 3573 3574 /* If the master is in SDOWN state we get INFO for slaves every second. 3575 * Otherwise we get it with the usual period so we need to account for 3576 * a larger delay. */ 3577 if (master->flags & SRI_S_DOWN) 3578 info_validity_time = SENTINEL_PING_PERIOD*5; 3579 else 3580 info_validity_time = SENTINEL_INFO_PERIOD*3; 3581 if (mstime() - slave->info_refresh > info_validity_time) continue; 3582 if (slave->master_link_down_time > max_master_down_time) continue; 3583 instance[instances++] = slave; 3584 } 3585 dictReleaseIterator(di); 3586 if (instances) { 3587 qsort(instance,instances,sizeof(sentinelRedisInstance*), 3588 compareSlavesForPromotion); 3589 selected = instance[0]; 3590 } 3591 zfree(instance); 3592 return selected; 3593 } 3594 3595 /* ---------------- Failover state machine implementation ------------------- */ 3596 void sentinelFailoverWaitStart(sentinelRedisInstance *ri) { 3597 char *leader; 3598 int isleader; 3599 3600 /* Check if we are the leader for the failover epoch. */ 3601 leader = sentinelGetLeader(ri, ri->failover_epoch); 3602 isleader = leader && strcasecmp(leader,server.runid) == 0; 3603 sdsfree(leader); 3604 3605 /* If I'm not the leader, and it is not a forced failover via 3606 * SENTINEL FAILOVER, then I can't continue with the failover. */ 3607 if (!isleader && !(ri->flags & SRI_FORCE_FAILOVER)) { 3608 int election_timeout = SENTINEL_ELECTION_TIMEOUT; 3609 3610 /* The election timeout is the MIN between SENTINEL_ELECTION_TIMEOUT 3611 * and the configured failover timeout. */ 3612 if (election_timeout > ri->failover_timeout) 3613 election_timeout = ri->failover_timeout; 3614 /* Abort the failover if I'm not the leader after some time. */ 3615 if (mstime() - ri->failover_start_time > election_timeout) { 3616 sentinelEvent(REDIS_WARNING,"-failover-abort-not-elected",ri,"%@"); 3617 sentinelAbortFailover(ri); 3618 } 3619 return; 3620 } 3621 sentinelEvent(REDIS_WARNING,"+elected-leader",ri,"%@"); 3622 ri->failover_state = SENTINEL_FAILOVER_STATE_SELECT_SLAVE; 3623 ri->failover_state_change_time = mstime(); 3624 sentinelEvent(REDIS_WARNING,"+failover-state-select-slave",ri,"%@"); 3625 } 3626 3627 void sentinelFailoverSelectSlave(sentinelRedisInstance *ri) { 3628 sentinelRedisInstance *slave = sentinelSelectSlave(ri); 3629 3630 /* We don't handle the timeout in this state as the function aborts 3631 * the failover or go forward in the next state. */ 3632 if (slave == NULL) { 3633 sentinelEvent(REDIS_WARNING,"-failover-abort-no-good-slave",ri,"%@"); 3634 sentinelAbortFailover(ri); 3635 } else { 3636 sentinelEvent(REDIS_WARNING,"+selected-slave",slave,"%@"); 3637 slave->flags |= SRI_PROMOTED; 3638 ri->promoted_slave = slave; 3639 ri->failover_state = SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE; 3640 ri->failover_state_change_time = mstime(); 3641 sentinelEvent(REDIS_NOTICE,"+failover-state-send-slaveof-noone", 3642 slave, "%@"); 3643 } 3644 } 3645 3646 void sentinelFailoverSendSlaveOfNoOne(sentinelRedisInstance *ri) { 3647 int retval; 3648 3649 /* We can't send the command to the promoted slave if it is now 3650 * disconnected. Retry again and again with this state until the timeout 3651 * is reached, then abort the failover. */ 3652 if (ri->promoted_slave->flags & SRI_DISCONNECTED) { 3653 if (mstime() - ri->failover_state_change_time > ri->failover_timeout) { 3654 sentinelEvent(REDIS_WARNING,"-failover-abort-slave-timeout",ri,"%@"); 3655 sentinelAbortFailover(ri); 3656 } 3657 return; 3658 } 3659 3660 /* Send SLAVEOF NO ONE command to turn the slave into a master. 3661 * We actually register a generic callback for this command as we don't 3662 * really care about the reply. We check if it worked indirectly observing 3663 * if INFO returns a different role (master instead of slave). */ 3664 retval = sentinelSendSlaveOf(ri->promoted_slave,NULL,0); 3665 if (retval != REDIS_OK) return; 3666 sentinelEvent(REDIS_NOTICE, "+failover-state-wait-promotion", 3667 ri->promoted_slave,"%@"); 3668 ri->failover_state = SENTINEL_FAILOVER_STATE_WAIT_PROMOTION; 3669 ri->failover_state_change_time = mstime(); 3670 } 3671 3672 /* We actually wait for promotion indirectly checking with INFO when the 3673 * slave turns into a master. */ 3674 void sentinelFailoverWaitPromotion(sentinelRedisInstance *ri) { 3675 /* Just handle the timeout. Switching to the next state is handled 3676 * by the function parsing the INFO command of the promoted slave. */ 3677 if (mstime() - ri->failover_state_change_time > ri->failover_timeout) { 3678 sentinelEvent(REDIS_WARNING,"-failover-abort-slave-timeout",ri,"%@"); 3679 sentinelAbortFailover(ri); 3680 } 3681 } 3682 3683 void sentinelFailoverDetectEnd(sentinelRedisInstance *master) { 3684 int not_reconfigured = 0, timeout = 0; 3685 dictIterator *di; 3686 dictEntry *de; 3687 mstime_t elapsed = mstime() - master->failover_state_change_time; 3688 3689 /* We can't consider failover finished if the promoted slave is 3690 * not reachable. */ 3691 if (master->promoted_slave == NULL || 3692 master->promoted_slave->flags & SRI_S_DOWN) return; 3693 3694 /* The failover terminates once all the reachable slaves are properly 3695 * configured. */ 3696 di = dictGetIterator(master->slaves); 3697 while((de = dictNext(di)) != NULL) { 3698 sentinelRedisInstance *slave = dictGetVal(de); 3699 3700 if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue; 3701 if (slave->flags & SRI_S_DOWN) continue; 3702 not_reconfigured++; 3703 } 3704 dictReleaseIterator(di); 3705 3706 /* Force end of failover on timeout. */ 3707 if (elapsed > master->failover_timeout) { 3708 not_reconfigured = 0; 3709 timeout = 1; 3710 sentinelEvent(REDIS_WARNING,"+failover-end-for-timeout",master,"%@"); 3711 } 3712 3713 if (not_reconfigured == 0) { 3714 sentinelEvent(REDIS_WARNING,"+failover-end",master,"%@"); 3715 master->failover_state = SENTINEL_FAILOVER_STATE_UPDATE_CONFIG; 3716 master->failover_state_change_time = mstime(); 3717 } 3718 3719 /* If I'm the leader it is a good idea to send a best effort SLAVEOF 3720 * command to all the slaves still not reconfigured to replicate with 3721 * the new master. */ 3722 if (timeout) { 3723 dictIterator *di; 3724 dictEntry *de; 3725 3726 di = dictGetIterator(master->slaves); 3727 while((de = dictNext(di)) != NULL) { 3728 sentinelRedisInstance *slave = dictGetVal(de); 3729 int retval; 3730 3731 if (slave->flags & 3732 (SRI_RECONF_DONE|SRI_RECONF_SENT|SRI_DISCONNECTED)) continue; 3733 3734 retval = sentinelSendSlaveOf(slave, 3735 master->promoted_slave->addr->ip, 3736 master->promoted_slave->addr->port); 3737 if (retval == REDIS_OK) { 3738 sentinelEvent(REDIS_NOTICE,"+slave-reconf-sent-be",slave,"%@"); 3739 slave->flags |= SRI_RECONF_SENT; 3740 } 3741 } 3742 dictReleaseIterator(di); 3743 } 3744 } 3745 3746 /* Send SLAVE OF <new master address> to all the remaining slaves that 3747 * still don't appear to have the configuration updated. */ 3748 void sentinelFailoverReconfNextSlave(sentinelRedisInstance *master) { 3749 dictIterator *di; 3750 dictEntry *de; 3751 int in_progress = 0; 3752 3753 di = dictGetIterator(master->slaves); 3754 while((de = dictNext(di)) != NULL) { 3755 sentinelRedisInstance *slave = dictGetVal(de); 3756 3757 if (slave->flags & (SRI_RECONF_SENT|SRI_RECONF_INPROG)) 3758 in_progress++; 3759 } 3760 dictReleaseIterator(di); 3761 3762 di = dictGetIterator(master->slaves); 3763 while(in_progress < master->parallel_syncs && 3764 (de = dictNext(di)) != NULL) 3765 { 3766 sentinelRedisInstance *slave = dictGetVal(de); 3767 int retval; 3768 3769 /* Skip the promoted slave, and already configured slaves. */ 3770 if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue; 3771 3772 /* If too much time elapsed without the slave moving forward to 3773 * the next state, consider it reconfigured even if it is not. 3774 * Sentinels will detect the slave as misconfigured and fix its 3775 * configuration later. */ 3776 if ((slave->flags & SRI_RECONF_SENT) && 3777 (mstime() - slave->slave_reconf_sent_time) > 3778 SENTINEL_SLAVE_RECONF_TIMEOUT) 3779 { 3780 sentinelEvent(REDIS_NOTICE,"-slave-reconf-sent-timeout",slave,"%@"); 3781 slave->flags &= ~SRI_RECONF_SENT; 3782 slave->flags |= SRI_RECONF_DONE; 3783 } 3784 3785 /* Nothing to do for instances that are disconnected or already 3786 * in RECONF_SENT state. */ 3787 if (slave->flags & (SRI_DISCONNECTED|SRI_RECONF_SENT|SRI_RECONF_INPROG)) 3788 continue; 3789 3790 /* Send SLAVEOF <new master>. */ 3791 retval = sentinelSendSlaveOf(slave, 3792 master->promoted_slave->addr->ip, 3793 master->promoted_slave->addr->port); 3794 if (retval == REDIS_OK) { 3795 slave->flags |= SRI_RECONF_SENT; 3796 slave->slave_reconf_sent_time = mstime(); 3797 sentinelEvent(REDIS_NOTICE,"+slave-reconf-sent",slave,"%@"); 3798 in_progress++; 3799 } 3800 } 3801 dictReleaseIterator(di); 3802 3803 /* Check if all the slaves are reconfigured and handle timeout. */ 3804 sentinelFailoverDetectEnd(master); 3805 } 3806 3807 /* This function is called when the slave is in 3808 * SENTINEL_FAILOVER_STATE_UPDATE_CONFIG state. In this state we need 3809 * to remove it from the master table and add the promoted slave instead. */ 3810 void sentinelFailoverSwitchToPromotedSlave(sentinelRedisInstance *master) { 3811 sentinelRedisInstance *ref = master->promoted_slave ? 3812 master->promoted_slave : master; 3813 3814 sentinelEvent(REDIS_WARNING,"+switch-master",master,"%s %s %d %s %d", 3815 master->name, master->addr->ip, master->addr->port, 3816 ref->addr->ip, ref->addr->port); 3817 3818 sentinelResetMasterAndChangeAddress(master,ref->addr->ip,ref->addr->port); 3819 } 3820 3821 void sentinelFailoverStateMachine(sentinelRedisInstance *ri) { 3822 redisAssert(ri->flags & SRI_MASTER); 3823 3824 if (!(ri->flags & SRI_FAILOVER_IN_PROGRESS)) return; 3825 3826 switch(ri->failover_state) { 3827 case SENTINEL_FAILOVER_STATE_WAIT_START: 3828 sentinelFailoverWaitStart(ri); 3829 break; 3830 case SENTINEL_FAILOVER_STATE_SELECT_SLAVE: 3831 sentinelFailoverSelectSlave(ri); 3832 break; 3833 case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE: 3834 sentinelFailoverSendSlaveOfNoOne(ri); 3835 break; 3836 case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION: 3837 sentinelFailoverWaitPromotion(ri); 3838 break; 3839 case SENTINEL_FAILOVER_STATE_RECONF_SLAVES: 3840 sentinelFailoverReconfNextSlave(ri); 3841 break; 3842 } 3843 } 3844 3845 /* Abort a failover in progress: 3846 * 3847 * This function can only be called before the promoted slave acknowledged 3848 * the slave -> master switch. Otherwise the failover can't be aborted and 3849 * will reach its end (possibly by timeout). */ 3850 void sentinelAbortFailover(sentinelRedisInstance *ri) { 3851 redisAssert(ri->flags & SRI_FAILOVER_IN_PROGRESS); 3852 redisAssert(ri->failover_state <= SENTINEL_FAILOVER_STATE_WAIT_PROMOTION); 3853 3854 ri->flags &= ~(SRI_FAILOVER_IN_PROGRESS|SRI_FORCE_FAILOVER); 3855 ri->failover_state = SENTINEL_FAILOVER_STATE_NONE; 3856 ri->failover_state_change_time = mstime(); 3857 if (ri->promoted_slave) { 3858 ri->promoted_slave->flags &= ~SRI_PROMOTED; 3859 ri->promoted_slave = NULL; 3860 } 3861 } 3862 3863 /* ======================== SENTINEL timer handler ========================== 3864 * This is the "main" our Sentinel, being sentinel completely non blocking 3865 * in design. The function is called every second. 3866 * -------------------------------------------------------------------------- */ 3867 3868 /* Perform scheduled operations for the specified Redis instance. */ 3869 void sentinelHandleRedisInstance(sentinelRedisInstance *ri) { 3870 /* ========== MONITORING HALF ============ */ 3871 /* Every kind of instance */ 3872 sentinelReconnectInstance(ri); 3873 sentinelSendPeriodicCommands(ri); 3874 3875 /* ============== ACTING HALF ============= */ 3876 /* We don't proceed with the acting half if we are in TILT mode. 3877 * TILT happens when we find something odd with the time, like a 3878 * sudden change in the clock. */ 3879 if (sentinel.tilt) { 3880 if (mstime()-sentinel.tilt_start_time < SENTINEL_TILT_PERIOD) return; 3881 sentinel.tilt = 0; 3882 sentinelEvent(REDIS_WARNING,"-tilt",NULL,"#tilt mode exited"); 3883 } 3884 3885 /* Every kind of instance */ 3886 sentinelCheckSubjectivelyDown(ri); 3887 3888 /* Masters and slaves */ 3889 if (ri->flags & (SRI_MASTER|SRI_SLAVE)) { 3890 /* Nothing so far. */ 3891 } 3892 3893 /* Only masters */ 3894 if (ri->flags & SRI_MASTER) { 3895 sentinelCheckObjectivelyDown(ri); 3896 if (sentinelStartFailoverIfNeeded(ri)) 3897 sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_ASK_FORCED); 3898 sentinelFailoverStateMachine(ri); 3899 sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_NO_FLAGS); 3900 } 3901 } 3902 3903 /* Perform scheduled operations for all the instances in the dictionary. 3904 * Recursively call the function against dictionaries of slaves. */ 3905 void sentinelHandleDictOfRedisInstances(dict *instances) { 3906 dictIterator *di; 3907 dictEntry *de; 3908 sentinelRedisInstance *switch_to_promoted = NULL; 3909 3910 /* There are a number of things we need to perform against every master. */ 3911 di = dictGetIterator(instances); 3912 while((de = dictNext(di)) != NULL) { 3913 sentinelRedisInstance *ri = dictGetVal(de); 3914 3915 sentinelHandleRedisInstance(ri); 3916 if (ri->flags & SRI_MASTER) { 3917 sentinelHandleDictOfRedisInstances(ri->slaves); 3918 sentinelHandleDictOfRedisInstances(ri->sentinels); 3919 if (ri->failover_state == SENTINEL_FAILOVER_STATE_UPDATE_CONFIG) { 3920 switch_to_promoted = ri; 3921 } 3922 } 3923 } 3924 if (switch_to_promoted) 3925 sentinelFailoverSwitchToPromotedSlave(switch_to_promoted); 3926 dictReleaseIterator(di); 3927 } 3928 3929 /* This function checks if we need to enter the TITL mode. 3930 * 3931 * The TILT mode is entered if we detect that between two invocations of the 3932 * timer interrupt, a negative amount of time, or too much time has passed. 3933 * Note that we expect that more or less just 100 milliseconds will pass 3934 * if everything is fine. However we'll see a negative number or a 3935 * difference bigger than SENTINEL_TILT_TRIGGER milliseconds if one of the 3936 * following conditions happen: 3937 * 3938 * 1) The Sentiel process for some time is blocked, for every kind of 3939 * random reason: the load is huge, the computer was frozen for some time 3940 * in I/O or alike, the process was stopped by a signal. Everything. 3941 * 2) The system clock was altered significantly. 3942 * 3943 * Under both this conditions we'll see everything as timed out and failing 3944 * without good reasons. Instead we enter the TILT mode and wait 3945 * for SENTINEL_TILT_PERIOD to elapse before starting to act again. 3946 * 3947 * During TILT time we still collect information, we just do not act. */ 3948 void sentinelCheckTiltCondition(void) { 3949 mstime_t now = mstime(); 3950 mstime_t delta = now - sentinel.previous_time; 3951 3952 if (delta < 0 || delta > SENTINEL_TILT_TRIGGER) { 3953 sentinel.tilt = 1; 3954 sentinel.tilt_start_time = mstime(); 3955 sentinelEvent(REDIS_WARNING,"+tilt",NULL,"#tilt mode entered"); 3956 } 3957 sentinel.previous_time = mstime(); 3958 } 3959 3960 void sentinelTimer(void) { 3961 sentinelCheckTiltCondition(); 3962 sentinelHandleDictOfRedisInstances(sentinel.masters); 3963 sentinelRunPendingScripts(); 3964 sentinelCollectTerminatedScripts(); 3965 sentinelKillTimedoutScripts(); 3966 3967 /* We continuously change the frequency of the Redis "timer interrupt" 3968 * in order to desynchronize every Sentinel from every other. 3969 * This non-determinism avoids that Sentinels started at the same time 3970 * exactly continue to stay synchronized asking to be voted at the 3971 * same time again and again (resulting in nobody likely winning the 3972 * election because of split brain voting). */ 3973 server.hz = REDIS_DEFAULT_HZ + rand() % REDIS_DEFAULT_HZ; 3974 } 3975 3976