1 /* Redis Sentinel implementation 
   2  * ----------------------------- 
   4  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 
   7  * Redistribution and use in source and binary forms, with or without 
   8  * modification, are permitted provided that the following conditions are met: 
  10  *   * Redistributions of source code must retain the above copyright notice, 
  11  *     this list of conditions and the following disclaimer. 
  12  *   * Redistributions in binary form must reproduce the above copyright 
  13  *     notice, this list of conditions and the following disclaimer in the 
  14  *     documentation and/or other materials provided with the distribution. 
  15  *   * Neither the name of Redis nor the names of its contributors may be used 
  16  *     to endorse or promote products derived from this software without 
  17  *     specific prior written permission. 
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  29  * POSSIBILITY OF SUCH DAMAGE. 
  37 #include <arpa/inet.h> 
  38 #include <sys/socket.h> 
  41 extern char **environ
; 
  43 #define REDIS_SENTINEL_PORT 26379 
  45 /* ======================== Sentinel global state =========================== */ 
  47 typedef long long mstime_t
; /* millisecond time type. */ 
  49 /* Address object, used to describe an ip:port pair. */ 
  50 typedef struct sentinelAddr 
{ 
  55 /* A Sentinel Redis Instance object is monitoring. */ 
  56 #define SRI_MASTER  (1<<0) 
  57 #define SRI_SLAVE   (1<<1) 
  58 #define SRI_SENTINEL (1<<2) 
  59 #define SRI_DISCONNECTED (1<<3) 
  60 #define SRI_S_DOWN (1<<4)   /* Subjectively down (no quorum). */ 
  61 #define SRI_O_DOWN (1<<5)   /* Objectively down (quorum reached). */ 
  62 #define SRI_MASTER_DOWN (1<<6) /* A Sentinel with this flag set thinks that 
  63                                    its master is down. */ 
  64 /* SRI_CAN_FAILOVER when set in an SRI_MASTER instance means that we are 
  65  * allowed to perform the failover for this master. 
  66  * When set in a SRI_SENTINEL instance means that sentinel is allowed to 
  67  * perform the failover on its master. */ 
  68 #define SRI_CAN_FAILOVER (1<<7) 
  69 #define SRI_FAILOVER_IN_PROGRESS (1<<8) /* Failover is in progress for 
  71 #define SRI_I_AM_THE_LEADER (1<<9)     /* We are the leader for this master. */ 
  72 #define SRI_PROMOTED (1<<10)            /* Slave selected for promotion. */ 
  73 #define SRI_RECONF_SENT (1<<11)     /* SLAVEOF <newmaster> sent. */ 
  74 #define SRI_RECONF_INPROG (1<<12)   /* Slave synchronization in progress. */ 
  75 #define SRI_RECONF_DONE (1<<13)     /* Slave synchronized with new master. */ 
  77 #define SENTINEL_INFO_PERIOD 10000 
  78 #define SENTINEL_PING_PERIOD 1000 
  79 #define SENTINEL_ASK_PERIOD 1000 
  80 #define SENTINEL_PUBLISH_PERIOD 5000 
  81 #define SENTINEL_DOWN_AFTER_PERIOD 30000 
  82 #define SENTINEL_HELLO_CHANNEL "__sentinel__:hello" 
  83 #define SENTINEL_TILT_TRIGGER 2000 
  84 #define SENTINEL_TILT_PERIOD (SENTINEL_PING_PERIOD*30) 
  85 #define SENTINEL_DEFAULT_SLAVE_PRIORITY 100 
  86 #define SENTINEL_PROMOTION_RETRY_PERIOD 30000 
  87 #define SENTINEL_SLAVE_RECONF_RETRY_PERIOD 10000 
  88 #define SENTINEL_DEFAULT_PARALLEL_SYNCS 1 
  89 #define SENTINEL_MIN_LINK_RECONNECT_PERIOD 15000 
  90 #define SENTINEL_DEFAULT_FAILOVER_TIMEOUT (60*15*1000) 
  91 #define SENTINEL_MAX_PENDING_COMMANDS 100 
  92 #define SENTINEL_EXTENDED_SDOWN_MULTIPLIER 10 
  94 /* How many milliseconds is an information valid? This applies for instance 
  95  * to the reply to SENTINEL IS-MASTER-DOWN-BY-ADDR replies. */ 
  96 #define SENTINEL_INFO_VALIDITY_TIME 5000 
  97 #define SENTINEL_FAILOVER_FIXED_DELAY 5000 
  98 #define SENTINEL_FAILOVER_MAX_RANDOM_DELAY 10000 
 100 /* Failover machine different states. */ 
 101 #define SENTINEL_FAILOVER_STATE_NONE 0  /* No failover in progress. */ 
 102 #define SENTINEL_FAILOVER_STATE_WAIT_START 1  /* Wait for failover_start_time*/  
 103 #define SENTINEL_FAILOVER_STATE_SELECT_SLAVE 2 /* Select slave to promote */ 
 104 #define SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE 3 /* Slave -> Master */ 
 105 #define SENTINEL_FAILOVER_STATE_WAIT_PROMOTION 4 /* Wait slave to change role */ 
 106 #define SENTINEL_FAILOVER_STATE_RECONF_SLAVES 5 /* SLAVEOF newmaster */ 
 107 #define SENTINEL_FAILOVER_STATE_WAIT_NEXT_SLAVE 6 /* wait replication */ 
 108 #define SENTINEL_FAILOVER_STATE_ALERT_CLIENTS 7 /* Run user script. */ 
 109 #define SENTINEL_FAILOVER_STATE_WAIT_ALERT_SCRIPT 8 /* Wait script exec. */ 
 110 #define SENTINEL_FAILOVER_STATE_DETECT_END 9 /* Check for failover end. */ 
 111 #define SENTINEL_FAILOVER_STATE_UPDATE_CONFIG 10 /* Monitor promoted slave. */ 
 113 #define SENTINEL_MASTER_LINK_STATUS_UP 0 
 114 #define SENTINEL_MASTER_LINK_STATUS_DOWN 1 
 116 /* Generic flags that can be used with different functions. */ 
 117 #define SENTINEL_NO_FLAGS 0 
 118 #define SENTINEL_GENERATE_EVENT 1 
 120 /* Script execution flags and limits. */ 
 121 #define SENTINEL_SCRIPT_NONE 0 
 122 #define SENTINEL_SCRIPT_RUNNING 1 
 123 #define SENTINEL_SCRIPT_MAX_QUEUE 256 
 124 #define SENTINEL_SCRIPT_MAX_RUNNING 16 
 125 #define SENTINEL_SCRIPT_MAX_RUNTIME 60000 /* 60 seconds max exec time. */ 
 126 #define SENTINEL_SCRIPT_MAX_RETRY 10 
 127 #define SENTINEL_SCRIPT_RETRY_DELAY 30000 /* 30 seconds between retries. */ 
 129 typedef struct sentinelRedisInstance 
{ 
 130     int flags
;      /* See SRI_... defines */ 
 131     char *name
;     /* Master name from the point of view of this sentinel. */ 
 132     char *runid
;    /* run ID of this instance. */ 
 133     sentinelAddr 
*addr
; /* Master host. */ 
 134     redisAsyncContext 
*cc
; /* Hiredis context for commands. */ 
 135     redisAsyncContext 
*pc
; /* Hiredis context for Pub / Sub. */ 
 136     int pending_commands
;   /* Number of commands sent waiting for a reply. */ 
 137     mstime_t cc_conn_time
; /* cc connection time. */ 
 138     mstime_t pc_conn_time
; /* pc connection time. */ 
 139     mstime_t pc_last_activity
; /* Last time we received any message. */ 
 140     mstime_t last_avail_time
; /* Last time the instance replied to ping with 
 141                                  a reply we consider valid. */ 
 142     mstime_t last_pong_time
;  /* Last time the instance replied to ping, 
 143                                  whatever the reply was. That's used to check 
 144                                  if the link is idle and must be reconnected. */ 
 145     mstime_t last_pub_time
;   /* Last time we sent hello via Pub/Sub. */ 
 146     mstime_t last_hello_time
; /* Only used if SRI_SENTINEL is set. Last time 
 147                                  we received an hello from this Sentinel 
 149     mstime_t last_master_down_reply_time
; /* Time of last reply to 
 150                                              SENTINEL is-master-down command. */ 
 151     mstime_t s_down_since_time
; /* Subjectively down since time. */ 
 152     mstime_t o_down_since_time
; /* Objectively down since time. */ 
 153     mstime_t down_after_period
; /* Consider it down after that period. */ 
 154     mstime_t info_refresh
;  /* Time at which we received INFO output from it. */ 
 156     /* Master specific. */ 
 157     dict 
*sentinels
;    /* Other sentinels monitoring the same master. */ 
 158     dict 
*slaves
;       /* Slaves for this master instance. */ 
 159     int quorum
;         /* Number of sentinels that need to agree on failure. */ 
 160     int parallel_syncs
; /* How many slaves to reconfigure at same time. */ 
 162     /* Slave specific. */ 
 163     mstime_t master_link_down_time
; /* Slave replication link down time. */ 
 164     int slave_priority
; /* Slave priority according to its INFO output. */ 
 165     mstime_t slave_reconf_sent_time
; /* Time at which we sent SLAVE OF <new> */ 
 166     struct sentinelRedisInstance 
*master
; /* Master instance if SRI_SLAVE is set. */ 
 167     char *slave_master_host
;    /* Master host as reported by INFO */ 
 168     int slave_master_port
;      /* Master port as reported by INFO */ 
 169     int slave_master_link_status
; /* Master link status as reported by INFO */ 
 171     char *leader
;       /* If this is a master instance, this is the runid of 
 172                            the Sentinel that should perform the failover. If 
 173                            this is a Sentinel, this is the runid of the Sentinel 
 174                            that this other Sentinel is voting as leader. 
 175                            This field is valid only if SRI_MASTER_DOWN is 
 176                            set on the Sentinel instance. */ 
 177     int failover_state
; /* See SENTINEL_FAILOVER_STATE_* defines. */ 
 178     mstime_t failover_state_change_time
; 
 179     mstime_t failover_start_time
;   /* When to start to failover if leader. */ 
 180     mstime_t failover_timeout
;      /* Max time to refresh failover state. */ 
 181     struct sentinelRedisInstance 
*promoted_slave
; /* Promoted slave instance. */ 
 182     /* Scripts executed to notify admin or reconfigure clients: when they 
 183      * are set to NULL no script is executed. */ 
 184     char *notification_script
; 
 185     char *client_reconfig_script
; 
 186 } sentinelRedisInstance
; 
 189 struct sentinelState 
{ 
 190     dict 
*masters
;      /* Dictionary of master sentinelRedisInstances. 
 191                            Key is the instance name, value is the 
 192                            sentinelRedisInstance structure pointer. */ 
 193     int tilt
;           /* Are we in TILT mode? */ 
 194     int running_scripts
;    /* Number of scripts in execution right now. */ 
 195     mstime_t tilt_start_time
;   /* When TITL started. */ 
 196     mstime_t previous_time
;     /* Time last time we ran the time handler. */ 
 197     list 
*scripts_queue
;    /* Queue of user scripts to execute. */ 
 200 /* A script execution job. */ 
 201 typedef struct sentinelScriptJob 
{ 
 202     int flags
;              /* Script job flags: SENTINEL_SCRIPT_* */ 
 203     int retry_num
;          /* Number of times we tried to execute it. */ 
 204     char **argv
;            /* Arguments to call the script. */ 
 205     mstime_t start_time
;    /* Script execution time if the script is running, 
 206                                otherwise 0 if we are allowed to retry the 
 207                                execution at any time. If the script is not 
 208                                running and it's not 0, it means: do not run 
 209                                before the specified time. */ 
 210     pid_t pid
;              /* Script execution pid. */ 
 213 /* ======================= hiredis ae.c adapters ============================= 
 214  * Note: this implementation is taken from hiredis/adapters/ae.h, however 
 215  * we have our modified copy for Sentinel in order to use our allocator 
 216  * and to have full control over how the adapter works. */ 
 218 typedef struct redisAeEvents 
{ 
 219     redisAsyncContext 
*context
; 
 222     int reading
, writing
; 
 225 static void redisAeReadEvent(aeEventLoop 
*el
, int fd
, void *privdata
, int mask
) { 
 226     ((void)el
); ((void)fd
); ((void)mask
); 
 228     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 229     redisAsyncHandleRead(e
->context
); 
 232 static void redisAeWriteEvent(aeEventLoop 
*el
, int fd
, void *privdata
, int mask
) { 
 233     ((void)el
); ((void)fd
); ((void)mask
); 
 235     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 236     redisAsyncHandleWrite(e
->context
); 
 239 static void redisAeAddRead(void *privdata
) { 
 240     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 241     aeEventLoop 
*loop 
= e
->loop
; 
 244         aeCreateFileEvent(loop
,e
->fd
,AE_READABLE
,redisAeReadEvent
,e
); 
 248 static void redisAeDelRead(void *privdata
) { 
 249     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 250     aeEventLoop 
*loop 
= e
->loop
; 
 253         aeDeleteFileEvent(loop
,e
->fd
,AE_READABLE
); 
 257 static void redisAeAddWrite(void *privdata
) { 
 258     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 259     aeEventLoop 
*loop 
= e
->loop
; 
 262         aeCreateFileEvent(loop
,e
->fd
,AE_WRITABLE
,redisAeWriteEvent
,e
); 
 266 static void redisAeDelWrite(void *privdata
) { 
 267     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 268     aeEventLoop 
*loop 
= e
->loop
; 
 271         aeDeleteFileEvent(loop
,e
->fd
,AE_WRITABLE
); 
 275 static void redisAeCleanup(void *privdata
) { 
 276     redisAeEvents 
*e 
= (redisAeEvents
*)privdata
; 
 277     redisAeDelRead(privdata
); 
 278     redisAeDelWrite(privdata
); 
 282 static int redisAeAttach(aeEventLoop 
*loop
, redisAsyncContext 
*ac
) { 
 283     redisContext 
*c 
= &(ac
->c
); 
 286     /* Nothing should be attached when something is already attached */ 
 287     if (ac
->ev
.data 
!= NULL
) 
 290     /* Create container for context and r/w events */ 
 291     e 
= (redisAeEvents
*)zmalloc(sizeof(*e
)); 
 295     e
->reading 
= e
->writing 
= 0; 
 297     /* Register functions to start/stop listening for events */ 
 298     ac
->ev
.addRead 
= redisAeAddRead
; 
 299     ac
->ev
.delRead 
= redisAeDelRead
; 
 300     ac
->ev
.addWrite 
= redisAeAddWrite
; 
 301     ac
->ev
.delWrite 
= redisAeDelWrite
; 
 302     ac
->ev
.cleanup 
= redisAeCleanup
; 
 308 /* ============================= Prototypes ================================= */ 
 310 void sentinelLinkEstablishedCallback(const redisAsyncContext 
*c
, int status
); 
 311 void sentinelDisconnectCallback(const redisAsyncContext 
*c
, int status
); 
 312 void sentinelReceiveHelloMessages(redisAsyncContext 
*c
, void *reply
, void *privdata
); 
 313 sentinelRedisInstance 
*sentinelGetMasterByName(char *name
); 
 314 char *sentinelGetSubjectiveLeader(sentinelRedisInstance 
*master
); 
 315 char *sentinelGetObjectiveLeader(sentinelRedisInstance 
*master
); 
 316 int yesnotoi(char *s
); 
 317 void sentinelDisconnectInstanceFromContext(const redisAsyncContext 
*c
); 
 318 void sentinelKillLink(sentinelRedisInstance 
*ri
, redisAsyncContext 
*c
); 
 319 const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance 
*ri
); 
 320 void sentinelAbortFailover(sentinelRedisInstance 
*ri
); 
 321 void sentinelEvent(int level
, char *type
, sentinelRedisInstance 
*ri
, const char *fmt
, ...); 
 322 sentinelRedisInstance 
*sentinelSelectSlave(sentinelRedisInstance 
*master
); 
 323 void sentinelScheduleScriptExecution(char *path
, ...); 
 325 /* ========================= Dictionary types =============================== */ 
 327 unsigned int dictSdsHash(const void *key
); 
 328 int dictSdsKeyCompare(void *privdata
, const void *key1
, const void *key2
); 
 329 void releaseSentinelRedisInstance(sentinelRedisInstance 
*ri
); 
 331 void dictInstancesValDestructor (void *privdata
, void *obj
) { 
 332     releaseSentinelRedisInstance(obj
); 
 335 /* Instance name (sds) -> instance (sentinelRedisInstance pointer) 
 337  * also used for: sentinelRedisInstance->sentinels dictionary that maps 
 338  * sentinels ip:port to last seen time in Pub/Sub hello message. */ 
 339 dictType instancesDictType 
= { 
 340     dictSdsHash
,               /* hash function */ 
 343     dictSdsKeyCompare
,         /* key compare */ 
 344     NULL
,                      /* key destructor */ 
 345     dictInstancesValDestructor 
/* val destructor */ 
 348 /* Instance runid (sds) -> votes (long casted to void*) 
 350  * This is useful into sentinelGetObjectiveLeader() function in order to 
 351  * count the votes and understand who is the leader. */ 
 352 dictType leaderVotesDictType 
= { 
 353     dictSdsHash
,               /* hash function */ 
 356     dictSdsKeyCompare
,         /* key compare */ 
 357     NULL
,                      /* key destructor */ 
 358     NULL                       
/* val destructor */ 
 361 /* =========================== Initialization =============================== */ 
 363 void sentinelCommand(redisClient 
*c
); 
 365 struct redisCommand sentinelcmds
[] = { 
 366     {"ping",pingCommand
,1,"",0,NULL
,0,0,0,0,0}, 
 367     {"sentinel",sentinelCommand
,-2,"",0,NULL
,0,0,0,0,0}, 
 368     {"subscribe",subscribeCommand
,-2,"",0,NULL
,0,0,0,0,0}, 
 369     {"unsubscribe",unsubscribeCommand
,-1,"",0,NULL
,0,0,0,0,0}, 
 370     {"psubscribe",psubscribeCommand
,-2,"",0,NULL
,0,0,0,0,0}, 
 371     {"punsubscribe",punsubscribeCommand
,-1,"",0,NULL
,0,0,0,0,0} 
 374 /* This function overwrites a few normal Redis config default with Sentinel 
 375  * specific defaults. */ 
 376 void initSentinelConfig(void) { 
 377     server
.port 
= REDIS_SENTINEL_PORT
; 
 380 /* Perform the Sentinel mode initialization. */ 
 381 void initSentinel(void) { 
 384     /* Remove usual Redis commands from the command table, then just add 
 385      * the SENTINEL command. */ 
 386     dictEmpty(server
.commands
); 
 387     for (j 
= 0; j 
< sizeof(sentinelcmds
)/sizeof(sentinelcmds
[0]); j
++) { 
 389         struct redisCommand 
*cmd 
= sentinelcmds
+j
; 
 391         retval 
= dictAdd(server
.commands
, sdsnew(cmd
->name
), cmd
); 
 392         redisAssert(retval 
== DICT_OK
); 
 395     /* Initialize various data structures. */ 
 396     sentinel
.masters 
= dictCreate(&instancesDictType
,NULL
); 
 398     sentinel
.tilt_start_time 
= mstime(); 
 399     sentinel
.previous_time 
= mstime(); 
 400     sentinel
.running_scripts 
= 0; 
 401     sentinel
.scripts_queue 
= listCreate(); 
 404 /* ============================== sentinelAddr ============================== */ 
 406 /* Create a sentinelAddr object and return it on success. 
 407  * On error NULL is returned and errno is set to: 
 408  *  ENOENT: Can't resolve the hostname. 
 409  *  EINVAL: Invalid port number. 
 411 sentinelAddr 
*createSentinelAddr(char *hostname
, int port
) { 
 415     if (port 
<= 0 || port 
> 65535) { 
 419     if (anetResolve(NULL
,hostname
,buf
) == ANET_ERR
) { 
 423     sa 
= zmalloc(sizeof(*sa
)); 
 424     sa
->ip 
= sdsnew(buf
); 
 429 /* Free a Sentinel address. Can't fail. */ 
 430 void releaseSentinelAddr(sentinelAddr 
*sa
) { 
 435 /* =========================== Events notification ========================== */ 
 437 /* Send an event to log, pub/sub, user notification script. 
 439  * 'level' is the log level for logging. Only REDIS_WARNING events will trigger 
 440  * the execution of the user notification script. 
 442  * 'type' is the message type, also used as a pub/sub channel name. 
 444  * 'ri', is the redis instance target of this event if applicable, and is 
 445  * used to obtain the path of the notification script to execute. 
 447  * The remaining arguments are printf-alike. 
 448  * If the format specifier starts with the two characters "%@" then ri is 
 449  * not NULL, and the message is prefixed with an instance identifier in the 
 452  *  <instance type> <instance name> <ip> <port> 
 454  *  If the instance type is not master, than the additional string is 
 455  *  added to specify the originating master: 
 457  *  @ <master name> <master ip> <master port> 
 459  *  Any other specifier after "%@" is processed by printf itself. 
 461 void sentinelEvent(int level
, char *type
, sentinelRedisInstance 
*ri
, 
 462                    const char *fmt
, ...) { 
 464     char msg
[REDIS_MAX_LOGMSG_LEN
]; 
 465     robj 
*channel
, *payload
; 
 468     if (fmt
[0] == '%' && fmt
[1] == '@') { 
 469         sentinelRedisInstance 
*master 
= (ri
->flags 
& SRI_MASTER
) ? 
 473             snprintf(msg
, sizeof(msg
), "%s %s %s %d @ %s %s %d", 
 474                 sentinelRedisInstanceTypeStr(ri
), 
 475                 ri
->name
, ri
->addr
->ip
, ri
->addr
->port
, 
 476                 master
->name
, master
->addr
->ip
, master
->addr
->port
); 
 478             snprintf(msg
, sizeof(msg
), "%s %s %s %d", 
 479                 sentinelRedisInstanceTypeStr(ri
), 
 480                 ri
->name
, ri
->addr
->ip
, ri
->addr
->port
); 
 487     /* Use vsprintf for the rest of the formatting if any. */ 
 488     if (fmt
[0] != '\0') { 
 490         vsnprintf(msg
+strlen(msg
), sizeof(msg
)-strlen(msg
), fmt
, ap
); 
 494     /* Log the message if the log level allows it to be logged. */ 
 495     if (level 
>= server
.verbosity
) 
 496         redisLog(level
,"%s %s",type
,msg
); 
 498     /* Publish the message via Pub/Sub if it's not a debugging one. */ 
 499     if (level 
!= REDIS_DEBUG
) { 
 500         channel 
= createStringObject(type
,strlen(type
)); 
 501         payload 
= createStringObject(msg
,strlen(msg
)); 
 502         pubsubPublishMessage(channel
,payload
); 
 503         decrRefCount(channel
); 
 504         decrRefCount(payload
); 
 507     /* Call the notification script if applicable. */ 
 508     if (level 
== REDIS_WARNING 
&& ri 
!= NULL
) { 
 509         sentinelRedisInstance 
*master 
= (ri
->flags 
& SRI_MASTER
) ? 
 511         if (master
->notification_script
) { 
 512             sentinelScheduleScriptExecution(master
->notification_script
, 
 518 /* ============================ script execution ============================ */ 
 520 /* Release a script job structure and all the associated data. */ 
 521 void sentinelReleaseScriptJob(sentinelScriptJob 
*sj
) { 
 524     while(sj
->argv
[j
]) sdsfree(sj
->argv
[j
++]); 
 529 #define SENTINEL_SCRIPT_MAX_ARGS 16 
 530 void sentinelScheduleScriptExecution(char *path
, ...) { 
 532     char *argv
[SENTINEL_SCRIPT_MAX_ARGS
+1]; 
 534     sentinelScriptJob 
*sj
; 
 537     while(argc 
< SENTINEL_SCRIPT_MAX_ARGS
) { 
 538         argv
[argc
] = va_arg(ap
,char*); 
 539         if (!argv
[argc
]) break; 
 540         argv
[argc
] = sdsnew(argv
[argc
]); /* Copy the string. */ 
 544     argv
[0] = sdsnew(path
); 
 546     sj 
= zmalloc(sizeof(*sj
)); 
 547     sj
->flags 
= SENTINEL_SCRIPT_NONE
; 
 549     sj
->argv 
= zmalloc(sizeof(char*)*(argc
+1)); 
 552     memcpy(sj
->argv
,argv
,sizeof(char*)*(argc
+1)); 
 554     listAddNodeTail(sentinel
.scripts_queue
,sj
); 
 556     /* Remove the oldest non running script if we already hit the limit. */ 
 557     if (listLength(sentinel
.scripts_queue
) > SENTINEL_SCRIPT_MAX_QUEUE
) { 
 561         listRewind(sentinel
.scripts_queue
,&li
); 
 562         while ((ln 
= listNext(&li
)) != NULL
) { 
 565             if (sj
->flags 
& SENTINEL_SCRIPT_RUNNING
) continue; 
 566             /* The first node is the oldest as we add on tail. */ 
 567             listDelNode(sentinel
.scripts_queue
,ln
); 
 568             sentinelReleaseScriptJob(sj
); 
 571         redisAssert(listLength(sentinel
.scripts_queue
) <= 
 572                     SENTINEL_SCRIPT_MAX_QUEUE
); 
 576 /* Lookup a script in the scripts queue via pid, and returns the list node 
 577  * (so that we can easily remove it from the queue if needed). */ 
 578 listNode 
*sentinelGetScriptListNodeByPid(pid_t pid
) { 
 582     listRewind(sentinel
.scripts_queue
,&li
); 
 583     while ((ln 
= listNext(&li
)) != NULL
) { 
 584         sentinelScriptJob 
*sj 
= ln
->value
; 
 586         if ((sj
->flags 
& SENTINEL_SCRIPT_RUNNING
) && sj
->pid 
== pid
) 
 592 /* Run pending scripts if we are not already at max number of running 
 594 void sentinelRunPendingScripts(void) { 
 597     mstime_t now 
= mstime(); 
 599     /* Find jobs that are not running and run them, from the top to the 
 600      * tail of the queue, so we run older jobs first. */ 
 601     listRewind(sentinel
.scripts_queue
,&li
); 
 602     while (sentinel
.running_scripts 
< SENTINEL_SCRIPT_MAX_RUNNING 
&& 
 603            (ln 
= listNext(&li
)) != NULL
) 
 605         sentinelScriptJob 
*sj 
= ln
->value
; 
 608         /* Skip if already running. */ 
 609         if (sj
->flags 
& SENTINEL_SCRIPT_RUNNING
) continue; 
 611         /* Skip if it's a retry, but not enough time has elapsed. */ 
 612         if (sj
->start_time 
&& sj
->start_time 
> now
) continue; 
 614         sj
->flags 
|= SENTINEL_SCRIPT_RUNNING
; 
 615         sj
->start_time 
= mstime(); 
 620             /* Parent (fork error). 
 621              * We report fork errors as signal 99, in order to unify the 
 622              * reporting with other kind of errors. */ 
 623             sentinelEvent(REDIS_WARNING
,"-script-error",NULL
, 
 624                           "%s %d %d", sj
->argv
[0], 99, 0); 
 625             sj
->flags 
&= ~SENTINEL_SCRIPT_RUNNING
; 
 627         } else if (pid 
== 0) { 
 629             execve(sj
->argv
[0],sj
->argv
,environ
); 
 630             /* If we are here an error occurred. */ 
 631             _exit(2); /* Don't retry execution. */ 
 633             sentinel
.running_scripts
++; 
 635             sentinelEvent(REDIS_DEBUG
,"+script-child",NULL
,"%ld",(long)pid
); 
 640 /* How much to delay the execution of a script that we need to retry after 
 643  * We double the retry delay for every further retry we do. So for instance 
 644  * if RETRY_DELAY is set to 30 seconds and the max number of retries is 10 
 645  * starting from the second attempt to execute the script the delays are: 
 646  * 30 sec, 60 sec, 2 min, 4 min, 8 min, 16 min, 32 min, 64 min, 128 min. */ 
 647 mstime_t 
sentinelScriptRetryDelay(int retry_num
) { 
 648     mstime_t delay 
= SENTINEL_SCRIPT_RETRY_DELAY
; 
 650     while (retry_num
-- > 1) delay 
*= 2; 
 654 /* Check for scripts that terminated, and remove them from the queue if the 
 655  * script terminated successfully. If instead the script was terminated by 
 656  * a signal, or returned exit code "1", it is scheduled to run again if 
 657  * the max number of retries did not already elapsed. */ 
 658 void sentinelCollectTerminatedScripts(void) { 
 662     while ((pid 
= wait3(&statloc
,WNOHANG
,NULL
)) > 0) { 
 663         int exitcode 
= WEXITSTATUS(statloc
); 
 666         sentinelScriptJob 
*sj
; 
 668         if (WIFSIGNALED(statloc
)) bysignal 
= WTERMSIG(statloc
); 
 669         sentinelEvent(REDIS_DEBUG
,"-script-child",NULL
,"%ld %d %d", 
 670             (long)pid
, exitcode
, bysignal
); 
 672         ln 
= sentinelGetScriptListNodeByPid(pid
); 
 674             redisLog(REDIS_WARNING
,"wait3() returned a pid (%ld) we can't find in our scripts execution queue!", (long)pid
); 
 679         /* If the script was terminated by a signal or returns an 
 680          * exit code of "1" (that means: please retry), we reschedule it 
 681          * if the max number of retries is not already reached. */ 
 682         if ((bysignal 
|| exitcode 
== 1) && 
 683             sj
->retry_num 
!= SENTINEL_SCRIPT_MAX_RETRY
) 
 685             sj
->flags 
&= ~SENTINEL_SCRIPT_RUNNING
; 
 687             sj
->start_time 
= mstime() + 
 688                              sentinelScriptRetryDelay(sj
->retry_num
); 
 690             /* Otherwise let's remove the script, but log the event if the 
 691              * execution did not terminated in the best of the ways. */ 
 692             if (bysignal 
|| exitcode 
!= 0) { 
 693                 sentinelEvent(REDIS_WARNING
,"-script-error",NULL
, 
 694                               "%s %d %d", sj
->argv
[0], bysignal
, exitcode
); 
 696             listDelNode(sentinel
.scripts_queue
,ln
); 
 697             sentinelReleaseScriptJob(sj
); 
 698             sentinel
.running_scripts
--; 
 703 /* Kill scripts in timeout, they'll be collected by the 
 704  * sentinelCollectTerminatedScripts() function. */ 
 705 void sentinelKillTimedoutScripts(void) { 
 708     mstime_t now 
= mstime(); 
 710     listRewind(sentinel
.scripts_queue
,&li
); 
 711     while ((ln 
= listNext(&li
)) != NULL
) { 
 712         sentinelScriptJob 
*sj 
= ln
->value
; 
 714         if (sj
->flags 
& SENTINEL_SCRIPT_RUNNING 
&& 
 715             (now 
- sj
->start_time
) > SENTINEL_SCRIPT_MAX_RUNTIME
) 
 717             sentinelEvent(REDIS_WARNING
,"-script-timeout",NULL
,"%s %ld", 
 718                 sj
->argv
[0], (long)sj
->pid
); 
 719             kill(sj
->pid
,SIGKILL
); 
 724 /* Implements SENTINEL PENDING-SCRIPTS command. */ 
 725 void sentinelPendingScriptsCommand(redisClient 
*c
) { 
 729     addReplyMultiBulkLen(c
,listLength(sentinel
.scripts_queue
)); 
 730     listRewind(sentinel
.scripts_queue
,&li
); 
 731     while ((ln 
= listNext(&li
)) != NULL
) { 
 732         sentinelScriptJob 
*sj 
= ln
->value
; 
 735         addReplyMultiBulkLen(c
,10); 
 737         addReplyBulkCString(c
,"argv"); 
 738         while (sj
->argv
[j
]) j
++; 
 739         addReplyMultiBulkLen(c
,j
); 
 741         while (sj
->argv
[j
]) addReplyBulkCString(c
,sj
->argv
[j
++]); 
 743         addReplyBulkCString(c
,"flags"); 
 744         addReplyBulkCString(c
, 
 745             (sj
->flags 
& SENTINEL_SCRIPT_RUNNING
) ? "running" : "scheduled"); 
 747         addReplyBulkCString(c
,"pid"); 
 748         addReplyBulkLongLong(c
,sj
->pid
); 
 750         if (sj
->flags 
& SENTINEL_SCRIPT_RUNNING
) { 
 751             addReplyBulkCString(c
,"run-time"); 
 752             addReplyBulkLongLong(c
,mstime() - sj
->start_time
); 
 754             mstime_t delay 
= sj
->start_time 
? (sj
->start_time
-mstime()) : 0; 
 755             if (delay 
< 0) delay 
= 0; 
 756             addReplyBulkCString(c
,"run-delay"); 
 757             addReplyBulkLongLong(c
,delay
); 
 760         addReplyBulkCString(c
,"retry-num"); 
 761         addReplyBulkLongLong(c
,sj
->retry_num
); 
 765 /* ========================== sentinelRedisInstance ========================= */ 
 767 /* Create a redis instance, the following fields must be populated by the 
 769  * runid: set to NULL but will be populated once INFO output is received. 
 770  * info_refresh: is set to 0 to mean that we never received INFO so far. 
 772  * If SRI_MASTER is set into initial flags the instance is added to 
 773  * sentinel.masters table. 
 775  * if SRI_SLAVE or SRI_SENTINEL is set then 'master' must be not NULL and the 
 776  * instance is added into master->slaves or master->sentinels table. 
 778  * If the instance is a slave or sentinel, the name parameter is ignored and 
 779  * is created automatically as hostname:port. 
 781  * The function fails if hostname can't be resolved or port is out of range. 
 782  * When this happens NULL is returned and errno is set accordingly to the 
 783  * createSentinelAddr() function. 
 785  * The function may also fail and return NULL with errno set to EBUSY if 
 786  * a master or slave with the same name already exists. */ 
 787 sentinelRedisInstance 
*createSentinelRedisInstance(char *name
, int flags
, char *hostname
, int port
, int quorum
, sentinelRedisInstance 
*master
) { 
 788     sentinelRedisInstance 
*ri
; 
 791     char slavename
[128], *sdsname
; 
 793     redisAssert(flags 
& (SRI_MASTER
|SRI_SLAVE
|SRI_SENTINEL
)); 
 794     redisAssert((flags 
& SRI_MASTER
) || master 
!= NULL
); 
 796     /* Check address validity. */ 
 797     addr 
= createSentinelAddr(hostname
,port
); 
 798     if (addr 
== NULL
) return NULL
; 
 800     /* For slaves and sentinel we use ip:port as name. */ 
 801     if (flags 
& (SRI_SLAVE
|SRI_SENTINEL
)) { 
 802         snprintf(slavename
,sizeof(slavename
),"%s:%d",hostname
,port
); 
 806     /* Make sure the entry is not duplicated. This may happen when the same 
 807      * name for a master is used multiple times inside the configuration or 
 808      * if we try to add multiple times a slave or sentinel with same ip/port 
 810     if (flags 
& SRI_MASTER
) table 
= sentinel
.masters
; 
 811     else if (flags 
& SRI_SLAVE
) table 
= master
->slaves
; 
 812     else if (flags 
& SRI_SENTINEL
) table 
= master
->sentinels
; 
 813     sdsname 
= sdsnew(name
); 
 814     if (dictFind(table
,sdsname
)) { 
 820     /* Create the instance object. */ 
 821     ri 
= zmalloc(sizeof(*ri
)); 
 822     /* Note that all the instances are started in the disconnected state, 
 823      * the event loop will take care of connecting them. */ 
 824     ri
->flags 
= flags 
| SRI_DISCONNECTED
; 
 830     ri
->pending_commands 
= 0; 
 831     ri
->cc_conn_time 
= 0; 
 832     ri
->pc_conn_time 
= 0; 
 833     ri
->pc_last_activity 
= 0; 
 834     ri
->last_avail_time 
= mstime(); 
 835     ri
->last_pong_time 
= mstime(); 
 836     ri
->last_pub_time 
= mstime(); 
 837     ri
->last_hello_time 
= mstime(); 
 838     ri
->last_master_down_reply_time 
= mstime(); 
 839     ri
->s_down_since_time 
= 0; 
 840     ri
->o_down_since_time 
= 0; 
 841     ri
->down_after_period 
= master 
? master
->down_after_period 
: 
 842                             SENTINEL_DOWN_AFTER_PERIOD
; 
 843     ri
->master_link_down_time 
= 0; 
 844     ri
->slave_priority 
= SENTINEL_DEFAULT_SLAVE_PRIORITY
; 
 845     ri
->slave_reconf_sent_time 
= 0; 
 846     ri
->slave_master_host 
= NULL
; 
 847     ri
->slave_master_port 
= 0; 
 848     ri
->slave_master_link_status 
= SENTINEL_MASTER_LINK_STATUS_DOWN
; 
 849     ri
->sentinels 
= dictCreate(&instancesDictType
,NULL
); 
 851     ri
->parallel_syncs 
= SENTINEL_DEFAULT_PARALLEL_SYNCS
; 
 853     ri
->slaves 
= dictCreate(&instancesDictType
,NULL
); 
 854     ri
->info_refresh 
= 0; 
 856     /* Failover state. */ 
 858     ri
->failover_state 
= SENTINEL_FAILOVER_STATE_NONE
; 
 859     ri
->failover_state_change_time 
= 0; 
 860     ri
->failover_start_time 
= 0; 
 861     ri
->failover_timeout 
= SENTINEL_DEFAULT_FAILOVER_TIMEOUT
; 
 862     ri
->promoted_slave 
= NULL
; 
 863     ri
->notification_script 
= NULL
; 
 864     ri
->client_reconfig_script 
= NULL
; 
 866     /* Add into the right table. */ 
 867     dictAdd(table
, ri
->name
, ri
); 
 871 /* Release this instance and all its slaves, sentinels, hiredis connections. 
 872  * This function also takes care of unlinking the instance from the main 
 873  * masters table (if it is a master) or from its master sentinels/slaves table 
 874  * if it is a slave or sentinel. */ 
 875 void releaseSentinelRedisInstance(sentinelRedisInstance 
*ri
) { 
 876     /* Release all its slaves or sentinels if any. */ 
 877     dictRelease(ri
->sentinels
); 
 878     dictRelease(ri
->slaves
); 
 880     /* Release hiredis connections. */ 
 881     if (ri
->cc
) sentinelKillLink(ri
,ri
->cc
); 
 882     if (ri
->pc
) sentinelKillLink(ri
,ri
->pc
); 
 884     /* Free other resources. */ 
 887     sdsfree(ri
->notification_script
); 
 888     sdsfree(ri
->client_reconfig_script
); 
 889     sdsfree(ri
->slave_master_host
); 
 891     releaseSentinelAddr(ri
->addr
); 
 893     /* Clear state into the master if needed. */ 
 894     if ((ri
->flags 
& SRI_SLAVE
) && (ri
->flags 
& SRI_PROMOTED
) && ri
->master
) 
 895         ri
->master
->promoted_slave 
= NULL
; 
 900 /* Lookup a slave in a master Redis instance, by ip and port. */ 
 901 sentinelRedisInstance 
*sentinelRedisInstanceLookupSlave( 
 902                 sentinelRedisInstance 
*ri
, char *ip
, int port
) 
 905     sentinelRedisInstance 
*slave
; 
 907     redisAssert(ri
->flags 
& SRI_MASTER
); 
 908     key 
= sdscatprintf(sdsempty(),"%s:%d",ip
,port
); 
 909     slave 
= dictFetchValue(ri
->slaves
,key
); 
 914 /* Return the name of the type of the instance as a string. */ 
 915 const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance 
*ri
) { 
 916     if (ri
->flags 
& SRI_MASTER
) return "master"; 
 917     else if (ri
->flags 
& SRI_SLAVE
) return "slave"; 
 918     else if (ri
->flags 
& SRI_SENTINEL
) return "sentinel"; 
 919     else return "unknown"; 
 922 /* This function removes all the instances found in the dictionary of instances 
 923  * 'd', having either: 
 925  * 1) The same ip/port as specified. 
 928  * "1" and "2" don't need to verify at the same time, just one is enough. 
 929  * If "runid" is NULL it is not checked. 
 930  * Similarly if "ip" is NULL it is not checked. 
 932  * This function is useful because every time we add a new Sentinel into 
 933  * a master's Sentinels dictionary, we want to be very sure about not 
 934  * having duplicated instances for any reason. This is so important because 
 935  * we use those other sentinels in order to run our quorum protocol to 
 936  * understand if it's time to proceeed with the fail over. 
 938  * Making sure no duplication is possible we greately improve the robustness 
 939  * of the quorum (otherwise we may end counting the same instance multiple 
 940  * times for some reason). 
 942  * The function returns the number of Sentinels removed. */ 
 943 int removeMatchingSentinelsFromMaster(sentinelRedisInstance 
*master
, char *ip
, int port
, char *runid
) { 
 948     di 
= dictGetSafeIterator(master
->sentinels
); 
 949     while((de 
= dictNext(di
)) != NULL
) { 
 950         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
 952         if ((ri
->runid 
&& runid 
&& strcmp(ri
->runid
,runid
) == 0) || 
 953             (ip 
&& strcmp(ri
->addr
->ip
,ip
) == 0 && port 
== ri
->addr
->port
)) 
 955             dictDelete(master
->sentinels
,ri
->name
); 
 959     dictReleaseIterator(di
); 
 963 /* Search an instance with the same runid, ip and port into a dictionary 
 964  * of instances. Return NULL if not found, otherwise return the instance 
 967  * runid or ip can be NULL. In such a case the search is performed only 
 968  * by the non-NULL field. */ 
 969 sentinelRedisInstance 
*getSentinelRedisInstanceByAddrAndRunID(dict 
*instances
, char *ip
, int port
, char *runid
) { 
 972     sentinelRedisInstance 
*instance 
= NULL
; 
 974     redisAssert(ip 
|| runid
);   /* User must pass at least one search param. */ 
 975     di 
= dictGetIterator(instances
); 
 976     while((de 
= dictNext(di
)) != NULL
) { 
 977         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
 979         if (runid 
&& !ri
->runid
) continue; 
 980         if ((runid 
== NULL 
|| strcmp(ri
->runid
, runid
) == 0) && 
 981             (ip 
== NULL 
|| (strcmp(ri
->addr
->ip
, ip
) == 0 && 
 982                             ri
->addr
->port 
== port
))) 
 988     dictReleaseIterator(di
); 
 992 /* Simple master lookup by name */ 
 993 sentinelRedisInstance 
*sentinelGetMasterByName(char *name
) { 
 994     sentinelRedisInstance 
*ri
; 
 995     sds sdsname 
= sdsnew(name
); 
 997     ri 
= dictFetchValue(sentinel
.masters
,sdsname
); 
1002 /* Add the specified flags to all the instances in the specified dictionary. */ 
1003 void sentinelAddFlagsToDictOfRedisInstances(dict 
*instances
, int flags
) { 
1007     di 
= dictGetIterator(instances
); 
1008     while((de 
= dictNext(di
)) != NULL
) { 
1009         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
1012     dictReleaseIterator(di
); 
1015 /* Remove the specified flags to all the instances in the specified 
1017 void sentinelDelFlagsToDictOfRedisInstances(dict 
*instances
, int flags
) { 
1021     di 
= dictGetIterator(instances
); 
1022     while((de 
= dictNext(di
)) != NULL
) { 
1023         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
1024         ri
->flags 
&= ~flags
; 
1026     dictReleaseIterator(di
); 
1029 /* Reset the state of a monitored master: 
1030  * 1) Remove all slaves. 
1031  * 2) Remove all sentinels. 
1032  * 3) Remove most of the flags resulting from runtime operations. 
1033  * 4) Reset timers to their default value. 
1034  * 5) In the process of doing this undo the failover if in progress. 
1035  * 6) Disconnect the connections with the master (will reconnect automatically). 
1037 void sentinelResetMaster(sentinelRedisInstance 
*ri
, int flags
) { 
1038     redisAssert(ri
->flags 
& SRI_MASTER
); 
1039     dictRelease(ri
->slaves
); 
1040     dictRelease(ri
->sentinels
); 
1041     ri
->slaves 
= dictCreate(&instancesDictType
,NULL
); 
1042     ri
->sentinels 
= dictCreate(&instancesDictType
,NULL
); 
1043     if (ri
->cc
) sentinelKillLink(ri
,ri
->cc
); 
1044     if (ri
->pc
) sentinelKillLink(ri
,ri
->pc
); 
1045     ri
->flags 
&= SRI_MASTER
|SRI_CAN_FAILOVER
|SRI_DISCONNECTED
; 
1047         sdsfree(ri
->leader
); 
1050     ri
->failover_state 
= SENTINEL_FAILOVER_STATE_NONE
; 
1051     ri
->failover_state_change_time 
= 0; 
1052     ri
->failover_start_time 
= 0; 
1053     ri
->promoted_slave 
= NULL
; 
1055     sdsfree(ri
->slave_master_host
); 
1057     ri
->slave_master_host 
= NULL
; 
1058     ri
->last_avail_time 
= mstime(); 
1059     ri
->last_pong_time 
= mstime(); 
1060     if (flags 
& SENTINEL_GENERATE_EVENT
) 
1061         sentinelEvent(REDIS_WARNING
,"+reset-master",ri
,"%@"); 
1064 /* Call sentinelResetMaster() on every master with a name matching the specified 
1066 int sentinelResetMastersByPattern(char *pattern
, int flags
) { 
1071     di 
= dictGetIterator(sentinel
.masters
); 
1072     while((de 
= dictNext(di
)) != NULL
) { 
1073         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
1076             if (stringmatch(pattern
,ri
->name
,0)) { 
1077                 sentinelResetMaster(ri
,flags
); 
1082     dictReleaseIterator(di
); 
1086 /* Reset the specified master with sentinelResetMaster(), and also change 
1087  * the ip:port address, but take the name of the instance unmodified. 
1089  * This is used to handle the +switch-master and +redirect-to-master events. 
1091  * The function returns REDIS_ERR if the address can't be resolved for some 
1092  * reason. Otherwise REDIS_OK is returned. 
1094  * TODO: make this reset so that original sentinels are re-added with 
1095  * same ip / port / runid. 
1098 int sentinelResetMasterAndChangeAddress(sentinelRedisInstance 
*master
, char *ip
, int port
) { 
1099     sentinelAddr 
*oldaddr
, *newaddr
; 
1101     newaddr 
= createSentinelAddr(ip
,port
); 
1102     if (newaddr 
== NULL
) return REDIS_ERR
; 
1103     sentinelResetMaster(master
,SENTINEL_NO_FLAGS
); 
1104     oldaddr 
= master
->addr
; 
1105     master
->addr 
= newaddr
; 
1106     /* Release the old address at the end so we are safe even if the function 
1107      * gets the master->addr->ip and master->addr->port as arguments. */ 
1108     releaseSentinelAddr(oldaddr
); 
1112 /* ============================ Config handling ============================= */ 
1113 char *sentinelHandleConfiguration(char **argv
, int argc
) { 
1114     sentinelRedisInstance 
*ri
; 
1116     if (!strcasecmp(argv
[0],"monitor") && argc 
== 5) { 
1117         /* monitor <name> <host> <port> <quorum> */ 
1118         int quorum 
= atoi(argv
[4]); 
1120         if (quorum 
<= 0) return "Quorum must be 1 or greater."; 
1121         if (createSentinelRedisInstance(argv
[1],SRI_MASTER
,argv
[2], 
1122                                         atoi(argv
[3]),quorum
,NULL
) == NULL
) 
1125             case EBUSY
: return "Duplicated master name."; 
1126             case ENOENT
: return "Can't resolve master instance hostname."; 
1127             case EINVAL
: return "Invalid port number"; 
1130     } else if (!strcasecmp(argv
[0],"down-after-milliseconds") && argc 
== 3) { 
1131         /* down-after-milliseconds <name> <milliseconds> */ 
1132         ri 
= sentinelGetMasterByName(argv
[1]); 
1133         if (!ri
) return "No such master with specified name."; 
1134         ri
->down_after_period 
= atoi(argv
[2]); 
1135         if (ri
->down_after_period 
<= 0) 
1136             return "negative or zero time parameter."; 
1137     } else if (!strcasecmp(argv
[0],"failover-timeout") && argc 
== 3) { 
1138         /* failover-timeout <name> <milliseconds> */ 
1139         ri 
= sentinelGetMasterByName(argv
[1]); 
1140         if (!ri
) return "No such master with specified name."; 
1141         ri
->failover_timeout 
= atoi(argv
[2]); 
1142         if (ri
->failover_timeout 
<= 0) 
1143             return "negative or zero time parameter."; 
1144     } else if (!strcasecmp(argv
[0],"can-failover") && argc 
== 3) { 
1145         /* can-failover <name> <yes/no> */ 
1146         int yesno 
= yesnotoi(argv
[2]); 
1148         ri 
= sentinelGetMasterByName(argv
[1]); 
1149         if (!ri
) return "No such master with specified name."; 
1150         if (yesno 
== -1) return "Argument must be either yes or no."; 
1152             ri
->flags 
|= SRI_CAN_FAILOVER
; 
1154             ri
->flags 
&= ~SRI_CAN_FAILOVER
; 
1155    } else if (!strcasecmp(argv
[0],"parallel-syncs") && argc 
== 3) { 
1156         /* parallel-syncs <name> <milliseconds> */ 
1157         ri 
= sentinelGetMasterByName(argv
[1]); 
1158         if (!ri
) return "No such master with specified name."; 
1159         ri
->parallel_syncs 
= atoi(argv
[2]); 
1160    } else if (!strcasecmp(argv
[0],"notification-script") && argc 
== 3) { 
1161         /* notification-script <name> <path> */ 
1162         ri 
= sentinelGetMasterByName(argv
[1]); 
1163         if (!ri
) return "No such master with specified name."; 
1164         if (access(argv
[2],X_OK
) == -1) 
1165             return "Notification script seems non existing or non executable."; 
1166         ri
->notification_script 
= sdsnew(argv
[2]); 
1167    } else if (!strcasecmp(argv
[0],"client-reconfig-script") && argc 
== 3) { 
1168         /* client-reconfig-script <name> <path> */ 
1169         ri 
= sentinelGetMasterByName(argv
[1]); 
1170         if (!ri
) return "No such master with specified name."; 
1171         if (access(argv
[2],X_OK
) == -1) 
1172             return "Client reconfiguration script seems non existing or " 
1174         ri
->client_reconfig_script 
= sdsnew(argv
[2]); 
1176         return "Unrecognized sentinel configuration statement."; 
1181 /* ====================== hiredis connection handling ======================= */ 
1183 /* Completely disconnect an hiredis link from an instance. */ 
1184 void sentinelKillLink(sentinelRedisInstance 
*ri
, redisAsyncContext 
*c
) { 
1187         ri
->pending_commands 
= 0; 
1189     if (ri
->pc 
== c
) ri
->pc 
= NULL
; 
1191     ri
->flags 
|= SRI_DISCONNECTED
; 
1195 /* This function takes an hiredis context that is in an error condition 
1196  * and make sure to mark the instance as disconnected performing the 
1199  * Note: we don't free the hiredis context as hiredis will do it for us 
1200  * for async conenctions. */ 
1201 void sentinelDisconnectInstanceFromContext(const redisAsyncContext 
*c
) { 
1202     sentinelRedisInstance 
*ri 
= c
->data
; 
1205     if (ri 
== NULL
) return; /* The instance no longer exists. */ 
1207     pubsub 
= (ri
->pc 
== c
); 
1208     sentinelEvent(REDIS_DEBUG
, pubsub 
? "-pubsub-link" : "-cmd-link", ri
, 
1209         "%@ #%s", c
->errstr
); 
1214     ri
->flags 
|= SRI_DISCONNECTED
; 
1217 void sentinelLinkEstablishedCallback(const redisAsyncContext 
*c
, int status
) { 
1218     if (status 
!= REDIS_OK
) { 
1219         sentinelDisconnectInstanceFromContext(c
); 
1221         sentinelRedisInstance 
*ri 
= c
->data
; 
1222         int pubsub 
= (ri
->pc 
== c
); 
1224         sentinelEvent(REDIS_DEBUG
, pubsub 
? "+pubsub-link" : "+cmd-link", ri
, 
1229 void sentinelDisconnectCallback(const redisAsyncContext 
*c
, int status
) { 
1230     sentinelDisconnectInstanceFromContext(c
); 
1233 /* Create the async connections for the specified instance if the instance 
1234  * is disconnected. Note that the SRI_DISCONNECTED flag is set even if just 
1235  * one of the two links (commands and pub/sub) is missing. */ 
1236 void sentinelReconnectInstance(sentinelRedisInstance 
*ri
) { 
1237     if (!(ri
->flags 
& SRI_DISCONNECTED
)) return; 
1239     /* Commands connection. */ 
1240     if (ri
->cc 
== NULL
) { 
1241         ri
->cc 
= redisAsyncConnect(ri
->addr
->ip
,ri
->addr
->port
); 
1243             sentinelEvent(REDIS_DEBUG
,"-cmd-link-reconnection",ri
,"%@ #%s", 
1245             sentinelKillLink(ri
,ri
->cc
); 
1247             ri
->cc_conn_time 
= mstime(); 
1249             redisAeAttach(server
.el
,ri
->cc
); 
1250             redisAsyncSetConnectCallback(ri
->cc
, 
1251                                             sentinelLinkEstablishedCallback
); 
1252             redisAsyncSetDisconnectCallback(ri
->cc
, 
1253                                             sentinelDisconnectCallback
); 
1257     if ((ri
->flags 
& SRI_MASTER
) && ri
->pc 
== NULL
) { 
1258         ri
->pc 
= redisAsyncConnect(ri
->addr
->ip
,ri
->addr
->port
); 
1260             sentinelEvent(REDIS_DEBUG
,"-pubsub-link-reconnection",ri
,"%@ #%s", 
1262             sentinelKillLink(ri
,ri
->pc
); 
1266             ri
->pc_conn_time 
= mstime(); 
1268             redisAeAttach(server
.el
,ri
->pc
); 
1269             redisAsyncSetConnectCallback(ri
->pc
, 
1270                                             sentinelLinkEstablishedCallback
); 
1271             redisAsyncSetDisconnectCallback(ri
->pc
, 
1272                                             sentinelDisconnectCallback
); 
1273             /* Now we subscribe to the Sentinels "Hello" channel. */ 
1274             retval 
= redisAsyncCommand(ri
->pc
, 
1275                 sentinelReceiveHelloMessages
, NULL
, "SUBSCRIBE %s", 
1276                     SENTINEL_HELLO_CHANNEL
); 
1277             if (retval 
!= REDIS_OK
) { 
1278                 /* If we can't subscribe, the Pub/Sub connection is useless 
1279                  * and we can simply disconnect it and try again. */ 
1280                 sentinelKillLink(ri
,ri
->pc
); 
1285     /* Clear the DISCONNECTED flags only if we have both the connections 
1286      * (or just the commands connection if this is a slave or a 
1287      * sentinel instance). */ 
1288     if (ri
->cc 
&& (ri
->flags 
& (SRI_SLAVE
|SRI_SENTINEL
) || ri
->pc
)) 
1289         ri
->flags 
&= ~SRI_DISCONNECTED
; 
1292 /* ======================== Redis instances pinging  ======================== */ 
1294 /* Process the INFO output from masters. */ 
1295 void sentinelRefreshInstanceInfo(sentinelRedisInstance 
*ri
, const char *info
) { 
1299     int runid_changed 
= 0;  /* true if runid changed. */ 
1300     int first_runid 
= 0;    /* true if this is the first runid we receive. */ 
1302     /* The following fields must be reset to a given value in the case they 
1303      * are not found at all in the INFO output. */ 
1304     ri
->master_link_down_time 
= 0; 
1306     /* Process line by line. */ 
1307     lines 
= sdssplitlen(info
,strlen(info
),"\r\n",2,&numlines
); 
1308     for (j 
= 0; j 
< numlines
; j
++) { 
1309         sentinelRedisInstance 
*slave
; 
1312         /* run_id:<40 hex chars>*/ 
1313         if (sdslen(l
) >= 47 && !memcmp(l
,"run_id:",7)) { 
1314             if (ri
->runid 
== NULL
) { 
1315                 ri
->runid 
= sdsnewlen(l
+7,40); 
1318                 if (strncmp(ri
->runid
,l
+7,40) != 0) { 
1320                     sentinelEvent(REDIS_NOTICE
,"+reboot",ri
,"%@"); 
1322                     ri
->runid 
= sdsnewlen(l
+7,40); 
1327         /* slave0:<ip>,<port>,<state> */ 
1328         if ((ri
->flags 
& SRI_MASTER
) && 
1330             !memcmp(l
,"slave",5) && isdigit(l
[5])) 
1332             char *ip
, *port
, *end
; 
1334             ip 
= strchr(l
,':'); if (!ip
) continue; 
1335             ip
++; /* Now ip points to start of ip address. */ 
1336             port 
= strchr(ip
,','); if (!port
) continue; 
1337             *port 
= '\0'; /* nul term for easy access. */ 
1338             port
++; /* Now port points to start of port number. */ 
1339             end 
= strchr(port
,','); if (!end
) continue; 
1340             *end 
= '\0'; /* nul term for easy access. */ 
1342             /* Check if we already have this slave into our table, 
1343              * otherwise add it. */ 
1344             if (sentinelRedisInstanceLookupSlave(ri
,ip
,atoi(port
)) == NULL
) { 
1345                 if ((slave 
= createSentinelRedisInstance(NULL
,SRI_SLAVE
,ip
, 
1346                             atoi(port
), ri
->quorum
,ri
)) != NULL
) 
1348                     sentinelEvent(REDIS_NOTICE
,"+slave",slave
,"%@"); 
1353         /* master_link_down_since_seconds:<seconds> */ 
1354         if (sdslen(l
) >= 32 && 
1355             !memcmp(l
,"master_link_down_since_seconds",30)) 
1357             ri
->master_link_down_time 
= strtoll(l
+31,NULL
,10)*1000; 
1361         if (!memcmp(l
,"role:master",11)) role 
= SRI_MASTER
; 
1362         else if (!memcmp(l
,"role:slave",10)) role 
= SRI_SLAVE
; 
1364         if (role 
== SRI_SLAVE
) { 
1365             /* master_host:<host> */ 
1366             if (sdslen(l
) >= 12 && !memcmp(l
,"master_host:",12)) { 
1367                 sdsfree(ri
->slave_master_host
); 
1368                 ri
->slave_master_host 
= sdsnew(l
+12); 
1371             /* master_port:<port> */ 
1372             if (sdslen(l
) >= 12 && !memcmp(l
,"master_port:",12)) 
1373                 ri
->slave_master_port 
= atoi(l
+12); 
1375             /* master_link_status:<status> */ 
1376             if (sdslen(l
) >= 19 && !memcmp(l
,"master_link_status:",19)) { 
1377                 ri
->slave_master_link_status 
= 
1378                     (strcasecmp(l
+19,"up") == 0) ? 
1379                     SENTINEL_MASTER_LINK_STATUS_UP 
: 
1380                     SENTINEL_MASTER_LINK_STATUS_DOWN
; 
1384     ri
->info_refresh 
= mstime(); 
1385     sdsfreesplitres(lines
,numlines
); 
1387     /* ---------------------------- Acting half ----------------------------- */ 
1388     if (sentinel
.tilt
) return; 
1390     /* Act if a master turned into a slave. */ 
1391     if ((ri
->flags 
& SRI_MASTER
) && role 
== SRI_SLAVE
) { 
1392         if (first_runid 
&& ri
->slave_master_host
) { 
1393             /* If it is the first time we receive INFO from it, but it's 
1394              * a slave while it was configured as a master, we want to monitor 
1395              * its master instead. */ 
1396             sentinelEvent(REDIS_WARNING
,"+redirect-to-master",ri
, 
1398                 ri
->name
, ri
->addr
->ip
, ri
->addr
->port
, 
1399                 ri
->slave_master_host
, ri
->slave_master_port
); 
1400             sentinelResetMasterAndChangeAddress(ri
,ri
->slave_master_host
, 
1401                                                    ri
->slave_master_port
); 
1406     /* Act if a slave turned into a master. */ 
1407     if ((ri
->flags 
& SRI_SLAVE
) && role 
== SRI_MASTER
) { 
1408         if (!(ri
->master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) && 
1409             (runid_changed 
|| first_runid
)) 
1411             /* If a slave turned into maser but: 
1413              * 1) Failover not in progress. 
1414              * 2) RunID hs changed, or its the first time we see an INFO output. 
1416              * We assume this is a reboot with a wrong configuration. 
1417              * Log the event and remove the slave. */ 
1420             sentinelEvent(REDIS_WARNING
,"-slave-restart-as-master",ri
,"%@ #removing it from the attached slaves"); 
1421             retval 
= dictDelete(ri
->master
->slaves
,ri
->name
); 
1422             redisAssert(retval 
== REDIS_OK
); 
1424         } else if (ri
->flags 
& SRI_PROMOTED
) { 
1425             /* If this is a promoted slave we can change state to the 
1426              * failover state machine. */ 
1427             if ((ri
->master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) && 
1428                 (ri
->master
->flags 
& SRI_I_AM_THE_LEADER
) && 
1429                 (ri
->master
->failover_state 
== 
1430                     SENTINEL_FAILOVER_STATE_WAIT_PROMOTION
)) 
1432                 ri
->master
->failover_state 
= SENTINEL_FAILOVER_STATE_RECONF_SLAVES
; 
1433                 ri
->master
->failover_state_change_time 
= mstime(); 
1434                 sentinelEvent(REDIS_WARNING
,"+promoted-slave",ri
,"%@"); 
1435                 sentinelEvent(REDIS_WARNING
,"+failover-state-reconf-slaves", 
1438         } else if (!(ri
->master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) || 
1439                     ((ri
->master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) && 
1440                      (ri
->master
->flags 
& SRI_I_AM_THE_LEADER
) && 
1441                      ri
->master
->failover_state 
== 
1442                      SENTINEL_FAILOVER_STATE_WAIT_START
)) 
1444             /* No failover in progress? Then it is the start of a failover 
1445              * and we are an observer. 
1447              * We also do that if we are a leader doing a failover, in wait 
1448              * start, but well, somebody else started before us. */ 
1450             if (ri
->master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) { 
1451                 sentinelEvent(REDIS_WARNING
,"-failover-abort-race", 
1453                 sentinelAbortFailover(ri
->master
); 
1456             ri
->master
->flags 
|= SRI_FAILOVER_IN_PROGRESS
; 
1457             sentinelEvent(REDIS_WARNING
,"+failover-detected",ri
->master
,"%@"); 
1458             ri
->master
->failover_state 
= SENTINEL_FAILOVER_STATE_DETECT_END
; 
1459             ri
->master
->failover_state_change_time 
= mstime(); 
1460             ri
->master
->promoted_slave 
= ri
; 
1461             ri
->flags 
|= SRI_PROMOTED
; 
1462             /* We are an observer, so we can only assume that the leader 
1463              * is reconfiguring the slave instances. For this reason we 
1464              * set all the instances as RECONF_SENT waiting for progresses 
1466             sentinelAddFlagsToDictOfRedisInstances(ri
->master
->slaves
, 
1471     /* Detect if the slave that is in the process of being reconfigured 
1473     if ((ri
->flags 
& SRI_SLAVE
) && role 
== SRI_SLAVE 
&& 
1474         (ri
->flags 
& (SRI_RECONF_SENT
|SRI_RECONF_INPROG
))) 
1476         /* SRI_RECONF_SENT -> SRI_RECONF_INPROG. */ 
1477         if ((ri
->flags 
& SRI_RECONF_SENT
) && 
1478             ri
->slave_master_host 
&& 
1479             strcmp(ri
->slave_master_host
, 
1480                     ri
->master
->promoted_slave
->addr
->ip
) == 0 && 
1481             ri
->slave_master_port 
== ri
->master
->promoted_slave
->addr
->port
) 
1483             ri
->flags 
&= ~SRI_RECONF_SENT
; 
1484             ri
->flags 
|= SRI_RECONF_INPROG
; 
1485             sentinelEvent(REDIS_NOTICE
,"+slave-reconf-inprog",ri
,"%@"); 
1488         /* SRI_RECONF_INPROG -> SRI_RECONF_DONE */ 
1489         if ((ri
->flags 
& SRI_RECONF_INPROG
) && 
1490             ri
->slave_master_link_status 
== SENTINEL_MASTER_LINK_STATUS_UP
) 
1492             ri
->flags 
&= ~SRI_RECONF_INPROG
; 
1493             ri
->flags 
|= SRI_RECONF_DONE
; 
1494             sentinelEvent(REDIS_NOTICE
,"+slave-reconf-done",ri
,"%@"); 
1495             /* If we are moving forward (a new slave is now configured) 
1496              * we update the change_time as we are conceptually passing 
1497              * to the next slave. */ 
1498             ri
->failover_state_change_time 
= mstime(); 
1503 void sentinelInfoReplyCallback(redisAsyncContext 
*c
, void *reply
, void *privdata
) { 
1504     sentinelRedisInstance 
*ri 
= c
->data
; 
1507     if (ri
) ri
->pending_commands
--; 
1508     if (!reply 
|| !ri
) return; 
1511     if (r
->type 
== REDIS_REPLY_STRING
) { 
1512         sentinelRefreshInstanceInfo(ri
,r
->str
); 
1516 /* Just discard the reply. We use this when we are not monitoring the return 
1517  * value of the command but its effects directly. */ 
1518 void sentinelDiscardReplyCallback(redisAsyncContext 
*c
, void *reply
, void *privdata
) { 
1519     sentinelRedisInstance 
*ri 
= c
->data
; 
1521     if (ri
) ri
->pending_commands
--; 
1524 void sentinelPingReplyCallback(redisAsyncContext 
*c
, void *reply
, void *privdata
) { 
1525     sentinelRedisInstance 
*ri 
= c
->data
; 
1528     if (ri
) ri
->pending_commands
--; 
1529     if (!reply 
|| !ri
) return; 
1532     if (r
->type 
== REDIS_REPLY_STATUS 
|| 
1533         r
->type 
== REDIS_REPLY_ERROR
) { 
1534         /* Update the "instance available" field only if this is an 
1535          * acceptable reply. */ 
1536         if (strncmp(r
->str
,"PONG",4) == 0 || 
1537             strncmp(r
->str
,"LOADING",7) == 0 || 
1538             strncmp(r
->str
,"MASTERDOWN",10) == 0) 
1540             ri
->last_avail_time 
= mstime(); 
1543     ri
->last_pong_time 
= mstime(); 
1546 /* This is called when we get the reply about the PUBLISH command we send 
1547  * to the master to advertise this sentinel. */ 
1548 void sentinelPublishReplyCallback(redisAsyncContext 
*c
, void *reply
, void *privdata
) { 
1549     sentinelRedisInstance 
*ri 
= c
->data
; 
1552     if (ri
) ri
->pending_commands
--; 
1553     if (!reply 
|| !ri
) return; 
1556     /* Only update pub_time if we actually published our message. Otherwise 
1557      * we'll retry against in 100 milliseconds. */ 
1558     if (r
->type 
!= REDIS_REPLY_ERROR
) 
1559         ri
->last_pub_time 
= mstime(); 
1562 /* This is our Pub/Sub callback for the Hello channel. It's useful in order 
1563  * to discover other sentinels attached at the same master. */ 
1564 void sentinelReceiveHelloMessages(redisAsyncContext 
*c
, void *reply
, void *privdata
) { 
1565     sentinelRedisInstance 
*ri 
= c
->data
; 
1568     if (!reply 
|| !ri
) return; 
1571     /* Update the last activity in the pubsub channel. Note that since we 
1572      * receive our messages as well this timestamp can be used to detect 
1573      * if the link is probably diconnected even if it seems otherwise. */ 
1574     ri
->pc_last_activity 
= mstime(); 
1576     /* Sanity check in the reply we expect, so that the code that follows 
1577      * can avoid to check for details. */ 
1578     if (r
->type 
!= REDIS_REPLY_ARRAY 
|| 
1580         r
->element
[0]->type 
!= REDIS_REPLY_STRING 
|| 
1581         r
->element
[1]->type 
!= REDIS_REPLY_STRING 
|| 
1582         r
->element
[2]->type 
!= REDIS_REPLY_STRING 
|| 
1583         strcmp(r
->element
[0]->str
,"message") != 0) return; 
1585     /* We are not interested in meeting ourselves */ 
1586     if (strstr(r
->element
[2]->str
,server
.runid
) != NULL
) return; 
1589         int numtokens
, port
, removed
, canfailover
; 
1590         char **token 
= sdssplitlen(r
->element
[2]->str
, 
1593         sentinelRedisInstance 
*sentinel
; 
1595         if (numtokens 
== 4) { 
1596             /* First, try to see if we already have this sentinel. */ 
1597             port 
= atoi(token
[1]); 
1598             canfailover 
= atoi(token
[3]); 
1599             sentinel 
= getSentinelRedisInstanceByAddrAndRunID( 
1600                             ri
->sentinels
,token
[0],port
,token
[2]); 
1603                 /* If not, remove all the sentinels that have the same runid 
1604                  * OR the same ip/port, because it's either a restart or a 
1605                  * network topology change. */ 
1606                 removed 
= removeMatchingSentinelsFromMaster(ri
,token
[0],port
, 
1609                     sentinelEvent(REDIS_NOTICE
,"-dup-sentinel",ri
, 
1610                         "%@ #duplicate of %s:%d or %s", 
1611                         token
[0],port
,token
[2]); 
1614                 /* Add the new sentinel. */ 
1615                 sentinel 
= createSentinelRedisInstance(NULL
,SRI_SENTINEL
, 
1616                                 token
[0],port
,ri
->quorum
,ri
); 
1618                     sentinelEvent(REDIS_NOTICE
,"+sentinel",sentinel
,"%@"); 
1619                     /* The runid is NULL after a new instance creation and 
1620                      * for Sentinels we don't have a later chance to fill it, 
1622                     sentinel
->runid 
= sdsnew(token
[2]); 
1626             /* Update the state of the Sentinel. */ 
1628                 sentinel
->last_hello_time 
= mstime(); 
1630                     sentinel
->flags 
|= SRI_CAN_FAILOVER
; 
1632                     sentinel
->flags 
&= ~SRI_CAN_FAILOVER
; 
1635         sdsfreesplitres(token
,numtokens
); 
1639 void sentinelPingInstance(sentinelRedisInstance 
*ri
) { 
1640     mstime_t now 
= mstime(); 
1641     mstime_t info_period
; 
1644     /* Return ASAP if we have already a PING or INFO already pending, or 
1645      * in the case the instance is not properly connected. */ 
1646     if (ri
->flags 
& SRI_DISCONNECTED
) return; 
1648     /* For INFO, PING, PUBLISH that are not critical commands to send we 
1649      * also have a limit of SENTINEL_MAX_PENDING_COMMANDS. We don't 
1650      * want to use a lot of memory just because a link is not working 
1651      * properly (note that anyway there is a redundant protection about this, 
1652      * that is, the link will be disconnected and reconnected if a long 
1653      * timeout condition is detected. */ 
1654     if (ri
->pending_commands 
>= SENTINEL_MAX_PENDING_COMMANDS
) return; 
1656     /* If this is a slave of a master in O_DOWN condition we start sending 
1657      * it INFO every second, instead of the usual SENTINEL_INFO_PERIOD 
1658      * period. In this state we want to closely monitor slaves in case they 
1659      * are turned into masters by another Sentinel, or by the sysadmin. */ 
1660     if ((ri
->flags 
& SRI_SLAVE
) && 
1661         (ri
->master
->flags 
& (SRI_O_DOWN
|SRI_FAILOVER_IN_PROGRESS
))) { 
1664         info_period 
= SENTINEL_INFO_PERIOD
; 
1667     if ((ri
->flags 
& SRI_SENTINEL
) == 0 && 
1668         (ri
->info_refresh 
== 0 || 
1669         (now 
- ri
->info_refresh
) > info_period
)) 
1671         /* Send INFO to masters and slaves, not sentinels. */ 
1672         retval 
= redisAsyncCommand(ri
->cc
, 
1673             sentinelInfoReplyCallback
, NULL
, "INFO"); 
1674         if (retval 
!= REDIS_OK
) return; 
1675         ri
->pending_commands
++; 
1676     } else if ((now 
- ri
->last_pong_time
) > SENTINEL_PING_PERIOD
) { 
1677         /* Send PING to all the three kinds of instances. */ 
1678         retval 
= redisAsyncCommand(ri
->cc
, 
1679             sentinelPingReplyCallback
, NULL
, "PING"); 
1680         if (retval 
!= REDIS_OK
) return; 
1681         ri
->pending_commands
++; 
1682     } else if ((ri
->flags 
& SRI_MASTER
) && 
1683                (now 
- ri
->last_pub_time
) > SENTINEL_PUBLISH_PERIOD
) 
1685         /* PUBLISH hello messages only to masters. */ 
1686         struct sockaddr_in sa
; 
1687         socklen_t salen 
= sizeof(sa
); 
1689         if (getsockname(ri
->cc
->c
.fd
,(struct sockaddr
*)&sa
,&salen
) != -1) { 
1692             snprintf(myaddr
,sizeof(myaddr
),"%s:%d:%s:%d", 
1693                 inet_ntoa(sa
.sin_addr
), server
.port
, server
.runid
, 
1694                 (ri
->flags 
& SRI_CAN_FAILOVER
) != 0); 
1695             retval 
= redisAsyncCommand(ri
->cc
, 
1696                 sentinelPublishReplyCallback
, NULL
, "PUBLISH %s %s", 
1697                     SENTINEL_HELLO_CHANNEL
,myaddr
); 
1698             if (retval 
!= REDIS_OK
) return; 
1699             ri
->pending_commands
++; 
1704 /* =========================== SENTINEL command ============================= */ 
1706 const char *sentinelFailoverStateStr(int state
) { 
1708     case SENTINEL_FAILOVER_STATE_NONE
: return "none"; 
1709     case SENTINEL_FAILOVER_STATE_WAIT_START
: return "wait_start"; 
1710     case SENTINEL_FAILOVER_STATE_SELECT_SLAVE
: return "select_slave"; 
1711     case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE
: return "send_slaveof_noone"; 
1712     case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION
: return "wait_promotion"; 
1713     case SENTINEL_FAILOVER_STATE_RECONF_SLAVES
: return "reconf_slaves"; 
1714     case SENTINEL_FAILOVER_STATE_ALERT_CLIENTS
: return "alert_clients"; 
1715     case SENTINEL_FAILOVER_STATE_DETECT_END
: return "detect_end"; 
1716     case SENTINEL_FAILOVER_STATE_UPDATE_CONFIG
: return "update_config"; 
1717     default: return "unknown"; 
1721 /* Redis instance to Redis protocol representation. */ 
1722 void addReplySentinelRedisInstance(redisClient 
*c
, sentinelRedisInstance 
*ri
) { 
1723     char *flags 
= sdsempty(); 
1727     mbl 
= addDeferredMultiBulkLength(c
); 
1729     addReplyBulkCString(c
,"name"); 
1730     addReplyBulkCString(c
,ri
->name
); 
1733     addReplyBulkCString(c
,"ip"); 
1734     addReplyBulkCString(c
,ri
->addr
->ip
); 
1737     addReplyBulkCString(c
,"port"); 
1738     addReplyBulkLongLong(c
,ri
->addr
->port
); 
1741     addReplyBulkCString(c
,"runid"); 
1742     addReplyBulkCString(c
,ri
->runid 
? ri
->runid 
: ""); 
1745     addReplyBulkCString(c
,"flags"); 
1746     if (ri
->flags 
& SRI_S_DOWN
) flags 
= sdscat(flags
,"s_down,"); 
1747     if (ri
->flags 
& SRI_O_DOWN
) flags 
= sdscat(flags
,"o_down,"); 
1748     if (ri
->flags 
& SRI_MASTER
) flags 
= sdscat(flags
,"master,"); 
1749     if (ri
->flags 
& SRI_SLAVE
) flags 
= sdscat(flags
,"slave,"); 
1750     if (ri
->flags 
& SRI_SENTINEL
) flags 
= sdscat(flags
,"sentinel,"); 
1751     if (ri
->flags 
& SRI_DISCONNECTED
) flags 
= sdscat(flags
,"disconnected,"); 
1752     if (ri
->flags 
& SRI_MASTER_DOWN
) flags 
= sdscat(flags
,"master_down,"); 
1753     if (ri
->flags 
& SRI_FAILOVER_IN_PROGRESS
) 
1754         flags 
= sdscat(flags
,"failover_in_progress,"); 
1755     if (ri
->flags 
& SRI_I_AM_THE_LEADER
) 
1756         flags 
= sdscat(flags
,"i_am_the_leader,"); 
1757     if (ri
->flags 
& SRI_PROMOTED
) flags 
= sdscat(flags
,"promoted,"); 
1758     if (ri
->flags 
& SRI_RECONF_SENT
) flags 
= sdscat(flags
,"reconf_sent,"); 
1759     if (ri
->flags 
& SRI_RECONF_INPROG
) flags 
= sdscat(flags
,"reconf_inprog,"); 
1760     if (ri
->flags 
& SRI_RECONF_DONE
) flags 
= sdscat(flags
,"reconf_done,"); 
1762     if (sdslen(flags
) != 0) flags 
= sdsrange(flags
,0,-2); /* remove last "," */ 
1763     addReplyBulkCString(c
,flags
); 
1767     addReplyBulkCString(c
,"pending-commands"); 
1768     addReplyBulkLongLong(c
,ri
->pending_commands
); 
1771     if (ri
->flags 
& SRI_FAILOVER_IN_PROGRESS
) { 
1772         addReplyBulkCString(c
,"failover-state"); 
1773         addReplyBulkCString(c
,(char*)sentinelFailoverStateStr(ri
->failover_state
)); 
1777     addReplyBulkCString(c
,"last-ok-ping-reply"); 
1778     addReplyBulkLongLong(c
,mstime() - ri
->last_avail_time
); 
1781     addReplyBulkCString(c
,"last-ping-reply"); 
1782     addReplyBulkLongLong(c
,mstime() - ri
->last_pong_time
); 
1785     if (ri
->flags 
& SRI_S_DOWN
) { 
1786         addReplyBulkCString(c
,"s-down-time"); 
1787         addReplyBulkLongLong(c
,mstime()-ri
->s_down_since_time
); 
1791     if (ri
->flags 
& SRI_O_DOWN
) { 
1792         addReplyBulkCString(c
,"o-down-time"); 
1793         addReplyBulkLongLong(c
,mstime()-ri
->o_down_since_time
); 
1797     /* Masters and Slaves */ 
1798     if (ri
->flags 
& (SRI_MASTER
|SRI_SLAVE
)) { 
1799         addReplyBulkCString(c
,"info-refresh"); 
1800         addReplyBulkLongLong(c
,mstime() - ri
->info_refresh
); 
1805     if (ri
->flags 
& SRI_MASTER
) { 
1806         addReplyBulkCString(c
,"num-slaves"); 
1807         addReplyBulkLongLong(c
,dictSize(ri
->slaves
)); 
1810         addReplyBulkCString(c
,"num-other-sentinels"); 
1811         addReplyBulkLongLong(c
,dictSize(ri
->sentinels
)); 
1814         addReplyBulkCString(c
,"quorum"); 
1815         addReplyBulkLongLong(c
,ri
->quorum
); 
1820     if (ri
->flags 
& SRI_SLAVE
) { 
1821         addReplyBulkCString(c
,"master-link-down-time"); 
1822         addReplyBulkLongLong(c
,ri
->master_link_down_time
); 
1825         addReplyBulkCString(c
,"master-link-status"); 
1826         addReplyBulkCString(c
, 
1827             (ri
->slave_master_link_status 
== SENTINEL_MASTER_LINK_STATUS_UP
) ? 
1831         addReplyBulkCString(c
,"master-host"); 
1832         addReplyBulkCString(c
, 
1833             ri
->slave_master_host 
? ri
->slave_master_host 
: "?"); 
1836         addReplyBulkCString(c
,"master-port"); 
1837         addReplyBulkLongLong(c
,ri
->slave_master_port
); 
1841     /* Only sentinels */ 
1842     if (ri
->flags 
& SRI_SENTINEL
) { 
1843         addReplyBulkCString(c
,"last-hello-message"); 
1844         addReplyBulkLongLong(c
,mstime() - ri
->last_hello_time
); 
1847         addReplyBulkCString(c
,"can-failover-its-master"); 
1848         addReplyBulkLongLong(c
,(ri
->flags 
& SRI_CAN_FAILOVER
) != 0); 
1851         if (ri
->flags 
& SRI_MASTER_DOWN
) { 
1852             addReplyBulkCString(c
,"subjective-leader"); 
1853             addReplyBulkCString(c
,ri
->leader 
? ri
->leader 
: "?"); 
1858     setDeferredMultiBulkLength(c
,mbl
,fields
*2); 
1861 /* Output a number of instances contanined inside a dictionary as 
1862  * Redis protocol. */ 
1863 void addReplyDictOfRedisInstances(redisClient 
*c
, dict 
*instances
) { 
1867     di 
= dictGetIterator(instances
); 
1868     addReplyMultiBulkLen(c
,dictSize(instances
)); 
1869     while((de 
= dictNext(di
)) != NULL
) { 
1870         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
1872         addReplySentinelRedisInstance(c
,ri
); 
1874     dictReleaseIterator(di
); 
1877 /* Lookup the named master into sentinel.masters. 
1878  * If the master is not found reply to the client with an error and returns 
1880 sentinelRedisInstance 
*sentinelGetMasterByNameOrReplyError(redisClient 
*c
, 
1883     sentinelRedisInstance 
*ri
; 
1885     ri 
= dictFetchValue(sentinel
.masters
,c
->argv
[2]->ptr
); 
1887         addReplyError(c
,"No such master with that name"); 
1893 void sentinelCommand(redisClient 
*c
) { 
1894     if (!strcasecmp(c
->argv
[1]->ptr
,"masters")) { 
1895         /* SENTINEL MASTERS */ 
1896         if (c
->argc 
!= 2) goto numargserr
; 
1898         addReplyDictOfRedisInstances(c
,sentinel
.masters
); 
1899     } else if (!strcasecmp(c
->argv
[1]->ptr
,"slaves")) { 
1900         /* SENTINEL SLAVES <master-name> */ 
1901         sentinelRedisInstance 
*ri
; 
1903         if (c
->argc 
!= 3) goto numargserr
; 
1904         if ((ri 
= sentinelGetMasterByNameOrReplyError(c
,c
->argv
[2])) == NULL
) 
1906         addReplyDictOfRedisInstances(c
,ri
->slaves
); 
1907     } else if (!strcasecmp(c
->argv
[1]->ptr
,"sentinels")) { 
1908         /* SENTINEL SENTINELS <master-name> */ 
1909         sentinelRedisInstance 
*ri
; 
1911         if (c
->argc 
!= 3) goto numargserr
; 
1912         if ((ri 
= sentinelGetMasterByNameOrReplyError(c
,c
->argv
[2])) == NULL
) 
1914         addReplyDictOfRedisInstances(c
,ri
->sentinels
); 
1915     } else if (!strcasecmp(c
->argv
[1]->ptr
,"is-master-down-by-addr")) { 
1916         /* SENTINEL IS-MASTER-DOWN-BY-ADDR <ip> <port> */ 
1917         sentinelRedisInstance 
*ri
; 
1918         char *leader 
= NULL
; 
1922         if (c
->argc 
!= 4) goto numargserr
; 
1923         if (getLongFromObjectOrReply(c
,c
->argv
[3],&port
,NULL
) != REDIS_OK
) 
1925         ri 
= getSentinelRedisInstanceByAddrAndRunID(sentinel
.masters
, 
1926             c
->argv
[2]->ptr
,port
,NULL
); 
1928         /* It exists? Is actually a master? Is subjectively down? It's down. 
1929          * Note: if we are in tilt mode we always reply with "0". */ 
1930         if (!sentinel
.tilt 
&& ri 
&& (ri
->flags 
& SRI_S_DOWN
) && 
1931                                     (ri
->flags 
& SRI_MASTER
)) 
1933         if (ri
) leader 
= sentinelGetSubjectiveLeader(ri
); 
1935         /* Reply with a two-elements multi-bulk reply: down state, leader. */ 
1936         addReplyMultiBulkLen(c
,2); 
1937         addReply(c
, isdown 
? shared
.cone 
: shared
.czero
); 
1938         addReplyBulkCString(c
, leader 
? leader 
: "?"); 
1939         if (leader
) sdsfree(leader
); 
1940     } else if (!strcasecmp(c
->argv
[1]->ptr
,"reset")) { 
1941         /* SENTINEL RESET <pattern> */ 
1942         if (c
->argc 
!= 3) goto numargserr
; 
1943         addReplyLongLong(c
,sentinelResetMastersByPattern(c
->argv
[2]->ptr
,SENTINEL_GENERATE_EVENT
)); 
1944     } else if (!strcasecmp(c
->argv
[1]->ptr
,"get-master-addr-by-name")) { 
1945         /* SENTINEL GET-MASTER-ADDR-BY-NAME <master-name> */ 
1946         sentinelRedisInstance 
*ri
; 
1948         if (c
->argc 
!= 3) goto numargserr
; 
1949         ri 
= sentinelGetMasterByName(c
->argv
[2]->ptr
); 
1951             addReply(c
,shared
.nullmultibulk
); 
1953             sentinelAddr 
*addr 
= ri
->addr
; 
1955             if ((ri
->flags 
& SRI_FAILOVER_IN_PROGRESS
) && ri
->promoted_slave
) 
1956                 addr 
= ri
->promoted_slave
->addr
; 
1957             addReplyMultiBulkLen(c
,2); 
1958             addReplyBulkCString(c
,addr
->ip
); 
1959             addReplyBulkLongLong(c
,addr
->port
); 
1961     } else if (!strcasecmp(c
->argv
[1]->ptr
,"pending-scripts")) { 
1962         /* SENTINEL PENDING-SCRIPTS */ 
1964         if (c
->argc 
!= 2) goto numargserr
; 
1965         sentinelPendingScriptsCommand(c
); 
1967         addReplyErrorFormat(c
,"Unknown sentinel subcommand '%s'", 
1968                                (char*)c
->argv
[1]->ptr
); 
1973     addReplyErrorFormat(c
,"Wrong number of commands for 'sentinel %s'", 
1974                           (char*)c
->argv
[1]->ptr
); 
1977 /* ===================== SENTINEL availability checks ======================= */ 
1979 /* Is this instance down from our point of view? */ 
1980 void sentinelCheckSubjectivelyDown(sentinelRedisInstance 
*ri
) { 
1981     mstime_t elapsed 
= mstime() - ri
->last_avail_time
; 
1983     /* Check if we are in need for a reconnection of one of the  
1984      * links, because we are detecting low activity. 
1986      * 1) Check if the command link seems connected, was connected not less 
1987      *    than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have an 
1988      *    idle time that is greater than down_after_period / 2 seconds. */ 
1990         (mstime() - ri
->cc_conn_time
) > SENTINEL_MIN_LINK_RECONNECT_PERIOD 
&& 
1991         (mstime() - ri
->last_pong_time
) > (ri
->down_after_period
/2)) 
1993         sentinelKillLink(ri
,ri
->cc
); 
1996     /* 2) Check if the pubsub link seems connected, was connected not less 
1997      *    than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have no 
1998      *    activity in the Pub/Sub channel for more than 
1999      *    SENTINEL_PUBLISH_PERIOD * 3. 
2002         (mstime() - ri
->pc_conn_time
) > SENTINEL_MIN_LINK_RECONNECT_PERIOD 
&& 
2003         (mstime() - ri
->pc_last_activity
) > (SENTINEL_PUBLISH_PERIOD
*3)) 
2005         sentinelKillLink(ri
,ri
->pc
); 
2008     /* Update the subjectively down flag. */ 
2009     if (elapsed 
> ri
->down_after_period
) { 
2010         /* Is subjectively down */ 
2011         if ((ri
->flags 
& SRI_S_DOWN
) == 0) { 
2012             sentinelEvent(REDIS_WARNING
,"+sdown",ri
,"%@"); 
2013             ri
->s_down_since_time 
= mstime(); 
2014             ri
->flags 
|= SRI_S_DOWN
; 
2017         /* Is subjectively up */ 
2018         if (ri
->flags 
& SRI_S_DOWN
) { 
2019             sentinelEvent(REDIS_WARNING
,"-sdown",ri
,"%@"); 
2020             ri
->flags 
&= ~SRI_S_DOWN
; 
2025 /* Is this instance down accordingly to the configured quorum? */ 
2026 void sentinelCheckObjectivelyDown(sentinelRedisInstance 
*master
) { 
2029     int quorum 
= 0, odown 
= 0; 
2031     if (master
->flags 
& SRI_S_DOWN
) { 
2032         /* Is down for enough sentinels? */ 
2033         quorum 
= 1; /* the current sentinel. */ 
2034         /* Count all the other sentinels. */ 
2035         di 
= dictGetIterator(master
->sentinels
); 
2036         while((de 
= dictNext(di
)) != NULL
) { 
2037             sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
2039             if (ri
->flags 
& SRI_MASTER_DOWN
) quorum
++; 
2041         dictReleaseIterator(di
); 
2042         if (quorum 
>= master
->quorum
) odown 
= 1; 
2045     /* Set the flag accordingly to the outcome. */ 
2047         if ((master
->flags 
& SRI_O_DOWN
) == 0) { 
2048             sentinelEvent(REDIS_WARNING
,"+odown",master
,"%@ #quorum %d/%d", 
2049                 quorum
, master
->quorum
); 
2050             master
->flags 
|= SRI_O_DOWN
; 
2051             master
->o_down_since_time 
= mstime(); 
2054         if (master
->flags 
& SRI_O_DOWN
) { 
2055             sentinelEvent(REDIS_WARNING
,"-odown",master
,"%@"); 
2056             master
->flags 
&= ~SRI_O_DOWN
; 
2061 /* Receive the SENTINEL is-master-down-by-addr reply, see the 
2062  * sentinelAskMasterStateToOtherSentinels() function for more information. */ 
2063 void sentinelReceiveIsMasterDownReply(redisAsyncContext 
*c
, void *reply
, void *privdata
) { 
2064     sentinelRedisInstance 
*ri 
= c
->data
; 
2067     if (ri
) ri
->pending_commands
--; 
2068     if (!reply 
|| !ri
) return; 
2071     /* Ignore every error or unexpected reply. 
2072      * Note that if the command returns an error for any reason we'll 
2073      * end clearing the SRI_MASTER_DOWN flag for timeout anyway. */ 
2074     if (r
->type 
== REDIS_REPLY_ARRAY 
&& r
->elements 
== 2 && 
2075         r
->element
[0]->type 
== REDIS_REPLY_INTEGER 
&& 
2076         r
->element
[1]->type 
== REDIS_REPLY_STRING
) 
2078         ri
->last_master_down_reply_time 
= mstime(); 
2079         if (r
->element
[0]->integer 
== 1) { 
2080             ri
->flags 
|= SRI_MASTER_DOWN
; 
2082             ri
->flags 
&= ~SRI_MASTER_DOWN
; 
2084         sdsfree(ri
->leader
); 
2085         ri
->leader 
= sdsnew(r
->element
[1]->str
); 
2089 /* If we think (subjectively) the master is down, we start sending 
2090  * SENTINEL IS-MASTER-DOWN-BY-ADDR requests to other sentinels 
2091  * in order to get the replies that allow to reach the quorum and 
2092  * possibly also mark the master as objectively down. */ 
2093 void sentinelAskMasterStateToOtherSentinels(sentinelRedisInstance 
*master
) { 
2097     di 
= dictGetIterator(master
->sentinels
); 
2098     while((de 
= dictNext(di
)) != NULL
) { 
2099         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
2100         mstime_t elapsed 
= mstime() - ri
->last_master_down_reply_time
; 
2104         /* If the master state from other sentinel is too old, we clear it. */ 
2105         if (elapsed 
> SENTINEL_INFO_VALIDITY_TIME
) { 
2106             ri
->flags 
&= ~SRI_MASTER_DOWN
; 
2107             sdsfree(ri
->leader
); 
2111         /* Only ask if master is down to other sentinels if: 
2113          * 1) We believe it is down, or there is a failover in progress. 
2114          * 2) Sentinel is connected. 
2115          * 3) We did not received the info within SENTINEL_ASK_PERIOD ms. */ 
2116         if ((master
->flags 
& (SRI_S_DOWN
|SRI_FAILOVER_IN_PROGRESS
)) == 0) 
2118         if (ri
->flags 
& SRI_DISCONNECTED
) continue; 
2119         if (mstime() - ri
->last_master_down_reply_time 
< SENTINEL_ASK_PERIOD
) 
2123         ll2string(port
,sizeof(port
),master
->addr
->port
); 
2124         retval 
= redisAsyncCommand(ri
->cc
, 
2125                     sentinelReceiveIsMasterDownReply
, NULL
, 
2126                     "SENTINEL is-master-down-by-addr %s %s", 
2127                     master
->addr
->ip
, port
); 
2128         if (retval 
== REDIS_OK
) ri
->pending_commands
++; 
2130     dictReleaseIterator(di
); 
2133 /* =============================== FAILOVER ================================= */ 
2135 /* Given a master get the "subjective leader", that is, among all the sentinels 
2136  * with given characteristics, the one with the lexicographically smaller 
2137  * runid. The characteristics required are: 
2139  * 1) Has SRI_CAN_FAILOVER flag. 
2140  * 2) Is not disconnected. 
2141  * 3) Recently answered to our ping (no longer than 
2142  *    SENTINEL_INFO_VALIDITY_TIME milliseconds ago). 
2144  * The function returns a pointer to an sds string representing the runid of the 
2145  * leader sentinel instance (from our point of view). Otherwise NULL is 
2146  * returned if there are no suitable sentinels. 
2149 int compareRunID(const void *a
, const void *b
) { 
2150     char **aptrptr 
= (char**)a
, **bptrptr 
= (char**)b
; 
2151     return strcasecmp(*aptrptr
, *bptrptr
); 
2154 char *sentinelGetSubjectiveLeader(sentinelRedisInstance 
*master
) { 
2158         zmalloc(sizeof(char*)*(dictSize(master
->sentinels
)+1)); 
2160     char *leader 
= NULL
; 
2162     if (master
->flags 
& SRI_CAN_FAILOVER
) { 
2163         /* Add myself if I'm a Sentinel that can failover this master. */ 
2164         instance
[instances
++] = server
.runid
; 
2167     di 
= dictGetIterator(master
->sentinels
); 
2168     while((de 
= dictNext(di
)) != NULL
) { 
2169         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
2170         mstime_t lag 
= mstime() - ri
->last_avail_time
; 
2172         if (lag 
> SENTINEL_INFO_VALIDITY_TIME 
|| 
2173             !(ri
->flags 
& SRI_CAN_FAILOVER
) || 
2174             (ri
->flags 
& SRI_DISCONNECTED
) || 
2177         instance
[instances
++] = ri
->runid
; 
2179     dictReleaseIterator(di
); 
2181     /* If we have at least one instance passing our checks, order the array 
2184         qsort(instance
,instances
,sizeof(char*),compareRunID
); 
2185         leader 
= sdsnew(instance
[0]); 
2191 struct sentinelLeader 
{ 
2193     unsigned long votes
; 
2196 /* Helper function for sentinelGetObjectiveLeader, increment the counter 
2197  * relative to the specified runid. */ 
2198 void sentinelObjectiveLeaderIncr(dict 
*counters
, char *runid
) { 
2199     dictEntry 
*de 
= dictFind(counters
,runid
); 
2203         oldval 
= dictGetUnsignedIntegerVal(de
); 
2204         dictSetUnsignedIntegerVal(de
,oldval
+1); 
2206         de 
= dictAddRaw(counters
,runid
); 
2207         redisAssert(de 
!= NULL
); 
2208         dictSetUnsignedIntegerVal(de
,1); 
2212 /* Scan all the Sentinels attached to this master to check what is the 
2213  * most voted leader among Sentinels. */ 
2214 char *sentinelGetObjectiveLeader(sentinelRedisInstance 
*master
) { 
2218     unsigned int voters 
= 0, voters_quorum
; 
2220     char *winner 
= NULL
; 
2222     redisAssert(master
->flags 
& (SRI_O_DOWN
|SRI_FAILOVER_IN_PROGRESS
)); 
2223     counters 
= dictCreate(&leaderVotesDictType
,NULL
); 
2225     /* Count my vote. */ 
2226     myvote 
= sentinelGetSubjectiveLeader(master
); 
2228         sentinelObjectiveLeaderIncr(counters
,myvote
); 
2232     /* Count other sentinels votes */ 
2233     di 
= dictGetIterator(master
->sentinels
); 
2234     while((de 
= dictNext(di
)) != NULL
) { 
2235         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
2236         if (ri
->leader 
== NULL
) continue; 
2237         /* If the failover is not already in progress we are only interested 
2238          * in Sentinels that believe the master is down. Otherwise the leader 
2239          * selection is useful for the "failover-takedown" when the original 
2240          * leader fails. In that case we consider all the voters. */ 
2241         if (!(master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) && 
2242             !(ri
->flags 
& SRI_MASTER_DOWN
)) continue; 
2243         sentinelObjectiveLeaderIncr(counters
,ri
->leader
); 
2246     dictReleaseIterator(di
); 
2247     voters_quorum 
= voters
/2+1; 
2249     /* Check what's the winner. For the winner to win, it needs two conditions: 
2250      * 1) Absolute majority between voters (50% + 1). 
2251      * 2) And anyway at least master->quorum votes. */ 
2253         uint64_t max_votes 
= 0; /* Max votes so far. */ 
2255         di 
= dictGetIterator(counters
); 
2256         while((de 
= dictNext(di
)) != NULL
) { 
2257             uint64_t votes 
= dictGetUnsignedIntegerVal(de
); 
2259             if (max_votes 
< votes
) { 
2261                 winner 
= dictGetKey(de
); 
2264         dictReleaseIterator(di
); 
2265         if (winner 
&& (max_votes 
< voters_quorum 
|| max_votes 
< master
->quorum
)) 
2268     winner 
= winner 
? sdsnew(winner
) : NULL
; 
2270     dictRelease(counters
); 
2274 /* This function checks if there are the conditions to start the failover, 
2277  * 1) Enough time has passed since O_DOWN. 
2278  * 2) The master is marked as SRI_CAN_FAILOVER, so we can failover it. 
2279  * 3) We are the objectively leader for this master. 
2281  * If the conditions are met we flag the master as SRI_FAILOVER_IN_PROGRESS 
2282  * and SRI_I_AM_THE_LEADER. 
2284 void sentinelStartFailover(sentinelRedisInstance 
*master
) { 
2288     /* We can't failover if the master is not in O_DOWN state or if 
2289      * there is not already a failover in progress (to perform the 
2290      * takedown if the leader died) or if this Sentinel is not allowed 
2291      * to start a failover. */ 
2292     if (!(master
->flags 
& SRI_CAN_FAILOVER
) || 
2293         !(master
->flags 
& (SRI_O_DOWN
|SRI_FAILOVER_IN_PROGRESS
))) return; 
2295     leader 
= sentinelGetObjectiveLeader(master
); 
2296     isleader 
= leader 
&& strcasecmp(leader
,server
.runid
) == 0; 
2299     /* If I'm not the leader, I can't failover for sure. */ 
2300     if (!isleader
) return; 
2302     /* If the failover is already in progress there are two options... */ 
2303     if (master
->flags 
& SRI_FAILOVER_IN_PROGRESS
) { 
2304         if (master
->flags 
& SRI_I_AM_THE_LEADER
) { 
2305             /* 1) I'm flagged as leader so I already started the failover. 
2309             mstime_t elapsed 
= mstime() - master
->failover_state_change_time
; 
2311             /* 2) I'm the new leader, but I'm not flagged as leader in the 
2312              *    master: I did not started the failover, but the original 
2313              *    leader has no longer the leadership. 
2315              *    In this case if the failover appears to be lagging 
2316              *    for at least 25% of the configured failover timeout, 
2317              *    I can assume I can take control. Otherwise 
2318              *    it's better to return and wait more. */ 
2319             if (elapsed 
< (master
->failover_timeout
/4)) return; 
2320             sentinelEvent(REDIS_WARNING
,"+failover-takedown",master
,"%@"); 
2321             /* We have already an elected slave if we are in 
2322              * FAILOVER_IN_PROGRESS state, that is, the slave that we 
2323              * observed turning into a master. */ 
2324             master
->failover_state 
= SENTINEL_FAILOVER_STATE_RECONF_SLAVES
; 
2325             /* As an observer we flagged all the slaves as RECONF_SENT but 
2326              * now we are in charge of actually sending the reconfiguration 
2327              * command so let's clear this flag for all the instances. */ 
2328             sentinelDelFlagsToDictOfRedisInstances(master
->slaves
, 
2332         /* Brand new failover as SRI_FAILOVER_IN_PROGRESS was not set. 
2334          * Do we have a slave to promote? Otherwise don't start a failover 
2336         if (sentinelSelectSlave(master
) == NULL
) return; 
2337         master
->failover_state 
= SENTINEL_FAILOVER_STATE_WAIT_START
; 
2340     master
->flags 
|= SRI_FAILOVER_IN_PROGRESS
|SRI_I_AM_THE_LEADER
; 
2341     sentinelEvent(REDIS_WARNING
,"+failover-triggered",master
,"%@"); 
2343     /* Pick a random delay if it's a fresh failover (WAIT_START), and not 
2344      * a recovery of a failover started by another sentinel. */ 
2345     if (master
->failover_state 
== SENTINEL_FAILOVER_STATE_WAIT_START
) { 
2346         master
->failover_start_time 
= mstime() + 
2347             SENTINEL_FAILOVER_FIXED_DELAY 
+ 
2348             (rand() % SENTINEL_FAILOVER_MAX_RANDOM_DELAY
); 
2349         sentinelEvent(REDIS_WARNING
,"+failover-state-wait-start",master
, 
2350             "%@ #starting in %lld milliseconds", 
2351             master
->failover_start_time
-mstime()); 
2353     master
->failover_state_change_time 
= mstime(); 
2356 /* Select a suitable slave to promote. The current algorithm only uses 
2357  * the following parameters: 
2359  * 1) None of the following conditions: S_DOWN, O_DOWN, DISCONNECTED. 
2360  * 2) last_avail_time more recent than SENTINEL_INFO_VALIDITY_TIME. 
2361  * 3) info_refresh more recent than SENTINEL_INFO_VALIDITY_TIME. 
2362  * 4) master_link_down_time no more than: 
2363  *     (now - master->s_down_since_time) + (master->down_after_period * 10). 
2365  * Among all the slaves matching the above conditions we select the slave 
2366  * with lower slave_priority. If priority is the same we select the slave 
2367  * with lexicographically smaller runid. 
2369  * The function returns the pointer to the selected slave, otherwise 
2370  * NULL if no suitable slave was found. 
2373 int compareSlavesForPromotion(const void *a
, const void *b
) { 
2374     sentinelRedisInstance 
**sa 
= (sentinelRedisInstance 
**)a
, 
2375                           **sb 
= (sentinelRedisInstance 
**)b
; 
2376     if ((*sa
)->slave_priority 
!= (*sb
)->slave_priority
) 
2377         return (*sa
)->slave_priority 
- (*sb
)->slave_priority
; 
2378     return strcasecmp((*sa
)->runid
,(*sb
)->runid
); 
2381 sentinelRedisInstance 
*sentinelSelectSlave(sentinelRedisInstance 
*master
) { 
2382     sentinelRedisInstance 
**instance 
= 
2383         zmalloc(sizeof(instance
[0])*dictSize(master
->slaves
)); 
2384     sentinelRedisInstance 
*selected 
= NULL
; 
2388     mstime_t max_master_down_time
; 
2390     max_master_down_time 
= (mstime() - master
->s_down_since_time
) + 
2391                            (master
->down_after_period 
* 10); 
2393     di 
= dictGetIterator(master
->slaves
); 
2394     while((de 
= dictNext(di
)) != NULL
) { 
2395         sentinelRedisInstance 
*slave 
= dictGetVal(de
); 
2396         mstime_t info_validity_time 
= mstime()-SENTINEL_INFO_VALIDITY_TIME
; 
2398         if (slave
->flags 
& (SRI_S_DOWN
|SRI_O_DOWN
|SRI_DISCONNECTED
)) continue; 
2399         if (slave
->last_avail_time 
< info_validity_time
) continue; 
2400         if (slave
->info_refresh 
< info_validity_time
) continue; 
2401         if (slave
->master_link_down_time 
> max_master_down_time
) continue; 
2402         instance
[instances
++] = slave
; 
2404     dictReleaseIterator(di
); 
2406         qsort(instance
,instances
,sizeof(sentinelRedisInstance
*), 
2407             compareSlavesForPromotion
); 
2408         selected 
= instance
[0]; 
2414 /* ---------------- Failover state machine implementation ------------------- */ 
2415 void sentinelFailoverWaitStart(sentinelRedisInstance 
*ri
) { 
2416     /* If we in "wait start" but the master is no longer in ODOWN nor in 
2417      * SDOWN condition we abort the failover. This is important as it 
2418      * prevents a useless failover in a a notable case of netsplit, where 
2419      * the senitnels are split from the redis instances. In this case 
2420      * the failover will not start while there is the split because no 
2421      * good slave can be reached. However when the split is resolved, we 
2422      * can go to waitstart if the slave is back rechable a few milliseconds 
2423      * before the master is. In that case when the master is back online 
2424      * we cancel the failover. */ 
2425     if ((ri
->flags 
& (SRI_S_DOWN
|SRI_O_DOWN
)) == 0) { 
2426         sentinelEvent(REDIS_WARNING
,"-failover-abort-master-is-back", 
2428         sentinelAbortFailover(ri
); 
2432     /* Start the failover going to the next state if enough time has 
2434     if (mstime() >= ri
->failover_start_time
) { 
2435         ri
->failover_state 
= SENTINEL_FAILOVER_STATE_SELECT_SLAVE
; 
2436         ri
->failover_state_change_time 
= mstime(); 
2437         sentinelEvent(REDIS_WARNING
,"+failover-state-select-slave",ri
,"%@"); 
2441 void sentinelFailoverSelectSlave(sentinelRedisInstance 
*ri
) { 
2442     sentinelRedisInstance 
*slave 
= sentinelSelectSlave(ri
); 
2444     if (slave 
== NULL
) { 
2445         sentinelEvent(REDIS_WARNING
,"-failover-abort-no-good-slave",ri
,"%@"); 
2446         sentinelAbortFailover(ri
); 
2448         sentinelEvent(REDIS_WARNING
,"+selected-slave",slave
,"%@"); 
2449         slave
->flags 
|= SRI_PROMOTED
; 
2450         ri
->promoted_slave 
= slave
; 
2451         ri
->failover_state 
= SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE
; 
2452         ri
->failover_state_change_time 
= mstime(); 
2453         sentinelEvent(REDIS_NOTICE
,"+failover-state-send-slaveof-noone", 
2458 void sentinelFailoverSendSlaveOfNoOne(sentinelRedisInstance 
*ri
) { 
2461     if (ri
->promoted_slave
->flags 
& SRI_DISCONNECTED
) return; 
2463     /* Send SLAVEOF NO ONE command to turn the slave into a master. 
2464      * We actually register a generic callback for this command as we don't 
2465      * really care about the reply. We check if it worked indirectly observing 
2466      * if INFO returns a different role (master instead of slave). */ 
2467     retval 
= redisAsyncCommand(ri
->promoted_slave
->cc
, 
2468         sentinelDiscardReplyCallback
, NULL
, "SLAVEOF NO ONE"); 
2469     if (retval 
!= REDIS_OK
) return; 
2470     ri
->promoted_slave
->pending_commands
++; 
2471     sentinelEvent(REDIS_NOTICE
, "+failover-state-wait-promotion", 
2472         ri
->promoted_slave
,"%@"); 
2473     ri
->failover_state 
= SENTINEL_FAILOVER_STATE_WAIT_PROMOTION
; 
2474     ri
->failover_state_change_time 
= mstime(); 
2477 /* We actually wait for promotion indirectly checking with INFO when the 
2478  * slave turns into a master. */ 
2479 void sentinelFailoverWaitPromotion(sentinelRedisInstance 
*ri
) { 
2480     mstime_t elapsed 
= mstime() - ri
->failover_state_change_time
; 
2482     if (elapsed 
>= SENTINEL_PROMOTION_RETRY_PERIOD
) { 
2483         sentinelEvent(REDIS_WARNING
,"-promotion-timeout",ri
->promoted_slave
, 
2485         sentinelEvent(REDIS_WARNING
,"+failover-state-select-slave",ri
,"%@"); 
2486         ri
->failover_state 
= SENTINEL_FAILOVER_STATE_SELECT_SLAVE
; 
2487         ri
->failover_state_change_time 
= mstime(); 
2488         ri
->promoted_slave
->flags 
&= ~SRI_PROMOTED
; 
2489         ri
->promoted_slave 
= NULL
; 
2493 void sentinelFailoverDetectEnd(sentinelRedisInstance 
*master
) { 
2494     int not_reconfigured 
= 0, timeout 
= 0; 
2497     mstime_t elapsed 
= mstime() - master
->failover_state_change_time
; 
2499     /* We can't consider failover finished if the promoted slave is 
2501     if (master
->promoted_slave 
== NULL 
|| 
2502         master
->promoted_slave
->flags 
& SRI_S_DOWN
) return; 
2504     /* The failover terminates once all the reachable slaves are properly 
2506     di 
= dictGetIterator(master
->slaves
); 
2507     while((de 
= dictNext(di
)) != NULL
) { 
2508         sentinelRedisInstance 
*slave 
= dictGetVal(de
); 
2510         if (slave
->flags 
& (SRI_PROMOTED
|SRI_RECONF_DONE
)) continue; 
2511         if (slave
->flags 
& SRI_S_DOWN
) continue; 
2514     dictReleaseIterator(di
); 
2516     /* Force end of failover on timeout. */ 
2517     if (elapsed 
> master
->failover_timeout
) { 
2518         not_reconfigured 
= 0; 
2520         sentinelEvent(REDIS_WARNING
,"+failover-end-for-timeout",master
,"%@"); 
2523     if (not_reconfigured 
== 0) { 
2524         sentinelEvent(REDIS_WARNING
,"+failover-end",master
,"%@"); 
2525         master
->failover_state 
= SENTINEL_FAILOVER_STATE_UPDATE_CONFIG
; 
2526         master
->failover_state_change_time 
= mstime(); 
2529     /* If I'm the leader it is a good idea to send a best effort SLAVEOF 
2530      * command to all the slaves still not reconfigured to replicate with 
2531      * the new master. */ 
2532     if (timeout 
&& (master
->flags 
& SRI_I_AM_THE_LEADER
)) { 
2535         char master_port
[32]; 
2537         ll2string(master_port
,sizeof(master_port
), 
2538             master
->promoted_slave
->addr
->port
); 
2540         di 
= dictGetIterator(master
->slaves
); 
2541         while((de 
= dictNext(di
)) != NULL
) { 
2542             sentinelRedisInstance 
*slave 
= dictGetVal(de
); 
2546                 (SRI_RECONF_DONE
|SRI_RECONF_SENT
|SRI_DISCONNECTED
)) continue; 
2548             retval 
= redisAsyncCommand(slave
->cc
, 
2549                 sentinelDiscardReplyCallback
, NULL
, "SLAVEOF %s %s", 
2550                     master
->promoted_slave
->addr
->ip
, 
2552             if (retval 
== REDIS_OK
) { 
2553                 sentinelEvent(REDIS_NOTICE
,"+slave-reconf-sent-be",slave
,"%@"); 
2554                 slave
->flags 
|= SRI_RECONF_SENT
; 
2557         dictReleaseIterator(di
); 
2561 /* Send SLAVE OF <new master address> to all the remaining slaves that 
2562  * still don't appear to have the configuration updated. */ 
2563 void sentinelFailoverReconfNextSlave(sentinelRedisInstance 
*master
) { 
2566     int in_progress 
= 0; 
2568     di 
= dictGetIterator(master
->slaves
); 
2569     while((de 
= dictNext(di
)) != NULL
) { 
2570         sentinelRedisInstance 
*slave 
= dictGetVal(de
); 
2572         if (slave
->flags 
& (SRI_RECONF_SENT
|SRI_RECONF_INPROG
)) 
2575     dictReleaseIterator(di
); 
2577     di 
= dictGetIterator(master
->slaves
); 
2578     while(in_progress 
< master
->parallel_syncs 
&& 
2579           (de 
= dictNext(di
)) != NULL
) 
2581         sentinelRedisInstance 
*slave 
= dictGetVal(de
); 
2583         char master_port
[32]; 
2585         /* Skip the promoted slave, and already configured slaves. */ 
2586         if (slave
->flags 
& (SRI_PROMOTED
|SRI_RECONF_DONE
)) continue; 
2588         /* Clear the SRI_RECONF_SENT flag if too much time elapsed without 
2589          * the slave moving forward to the next state. */ 
2590         if ((slave
->flags 
& SRI_RECONF_SENT
) && 
2591             (mstime() - slave
->slave_reconf_sent_time
) > 
2592             SENTINEL_SLAVE_RECONF_RETRY_PERIOD
) 
2594             sentinelEvent(REDIS_NOTICE
,"-slave-reconf-sent-timeout",slave
,"%@"); 
2595             slave
->flags 
&= ~SRI_RECONF_SENT
; 
2598         /* Nothing to do for instances that are disconnected or already 
2599          * in RECONF_SENT state. */ 
2600         if (slave
->flags 
& (SRI_DISCONNECTED
|SRI_RECONF_SENT
|SRI_RECONF_INPROG
)) 
2603         /* Send SLAVEOF <new master>. */ 
2604         ll2string(master_port
,sizeof(master_port
), 
2605             master
->promoted_slave
->addr
->port
); 
2606         retval 
= redisAsyncCommand(slave
->cc
, 
2607             sentinelDiscardReplyCallback
, NULL
, "SLAVEOF %s %s", 
2608                 master
->promoted_slave
->addr
->ip
, 
2610         if (retval 
== REDIS_OK
) { 
2611             slave
->flags 
|= SRI_RECONF_SENT
; 
2612             slave
->pending_commands
++; 
2613             slave
->slave_reconf_sent_time 
= mstime(); 
2614             sentinelEvent(REDIS_NOTICE
,"+slave-reconf-sent",slave
,"%@"); 
2618     dictReleaseIterator(di
); 
2619     sentinelFailoverDetectEnd(master
); 
2622 /* This function is called when the slave is in 
2623  * SENTINEL_FAILOVER_STATE_UPDATE_CONFIG state. In this state we need 
2624  * to remove it from the master table and add the promoted slave instead. 
2626  * If there are no promoted slaves as this instance is unique, we remove 
2627  * and re-add it with the same address to trigger a complete state 
2629 void sentinelFailoverSwitchToPromotedSlave(sentinelRedisInstance 
*master
) { 
2630     sentinelRedisInstance 
*ref 
= master
->promoted_slave 
? 
2631                                  master
->promoted_slave 
: master
; 
2633     sentinelEvent(REDIS_WARNING
,"+switch-master",master
,"%s %s %d %s %d", 
2634         master
->name
, master
->addr
->ip
, master
->addr
->port
, 
2635         ref
->addr
->ip
, ref
->addr
->port
); 
2637     sentinelResetMasterAndChangeAddress(master
,ref
->addr
->ip
,ref
->addr
->port
); 
2640 void sentinelFailoverStateMachine(sentinelRedisInstance 
*ri
) { 
2641     redisAssert(ri
->flags 
& SRI_MASTER
); 
2643     if (!(ri
->flags 
& SRI_FAILOVER_IN_PROGRESS
)) return; 
2645     switch(ri
->failover_state
) { 
2646         case SENTINEL_FAILOVER_STATE_WAIT_START
: 
2647             sentinelFailoverWaitStart(ri
); 
2649         case SENTINEL_FAILOVER_STATE_SELECT_SLAVE
: 
2650             sentinelFailoverSelectSlave(ri
); 
2652         case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE
: 
2653             sentinelFailoverSendSlaveOfNoOne(ri
); 
2655         case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION
: 
2656             sentinelFailoverWaitPromotion(ri
); 
2658         case SENTINEL_FAILOVER_STATE_RECONF_SLAVES
: 
2659             sentinelFailoverReconfNextSlave(ri
); 
2661         case SENTINEL_FAILOVER_STATE_DETECT_END
: 
2662             sentinelFailoverDetectEnd(ri
); 
2667 /* Abort a failover in progress with the following steps: 
2668  * 1) If this instance is the leaer send a SLAVEOF command to all the already 
2669  *    reconfigured slaves if any to configure them to replicate with the 
2671  * 2) For both leaders and observers: clear the failover flags and state in 
2672  *    the master instance. 
2673  * 3) If there is already a promoted slave and we are the leader, and this 
2674  *    slave is not DISCONNECTED, try to reconfigure it to replicate 
2675  *    back to the master as well, sending a best effort SLAVEOF command. 
2677 void sentinelAbortFailover(sentinelRedisInstance 
*ri
) { 
2678     char master_port
[32]; 
2682     redisAssert(ri
->flags 
& SRI_FAILOVER_IN_PROGRESS
); 
2683     ll2string(master_port
,sizeof(master_port
),ri
->addr
->port
); 
2685     /* Clear failover related flags from slaves. 
2686      * Also if we are the leader make sure to send SLAVEOF commands to all the 
2687      * already reconfigured slaves in order to turn them back into slaves of 
2688      * the original master. */ 
2689     di 
= dictGetIterator(ri
->slaves
); 
2690     while((de 
= dictNext(di
)) != NULL
) { 
2691         sentinelRedisInstance 
*slave 
= dictGetVal(de
); 
2692         if ((ri
->flags 
& SRI_I_AM_THE_LEADER
) && 
2693             !(slave
->flags 
& SRI_DISCONNECTED
) && 
2694              (slave
->flags 
& (SRI_PROMOTED
|SRI_RECONF_SENT
|SRI_RECONF_INPROG
| 
2699             retval 
= redisAsyncCommand(slave
->cc
, 
2700                 sentinelDiscardReplyCallback
, NULL
, "SLAVEOF %s %s", 
2703             if (retval 
== REDIS_OK
) 
2704                 sentinelEvent(REDIS_NOTICE
,"-slave-reconf-undo",slave
,"%@"); 
2706         slave
->flags 
&= ~(SRI_RECONF_SENT
|SRI_RECONF_INPROG
|SRI_RECONF_DONE
); 
2708     dictReleaseIterator(di
); 
2710     ri
->flags 
&= ~(SRI_FAILOVER_IN_PROGRESS
|SRI_I_AM_THE_LEADER
); 
2711     ri
->failover_state 
= SENTINEL_FAILOVER_STATE_NONE
; 
2712     ri
->failover_state_change_time 
= mstime(); 
2713     if (ri
->promoted_slave
) { 
2714         ri
->promoted_slave
->flags 
&= ~SRI_PROMOTED
; 
2715         ri
->promoted_slave 
= NULL
; 
2719 /* The following is called only for master instances and will abort the 
2720  * failover process if: 
2722  * 1) The failover is in progress. 
2723  * 2) We already promoted a slave. 
2724  * 3) The promoted slave is in extended SDOWN condition. 
2726 void sentinelAbortFailoverIfNeeded(sentinelRedisInstance 
*ri
) { 
2727     /* Failover is in progress? Do we have a promoted slave? */ 
2728     if (!(ri
->flags 
& SRI_FAILOVER_IN_PROGRESS
) || !ri
->promoted_slave
) return; 
2730     /* Is the promoted slave into an extended SDOWN state? */ 
2731     if (!(ri
->promoted_slave
->flags 
& SRI_S_DOWN
) || 
2732         (mstime() - ri
->promoted_slave
->s_down_since_time
) < 
2733         (ri
->down_after_period 
* SENTINEL_EXTENDED_SDOWN_MULTIPLIER
)) return; 
2735     sentinelEvent(REDIS_WARNING
,"-failover-abort-x-sdown",ri
->promoted_slave
,"%@"); 
2736     sentinelAbortFailover(ri
); 
2739 /* ======================== SENTINEL timer handler ========================== 
2740  * This is the "main" our Sentinel, being sentinel completely non blocking 
2741  * in design. The function is called every second. 
2742  * -------------------------------------------------------------------------- */ 
2744 /* Perform scheduled operations for the specified Redis instance. */ 
2745 void sentinelHandleRedisInstance(sentinelRedisInstance 
*ri
) { 
2746     /* ========== MONITORING HALF ============ */ 
2747     /* Every kind of instance */ 
2748     sentinelReconnectInstance(ri
); 
2749     sentinelPingInstance(ri
); 
2751     /* Masters and slaves */ 
2752     if (ri
->flags 
& (SRI_MASTER
|SRI_SLAVE
)) { 
2753         /* Nothing so far. */ 
2757     if (ri
->flags 
& SRI_MASTER
) { 
2758         sentinelAskMasterStateToOtherSentinels(ri
); 
2761     /* ============== ACTING HALF ============= */ 
2762     /* We don't proceed with the acting half if we are in TILT mode. 
2763      * TILT happens when we find something odd with the time, like a 
2764      * sudden change in the clock. */ 
2765     if (sentinel
.tilt
) { 
2766         if (mstime()-sentinel
.tilt_start_time 
< SENTINEL_TILT_PERIOD
) return; 
2768         sentinelEvent(REDIS_WARNING
,"-tilt",NULL
,"#tilt mode exited"); 
2771     /* Every kind of instance */ 
2772     sentinelCheckSubjectivelyDown(ri
); 
2774     /* Masters and slaves */ 
2775     if (ri
->flags 
& (SRI_MASTER
|SRI_SLAVE
)) { 
2776         /* Nothing so far. */ 
2780     if (ri
->flags 
& SRI_MASTER
) { 
2781         sentinelCheckObjectivelyDown(ri
); 
2782         sentinelStartFailover(ri
); 
2783         sentinelFailoverStateMachine(ri
); 
2784         sentinelAbortFailoverIfNeeded(ri
); 
2788 /* Perform scheduled operations for all the instances in the dictionary. 
2789  * Recursively call the function against dictionaries of slaves. */ 
2790 void sentinelHandleDictOfRedisInstances(dict 
*instances
) { 
2793     sentinelRedisInstance 
*switch_to_promoted 
= NULL
; 
2795     /* There are a number of things we need to perform against every master. */ 
2796     di 
= dictGetIterator(instances
); 
2797     while((de 
= dictNext(di
)) != NULL
) { 
2798         sentinelRedisInstance 
*ri 
= dictGetVal(de
); 
2800         sentinelHandleRedisInstance(ri
); 
2801         if (ri
->flags 
& SRI_MASTER
) { 
2802             sentinelHandleDictOfRedisInstances(ri
->slaves
); 
2803             sentinelHandleDictOfRedisInstances(ri
->sentinels
); 
2804             if (ri
->failover_state 
== SENTINEL_FAILOVER_STATE_UPDATE_CONFIG
) { 
2805                 switch_to_promoted 
= ri
; 
2809     if (switch_to_promoted
) 
2810         sentinelFailoverSwitchToPromotedSlave(switch_to_promoted
); 
2811     dictReleaseIterator(di
); 
2814 /* This function checks if we need to enter the TITL mode. 
2816  * The TILT mode is entered if we detect that between two invocations of the 
2817  * timer interrupt, a negative amount of time, or too much time has passed. 
2818  * Note that we expect that more or less just 100 milliseconds will pass 
2819  * if everything is fine. However we'll see a negative number or a 
2820  * difference bigger than SENTINEL_TILT_TRIGGER milliseconds if one of the 
2821  * following conditions happen: 
2823  * 1) The Sentiel process for some time is blocked, for every kind of 
2824  * random reason: the load is huge, the computer was freezed for some time 
2825  * in I/O or alike, the process was stopped by a signal. Everything. 
2826  * 2) The system clock was altered significantly. 
2828  * Under both this conditions we'll see everything as timed out and failing 
2829  * without good reasons. Instead we enter the TILT mode and wait 
2830  * for SENTIENL_TILT_PERIOD to elapse before starting to act again. 
2832  * During TILT time we still collect information, we just do not act. */ 
2833 void sentinelCheckTiltCondition(void) { 
2834     mstime_t now 
= mstime(); 
2835     mstime_t delta 
= now 
- sentinel
.previous_time
; 
2837     if (delta 
< 0 || delta 
> SENTINEL_TILT_TRIGGER
) { 
2839         sentinel
.tilt_start_time 
= mstime(); 
2840         sentinelEvent(REDIS_WARNING
,"+tilt",NULL
,"#tilt mode entered"); 
2842     sentinel
.previous_time 
= mstime(); 
2845 void sentinelTimer(void) { 
2846     sentinelCheckTiltCondition(); 
2847     sentinelHandleDictOfRedisInstances(sentinel
.masters
); 
2848     sentinelRunPendingScripts(); 
2849     sentinelCollectTerminatedScripts(); 
2850     sentinelKillTimedoutScripts();