* FAILOVER [TO [FORCE]] [ABORT] [TIMEOUT ] * * This command will coordinate a failover between the master and one * of its replicas. The happy path contains the following steps: * 1) The master will initiate a client pause write, to stop replication * traffic. * 2) The master will periodically check if any of its replicas has * consumed the entire replication stream
| 5124 | * will attempt forever and must be manually aborted. |
| 5125 | */ |
| 5126 | void failoverCommand(client *c) { |
| 5127 | if (g_pserver->cluster_enabled) { |
| 5128 | addReplyError(c,"FAILOVER not allowed in cluster mode. " |
| 5129 | "Use CLUSTER FAILOVER command instead."); |
| 5130 | return; |
| 5131 | } |
| 5132 | |
| 5133 | if (g_pserver->fActiveReplica) { |
| 5134 | addReplyError(c,"FAILOVER not allowed in active replication mode"); |
| 5135 | return; |
| 5136 | } |
| 5137 | |
| 5138 | /* Handle special case for abort */ |
| 5139 | if ((c->argc == 2) && !strcasecmp(szFromObj(c->argv[1]),"abort")) { |
| 5140 | if (g_pserver->failover_state == NO_FAILOVER) { |
| 5141 | addReplyError(c, "No failover in progress."); |
| 5142 | return; |
| 5143 | } |
| 5144 | |
| 5145 | redisMaster *mi = listLength(g_pserver->masters) ? (redisMaster*)listNodeValue(listFirst(g_pserver->masters)) : nullptr; |
| 5146 | abortFailover(mi, "Failover manually aborted"); |
| 5147 | addReply(c,shared.ok); |
| 5148 | return; |
| 5149 | } |
| 5150 | |
| 5151 | long timeout_in_ms = 0; |
| 5152 | int force_flag = 0; |
| 5153 | long port = 0; |
| 5154 | char *host = NULL; |
| 5155 | |
| 5156 | /* Parse the command for syntax and arguments. */ |
| 5157 | for (int j = 1; j < c->argc; j++) { |
| 5158 | if (!strcasecmp(szFromObj(c->argv[j]),"timeout") && (j + 1 < c->argc) && |
| 5159 | timeout_in_ms == 0) |
| 5160 | { |
| 5161 | if (getLongFromObjectOrReply(c,c->argv[j + 1], |
| 5162 | &timeout_in_ms,NULL) != C_OK) return; |
| 5163 | if (timeout_in_ms <= 0) { |
| 5164 | addReplyError(c,"FAILOVER timeout must be greater than 0"); |
| 5165 | return; |
| 5166 | } |
| 5167 | j++; |
| 5168 | } else if (!strcasecmp(szFromObj(c->argv[j]),"to") && (j + 2 < c->argc) && |
| 5169 | !host) |
| 5170 | { |
| 5171 | if (getLongFromObjectOrReply(c,c->argv[j + 2],&port,NULL) != C_OK) |
| 5172 | return; |
| 5173 | host = szFromObj(c->argv[j + 1]); |
| 5174 | j += 2; |
| 5175 | } else if (!strcasecmp(szFromObj(c->argv[j]),"force") && !force_flag) { |
| 5176 | force_flag = 1; |
| 5177 | } else { |
| 5178 | addReplyErrorObject(c,shared.syntaxerr); |
| 5179 | return; |
| 5180 | } |
| 5181 | } |
| 5182 | |
| 5183 | if (g_pserver->failover_state != NO_FAILOVER) { |
nothing calls this directly
no test coverage detected