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