Commit b34fc03e authored by Oran Agra's avatar Oran Agra
Browse files

Merge unstable into 6.2

parents b8c67ce4 4f8458d8
...@@ -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++;
} }
...@@ -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.
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