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

Code before:
            if (!strcasecmp(c->argv[2]->ptr, "hard")) {
                hard = 1;
            } else if (!strcasecmp(c->argv[2]->ptr, "soft")) {
                hard = 0;
            } else {
                addReplyErrorObject(c, shared.syntaxerr);
                return 1;
            }
        }

        /* Replicas can be reset while containing data, but not primary nodes
         * that must be empty. */
        if (clusterNodeIsPrimary(myself) && kvstoreSize(c->db->keys) != 0) {
            addReplyError(c, "CLUSTER RESET can't be called with "
                             "master nodes containing keys");
            return 1;
        }
        clusterReset(hard);
        addReply(c, shared.ok);
    } else if (!strcasecmp(c->argv[1]->ptr, "links") && c->argc == 2) {
        /* CLUSTER LINKS */
        addReplyClusterLinksDescription(c);
    } else if (!strcasecmp(c->argv[1]->ptr, "flushslot") && (c->argc == 3 || c->argc == 4)) {
        /* CLUSTER FLUSHSLOT <slot> [ASYNC|SYNC] */
        int slot;
        int lazy = 1;
        if ((slot = getSlotOrReply(c, c->argv[2])) == -1) return 1;
        if (c->argc == 4) {
            if (!strcasecmp(c->argv[3]->ptr, "async")) {
                lazy = 1;
            } else if (!strcasecmp(c->argv[3]->ptr, "sync")) {
                lazy = 0;
            } else {
                addReplyErrorObject(c, shared.syntaxerr);
                return 1;
            }
        }
        delKeysInSlot(slot, lazy);
        addReply(c, shared.ok);
    } else {
        return 0;
    }

    return 1;
}

const char **clusterCommandExtendedHelp(void) {
    static const char *help[] = {
        "ADDSLOTS <slot> [<slot> ...]",
        "    Assign slots to current node.",
        "ADDSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]",

Review comment (suggestion):
Let's use `server.lazyfree_lazy_user_flush` by default? That's the default for FLUSHALL when the caller doesn't specify sync or async.

Code after:
        if (!strcasecmp(c->argv[i]->ptr, "timeout")) {
            if (i + 1 >= c->argc) {
                addReplyError(c, "Missing timeout value");
                return 0;
            }
            if (getTimeoutFromObjectOrReply(c, c->argv[i + 1], &timeout, UNIT_MILLISECONDS) != C_OK) return 0;
        }
    }

    *slot_out = slot;
    *node_out = n;
    *timeout_out = timeout;
    return 1;
}

void clusterCommandSetSlot(client *c) {
    int slot;
    mstime_t timeout_ms;
    clusterNode *n;

    if (!clusterParseSetSlotCommand(c, &slot, &n, &timeout_ms)) return;

    /* Enhance cluster topology change resilience against primary failures by
     * replicating SETSLOT before execution.
     *
     * Cluster topology changes such slot ownership and migrating states must
     * be replicated to replicas before applying them to the primary. This
     * guarantees that after a command is successfully executed, the new state
     * won't be lost due to a primary node failure. The following example
     * illustrates how a cluster state can be lost during slot ownership
     * finalization:
     *
     * When finalizing the slot, the target primary node B might send a cluster
     * PONG to the source primary node A before the SETSLOT command is replicated
     * to replica node B'. If primary node B crashes at this point, B' will be in
     * the importing state and the slot will have no owner.
     *
     * To mitigate this issue, the following order needs to be enforced for slot
     * migration finalization such that the replicas finalize the slot ownership
     * before the primary:
     *
     * 1. Client C issues SETSLOT n NODE B against node B.
     * 2. Primary B replicates `SETSLOT n NODE B` to all of its replicas (e.g., B', B'').
     * 3. Upon replication completion, primary B executes `SETSLOT n NODE B` and
     *    returns success to client C.
     * 4. The following steps can happen in parallel:
     *   a. Client C issues `SETSLOT n NODE B` against primary A.
     *   b. Primary B gossips its new slot ownership to the cluster (including A, A', etc.).
     *
     * This ensures that all replicas have the latest topology information, enabling
     * a reliable slot ownership transfer even if the primary node went down during