Unverified Commit ec2d1807 authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge 6.2 RC2

parents b8c67ce4 049f2f08
...@@ -94,7 +94,7 @@ void rdbReportError(int corruption_error, int linenum, char *reason, ...) { ...@@ -94,7 +94,7 @@ void rdbReportError(int corruption_error, int linenum, char *reason, ...) {
exit(1); exit(1);
} }
static int rdbWriteRaw(rio *rdb, void *p, size_t len) { static ssize_t rdbWriteRaw(rio *rdb, void *p, size_t len) {
if (rdb && rioWrite(rdb,p,len) == 0) if (rdb && rioWrite(rdb,p,len) == 0)
return -1; return -1;
return len; return len;
...@@ -1219,9 +1219,11 @@ int rdbSaveRio(rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) { ...@@ -1219,9 +1219,11 @@ int rdbSaveRio(rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
dictIterator *di = NULL; dictIterator *di = NULL;
dictEntry *de; dictEntry *de;
char magic[10]; char magic[10];
int j;
uint64_t cksum; uint64_t cksum;
size_t processed = 0; size_t processed = 0;
int j;
long key_count = 0;
long long cow_updated_time = 0;
if (server.rdb_checksum) if (server.rdb_checksum)
rdb->update_cksum = rioGenericUpdateChecksum; rdb->update_cksum = rioGenericUpdateChecksum;
...@@ -1267,6 +1269,23 @@ int rdbSaveRio(rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) { ...@@ -1267,6 +1269,23 @@ int rdbSaveRio(rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
processed = rdb->processed_bytes; processed = rdb->processed_bytes;
aofReadDiffFromParent(); aofReadDiffFromParent();
} }
/* Update COW info every 1 second (approximately).
* in order to avoid calling mstime() on each iteration, we will
* check the diff every 1024 keys */
if ((key_count & 1023) == 0) {
key_count = 0;
long long now = mstime();
if (now - cow_updated_time >= 1000) {
if (rdbflags & RDBFLAGS_AOF_PREAMBLE) {
sendChildCOWInfo(CHILD_TYPE_AOF, 0, "AOF rewrite");
} else {
sendChildCOWInfo(CHILD_TYPE_RDB, 0, "RDB");
}
cow_updated_time = now;
}
}
key_count++;
} }
dictReleaseIterator(di); dictReleaseIterator(di);
di = NULL; /* So that we don't release it again on error. */ di = NULL; /* So that we don't release it again on error. */
...@@ -1410,7 +1429,6 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { ...@@ -1410,7 +1429,6 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) {
server.dirty_before_bgsave = server.dirty; server.dirty_before_bgsave = server.dirty;
server.lastbgsave_try = time(NULL); server.lastbgsave_try = time(NULL);
openChildInfoPipe();
if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) { if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) {
int retval; int retval;
...@@ -1420,13 +1438,12 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { ...@@ -1420,13 +1438,12 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) {
redisSetCpuAffinity(server.bgsave_cpulist); redisSetCpuAffinity(server.bgsave_cpulist);
retval = rdbSave(filename,rsi); retval = rdbSave(filename,rsi);
if (retval == C_OK) { if (retval == C_OK) {
sendChildCOWInfo(CHILD_TYPE_RDB, "RDB"); sendChildCOWInfo(CHILD_TYPE_RDB, 1, "RDB");
} }
exitFromChild((retval == C_OK) ? 0 : 1); exitFromChild((retval == C_OK) ? 0 : 1);
} else { } else {
/* Parent */ /* Parent */
if (childpid == -1) { if (childpid == -1) {
closeChildInfoPipe();
server.lastbgsave_status = C_ERR; server.lastbgsave_status = C_ERR;
serverLog(LL_WARNING,"Can't save in background: fork: %s", serverLog(LL_WARNING,"Can't save in background: fork: %s",
strerror(errno)); strerror(errno));
...@@ -1434,9 +1451,7 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { ...@@ -1434,9 +1451,7 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) {
} }
serverLog(LL_NOTICE,"Background saving started by pid %ld",(long) childpid); serverLog(LL_NOTICE,"Background saving started by pid %ld",(long) childpid);
server.rdb_save_time_start = time(NULL); server.rdb_save_time_start = time(NULL);
server.rdb_child_pid = childpid;
server.rdb_child_type = RDB_CHILD_TYPE_DISK; server.rdb_child_type = RDB_CHILD_TYPE_DISK;
updateDictResizePolicy();
return C_OK; return C_OK;
} }
return C_OK; /* unreached */ return C_OK; /* unreached */
...@@ -2654,7 +2669,7 @@ static void backgroundSaveDoneHandlerDisk(int exitcode, int bysignal) { ...@@ -2654,7 +2669,7 @@ static void backgroundSaveDoneHandlerDisk(int exitcode, int bysignal) {
serverLog(LL_WARNING, serverLog(LL_WARNING,
"Background saving terminated by signal %d", bysignal); "Background saving terminated by signal %d", bysignal);
latencyStartMonitor(latency); latencyStartMonitor(latency);
rdbRemoveTempFile(server.rdb_child_pid, 0); rdbRemoveTempFile(server.child_pid, 0);
latencyEndMonitor(latency); latencyEndMonitor(latency);
latencyAddSampleIfNeeded("rdb-unlink-temp-file",latency); latencyAddSampleIfNeeded("rdb-unlink-temp-file",latency);
/* SIGUSR1 is whitelisted, so we have a way to kill a child without /* SIGUSR1 is whitelisted, so we have a way to kill a child without
...@@ -2706,7 +2721,6 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) { ...@@ -2706,7 +2721,6 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) {
break; break;
} }
server.rdb_child_pid = -1;
server.rdb_child_type = RDB_CHILD_TYPE_NONE; server.rdb_child_type = RDB_CHILD_TYPE_NONE;
server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start; server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start;
server.rdb_save_time_start = -1; server.rdb_save_time_start = -1;
...@@ -2719,10 +2733,13 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) { ...@@ -2719,10 +2733,13 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) {
* the child did not exit for an error, but because we wanted), and performs * the child did not exit for an error, but because we wanted), and performs
* the cleanup needed. */ * the cleanup needed. */
void killRDBChild(void) { void killRDBChild(void) {
kill(server.rdb_child_pid,SIGUSR1); kill(server.child_pid, SIGUSR1);
rdbRemoveTempFile(server.rdb_child_pid, 0); /* Because we are not using here wait4 (like we have in killAppendOnlyChild
closeChildInfoPipe(); * and TerminateModuleForkChild), all the cleanup operations is done by
updateDictResizePolicy(); * checkChildrenDone, that later will find that the process killed.
* This includes:
* - resetChildState
* - rdbRemoveTempFile */
} }
/* Spawn an RDB child that writes the RDB to the sockets of the slaves /* Spawn an RDB child that writes the RDB to the sockets of the slaves
...@@ -2773,7 +2790,6 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { ...@@ -2773,7 +2790,6 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
} }
/* Create the child process. */ /* Create the child process. */
openChildInfoPipe();
if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) { if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) {
/* Child */ /* Child */
int retval, dummy; int retval, dummy;
...@@ -2789,7 +2805,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { ...@@ -2789,7 +2805,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
retval = C_ERR; retval = C_ERR;
if (retval == C_OK) { if (retval == C_OK) {
sendChildCOWInfo(CHILD_TYPE_RDB, "RDB"); sendChildCOWInfo(CHILD_TYPE_RDB, 1, "RDB");
} }
rioFreeFd(&rdb); rioFreeFd(&rdb);
...@@ -2824,14 +2840,11 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { ...@@ -2824,14 +2840,11 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
server.rdb_pipe_conns = NULL; server.rdb_pipe_conns = NULL;
server.rdb_pipe_numconns = 0; server.rdb_pipe_numconns = 0;
server.rdb_pipe_numconns_writing = 0; server.rdb_pipe_numconns_writing = 0;
closeChildInfoPipe();
} else { } else {
serverLog(LL_NOTICE,"Background RDB transfer started by pid %ld", serverLog(LL_NOTICE,"Background RDB transfer started by pid %ld",
(long) childpid); (long) childpid);
server.rdb_save_time_start = time(NULL); server.rdb_save_time_start = time(NULL);
server.rdb_child_pid = childpid;
server.rdb_child_type = RDB_CHILD_TYPE_SOCKET; server.rdb_child_type = RDB_CHILD_TYPE_SOCKET;
updateDictResizePolicy();
close(rdb_pipe_write); /* close write in parent so that it can detect the close on the child. */ close(rdb_pipe_write); /* close write in parent so that it can detect the close on the child. */
if (aeCreateFileEvent(server.el, server.rdb_pipe_read, AE_READABLE, rdbPipeReadHandler,NULL) == AE_ERR) { if (aeCreateFileEvent(server.el, server.rdb_pipe_read, AE_READABLE, rdbPipeReadHandler,NULL) == AE_ERR) {
serverPanic("Unrecoverable error creating server.rdb_pipe_read file event."); serverPanic("Unrecoverable error creating server.rdb_pipe_read file event.");
...@@ -2843,7 +2856,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { ...@@ -2843,7 +2856,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
} }
void saveCommand(client *c) { void saveCommand(client *c) {
if (server.rdb_child_pid != -1) { if (server.child_type == CHILD_TYPE_RDB) {
addReplyError(c,"Background save already in progress"); addReplyError(c,"Background save already in progress");
return; return;
} }
...@@ -2852,7 +2865,7 @@ void saveCommand(client *c) { ...@@ -2852,7 +2865,7 @@ void saveCommand(client *c) {
if (rdbSave(server.rdb_filename,rsiptr) == C_OK) { if (rdbSave(server.rdb_filename,rsiptr) == C_OK) {
addReply(c,shared.ok); addReply(c,shared.ok);
} else { } else {
addReply(c,shared.err); addReplyErrorObject(c,shared.err);
} }
} }
...@@ -2866,7 +2879,7 @@ void bgsaveCommand(client *c) { ...@@ -2866,7 +2879,7 @@ void bgsaveCommand(client *c) {
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"schedule")) { if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"schedule")) {
schedule = 1; schedule = 1;
} else { } else {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
return; return;
} }
} }
...@@ -2874,7 +2887,7 @@ void bgsaveCommand(client *c) { ...@@ -2874,7 +2887,7 @@ void bgsaveCommand(client *c) {
rdbSaveInfo rsi, *rsiptr; rdbSaveInfo rsi, *rsiptr;
rsiptr = rdbPopulateSaveInfo(&rsi); rsiptr = rdbPopulateSaveInfo(&rsi);
if (server.rdb_child_pid != -1) { if (server.child_type == CHILD_TYPE_RDB) {
addReplyError(c,"Background save already in progress"); addReplyError(c,"Background save already in progress");
} else if (hasActiveChildProcess()) { } else if (hasActiveChildProcess()) {
if (schedule) { if (schedule) {
...@@ -2889,7 +2902,7 @@ void bgsaveCommand(client *c) { ...@@ -2889,7 +2902,7 @@ void bgsaveCommand(client *c) {
} else if (rdbSaveBackground(server.rdb_filename,rsiptr) == C_OK) { } else if (rdbSaveBackground(server.rdb_filename,rsiptr) == C_OK) {
addReplyStatus(c,"Background saving started"); addReplyStatus(c,"Background saving started");
} else { } else {
addReply(c,shared.err); addReplyErrorObject(c,shared.err);
} }
} }
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "crc16_slottable.h" #include "crc16_slottable.h"
#include "hdr_histogram.h" #include "hdr_histogram.h"
#include "cli_common.h" #include "cli_common.h"
#include "mt19937-64.h"
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
#define RANDPTR_INITIAL_SIZE 8 #define RANDPTR_INITIAL_SIZE 8
...@@ -1182,8 +1183,8 @@ static int fetchClusterConfiguration() { ...@@ -1182,8 +1183,8 @@ static int fetchClusterConfiguration() {
} }
if (myself) { if (myself) {
node = firstNode; node = firstNode;
if (node->ip == NULL && ip != NULL) { if (ip != NULL && strcmp(node->ip, ip) != 0) {
node->ip = ip; node->ip = sdsnew(ip);
node->port = port; node->port = port;
} }
} else { } else {
...@@ -1677,6 +1678,7 @@ int main(int argc, const char **argv) { ...@@ -1677,6 +1678,7 @@ int main(int argc, const char **argv) {
client c; client c;
srandom(time(NULL) ^ getpid()); srandom(time(NULL) ^ getpid());
init_genrand64(ustime() ^ getpid());
signal(SIGHUP, SIG_IGN); signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
......
...@@ -27,10 +27,13 @@ ...@@ -27,10 +27,13 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "mt19937-64.h"
#include "server.h" #include "server.h"
#include "rdb.h" #include "rdb.h"
#include <stdarg.h> #include <stdarg.h>
#include <sys/time.h>
#include <unistd.h>
void createSharedObjects(void); void createSharedObjects(void);
void rdbLoadProgressCallback(rio *r, const void *buf, size_t len); void rdbLoadProgressCallback(rio *r, const void *buf, size_t len);
...@@ -362,10 +365,16 @@ err: ...@@ -362,10 +365,16 @@ err:
* Otherwise if called with a non NULL fp, the function returns C_OK or * Otherwise if called with a non NULL fp, the function returns C_OK or
* C_ERR depending on the success or failure. */ * C_ERR depending on the success or failure. */
int redis_check_rdb_main(int argc, char **argv, FILE *fp) { int redis_check_rdb_main(int argc, char **argv, FILE *fp) {
struct timeval tv;
if (argc != 2 && fp == NULL) { if (argc != 2 && fp == NULL) {
fprintf(stderr, "Usage: %s <rdb-file-name>\n", argv[0]); fprintf(stderr, "Usage: %s <rdb-file-name>\n", argv[0]);
exit(1); exit(1);
} }
gettimeofday(&tv, NULL);
init_genrand64(((long long) tv.tv_sec * 1000000 + tv.tv_usec) ^ getpid());
/* In order to call the loading functions we need to create the shared /* In order to call the loading functions we need to create the shared
* integer objects, however since this function may be called from * integer objects, however since this function may be called from
* an already initialized Redis instance, check if we really need to. */ * an already initialized Redis instance, check if we really need to. */
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include "anet.h" #include "anet.h"
#include "ae.h" #include "ae.h"
#include "cli_common.h" #include "cli_common.h"
#include "mt19937-64.h"
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
...@@ -5578,7 +5579,7 @@ static int clusterManagerCommandCreate(int argc, char **argv) { ...@@ -5578,7 +5579,7 @@ static int clusterManagerCommandCreate(int argc, char **argv) {
if (last > CLUSTER_MANAGER_SLOTS || i == (masters_count - 1)) if (last > CLUSTER_MANAGER_SLOTS || i == (masters_count - 1))
last = CLUSTER_MANAGER_SLOTS - 1; last = CLUSTER_MANAGER_SLOTS - 1;
if (last < first) last = first; if (last < first) last = first;
printf("Master[%d] -> Slots %lu - %lu\n", i, first, last); printf("Master[%d] -> Slots %ld - %ld\n", i, first, last);
master->slots_count = 0; master->slots_count = 0;
for (j = first; j <= last; j++) { for (j = first; j <= last; j++) {
master->slots[j] = 1; master->slots[j] = 1;
...@@ -7131,7 +7132,9 @@ static void getRDB(clusterManagerNode *node) { ...@@ -7131,7 +7132,9 @@ static void getRDB(clusterManagerNode *node) {
} else { } else {
fprintf(stderr,"Transfer finished with success.\n"); fprintf(stderr,"Transfer finished with success.\n");
} }
redisFree(s); /* Close the file descriptor ASAP as fsync() may take time. */ redisFree(s); /* Close the connection ASAP as fsync() may take time. */
if (node)
node->context = NULL;
fsync(fd); fsync(fd);
close(fd); close(fd);
fprintf(stderr,"Transfer finished with success.\n"); fprintf(stderr,"Transfer finished with success.\n");
...@@ -8123,6 +8126,7 @@ static sds askPassword(const char *msg) { ...@@ -8123,6 +8126,7 @@ static sds askPassword(const char *msg) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
int firstarg; int firstarg;
struct timeval tv;
config.hostip = sdsnew("127.0.0.1"); config.hostip = sdsnew("127.0.0.1");
config.hostport = 6379; config.hostport = 6379;
...@@ -8219,6 +8223,9 @@ int main(int argc, char **argv) { ...@@ -8219,6 +8223,9 @@ int main(int argc, char **argv) {
} }
#endif #endif
gettimeofday(&tv, NULL);
init_genrand64(((long long) tv.tv_sec * 1000000 + tv.tv_usec) ^ getpid());
/* Cluster Manager mode */ /* Cluster Manager mode */
if (CLUSTER_MANAGER_MODE()) { if (CLUSTER_MANAGER_MODE()) {
clusterManagerCommandProc *proc = validateClusterManagerCommand(); clusterManagerCommandProc *proc = validateClusterManagerCommand();
......
...@@ -778,6 +778,7 @@ REDISMODULE_API int (*RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilt ...@@ -778,6 +778,7 @@ REDISMODULE_API int (*RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilt
REDISMODULE_API int (*RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_Fork)(RedisModuleForkDoneHandler cb, void *user_data) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_Fork)(RedisModuleForkDoneHandler cb, void *user_data) REDISMODULE_ATTR;
REDISMODULE_API void (*RedisModule_SendChildCOWInfo)(void) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ExitFromChild)(int retcode) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ExitFromChild)(int retcode) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_KillForkChild)(int child_pid) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KillForkChild)(int child_pid) REDISMODULE_ATTR;
REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)() REDISMODULE_ATTR; REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)() REDISMODULE_ATTR;
...@@ -1033,6 +1034,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int ...@@ -1033,6 +1034,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(CommandFilterArgReplace); REDISMODULE_GET_API(CommandFilterArgReplace);
REDISMODULE_GET_API(CommandFilterArgDelete); REDISMODULE_GET_API(CommandFilterArgDelete);
REDISMODULE_GET_API(Fork); REDISMODULE_GET_API(Fork);
REDISMODULE_GET_API(SendChildCOWInfo);
REDISMODULE_GET_API(ExitFromChild); REDISMODULE_GET_API(ExitFromChild);
REDISMODULE_GET_API(KillForkChild); REDISMODULE_GET_API(KillForkChild);
REDISMODULE_GET_API(GetUsedMemoryRatio); REDISMODULE_GET_API(GetUsedMemoryRatio);
......
This diff is collapsed.
...@@ -366,10 +366,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) { ...@@ -366,10 +366,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
lua_gettable(lua,-2); lua_gettable(lua,-2);
t = lua_type(lua,-1); t = lua_type(lua,-1);
if (t == LUA_TSTRING) { if (t == LUA_TSTRING) {
sds err = sdsnew(lua_tostring(lua,-1)); addReplyErrorFormat(c,"-%s",lua_tostring(lua,-1));
sdsmapchars(err,"\r\n"," ",2);
addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err));
sdsfree(err);
lua_pop(lua,2); lua_pop(lua,2);
return; return;
} }
...@@ -410,9 +407,9 @@ void luaReplyToRedisReply(client *c, lua_State *lua) { ...@@ -410,9 +407,9 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
lua_pushnil(lua); /* Use nil to start iteration. */ lua_pushnil(lua); /* Use nil to start iteration. */
while (lua_next(lua,-2)) { while (lua_next(lua,-2)) {
/* Stack now: table, key, value */ /* Stack now: table, key, value */
luaReplyToRedisReply(c, lua); /* Return value. */ lua_pushvalue(lua,-2); /* Dup key before consuming. */
lua_pushvalue(lua,-1); /* Dup key before consuming. */
luaReplyToRedisReply(c, lua); /* Return key. */ luaReplyToRedisReply(c, lua); /* Return key. */
luaReplyToRedisReply(c, lua); /* Return value. */
/* Stack now: table, key. */ /* Stack now: table, key. */
maplen++; maplen++;
} }
...@@ -694,11 +691,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) { ...@@ -694,11 +691,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,&error_code) != if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,&error_code) !=
server.cluster->myself) server.cluster->myself)
{ {
if (error_code == CLUSTER_REDIR_DOWN_RO_STATE) { if (error_code == CLUSTER_REDIR_DOWN_RO_STATE) {
luaPushError(lua, luaPushError(lua,
"Lua script attempted to execute a write command while the " "Lua script attempted to execute a write command while the "
"cluster is down and readonly"); "cluster is down and readonly");
} else if (error_code == CLUSTER_REDIR_DOWN_STATE) { } else if (error_code == CLUSTER_REDIR_DOWN_STATE) {
luaPushError(lua, luaPushError(lua,
"Lua script attempted to execute a command while the " "Lua script attempted to execute a command while the "
"cluster is down"); "cluster is down");
...@@ -721,7 +718,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) { ...@@ -721,7 +718,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
server.lua_write_dirty && server.lua_write_dirty &&
server.lua_repl != PROPAGATE_NONE) server.lua_repl != PROPAGATE_NONE)
{ {
execCommandPropagateMulti(server.lua_caller); execCommandPropagateMulti(server.lua_caller->db->id);
server.lua_multi_emitted = 1; server.lua_multi_emitted = 1;
/* Now we are in the MULTI context, the lua_client should be /* Now we are in the MULTI context, the lua_client should be
* flag as CLIENT_MULTI. */ * flag as CLIENT_MULTI. */
...@@ -1638,7 +1635,7 @@ void evalGenericCommand(client *c, int evalsha) { ...@@ -1638,7 +1635,7 @@ void evalGenericCommand(client *c, int evalsha) {
if (server.lua_replicate_commands) { if (server.lua_replicate_commands) {
preventCommandPropagation(c); preventCommandPropagation(c);
if (server.lua_multi_emitted) { if (server.lua_multi_emitted) {
execCommandPropagateExec(c); execCommandPropagateExec(c->db->id);
} }
} }
...@@ -1710,11 +1707,16 @@ void evalShaCommand(client *c) { ...@@ -1710,11 +1707,16 @@ void evalShaCommand(client *c) {
void scriptCommand(client *c) { void scriptCommand(client *c) {
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) { if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
const char *help[] = { const char *help[] = {
"DEBUG (yes|sync|no) -- Set the debug mode for subsequent scripts executed.", "DEBUG (YES|SYNC|NO)",
"EXISTS <sha1> [<sha1> ...] -- Return information about the existence of the scripts in the script cache.", " Set the debug mode for subsequent scripts executed.",
"FLUSH -- Flush the Lua scripts cache. Very dangerous on replicas.", "EXISTS <sha1> [<sha1> ...]",
"KILL -- Kill the currently executing Lua script.", " Return information about the existence of the scripts in the script cache.",
"LOAD <script> -- Load a script into the scripts cache, without executing it.", "FLUSH",
" Flush the Lua scripts cache. Very dangerous on replicas.",
"KILL",
" Kill the currently executing Lua script.",
"LOAD <script>",
" Load a script into the scripts cache without executing it.",
NULL NULL
}; };
addReplyHelp(c, help); addReplyHelp(c, help);
...@@ -1740,11 +1742,11 @@ NULL ...@@ -1740,11 +1742,11 @@ NULL
forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF); forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF);
} else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) { } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) {
if (server.lua_caller == NULL) { if (server.lua_caller == NULL) {
addReplySds(c,sdsnew("-NOTBUSY No scripts in execution right now.\r\n")); addReplyError(c,"-NOTBUSY No scripts in execution right now.");
} else if (server.lua_caller->flags & CLIENT_MASTER) { } else if (server.lua_caller->flags & CLIENT_MASTER) {
addReplySds(c,sdsnew("-UNKILLABLE The busy script was sent by a master instance in the context of replication and cannot be killed.\r\n")); addReplyError(c,"-UNKILLABLE The busy script was sent by a master instance in the context of replication and cannot be killed.");
} else if (server.lua_write_dirty) { } else if (server.lua_write_dirty) {
addReplySds(c,sdsnew("-UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.\r\n")); addReplyError(c,"-UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.");
} else { } else {
server.lua_kill = 1; server.lua_kill = 1;
addReply(c,shared.ok); addReply(c,shared.ok);
...@@ -1765,7 +1767,7 @@ NULL ...@@ -1765,7 +1767,7 @@ NULL
addReply(c,shared.ok); addReply(c,shared.ok);
c->flags |= CLIENT_LUA_DEBUG_SYNC; c->flags |= CLIENT_LUA_DEBUG_SYNC;
} else { } else {
addReplyError(c,"Use SCRIPT DEBUG yes/sync/no"); addReplyError(c,"Use SCRIPT DEBUG YES/SYNC/NO");
return; return;
} }
} else { } else {
......
...@@ -642,7 +642,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) { ...@@ -642,7 +642,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
/* To avoid continuous reallocations, let's start with a buffer that /* To avoid continuous reallocations, let's start with a buffer that
* can hold at least two times the format string itself. It's not the * can hold at least two times the format string itself. It's not the
* best heuristic but seems to work in practice. */ * best heuristic but seems to work in practice. */
s = sdsMakeRoomFor(s, initlen + strlen(fmt)*2); s = sdsMakeRoomFor(s, strlen(fmt)*2);
va_start(ap,fmt); va_start(ap,fmt);
f = fmt; /* Next format specifier byte to process. */ f = fmt; /* Next format specifier byte to process. */
i = initlen; /* Position of the next byte to write to dest str. */ i = initlen; /* Position of the next byte to write to dest str. */
...@@ -1159,8 +1159,8 @@ void sds_free(void *ptr) { s_free(ptr); } ...@@ -1159,8 +1159,8 @@ void sds_free(void *ptr) { s_free(ptr); }
#ifdef REDIS_TEST #ifdef REDIS_TEST
#include <stdio.h> #include <stdio.h>
#include <limits.h>
#include "testhelp.h" #include "testhelp.h"
#include "limits.h"
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
int sdsTest(int argc, char **argv) { int sdsTest(int argc, char **argv) {
...@@ -1171,12 +1171,12 @@ int sdsTest(int argc, char **argv) { ...@@ -1171,12 +1171,12 @@ int sdsTest(int argc, char **argv) {
sds x = sdsnew("foo"), y; sds x = sdsnew("foo"), y;
test_cond("Create a string and obtain the length", test_cond("Create a string and obtain the length",
sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0);
sdsfree(x); sdsfree(x);
x = sdsnewlen("foo",2); x = sdsnewlen("foo",2);
test_cond("Create a string with specified length", test_cond("Create a string with specified length",
sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0);
x = sdscat(x,"bar"); x = sdscat(x,"bar");
test_cond("Strings concatenation", test_cond("Strings concatenation",
...@@ -1184,22 +1184,22 @@ int sdsTest(int argc, char **argv) { ...@@ -1184,22 +1184,22 @@ int sdsTest(int argc, char **argv) {
x = sdscpy(x,"a"); x = sdscpy(x,"a");
test_cond("sdscpy() against an originally longer string", test_cond("sdscpy() against an originally longer string",
sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) sdslen(x) == 1 && memcmp(x,"a\0",2) == 0);
x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
test_cond("sdscpy() against an originally shorter string", test_cond("sdscpy() against an originally shorter string",
sdslen(x) == 33 && sdslen(x) == 33 &&
memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0);
sdsfree(x); sdsfree(x);
x = sdscatprintf(sdsempty(),"%d",123); x = sdscatprintf(sdsempty(),"%d",123);
test_cond("sdscatprintf() seems working in the base case", test_cond("sdscatprintf() seems working in the base case",
sdslen(x) == 3 && memcmp(x,"123\0",4) == 0) sdslen(x) == 3 && memcmp(x,"123\0",4) == 0);
sdsfree(x); sdsfree(x);
x = sdscatprintf(sdsempty(),"a%cb",0); x = sdscatprintf(sdsempty(),"a%cb",0);
test_cond("sdscatprintf() seems working with \\0 inside of result", test_cond("sdscatprintf() seems working with \\0 inside of result",
sdslen(x) == 3 && memcmp(x,"a\0""b\0",4) == 0) sdslen(x) == 3 && memcmp(x,"a\0""b\0",4) == 0);
{ {
sdsfree(x); sdsfree(x);
...@@ -1209,7 +1209,7 @@ int sdsTest(int argc, char **argv) { ...@@ -1209,7 +1209,7 @@ int sdsTest(int argc, char **argv) {
} }
x = sdscatprintf(sdsempty(),"%0*d",(int)sizeof(etalon),0); x = sdscatprintf(sdsempty(),"%0*d",(int)sizeof(etalon),0);
test_cond("sdscatprintf() can print 1MB", test_cond("sdscatprintf() can print 1MB",
sdslen(x) == sizeof(etalon) && memcmp(x,etalon,sizeof(etalon)) == 0) sdslen(x) == sizeof(etalon) && memcmp(x,etalon,sizeof(etalon)) == 0);
} }
sdsfree(x); sdsfree(x);
...@@ -1218,7 +1218,7 @@ int sdsTest(int argc, char **argv) { ...@@ -1218,7 +1218,7 @@ int sdsTest(int argc, char **argv) {
test_cond("sdscatfmt() seems working in the base case", test_cond("sdscatfmt() seems working in the base case",
sdslen(x) == 60 && sdslen(x) == 60 &&
memcmp(x,"--Hello Hi! World -9223372036854775808," memcmp(x,"--Hello Hi! World -9223372036854775808,"
"9223372036854775807--",60) == 0) "9223372036854775807--",60) == 0);
printf("[%s]\n",x); printf("[%s]\n",x);
sdsfree(x); sdsfree(x);
...@@ -1226,85 +1226,85 @@ int sdsTest(int argc, char **argv) { ...@@ -1226,85 +1226,85 @@ int sdsTest(int argc, char **argv) {
x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX); x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
test_cond("sdscatfmt() seems working with unsigned numbers", test_cond("sdscatfmt() seems working with unsigned numbers",
sdslen(x) == 35 && sdslen(x) == 35 &&
memcmp(x,"--4294967295,18446744073709551615--",35) == 0) memcmp(x,"--4294967295,18446744073709551615--",35) == 0);
sdsfree(x); sdsfree(x);
x = sdsnew(" x "); x = sdsnew(" x ");
sdstrim(x," x"); sdstrim(x," x");
test_cond("sdstrim() works when all chars match", test_cond("sdstrim() works when all chars match",
sdslen(x) == 0) sdslen(x) == 0);
sdsfree(x); sdsfree(x);
x = sdsnew(" x "); x = sdsnew(" x ");
sdstrim(x," "); sdstrim(x," ");
test_cond("sdstrim() works when a single char remains", test_cond("sdstrim() works when a single char remains",
sdslen(x) == 1 && x[0] == 'x') sdslen(x) == 1 && x[0] == 'x');
sdsfree(x); sdsfree(x);
x = sdsnew("xxciaoyyy"); x = sdsnew("xxciaoyyy");
sdstrim(x,"xy"); sdstrim(x,"xy");
test_cond("sdstrim() correctly trims characters", test_cond("sdstrim() correctly trims characters",
sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0);
y = sdsdup(x); y = sdsdup(x);
sdsrange(y,1,1); sdsrange(y,1,1);
test_cond("sdsrange(...,1,1)", test_cond("sdsrange(...,1,1)",
sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) sdslen(y) == 1 && memcmp(y,"i\0",2) == 0);
sdsfree(y); sdsfree(y);
y = sdsdup(x); y = sdsdup(x);
sdsrange(y,1,-1); sdsrange(y,1,-1);
test_cond("sdsrange(...,1,-1)", test_cond("sdsrange(...,1,-1)",
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0);
sdsfree(y); sdsfree(y);
y = sdsdup(x); y = sdsdup(x);
sdsrange(y,-2,-1); sdsrange(y,-2,-1);
test_cond("sdsrange(...,-2,-1)", test_cond("sdsrange(...,-2,-1)",
sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0);
sdsfree(y); sdsfree(y);
y = sdsdup(x); y = sdsdup(x);
sdsrange(y,2,1); sdsrange(y,2,1);
test_cond("sdsrange(...,2,1)", test_cond("sdsrange(...,2,1)",
sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdslen(y) == 0 && memcmp(y,"\0",1) == 0);
sdsfree(y); sdsfree(y);
y = sdsdup(x); y = sdsdup(x);
sdsrange(y,1,100); sdsrange(y,1,100);
test_cond("sdsrange(...,1,100)", test_cond("sdsrange(...,1,100)",
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0);
sdsfree(y); sdsfree(y);
y = sdsdup(x); y = sdsdup(x);
sdsrange(y,100,100); sdsrange(y,100,100);
test_cond("sdsrange(...,100,100)", test_cond("sdsrange(...,100,100)",
sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdslen(y) == 0 && memcmp(y,"\0",1) == 0);
sdsfree(y); sdsfree(y);
sdsfree(x); sdsfree(x);
x = sdsnew("foo"); x = sdsnew("foo");
y = sdsnew("foa"); y = sdsnew("foa");
test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0);
sdsfree(y); sdsfree(y);
sdsfree(x); sdsfree(x);
x = sdsnew("bar"); x = sdsnew("bar");
y = sdsnew("bar"); y = sdsnew("bar");
test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0);
sdsfree(y); sdsfree(y);
sdsfree(x); sdsfree(x);
x = sdsnew("aar"); x = sdsnew("aar");
y = sdsnew("bar"); y = sdsnew("bar");
test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0);
sdsfree(y); sdsfree(y);
sdsfree(x); sdsfree(x);
x = sdsnewlen("\a\n\0foo\r",7); x = sdsnewlen("\a\n\0foo\r",7);
y = sdscatrepr(sdsempty(),x,sdslen(x)); y = sdscatrepr(sdsempty(),x,sdslen(x));
test_cond("sdscatrepr(...data...)", test_cond("sdscatrepr(...data...)",
memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0);
{ {
unsigned int oldfree; unsigned int oldfree;
...@@ -1343,7 +1343,7 @@ int sdsTest(int argc, char **argv) { ...@@ -1343,7 +1343,7 @@ int sdsTest(int argc, char **argv) {
sdsfree(x); sdsfree(x);
} }
} }
test_report() test_report();
return 0; return 0;
} }
#endif #endif
...@@ -469,7 +469,7 @@ struct redisCommand sentinelcmds[] = { ...@@ -469,7 +469,7 @@ struct redisCommand sentinelcmds[] = {
{"client",clientCommand,-2,"admin random @connection",0,NULL,0,0,0,0,0}, {"client",clientCommand,-2,"admin random @connection",0,NULL,0,0,0,0,0},
{"shutdown",shutdownCommand,-1,"admin",0,NULL,0,0,0,0,0}, {"shutdown",shutdownCommand,-1,"admin",0,NULL,0,0,0,0,0},
{"auth",authCommand,-2,"no-auth fast @connection",0,NULL,0,0,0,0,0}, {"auth",authCommand,-2,"no-auth fast @connection",0,NULL,0,0,0,0,0},
{"hello",helloCommand,-2,"no-auth fast @connection",0,NULL,0,0,0,0,0}, {"hello",helloCommand,-1,"no-auth fast @connection",0,NULL,0,0,0,0,0},
{"acl",aclCommand,-2,"admin",0,NULL,0,0,0,0,0,0}, {"acl",aclCommand,-2,"admin",0,NULL,0,0,0,0,0,0},
{"command",commandCommand,-1, "random @connection", 0,NULL,0,0,0,0,0,0} {"command",commandCommand,-1, "random @connection", 0,NULL,0,0,0,0,0,0}
}; };
...@@ -3090,25 +3090,45 @@ int sentinelIsQuorumReachable(sentinelRedisInstance *master, int *usableptr) { ...@@ -3090,25 +3090,45 @@ int sentinelIsQuorumReachable(sentinelRedisInstance *master, int *usableptr) {
void sentinelCommand(client *c) { void sentinelCommand(client *c) {
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) { if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
const char *help[] = { const char *help[] = {
"MASTERS -- Show a list of monitored masters and their state.", "CKQUORUM <master-name>",
"MASTER <master-name> -- Show the state and info of the specified master.", " Check if the current Sentinel configuration is able to reach the quorum",
"REPLICAS <master-name> -- Show a list of replicas for this master and their state.", " needed to failover a master and the majority needed to authorize the",
"SENTINELS <master-name> -- Show a list of Sentinel instances for this master and their state.", " failover.",
"MYID -- Show Current Sentinel Id", "GET-MASTER-ADDR-BY-NAME <master-name>",
"IS-MASTER-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid> -- Check if the master specified by ip:port is down from current Sentinel's point of view.", " Return the ip and port number of the master with that name.",
"GET-MASTER-ADDR-BY-NAME <master-name> -- Return the ip and port number of the master with that name.", "FAILOVER <master-name>",
"RESET <pattern> -- Reset masters for specific master name matching this pattern.", " Manually failover a master node without asking for agreement from other",
"FAILOVER <master-name> -- Manually failover a master node without asking for agreement from other Sentinels", " Sentinels",
"PENDING-SCRIPTS -- Get pending scripts information.", "FLUSHCONFIG",
"MONITOR <name> <ip> <port> <quorum> -- Start monitoring a new master with the specified name, ip, port and quorum.", " Force Sentinel to rewrite its configuration on disk, including the current",
"FLUSHCONFIG -- Force Sentinel to rewrite its configuration on disk, including the current Sentinel state.", " Sentinel state.",
"REMOVE <master-name> -- Remove master from Sentinel's monitor list.", "INFO-CACHE <master-name>",
"CKQUORUM <master-name> -- Check if the current Sentinel configuration is able to reach the quorum needed to failover a master " " Return last cached INFO output from masters and all its replicas.",
"and the majority needed to authorize the failover.", "IS-MASTER-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid>",
"SET <master-name> <option> <value> -- Set configuration paramters for certain masters.", " Check if the master specified by ip:port is down from current Sentinel's",
"INFO-CACHE <master-name> -- Return last cached INFO output from masters and all its replicas.", " point of view.",
"SIMULATE-FAILURE (crash-after-election|crash-after-promotion|help) -- Simulate a Sentinel crash.", "MASTER <master-name>",
"HELP -- Prints this help.", " Show the state and info of the specified master.",
"MASTERS",
" Show a list of monitored masters and their state.",
"MONITOR <name> <ip> <port> <quorum>",
" Start monitoring a new master with the specified name, ip, port and quorum.",
"MYID",
" Return the ID of the Sentinel instance.",
"PENDING-SCRIPTS",
" Get pending scripts information.",
"REMOVE <master-name>",
" Remove master from Sentinel's monitor list.",
"REPLICAS <master-name>",
" Show a list of replicas for this master and their state.",
"RESET <pattern>",
" Reset masters for specific master name matching this pattern.",
"SENTINELS <master-name>",
" Show a list of Sentinel instances for this master and their state.",
"SET <master-name> <option> <value>",
" Set configuration paramters for certain masters.",
"SIMULATE-FAILURE (CRASH-AFTER-ELECTION|CRASH-AFTER-PROMOTION|HELP)",
" Simulate a Sentinel crash.",
NULL NULL
}; };
addReplyHelp(c, help); addReplyHelp(c, help);
...@@ -3446,7 +3466,7 @@ numargserr: ...@@ -3446,7 +3466,7 @@ numargserr:
/* SENTINEL INFO [section] */ /* SENTINEL INFO [section] */
void sentinelInfoCommand(client *c) { void sentinelInfoCommand(client *c) {
if (c->argc > 2) { if (c->argc > 2) {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
return; return;
} }
...@@ -3579,14 +3599,13 @@ void sentinelSetCommand(client *c) { ...@@ -3579,14 +3599,13 @@ void sentinelSetCommand(client *c) {
"Reconfiguration of scripts path is denied for " "Reconfiguration of scripts path is denied for "
"security reasons. Check the deny-scripts-reconfig " "security reasons. Check the deny-scripts-reconfig "
"configuration directive in your Sentinel configuration"); "configuration directive in your Sentinel configuration");
return; goto seterr;
} }
if (strlen(value) && access(value,X_OK) == -1) { if (strlen(value) && access(value,X_OK) == -1) {
addReplyError(c, addReplyError(c,
"Notification script seems non existing or non executable"); "Notification script seems non existing or non executable");
if (changes) sentinelFlushConfig(); goto seterr;
return;
} }
sdsfree(ri->notification_script); sdsfree(ri->notification_script);
ri->notification_script = strlen(value) ? sdsnew(value) : NULL; ri->notification_script = strlen(value) ? sdsnew(value) : NULL;
...@@ -3599,15 +3618,14 @@ void sentinelSetCommand(client *c) { ...@@ -3599,15 +3618,14 @@ void sentinelSetCommand(client *c) {
"Reconfiguration of scripts path is denied for " "Reconfiguration of scripts path is denied for "
"security reasons. Check the deny-scripts-reconfig " "security reasons. Check the deny-scripts-reconfig "
"configuration directive in your Sentinel configuration"); "configuration directive in your Sentinel configuration");
return; goto seterr;
} }
if (strlen(value) && access(value,X_OK) == -1) { if (strlen(value) && access(value,X_OK) == -1) {
addReplyError(c, addReplyError(c,
"Client reconfiguration script seems non existing or " "Client reconfiguration script seems non existing or "
"non executable"); "non executable");
if (changes) sentinelFlushConfig(); goto seterr;
return;
} }
sdsfree(ri->client_reconfig_script); sdsfree(ri->client_reconfig_script);
ri->client_reconfig_script = strlen(value) ? sdsnew(value) : NULL; ri->client_reconfig_script = strlen(value) ? sdsnew(value) : NULL;
...@@ -3657,8 +3675,7 @@ void sentinelSetCommand(client *c) { ...@@ -3657,8 +3675,7 @@ void sentinelSetCommand(client *c) {
} else { } else {
addReplyErrorFormat(c,"Unknown option or number of arguments for " addReplyErrorFormat(c,"Unknown option or number of arguments for "
"SENTINEL SET '%s'", option); "SENTINEL SET '%s'", option);
if (changes) sentinelFlushConfig(); goto seterr;
return;
} }
/* Log the event. */ /* Log the event. */
...@@ -3684,9 +3701,11 @@ void sentinelSetCommand(client *c) { ...@@ -3684,9 +3701,11 @@ void sentinelSetCommand(client *c) {
return; return;
badfmt: /* Bad format errors */ badfmt: /* Bad format errors */
if (changes) sentinelFlushConfig();
addReplyErrorFormat(c,"Invalid argument '%s' for SENTINEL SET '%s'", addReplyErrorFormat(c,"Invalid argument '%s' for SENTINEL SET '%s'",
(char*)c->argv[badarg]->ptr,option); (char*)c->argv[badarg]->ptr,option);
seterr:
if (changes) sentinelFlushConfig();
return;
} }
/* Our fake PUBLISH command: it is actually useful only to receive hello messages /* Our fake PUBLISH command: it is actually useful only to receive hello messages
......
This diff is collapsed.
This diff is collapsed.
...@@ -142,11 +142,15 @@ void slowlogReset(void) { ...@@ -142,11 +142,15 @@ void slowlogReset(void) {
void slowlogCommand(client *c) { void slowlogCommand(client *c) {
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) { if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
const char *help[] = { const char *help[] = {
"GET [count] -- Return top entries from the slowlog (default: 10)." "GET [<count>]",
" Entries are made of:", " Return top <count> entries from the slowlog (default: 10). Entries are",
" id, timestamp, time in microseconds, arguments array, client IP and port, client name", " made of:",
"LEN -- Return the length of the slowlog.", " id, timestamp, time in microseconds, arguments array, client IP and port,",
"RESET -- Reset the slowlog.", " client name",
"LEN",
" Return the length of the slowlog.",
"RESET",
" Reset the slowlog.",
NULL NULL
}; };
addReplyHelp(c, help); addReplyHelp(c, help);
......
...@@ -256,7 +256,7 @@ void sortCommand(client *c) { ...@@ -256,7 +256,7 @@ void sortCommand(client *c) {
getop++; getop++;
j++; j++;
} else { } else {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
syntax_error++; syntax_error++;
break; break;
} }
...@@ -270,7 +270,7 @@ void sortCommand(client *c) { ...@@ -270,7 +270,7 @@ void sortCommand(client *c) {
} }
/* Lookup the key to sort. It must be of the right types */ /* Lookup the key to sort. It must be of the right types */
if (storekey) if (!storekey)
sortval = lookupKeyRead(c->db,c->argv[1]); sortval = lookupKeyRead(c->db,c->argv[1]);
else else
sortval = lookupKeyWrite(c->db,c->argv[1]); sortval = lookupKeyWrite(c->db,c->argv[1]);
...@@ -279,7 +279,7 @@ void sortCommand(client *c) { ...@@ -279,7 +279,7 @@ void sortCommand(client *c) {
sortval->type != OBJ_ZSET) sortval->type != OBJ_ZSET)
{ {
listRelease(operations); listRelease(operations);
addReply(c,shared.wrongtypeerr); addReplyErrorObject(c,shared.wrongtypeerr);
return; return;
} }
......
...@@ -644,7 +644,7 @@ void hsetCommand(client *c) { ...@@ -644,7 +644,7 @@ void hsetCommand(client *c) {
} }
signalModifiedKey(c,c->db,c->argv[1]); signalModifiedKey(c,c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id); notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id);
server.dirty++; server.dirty += (c->argc - 2)/2;
} }
void hincrbyCommand(client *c) { void hincrbyCommand(client *c) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment