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

Code before:
    return 1;
}

/* Set replication to the specified primary address and port. */
void replicationSetPrimary(char *ip, int port, int full_sync_required) {
    int was_primary = server.primary_host == NULL;

    sdsfree(server.primary_host);
    server.primary_host = NULL;
    if (server.primary) {
        /* When joining 'myself' to a new primary, set the dont_cache_primary flag
         * if a full sync is required. This happens when 'myself' was previously
         * part of a different shard from the new primary. Since 'myself' does not
         * have the replication history of the shard it is joining, clearing the
         * cached primary is necessary to ensure proper replication behavior. */
        server.primary->flag.dont_cache_primary = full_sync_required;
        freeClient(server.primary);
    }

    /* Setting primary_host only after the call to freeClient since it calls
     * replicationHandlePrimaryDisconnection which can trigger a re-connect
     * directly from within that call. */
    server.primary_host = sdsnew(ip);
    server.primary_port = port;

    if (!server.cluster_enabled) {
        disconnectAllBlockedClients(); /* Clients blocked in primary, now replica. */
    }

    /* Update oom_score_adj */
    setOOMScoreAdj(-1);

    /* Here we don't disconnect with replicas, since they may hopefully be able
     * to partially resync with us. We will disconnect with replicas and force
     * them to resync with us when changing replid on partially resync with new
     * primary, or finishing transferring RDB and preparing loading DB on full
     * sync with new primary. */

    cancelReplicationHandshake(0);

    /* Before destroying our primary state, create a cached primary using
     * our own parameters, to later PSYNC with the new primary. */
    if (was_primary && !full_sync_required) {
        replicationDiscardCachedPrimary();
        replicationCachePrimaryUsingMyself();
    }

    /* Fire the role change modules event. */
    moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICATION_ROLE_CHANGED, VALKEYMODULE_EVENT_REPLROLECHANGED_NOW_REPLICA,
                          NULL);


Review comment (suggestion):
minor: can we add some comment above stating why this HAS to come after we set the new primary host (since unblocking clients might require redirecting to the new primary)

BTW - I think in the current implementation clients blocked on xread are also disco. we might consider changing this in a separate PR

Code after:
    /* Try a partial resynchronization. If we don't have a cached primary
     * replicaSendPsyncCommand() will at least try to use PSYNC
     * to start a full resynchronization so that we get the primary replid
     * and the global offset, to try a partial resync at the next
     * reconnection attempt. */
    case REPL_STATE_SEND_PSYNC:
    case_send_psync:
        if (syncWithPrimaryHandleSendPsyncState(conn) == C_ERR) {
            syncWithPrimaryHandleError(&conn);
            return;
        }
        server.repl_state = REPL_STATE_RECEIVE_PSYNC_REPLY;
        return;
    /* If reached this point, we should be in REPL_STATE_RECEIVE_PSYNC_REPLY. */
    default:
        if (server.repl_state != REPL_STATE_RECEIVE_PSYNC_REPLY) {
            serverLog(LL_WARNING,
                      "syncWithPrimary(): state machine error, "
                      "state should be RECEIVE_PSYNC but is %d",
                      server.repl_state);
            syncWithPrimaryHandleError(&conn);
            return;
        }
    }

    psync_result = replicaProcessPsyncReply(conn);
    if (psync_result == PSYNC_WAIT_REPLY) return; /* Try again later... */

    /* Check the status of the planned failover. We expect PSYNC_CONTINUE,
     * but there is nothing technically wrong with a full resync which
     * could happen in edge cases. */
    if (server.failover_state == FAILOVER_IN_PROGRESS) {
        if (psync_result == PSYNC_CONTINUE || psync_result == PSYNC_FULLRESYNC) {
            clearFailoverState(true);
        } else {
            abortFailover("Failover target rejected psync request");
            return;
        }
    }

    /* If the primary is in an transient error, we should try to PSYNC
     * from scratch later, so go to the error path. This happens when
     * the server is loading the dataset or is not connected with its
     * primary and so forth. */
    if (psync_result == PSYNC_TRY_LATER) {
        syncWithPrimaryHandleError(&conn);
        return;
    }

    /* Note: if PSYNC does not return WAIT_REPLY, it will take care of
     * uninstalling the read handler from the file descriptor. */