Repository: valkey-io/valkey
File: src/cluster_legacy.c (C)

Code before:
    } else if (!strcasecmp(c->argv[1]->ptr, "failover") && (c->argc >= 2)) {
        /* CLUSTER FAILOVER [FORCE|TAKEOVER] [REPLICAID <NODE ID>]
         * REPLICAID is currently available only for internal so we won't
         * put it into the JSON file. */
        int force = 0, takeover = 0;
        robj *replicaid = NULL;

        for (int j = 2; j < c->argc; j++) {
            int moreargs = (c->argc - 1) - j;
            if (!strcasecmp(c->argv[j]->ptr, "force")) {
                force = 1;
            } else if (!strcasecmp(c->argv[j]->ptr, "takeover")) {
                takeover = 1;
                force = 1; /* Takeover also implies force. */
            } else if (c == server.primary && !strcasecmp(c->argv[j]->ptr, "replicaid") && moreargs) {
                /* This option is currently available only for primary. */
                j++;
                replicaid = c->argv[j];
            } else {
                addReplyErrorObject(c, shared.syntaxerr);
                return 1;
            }
        }

        /* Check if it should be executed by myself. */
        if (replicaid != NULL && memcmp(replicaid->ptr, myself->name, CLUSTER_NAMELEN) != 0) {
            /* Ignore this command, including the sanity check and the process. */
            addReply(c, shared.ok);
            return 1;
        }

        /* Check preconditions. */
        if (clusterNodeIsPrimary(myself)) {
            addReplyError(c, "You should send CLUSTER FAILOVER to a replica");
            return 1;
        } else if (myself->replicaof == NULL) {
            addReplyError(c, "I'm a replica but my master is unknown to me");
            return 1;
        } else if (!force && (nodeFailed(myself->replicaof) || myself->replicaof->link == NULL)) {
            addReplyError(c, "Master is down or failed, please use CLUSTER FAILOVER FORCE");
            return 1;
        }
        resetManualFailover();
        server.cluster->mf_end = mstime() + CLUSTER_MF_TIMEOUT;
        sds client = catClientInfoShortString(sdsempty(), c, server.hide_user_data_from_log);

        if (takeover) {
            /* A takeover does not perform any initial check. It just
             * generates a new configuration epoch for this node without
             * consensus, claims the primary's slots, and broadcast the new
             * configuration. */

Review comment (suggestion):
I don't think we should just not document it. Someone will find it and use it, so I think removing it becomes a breaking change. All other arguments, including other internal commands, are documented in the json files.

Code after:
        if (myself->replicaof == n) {
            addReply(c, shared.ok);
            return 1;
        }

        /* Set the primary.
         * If the instance is a primary, it is an empty primary.
         * If the instance is a replica, it had a totally different replication history.
         * In these both cases, myself as a replica has to do a full sync. */
        clusterSetPrimary(n, 1, 1);
        clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_BROADCAST_ALL);
        addReply(c, shared.ok);
    } else if (!strcasecmp(c->argv[1]->ptr, "count-failure-reports") && c->argc == 3) {
        /* CLUSTER COUNT-FAILURE-REPORTS <NODE ID> */
        clusterNode *n = clusterLookupNode(c->argv[2]->ptr, sdslen(c->argv[2]->ptr));

        if (!n) {
            addReplyErrorFormat(c, "Unknown node %s", (char *)c->argv[2]->ptr);
            return 1;
        } else {
            addReplyLongLong(c, clusterNodeFailureReportsCount(n));
        }
    } else if (!strcasecmp(c->argv[1]->ptr, "failover") && (c->argc >= 2)) {
        /* CLUSTER FAILOVER [FORCE|TAKEOVER] [REPLICAID <NODE ID>]
         * REPLICAID is currently available only for internal so we won't
         * put it into the JSON file. */
        int force = 0, takeover = 0;
        robj *replicaid = NULL;

        for (int j = 2; j < c->argc; j++) {
            int moreargs = (c->argc - 1) - j;
            if (!strcasecmp(c->argv[j]->ptr, "force")) {
                force = 1;
            } else if (!strcasecmp(c->argv[j]->ptr, "takeover")) {
                takeover = 1;
                force = 1; /* Takeover also implies force. */
            } else if (c == server.primary && !strcasecmp(c->argv[j]->ptr, "replicaid") && moreargs) {
                /* This option is currently available only for primary. */
                j++;
                replicaid = c->argv[j];
            } else {
                addReplyErrorObject(c, shared.syntaxerr);
                return 1;
            }
        }

        /* Check if it should be executed by myself. */
        if (replicaid != NULL && memcmp(replicaid->ptr, myself->name, CLUSTER_NAMELEN) != 0) {
            /* Ignore this command, including the sanity check and the process. */
            addReply(c, shared.ok);
            return 1;