Refactor return and goto statements (#945)
Consolidate the cleanup of local variables to a single point within the method, ensuring proper resource management and p reventing memory leaks or double-free issues. Previoslly descused here: - https://github.com/valkey-io/valkey/pull/60#discussion_r1667872633 - https://github.com/valkey-io/valkey/pull/60#discussion_r1668045666 --------- Signed-off-by: naglera <anagler123@gmail.com> Signed-off-by: Amit Nagler <58042354+naglera@users.noreply.github.com> Co-authored-by: Ping Xie <pingxie@outlook.com>
This commit is contained in:
parent
247a8f23c5
commit
b0f23df165
@ -53,8 +53,9 @@ int replicaPutOnline(client *replica);
|
|||||||
void replicaStartCommandStream(client *replica);
|
void replicaStartCommandStream(client *replica);
|
||||||
int cancelReplicationHandshake(int reconnect);
|
int cancelReplicationHandshake(int reconnect);
|
||||||
void replicationSteadyStateInit(void);
|
void replicationSteadyStateInit(void);
|
||||||
void setupMainConnForPsync(connection *conn);
|
void dualChannelSetupMainConnForPsync(connection *conn);
|
||||||
void dualChannelSyncHandleRdbLoadCompletion(void);
|
void dualChannelSyncHandleRdbLoadCompletion(void);
|
||||||
|
static void dualChannelFullSyncWithPrimary(connection *conn);
|
||||||
|
|
||||||
/* We take a global flag to remember if this instance generated an RDB
|
/* We take a global flag to remember if this instance generated an RDB
|
||||||
* because of replication, so that we can remove the RDB file in case
|
* because of replication, so that we can remove the RDB file in case
|
||||||
@ -2588,13 +2589,135 @@ int sendCurrentOffsetToReplica(client *replica) {
|
|||||||
return C_OK;
|
return C_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dualChannelReplHandleHandshake(connection *conn, sds *err) {
|
||||||
|
serverLog(LL_DEBUG, "Received first reply from primary using rdb connection.");
|
||||||
|
/* AUTH with the primary if required. */
|
||||||
|
if (server.primary_auth) {
|
||||||
|
char *args[] = {"AUTH", NULL, NULL};
|
||||||
|
size_t lens[] = {4, 0, 0};
|
||||||
|
int argc = 1;
|
||||||
|
if (server.primary_user) {
|
||||||
|
args[argc] = server.primary_user;
|
||||||
|
lens[argc] = strlen(server.primary_user);
|
||||||
|
argc++;
|
||||||
|
}
|
||||||
|
args[argc] = server.primary_auth;
|
||||||
|
lens[argc] = sdslen(server.primary_auth);
|
||||||
|
argc++;
|
||||||
|
*err = sendCommandArgv(conn, argc, args, lens);
|
||||||
|
if (*err) {
|
||||||
|
serverLog(LL_WARNING, "Sending command to primary in dual channel replication handshake: %s", *err);
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Send replica listening port to primary for clarification */
|
||||||
|
sds portstr = getReplicaPortString();
|
||||||
|
*err = sendCommand(conn, "REPLCONF", "capa", "eof", "rdb-only", "1", "rdb-channel", "1", "listening-port", portstr,
|
||||||
|
NULL);
|
||||||
|
sdsfree(portstr);
|
||||||
|
if (*err) {
|
||||||
|
serverLog(LL_WARNING, "Sending command to primary in dual channel replication handshake: %s", *err);
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connSetReadHandler(conn, dualChannelFullSyncWithPrimary) == C_ERR) {
|
||||||
|
char conninfo[CONN_INFO_LEN];
|
||||||
|
serverLog(LL_WARNING, "Can't create readable event for SYNC: %s (%s)", strerror(errno),
|
||||||
|
connGetInfo(conn, conninfo, sizeof(conninfo)));
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
return C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dualChannelReplHandleAuthReply(connection *conn, sds *err) {
|
||||||
|
*err = receiveSynchronousResponse(conn);
|
||||||
|
if (*err == NULL) {
|
||||||
|
serverLog(LL_WARNING, "Primary did not respond to auth command during SYNC handshake");
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
if ((*err)[0] == '-') {
|
||||||
|
serverLog(LL_WARNING, "Unable to AUTH to Primary: %s", *err);
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY;
|
||||||
|
return C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dualChannelReplHandleReplconfReply(connection *conn, sds *err) {
|
||||||
|
*err = receiveSynchronousResponse(conn);
|
||||||
|
if (*err == NULL) {
|
||||||
|
serverLog(LL_WARNING, "Primary did not respond to replconf command during SYNC handshake");
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*err[0] == '-') {
|
||||||
|
serverLog(LL_NOTICE, "Server does not support sync with offset, dual channel sync approach cannot be used: %s",
|
||||||
|
*err);
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
if (connSyncWrite(conn, "SYNC\r\n", 6, server.repl_syncio_timeout * 1000) == -1) {
|
||||||
|
serverLog(LL_WARNING, "I/O error writing to Primary: %s", connGetLastError(conn));
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
return C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dualChannelReplHandleEndOffsetResponse(connection *conn, sds *err) {
|
||||||
|
uint64_t rdb_client_id;
|
||||||
|
*err = receiveSynchronousResponse(conn);
|
||||||
|
if (*err == NULL) {
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
if (*err[0] == '\0') {
|
||||||
|
/* Retry again later */
|
||||||
|
serverLog(LL_DEBUG, "Received empty $ENDOFF response");
|
||||||
|
return C_RETRY;
|
||||||
|
}
|
||||||
|
long long reploffset;
|
||||||
|
char primary_replid[CONFIG_RUN_ID_SIZE + 1];
|
||||||
|
int dbid;
|
||||||
|
/* Parse end offset response */
|
||||||
|
char *endoff_format = "$ENDOFF:%lld %40s %d %llu";
|
||||||
|
if (sscanf(*err, endoff_format, &reploffset, primary_replid, &dbid, &rdb_client_id) != 4) {
|
||||||
|
serverLog(LL_WARNING, "Received unexpected $ENDOFF response: %s", *err);
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
server.rdb_client_id = rdb_client_id;
|
||||||
|
server.primary_initial_offset = reploffset;
|
||||||
|
|
||||||
|
/* Initiate repl_provisional_primary to act as this replica temp primary until RDB is loaded */
|
||||||
|
server.repl_provisional_primary.conn = server.repl_transfer_s;
|
||||||
|
memcpy(server.repl_provisional_primary.replid, primary_replid, CONFIG_RUN_ID_SIZE);
|
||||||
|
server.repl_provisional_primary.reploff = reploffset;
|
||||||
|
server.repl_provisional_primary.read_reploff = reploffset;
|
||||||
|
server.repl_provisional_primary.dbid = dbid;
|
||||||
|
|
||||||
|
/* Now that we have the snapshot end-offset, we can ask for psync from that offset. Prepare the
|
||||||
|
* main connection accordingly.*/
|
||||||
|
server.repl_transfer_s->state = CONN_STATE_CONNECTED;
|
||||||
|
server.repl_state = REPL_STATE_SEND_HANDSHAKE;
|
||||||
|
serverAssert(connSetReadHandler(server.repl_transfer_s, dualChannelSetupMainConnForPsync) != C_ERR);
|
||||||
|
dualChannelSetupMainConnForPsync(server.repl_transfer_s);
|
||||||
|
|
||||||
|
/* As the next block we will receive using this connection is the rdb, we need to prepare
|
||||||
|
* the connection accordingly */
|
||||||
|
serverAssert(connSetReadHandler(server.repl_rdb_transfer_s, readSyncBulkPayload) != C_ERR);
|
||||||
|
server.repl_transfer_size = -1;
|
||||||
|
server.repl_transfer_read = 0;
|
||||||
|
server.repl_transfer_last_fsync_off = 0;
|
||||||
|
server.repl_transfer_lastio = server.unixtime;
|
||||||
|
|
||||||
|
return C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Replication: Replica side.
|
/* Replication: Replica side.
|
||||||
* This connection handler is used to initialize the RDB connection (dual-channel-replication).
|
* This connection handler is used to initialize the RDB connection (dual-channel-replication).
|
||||||
* Once a replica with dual-channel-replication enabled, denied from PSYNC with its primary,
|
* Once a replica with dual-channel-replication enabled, denied from PSYNC with its primary,
|
||||||
* fullSyncWithPrimary begins its role. The connection handler prepares server.repl_rdb_transfer_s
|
* dualChannelFullSyncWithPrimary begins its role. The connection handler prepares server.repl_rdb_transfer_s
|
||||||
* for a rdb stream, and server.repl_transfer_s for incremental replication data stream. */
|
* for a rdb stream, and server.repl_transfer_s for incremental replication data stream. */
|
||||||
static void fullSyncWithPrimary(connection *conn) {
|
static void dualChannelFullSyncWithPrimary(connection *conn) {
|
||||||
char *err = NULL;
|
char *err = NULL;
|
||||||
|
int ret = 0;
|
||||||
serverAssert(conn == server.repl_rdb_transfer_s);
|
serverAssert(conn == server.repl_rdb_transfer_s);
|
||||||
/* If this event fired after the user turned the instance into a primary
|
/* If this event fired after the user turned the instance into a primary
|
||||||
* with REPLICAOF NO ONE we must just return ASAP. */
|
* with REPLICAOF NO ONE we must just return ASAP. */
|
||||||
@ -2607,138 +2730,40 @@ static void fullSyncWithPrimary(connection *conn) {
|
|||||||
serverLog(LL_WARNING, "Error condition on socket for dual channel replication: %s", connGetLastError(conn));
|
serverLog(LL_WARNING, "Error condition on socket for dual channel replication: %s", connGetLastError(conn));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/* Send replica capabilities */
|
switch (server.repl_rdb_channel_state) {
|
||||||
if (server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_SEND_HANDSHAKE) {
|
case REPL_DUAL_CHANNEL_SEND_HANDSHAKE:
|
||||||
serverLog(LL_DEBUG, "Received first reply from primary using rdb connection.");
|
ret = dualChannelReplHandleHandshake(conn, &err);
|
||||||
/* AUTH with the primary if required. */
|
if (ret == C_OK) server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_AUTH_REPLY;
|
||||||
|
break;
|
||||||
|
case REPL_DUAL_CHANNEL_RECEIVE_AUTH_REPLY:
|
||||||
if (server.primary_auth) {
|
if (server.primary_auth) {
|
||||||
char *args[] = {"AUTH", NULL, NULL};
|
ret = dualChannelReplHandleAuthReply(conn, &err);
|
||||||
size_t lens[] = {4, 0, 0};
|
if (ret == C_OK) server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY;
|
||||||
int argc = 1;
|
/* Wait for next bulk before trying to read replconf reply. */
|
||||||
if (server.primary_user) {
|
break;
|
||||||
args[argc] = server.primary_user;
|
|
||||||
lens[argc] = strlen(server.primary_user);
|
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
args[argc] = server.primary_auth;
|
|
||||||
lens[argc] = sdslen(server.primary_auth);
|
|
||||||
argc++;
|
|
||||||
err = sendCommandArgv(conn, argc, args, lens);
|
|
||||||
if (err) {
|
|
||||||
serverLog(LL_WARNING, "Sending command to primary in dual channel replication handshake: %s", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Send replica listening port to primary for clarification */
|
|
||||||
sds portstr = getReplicaPortString();
|
|
||||||
err = sendCommand(conn, "REPLCONF", "capa", "eof", "rdb-only", "1", "rdb-channel", "1", "listening-port",
|
|
||||||
portstr, NULL);
|
|
||||||
sdsfree(portstr);
|
|
||||||
if (err) {
|
|
||||||
serverLog(LL_WARNING, "Sending command to primary in dual channel replication handshake: %s", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_AUTH_REPLY;
|
|
||||||
|
|
||||||
if (connSetReadHandler(conn, fullSyncWithPrimary) == C_ERR) {
|
|
||||||
char conninfo[CONN_INFO_LEN];
|
|
||||||
serverLog(LL_WARNING, "Can't create readable event for SYNC: %s (%s)", strerror(errno),
|
|
||||||
connGetInfo(conn, conninfo, sizeof(conninfo)));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_RECEIVE_AUTH_REPLY && !server.primary_auth) {
|
|
||||||
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY;
|
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY;
|
||||||
|
/* fall through */
|
||||||
|
case REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY:
|
||||||
|
ret = dualChannelReplHandleReplconfReply(conn, &err);
|
||||||
|
if (ret == C_OK) server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_ENDOFF;
|
||||||
|
break;
|
||||||
|
case REPL_DUAL_CHANNEL_RECEIVE_ENDOFF:
|
||||||
|
ret = dualChannelReplHandleEndOffsetResponse(conn, &err);
|
||||||
|
if (ret == C_OK) server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RDB_LOAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
serverPanic("Unexpected dual replication state: %d", server.repl_rdb_channel_state);
|
||||||
}
|
}
|
||||||
/* Receive AUTH reply. */
|
if (ret == C_ERR) goto error;
|
||||||
if (server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_RECEIVE_AUTH_REPLY) {
|
sdsfree(err);
|
||||||
err = receiveSynchronousResponse(conn);
|
return;
|
||||||
if (err == NULL) {
|
|
||||||
serverLog(LL_WARNING, "Primary did not respond to auth command during SYNC handshake");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (err[0] == '-') {
|
|
||||||
serverLog(LL_WARNING, "Unable to AUTH to Primary: %s", err);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
sdsfree(err);
|
|
||||||
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Receive replconf response */
|
|
||||||
if (server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_RECEIVE_REPLCONF_REPLY) {
|
|
||||||
err = receiveSynchronousResponse(conn);
|
|
||||||
if (err == NULL) {
|
|
||||||
serverLog(LL_WARNING, "Primary did not respond to replconf command during SYNC handshake");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err[0] == '-') {
|
|
||||||
serverLog(LL_NOTICE,
|
|
||||||
"Server does not support sync with offset, dual channel sync approach cannot be used: %s", err);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (connSyncWrite(conn, "SYNC\r\n", 6, server.repl_syncio_timeout * 1000) == -1) {
|
|
||||||
serverLog(LL_WARNING, "I/O error writing to Primary: %s", connGetLastError(conn));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
sdsfree(err);
|
|
||||||
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RECEIVE_ENDOFF;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Receive end offset response */
|
|
||||||
if (server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_RECEIVE_ENDOFF) {
|
|
||||||
uint64_t rdb_client_id;
|
|
||||||
err = receiveSynchronousResponse(conn);
|
|
||||||
if (err == NULL) goto error;
|
|
||||||
if (err[0] == '\0') {
|
|
||||||
/* Retry again later */
|
|
||||||
serverLog(LL_DEBUG, "Received empty $ENDOFF response");
|
|
||||||
sdsfree(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long long reploffset;
|
|
||||||
char primary_replid[CONFIG_RUN_ID_SIZE + 1];
|
|
||||||
int dbid;
|
|
||||||
/* Parse end offset response */
|
|
||||||
char *endoff_format = "$ENDOFF:%lld %40s %d %llu";
|
|
||||||
if (sscanf(err, endoff_format, &reploffset, primary_replid, &dbid, &rdb_client_id) != 4) {
|
|
||||||
serverLog(LL_WARNING, "Received unexpected $ENDOFF response: %s", err);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
sdsfree(err);
|
|
||||||
server.rdb_client_id = rdb_client_id;
|
|
||||||
server.primary_initial_offset = reploffset;
|
|
||||||
|
|
||||||
/* Initiate repl_provisional_primary to act as this replica temp primary until RDB is loaded */
|
|
||||||
server.repl_provisional_primary.conn = server.repl_transfer_s;
|
|
||||||
memcpy(server.repl_provisional_primary.replid, primary_replid, CONFIG_RUN_ID_SIZE);
|
|
||||||
server.repl_provisional_primary.reploff = reploffset;
|
|
||||||
server.repl_provisional_primary.read_reploff = reploffset;
|
|
||||||
server.repl_provisional_primary.dbid = dbid;
|
|
||||||
|
|
||||||
/* Now that we have the snapshot end-offset, we can ask for psync from that offset. Prepare the
|
|
||||||
* main connection accordingly.*/
|
|
||||||
server.repl_transfer_s->state = CONN_STATE_CONNECTED;
|
|
||||||
server.repl_state = REPL_STATE_SEND_HANDSHAKE;
|
|
||||||
serverAssert(connSetReadHandler(server.repl_transfer_s, setupMainConnForPsync) != C_ERR);
|
|
||||||
setupMainConnForPsync(server.repl_transfer_s);
|
|
||||||
|
|
||||||
/* As the next block we will receive using this connection is the rdb, we need to prepare
|
|
||||||
* the connection accordingly */
|
|
||||||
serverAssert(connSetReadHandler(server.repl_rdb_transfer_s, readSyncBulkPayload) != C_ERR);
|
|
||||||
server.repl_transfer_size = -1;
|
|
||||||
server.repl_transfer_read = 0;
|
|
||||||
server.repl_transfer_last_fsync_off = 0;
|
|
||||||
server.repl_transfer_lastio = server.unixtime;
|
|
||||||
|
|
||||||
server.repl_rdb_channel_state = REPL_DUAL_CHANNEL_RDB_LOAD;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
sdsfree(err);
|
if (err) {
|
||||||
|
serverLog(LL_WARNING, "Dual channel sync failed with error %s", err);
|
||||||
|
sdsfree(err);
|
||||||
|
}
|
||||||
if (server.repl_transfer_s) {
|
if (server.repl_transfer_s) {
|
||||||
connClose(server.repl_transfer_s);
|
connClose(server.repl_transfer_s);
|
||||||
server.repl_transfer_s = NULL;
|
server.repl_transfer_s = NULL;
|
||||||
@ -2751,7 +2776,6 @@ error:
|
|||||||
server.repl_transfer_fd = -1;
|
server.repl_transfer_fd = -1;
|
||||||
server.repl_state = REPL_STATE_CONNECT;
|
server.repl_state = REPL_STATE_CONNECT;
|
||||||
replicationAbortDualChannelSyncTransfer();
|
replicationAbortDualChannelSyncTransfer();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replication: Replica side.
|
/* Replication: Replica side.
|
||||||
@ -2920,24 +2944,23 @@ void dualChannelSyncSuccess(void) {
|
|||||||
/* Replication: Replica side.
|
/* Replication: Replica side.
|
||||||
* Main channel successfully established psync with primary. Check whether the rdb channel
|
* Main channel successfully established psync with primary. Check whether the rdb channel
|
||||||
* has completed its part and act accordingly. */
|
* has completed its part and act accordingly. */
|
||||||
void dualChannelSyncHandlePsync(void) {
|
int dualChannelSyncHandlePsync(void) {
|
||||||
serverAssert(server.repl_state == REPL_STATE_RECEIVE_PSYNC_REPLY);
|
serverAssert(server.repl_state == REPL_STATE_RECEIVE_PSYNC_REPLY);
|
||||||
if (server.repl_rdb_channel_state < REPL_DUAL_CHANNEL_RDB_LOADED) {
|
if (server.repl_rdb_channel_state < REPL_DUAL_CHANNEL_RDB_LOADED) {
|
||||||
/* RDB is still loading */
|
/* RDB is still loading */
|
||||||
if (connSetReadHandler(server.repl_provisional_primary.conn, bufferReplData) == C_ERR) {
|
if (connSetReadHandler(server.repl_provisional_primary.conn, bufferReplData) == C_ERR) {
|
||||||
serverLog(LL_WARNING, "Error while setting readable handler: %s", strerror(errno));
|
serverLog(LL_WARNING, "Error while setting readable handler: %s", strerror(errno));
|
||||||
cancelReplicationHandshake(1);
|
cancelReplicationHandshake(1);
|
||||||
return;
|
return C_ERR;
|
||||||
}
|
}
|
||||||
replDataBufInit();
|
replDataBufInit();
|
||||||
server.repl_state = REPL_STATE_TRANSFER;
|
return C_OK;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
serverAssert(server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_RDB_LOADED);
|
serverAssert(server.repl_rdb_channel_state == REPL_DUAL_CHANNEL_RDB_LOADED);
|
||||||
/* RDB is loaded */
|
/* RDB is loaded */
|
||||||
serverLog(LL_DEBUG, "Dual channel sync - psync established after rdb load");
|
serverLog(LL_DEBUG, "Dual channel sync - psync established after rdb load");
|
||||||
dualChannelSyncSuccess();
|
dualChannelSyncSuccess();
|
||||||
return;
|
return C_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replication: Replica side.
|
/* Replication: Replica side.
|
||||||
@ -3195,46 +3218,54 @@ int replicaTryPartialResynchronization(connection *conn, int read_reply) {
|
|||||||
return PSYNC_NOT_SUPPORTED;
|
return PSYNC_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replication: Replica side.
|
|
||||||
* This connection handler fires after rdb-connection was initialized. We use it
|
sds getTryPsyncString(int result) {
|
||||||
* to adjust the replica main for loading incremental changes into the local buffer. */
|
switch (result) {
|
||||||
void setupMainConnForPsync(connection *conn) {
|
case PSYNC_WRITE_ERROR: return sdsnew("PSYNC_WRITE_ERROR");
|
||||||
int psync_result = -1;
|
case PSYNC_WAIT_REPLY: return sdsnew("PSYNC_WAIT_REPLY");
|
||||||
|
case PSYNC_CONTINUE: return sdsnew("PSYNC_CONTINUE");
|
||||||
|
case PSYNC_FULLRESYNC: return sdsnew("PSYNC_FULLRESYNC");
|
||||||
|
case PSYNC_NOT_SUPPORTED: return sdsnew("PSYNC_NOT_SUPPORTED");
|
||||||
|
case PSYNC_TRY_LATER: return sdsnew("PSYNC_TRY_LATER");
|
||||||
|
case PSYNC_FULLRESYNC_DUAL_CHANNEL: return sdsnew("PSYNC_FULLRESYNC_DUAL_CHANNEL");
|
||||||
|
default: return sdsnew("Unknown result");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dualChannelReplMainConnSendHandshake(connection *conn, sds *err) {
|
||||||
char llstr[LONG_STR_SIZE];
|
char llstr[LONG_STR_SIZE];
|
||||||
char *err = NULL;
|
ull2string(llstr, sizeof(llstr), server.rdb_client_id);
|
||||||
if (server.repl_state == REPL_STATE_SEND_HANDSHAKE) {
|
*err = sendCommand(conn, "REPLCONF", "set-rdb-client-id", llstr, NULL);
|
||||||
/* We already have an initialized connection at primary side, we only need to associate it with RDB connection */
|
if (*err) return C_ERR;
|
||||||
ull2string(llstr, sizeof(llstr), server.rdb_client_id);
|
server.repl_state = REPL_STATE_RECEIVE_CAPA_REPLY;
|
||||||
err = sendCommand(conn, "REPLCONF", "set-rdb-client-id", llstr, NULL);
|
return C_OK;
|
||||||
if (err) goto error;
|
}
|
||||||
server.repl_state = REPL_STATE_RECEIVE_CAPA_REPLY;
|
|
||||||
sdsfree(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (server.repl_state == REPL_STATE_RECEIVE_CAPA_REPLY) {
|
int dualChannelReplMainConnRecvCapaReply(connection *conn, sds *err) {
|
||||||
err = receiveSynchronousResponse(conn);
|
*err = receiveSynchronousResponse(conn);
|
||||||
if (err == NULL) goto error;
|
if (*err == NULL) return C_ERR;
|
||||||
if (err[0] == '-') {
|
if ((*err)[0] == '-') {
|
||||||
serverLog(LL_NOTICE, "Primary does not understand REPLCONF identify: %s", err);
|
serverLog(LL_NOTICE, "Primary does not understand REPLCONF identify: %s", *err);
|
||||||
goto error;
|
return C_ERR;
|
||||||
}
|
|
||||||
sdsfree(err);
|
|
||||||
err = NULL;
|
|
||||||
server.repl_state = REPL_STATE_SEND_PSYNC;
|
|
||||||
}
|
}
|
||||||
|
server.repl_state = REPL_STATE_SEND_PSYNC;
|
||||||
|
return C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (server.repl_state == REPL_STATE_SEND_PSYNC) {
|
int dualChannelReplMainConnSendPsync(connection *conn, sds *err) {
|
||||||
if (server.debug_pause_after_fork) debugPauseProcess();
|
if (server.debug_pause_after_fork) debugPauseProcess();
|
||||||
if (replicaTryPartialResynchronization(conn, 0) == PSYNC_WRITE_ERROR) {
|
if (replicaTryPartialResynchronization(conn, 0) == PSYNC_WRITE_ERROR) {
|
||||||
serverLog(LL_WARNING, "Aborting dual channel sync. Write error.");
|
serverLog(LL_WARNING, "Aborting dual channel sync. Write error.");
|
||||||
cancelReplicationHandshake(1);
|
*err = sdsnew(connGetLastError(conn));
|
||||||
}
|
return C_ERR;
|
||||||
server.repl_state = REPL_STATE_RECEIVE_PSYNC_REPLY;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
psync_result = replicaTryPartialResynchronization(conn, 1);
|
server.repl_state = REPL_STATE_RECEIVE_PSYNC_REPLY;
|
||||||
if (psync_result == PSYNC_WAIT_REPLY) return; /* Try again later... */
|
return C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dualChannelReplMainConnRecvPsyncReply(connection *conn, sds *err) {
|
||||||
|
int psync_result = replicaTryPartialResynchronization(conn, 1);
|
||||||
|
if (psync_result == PSYNC_WAIT_REPLY) return C_OK; /* Try again later... */
|
||||||
|
|
||||||
if (psync_result == PSYNC_CONTINUE) {
|
if (psync_result == PSYNC_CONTINUE) {
|
||||||
serverLog(LL_NOTICE, "PRIMARY <-> REPLICA sync: Primary accepted a Partial Resynchronization%s",
|
serverLog(LL_NOTICE, "PRIMARY <-> REPLICA sync: Primary accepted a Partial Resynchronization%s",
|
||||||
@ -3244,15 +3275,52 @@ void setupMainConnForPsync(connection *conn) {
|
|||||||
"accept connections in read-write mode.\n");
|
"accept connections in read-write mode.\n");
|
||||||
}
|
}
|
||||||
dualChannelSyncHandlePsync();
|
dualChannelSyncHandlePsync();
|
||||||
return;
|
return C_OK;
|
||||||
|
}
|
||||||
|
*err = getTryPsyncString(psync_result);
|
||||||
|
return C_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replication: Replica side.
|
||||||
|
* This connection handler fires after rdb-connection was initialized. We use it
|
||||||
|
* to adjust the replica main for loading incremental changes into the local buffer. */
|
||||||
|
void dualChannelSetupMainConnForPsync(connection *conn) {
|
||||||
|
char *err = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (server.repl_state) {
|
||||||
|
case REPL_STATE_SEND_HANDSHAKE:
|
||||||
|
ret = dualChannelReplMainConnSendHandshake(conn, &err);
|
||||||
|
if (ret == C_OK) server.repl_state = REPL_STATE_RECEIVE_CAPA_REPLY;
|
||||||
|
break;
|
||||||
|
case REPL_STATE_RECEIVE_CAPA_REPLY:
|
||||||
|
ret = dualChannelReplMainConnRecvCapaReply(conn, &err);
|
||||||
|
if (ret == C_ERR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == C_OK) server.repl_state = REPL_STATE_SEND_PSYNC;
|
||||||
|
sdsfree(err);
|
||||||
|
err = NULL;
|
||||||
|
/* fall through */
|
||||||
|
case REPL_STATE_SEND_PSYNC:
|
||||||
|
ret = dualChannelReplMainConnSendPsync(conn, &err);
|
||||||
|
if (ret == C_OK) server.repl_state = REPL_STATE_RECEIVE_PSYNC_REPLY;
|
||||||
|
break;
|
||||||
|
case REPL_STATE_RECEIVE_PSYNC_REPLY:
|
||||||
|
ret = dualChannelReplMainConnRecvPsyncReply(conn, &err);
|
||||||
|
if (ret == C_OK && server.repl_rdb_channel_state != REPL_DUAL_CHANNEL_STATE_NONE)
|
||||||
|
server.repl_state = REPL_STATE_TRANSFER;
|
||||||
|
/* In case the RDB is already loaded, the repl_state will be set during establishPrimaryConnection. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
serverPanic("Unexpected replication state: %d", server.repl_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
if (ret == C_ERR) {
|
||||||
|
serverLog(LL_WARNING, "Aborting dual channel sync. Main channel psync result %d %s", ret, err ? err : "");
|
||||||
|
cancelReplicationHandshake(1);
|
||||||
|
}
|
||||||
sdsfree(err);
|
sdsfree(err);
|
||||||
/* The dual-channel sync session must be aborted for any psync_result other than PSYNC_CONTINUE or PSYNC_WAIT_REPLY.
|
|
||||||
*/
|
|
||||||
serverLog(LL_WARNING, "Aborting dual channel sync. Main channel psync result %d", psync_result);
|
|
||||||
cancelReplicationHandshake(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3625,7 +3693,7 @@ void syncWithPrimary(connection *conn) {
|
|||||||
/* Create RDB connection */
|
/* Create RDB connection */
|
||||||
server.repl_rdb_transfer_s = connCreate(connTypeOfReplication());
|
server.repl_rdb_transfer_s = connCreate(connTypeOfReplication());
|
||||||
if (connConnect(server.repl_rdb_transfer_s, server.primary_host, server.primary_port, server.bind_source_addr,
|
if (connConnect(server.repl_rdb_transfer_s, server.primary_host, server.primary_port, server.bind_source_addr,
|
||||||
fullSyncWithPrimary) == C_ERR) {
|
dualChannelFullSyncWithPrimary) == C_ERR) {
|
||||||
serverLog(LL_WARNING, "Unable to connect to Primary: %s", connGetLastError(server.repl_transfer_s));
|
serverLog(LL_WARNING, "Unable to connect to Primary: %s", connGetLastError(server.repl_transfer_s));
|
||||||
connClose(server.repl_rdb_transfer_s);
|
connClose(server.repl_rdb_transfer_s);
|
||||||
server.repl_rdb_transfer_s = NULL;
|
server.repl_rdb_transfer_s = NULL;
|
||||||
|
@ -110,6 +110,7 @@ struct hdr_histogram;
|
|||||||
/* Error codes */
|
/* Error codes */
|
||||||
#define C_OK 0
|
#define C_OK 0
|
||||||
#define C_ERR -1
|
#define C_ERR -1
|
||||||
|
#define C_RETRY -2
|
||||||
|
|
||||||
/* Static server configuration */
|
/* Static server configuration */
|
||||||
#define CONFIG_DEFAULT_HZ 10 /* Time interrupt calls/sec. */
|
#define CONFIG_DEFAULT_HZ 10 /* Time interrupt calls/sec. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user