* 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
| 3612 | * will attempt forever and must be manually aborted. |
| 3613 | */ |
| 3614 | void failoverCommand(client *c) { |
| 3615 | if (server.cluster_enabled) { |
| 3616 | addReplyError(c,"FAILOVER not allowed in cluster mode. " |
| 3617 | "Use CLUSTER FAILOVER command instead."); |
| 3618 | return; |
| 3619 | } |
| 3620 | |
| 3621 | /* Handle special case for abort */ |
| 3622 | if ((c->argc == 2) && !strcasecmp(c->argv[1]->ptr,"abort")) { |
| 3623 | if (server.failover_state == NO_FAILOVER) { |
| 3624 | addReplyError(c, "No failover in progress."); |
| 3625 | return; |
| 3626 | } |
| 3627 | |
| 3628 | abortFailover("Failover manually aborted"); |
| 3629 | addReply(c,shared.ok); |
| 3630 | return; |
| 3631 | } |
| 3632 | |
| 3633 | long timeout_in_ms = 0; |
| 3634 | int force_flag = 0; |
| 3635 | long port = 0; |
| 3636 | char *host = NULL; |
| 3637 | |
| 3638 | /* Parse the command for syntax and arguments. */ |
| 3639 | for (int j = 1; j < c->argc; j++) { |
| 3640 | if (!strcasecmp(c->argv[j]->ptr,"timeout") && (j + 1 < c->argc) && |
| 3641 | timeout_in_ms == 0) |
| 3642 | { |
| 3643 | if (getLongFromObjectOrReply(c,c->argv[j + 1], |
| 3644 | &timeout_in_ms,NULL) != C_OK) return; |
| 3645 | if (timeout_in_ms <= 0) { |
| 3646 | addReplyError(c,"FAILOVER timeout must be greater than 0"); |
| 3647 | return; |
| 3648 | } |
| 3649 | j++; |
| 3650 | } else if (!strcasecmp(c->argv[j]->ptr,"to") && (j + 2 < c->argc) && |
| 3651 | !host) |
| 3652 | { |
| 3653 | if (getLongFromObjectOrReply(c,c->argv[j + 2],&port,NULL) != C_OK) |
| 3654 | return; |
| 3655 | host = c->argv[j + 1]->ptr; |
| 3656 | j += 2; |
| 3657 | } else if (!strcasecmp(c->argv[j]->ptr,"force") && !force_flag) { |
| 3658 | force_flag = 1; |
| 3659 | } else { |
| 3660 | addReplyErrorObject(c,shared.syntaxerr); |
| 3661 | return; |
| 3662 | } |
| 3663 | } |
| 3664 | |
| 3665 | if (server.failover_state != NO_FAILOVER) { |
| 3666 | addReplyError(c,"FAILOVER already in progress."); |
| 3667 | return; |
| 3668 | } |
| 3669 | |
| 3670 | if (server.masterhost) { |
| 3671 | addReplyError(c,"FAILOVER is not valid when server is a replica."); |
nothing calls this directly
no test coverage detected