From 9bd212cf241154d22849ef2addd0d5a7551b3a55 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Fri, 18 Dec 2020 00:02:57 +0200 Subject: [PATCH] syncWithMaster: sendSynchronousCommand split to send, and receive This is just a refactoring commit. This function was never actually used as a synchronous (do both send or receive), it was always used only ine one of the two modes, which meant it has to take extra arguments that are not relevant for the other. Besides that, a tool that sends a synchronous command, it not something we want in our toolbox (synchronous IO in single threaded app is evil). sendSynchronousCommand was now refactored into separate sending and receiving APIs, and the sending part has two variants, one taking vaargs, and the other taking argc+argv (and an optional length array which means you can use binary sds strings). --- src/replication.c | 173 ++++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 75 deletions(-) diff --git a/src/replication.c b/src/replication.c index 8a15c01a7..4977bba42 100644 --- a/src/replication.c +++ b/src/replication.c @@ -1827,72 +1827,94 @@ error: return; } -/* Send a synchronous command to the master. Used to send AUTH and - * REPLCONF commands before starting the replication with SYNC. +char *receiveSynchronousResponse(connection *conn) { + char buf[256]; + /* Read the reply from the server. */ + if (connSyncReadLine(conn,buf,sizeof(buf),server.repl_syncio_timeout*1000) == -1) + { + return sdscatprintf(sdsempty(),"-Reading from master: %s", + strerror(errno)); + } + server.repl_transfer_lastio = server.unixtime; + return sdsnew(buf); +} + +/* Send a pre-formatted multi-bulk command to the connection. */ +char* sendCommandRaw(connection *conn, sds cmd) { + if (connSyncWrite(conn,cmd,sdslen(cmd),server.repl_syncio_timeout*1000) == -1) { + return sdscatprintf(sdsempty(),"-Writing to master: %s", + connGetLastError(conn)); + } + return NULL; +} + +/* Compose a multi-bulk command and send it to the connection. + * Used to send AUTH and REPLCONF commands to the master before starting the + * replication. + * + * Takes a list of char* arguments, terminated by a NULL argument. * * The command returns an sds string representing the result of the * operation. On error the first byte is a "-". */ -#define SYNC_CMD_READ (1<<0) -#define SYNC_CMD_WRITE (1<<1) -#define SYNC_CMD_WRITE_SDS (1<<2) -#define SYNC_CMD_FULL (SYNC_CMD_READ|SYNC_CMD_WRITE) -char *sendSynchronousCommand(int flags, connection *conn, ...) { +char *sendCommand(connection *conn, ...) { + va_list ap; + sds cmd = sdsempty(); + sds cmdargs = sdsempty(); + size_t argslen = 0; + char *arg; /* Create the command to send to the master, we use redis binary * protocol to make sure correct arguments are sent. This function * is not safe for all binary data. */ - if (flags & SYNC_CMD_WRITE) { - char *arg; - va_list ap; - sds cmd = sdsempty(); - sds cmdargs = sdsempty(); - size_t argslen = 0; - va_start(ap,conn); - - while(1) { - arg = va_arg(ap, char*); - if (arg == NULL) break; - if (flags & SYNC_CMD_WRITE_SDS) { - cmdargs = sdscatprintf(cmdargs,"$%zu\r\n", sdslen((sds)arg)); - cmdargs = sdscatsds(cmdargs, (sds)arg); - cmdargs = sdscat(cmdargs, "\r\n"); - } else { - cmdargs = sdscatprintf(cmdargs,"$%zu\r\n%s\r\n",strlen(arg),arg); - } - argslen++; - } - - va_end(ap); - - cmd = sdscatprintf(cmd,"*%zu\r\n",argslen); - cmd = sdscatsds(cmd,cmdargs); - sdsfree(cmdargs); - - /* Transfer command to the server. */ - if (connSyncWrite(conn,cmd,sdslen(cmd),server.repl_syncio_timeout*1000) - == -1) - { - sdsfree(cmd); - return sdscatprintf(sdsempty(),"-Writing to master: %s", - connGetLastError(conn)); - } - sdsfree(cmd); + va_start(ap,conn); + while(1) { + arg = va_arg(ap, char*); + if (arg == NULL) break; + cmdargs = sdscatprintf(cmdargs,"$%zu\r\n%s\r\n",strlen(arg),arg); + argslen++; } - /* Read the reply from the server. */ - if (flags & SYNC_CMD_READ) { - char buf[256]; + cmd = sdscatprintf(cmd,"*%zu\r\n",argslen); + cmd = sdscatsds(cmd,cmdargs); + sdsfree(cmdargs); - if (connSyncReadLine(conn,buf,sizeof(buf),server.repl_syncio_timeout*1000) - == -1) - { - return sdscatprintf(sdsempty(),"-Reading from master: %s", - strerror(errno)); - } - server.repl_transfer_lastio = server.unixtime; - return sdsnew(buf); + va_end(ap); + char* err = sendCommandRaw(conn, cmd); + sdsfree(cmd); + if(err) + return err; + return NULL; +} + +/* Compose a multi-bulk command and send it to the connection. + * Used to send AUTH and REPLCONF commands to the master before starting the + * replication. + * + * argv_lens is optional, when NULL, strlen is used. + * + * The command returns an sds string representing the result of the + * operation. On error the first byte is a "-". + */ +char *sendCommandArgv(connection *conn, int argc, char **argv, size_t *argv_lens) { + sds cmd = sdsempty(); + char *arg; + int i; + + /* Create the command to send to the master. */ + cmd = sdscatfmt(cmd,"*%i\r\n",argc); + for (i=0; i