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

Code before:
        /* I can't replicate myself. */
        if (n == myself) {
            addReplyError(c, "Can't replicate myself");
            return 1;
        }

        /* Can't replicate a replica. */
        if (nodeIsReplica(n)) {
            addReplyError(c, "I can only replicate a master, not a replica.");
            return 1;
        }

        /* If the instance is currently a primary, it should have no assigned
         * slots nor keys to accept to replicate some other node.
         * Replicas can switch to another primary without issues. */
        if (clusterNodeIsPrimary(myself) && (myself->numslots != 0 || kvstoreSize(server.db[0].keys) != 0)) {
            addReplyError(c, "To set a master the node must be empty and "
                             "without assigned slots.");
            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, 0);
        clusterBroadcastPong(CLUSTER_BROADCAST_ALL);
        clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_SAVE_CONFIG);
        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 || c->argc == 3)) {
        /* CLUSTER FAILOVER [FORCE|TAKEOVER] */
        int force = 0, takeover = 0;

        if (c->argc == 3) {
            if (!strcasecmp(c->argv[2]->ptr, "force")) {
                force = 1;
            } else if (!strcasecmp(c->argv[2]->ptr, "takeover")) {
                takeover = 1;
                force = 1; /* Takeover also implies force. */
            } else {
                addReplyErrorObject(c, shared.syntaxerr);

Review comment (suggestion):
It is a corner case but, for correctness, we should still check `areInSameShard`. I don't know why people would do it but since we allow a replica node to reconnect with its primary via `cluster replicate`, PSYNC should be supported in this case.

Code after:
        /* I can't replicate myself. */
        if (n == myself) {
            addReplyError(c, "Can't replicate myself");
            return 1;
        }

        /* Can't replicate a replica. */
        if (nodeIsReplica(n)) {
            addReplyError(c, "I can only replicate a master, not a replica.");
            return 1;
        }

        /* If the instance is currently a primary, it should have no assigned
         * slots nor keys to accept to replicate some other node.
         * Replicas can switch to another primary without issues. */
        if (clusterNodeIsPrimary(myself) && (myself->numslots != 0 || kvstoreSize(server.db[0].keys) != 0)) {
            addReplyError(c, "To set a master the node must be empty and "
                             "without assigned slots.");
            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);
        clusterBroadcastPong(CLUSTER_BROADCAST_ALL);
        clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_SAVE_CONFIG);
        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 || c->argc == 3)) {
        /* CLUSTER FAILOVER [FORCE|TAKEOVER] */
        int force = 0, takeover = 0;

        if (c->argc == 3) {
            if (!strcasecmp(c->argv[2]->ptr, "force")) {
                force = 1;
            } else if (!strcasecmp(c->argv[2]->ptr, "takeover")) {
                takeover = 1;
                force = 1; /* Takeover also implies force. */
            } else {
                addReplyErrorObject(c, shared.syntaxerr);