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

Code before:
     * so in here it is a best effort. */
    char buf[128];
    size_t buflen = snprintf(buf, sizeof(buf),
                             "*5\r\n$7\r\nCLUSTER\r\n"
                             "$8\r\nFAILOVER\r\n"
                             "$5\r\nFORCE\r\n"
                             "$9\r\nREPLICAID\r\n"
                             "$%d\r\n%.*s\r\n",
                             CLUSTER_NAMELEN,
                             CLUSTER_NAMELEN,
                             best_replica->repl_data->replica_nodeid);
    serverAssert(buflen <= 128);
    /* Must install write handler for all replicas first before feeding
     * replication stream. */
    prepareReplicasToWrite();
    feedReplicationBuffer(buf, buflen);
    serverLog(LL_NOTICE, "Perform auto failover to replica %s on shutdown.", best_replica->repl_data->replica_nodeid);
}

/* Called when a cluster node receives SHUTDOWN. */
void clusterHandleServerShutdown(bool auto_failover) {
    /* Check if we are able to do the auto failover on shutdown. */
    if (auto_failover) clusterAutoFailoverOnShutdown();

    /* The error logs have been logged in the save function if the save fails. */
    serverLog(LL_NOTICE, "Saving the cluster configuration file before exiting.");
    clusterSaveConfig(1);

#if !defined(__sun)
    /* Unlock the cluster config file before shutdown, see clusterLockConfig.
     *
     * This is needed if you shutdown a very large server process, it will take
     * a while for the OS to release resources and unlock the cluster configuration
     * file. Therefore, if we immediately try to restart the server process, it
     * may not be able to acquire the lock on the cluster configuration file and
     * fail to start. We explicitly releases the lock on the cluster configuration
     * file on shutdown, rather than relying on the OS to release the lock, which
     * is a cleaner and safer way to release acquired resources. */
    if (server.cluster_config_file_lock_fd != -1) {
        flock(server.cluster_config_file_lock_fd, LOCK_UN | LOCK_NB);
    }
#endif /* __sun */
}

/* Reset a node performing a soft or hard reset:
 *
 * 1) All other nodes are forgotten.
 * 2) All the assigned / open slots are released.
 * 3) If the node is a replica, it turns into a primary.
 * 4) Only for hard reset: a new Node ID is generated.
 * 5) Only for hard reset: currentEpoch and configEpoch are set to 0.

Review comment (bug):
nitpicks on names

1. `auto` isn't necessary imo - it is implied that the code is doing the work
2. the original function `clusterHandleServerShutdown` doesn't know where/why it is invoked. it just merely provides the failover functionality. 

```suggestion
    if (failover) clusterInitiateGracefulFailover();
```

Code after:
    /* Send the CLUSTER FAILOVER FORCE REPLICAID node-id to all replicas since
     * it is a shared replication buffer, but only the replica with the matching
     * node-id will execute it. The caller will call flushReplicasOutputBuffers,
     * so in here it is a best effort. */
    char buf[128];
    size_t buflen = snprintf(buf, sizeof(buf),
                             "*5\r\n$7\r\nCLUSTER\r\n"
                             "$8\r\nFAILOVER\r\n"
                             "$5\r\nFORCE\r\n"
                             "$9\r\nREPLICAID\r\n"
                             "$%d\r\n%.*s\r\n",
                             CLUSTER_NAMELEN,
                             CLUSTER_NAMELEN,
                             best_replica->repl_data->replica_nodeid);
    serverAssert(buflen <= 128);
    /* Must install write handler for all replicas first before feeding
     * replication stream. */
    prepareReplicasToWrite();
    feedReplicationBuffer(buf, buflen);
    serverLog(LL_NOTICE, "Perform auto failover to replica %s on shutdown.", best_replica->repl_data->replica_nodeid);
}

/* Called when a cluster node receives SHUTDOWN. */
void clusterHandleServerShutdown(bool auto_failover) {
    /* Check if we are able to do the auto failover on shutdown. */
    if (auto_failover) clusterAutoFailoverOnShutdown();

    /* The error logs have been logged in the save function if the save fails. */
    serverLog(LL_NOTICE, "Saving the cluster configuration file before exiting.");
    clusterSaveConfig(1);

#if !defined(__sun)
    /* Unlock the cluster config file before shutdown, see clusterLockConfig.
     *
     * This is needed if you shutdown a very large server process, it will take
     * a while for the OS to release resources and unlock the cluster configuration
     * file. Therefore, if we immediately try to restart the server process, it
     * may not be able to acquire the lock on the cluster configuration file and
     * fail to start. We explicitly releases the lock on the cluster configuration
     * file on shutdown, rather than relying on the OS to release the lock, which
     * is a cleaner and safer way to release acquired resources. */
    if (server.cluster_config_file_lock_fd != -1) {
        flock(server.cluster_config_file_lock_fd, LOCK_UN | LOCK_NB);
    }
#endif /* __sun */
}

/* Reset a node performing a soft or hard reset:
 *
 * 1) All other nodes are forgotten.
 * 2) All the assigned / open slots are released.