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++;
} }
...@@ -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.
...@@ -476,7 +476,7 @@ void spopWithCountCommand(client *c) { ...@@ -476,7 +476,7 @@ void spopWithCountCommand(client *c) {
/* Generate an SPOP keyspace notification */ /* Generate an SPOP keyspace notification */
notifyKeyspaceEvent(NOTIFY_SET,"spop",c->argv[1],c->db->id); notifyKeyspaceEvent(NOTIFY_SET,"spop",c->argv[1],c->db->id);
server.dirty += count; server.dirty += (count >= size) ? size : count;
/* CASE 1: /* CASE 1:
* The number of requested elements is greater than or equal to * The number of requested elements is greater than or equal to
...@@ -492,7 +492,6 @@ void spopWithCountCommand(client *c) { ...@@ -492,7 +492,6 @@ void spopWithCountCommand(client *c) {
/* Propagate this command as a DEL operation */ /* Propagate this command as a DEL operation */
rewriteClientCommandVector(c,2,shared.del,c->argv[1]); rewriteClientCommandVector(c,2,shared.del,c->argv[1]);
signalModifiedKey(c,c->db,c->argv[1]); signalModifiedKey(c,c->db,c->argv[1]);
server.dirty++;
return; return;
} }
...@@ -594,7 +593,6 @@ void spopWithCountCommand(client *c) { ...@@ -594,7 +593,6 @@ void spopWithCountCommand(client *c) {
decrRefCount(propargv[0]); decrRefCount(propargv[0]);
preventCommandPropagation(c); preventCommandPropagation(c);
signalModifiedKey(c,c->db,c->argv[1]); signalModifiedKey(c,c->db,c->argv[1]);
server.dirty++;
} }
void spopCommand(client *c) { void spopCommand(client *c) {
...@@ -607,7 +605,7 @@ void spopCommand(client *c) { ...@@ -607,7 +605,7 @@ void spopCommand(client *c) {
spopWithCountCommand(c); spopWithCountCommand(c);
return; return;
} else if (c->argc > 3) { } else if (c->argc > 3) {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
return; return;
} }
...@@ -803,7 +801,7 @@ void srandmemberCommand(client *c) { ...@@ -803,7 +801,7 @@ void srandmemberCommand(client *c) {
srandmemberWithCountCommand(c); srandmemberWithCountCommand(c);
return; return;
} else if (c->argc > 3) { } else if (c->argc > 3) {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
return; return;
} }
......
This diff is collapsed.
...@@ -153,7 +153,7 @@ void setCommand(client *c) { ...@@ -153,7 +153,7 @@ void setCommand(client *c) {
expire = next; expire = next;
j++; j++;
} else { } else {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
return; return;
} }
} }
...@@ -528,7 +528,7 @@ void stralgoCommand(client *c) { ...@@ -528,7 +528,7 @@ void stralgoCommand(client *c) {
if (!strcasecmp(c->argv[1]->ptr,"lcs")) { if (!strcasecmp(c->argv[1]->ptr,"lcs")) {
stralgoLCS(c); stralgoLCS(c);
} else { } else {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
} }
} }
...@@ -589,7 +589,7 @@ void stralgoLCS(client *c) { ...@@ -589,7 +589,7 @@ void stralgoLCS(client *c) {
b = objb->ptr; b = objb->ptr;
j += 2; j += 2;
} else { } else {
addReply(c,shared.syntaxerr); addReplyErrorObject(c,shared.syntaxerr);
goto cleanup; goto cleanup;
} }
} }
......
This diff is collapsed.
...@@ -44,7 +44,7 @@ int __test_num = 0; ...@@ -44,7 +44,7 @@ int __test_num = 0;
#define test_cond(descr,_c) do { \ #define test_cond(descr,_c) do { \
__test_num++; printf("%d - %s: ", __test_num, descr); \ __test_num++; printf("%d - %s: ", __test_num, descr); \
if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \ if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \
} while(0); } while(0)
#define test_report() do { \ #define test_report() do { \
printf("%d tests, %d passed, %d failed\n", __test_num, \ printf("%d tests, %d passed, %d failed\n", __test_num, \
__test_num-__failed_tests, __failed_tests); \ __test_num-__failed_tests, __failed_tests); \
...@@ -52,6 +52,6 @@ int __test_num = 0; ...@@ -52,6 +52,6 @@ int __test_num = 0;
printf("=== WARNING === We have failed tests here...\n"); \ printf("=== WARNING === We have failed tests here...\n"); \
exit(1); \ exit(1); \
} \ } \
} while(0); } while(0)
#endif #endif
...@@ -99,6 +99,57 @@ void disableTracking(client *c) { ...@@ -99,6 +99,57 @@ void disableTracking(client *c) {
} }
} }
static int stringCheckPrefix(unsigned char *s1, size_t s1_len, unsigned char *s2, size_t s2_len) {
size_t min_length = s1_len < s2_len ? s1_len : s2_len;
return memcmp(s1,s2,min_length) == 0;
}
/* Check if any of the provided prefixes collide with one another or
* with an existing prefix for the client. A collision is defined as two
* prefixes that will emit an invalidation for the same key. If no prefix
* collision is found, 1 is return, otherwise 0 is returned and the client
* has an error emitted describing the error. */
int checkPrefixCollisionsOrReply(client *c, robj **prefixes, size_t numprefix) {
for (size_t i = 0; i < numprefix; i++) {
/* Check input list has no overlap with existing prefixes. */
if (c->client_tracking_prefixes) {
raxIterator ri;
raxStart(&ri,c->client_tracking_prefixes);
raxSeek(&ri,"^",NULL,0);
while(raxNext(&ri)) {
if (stringCheckPrefix(ri.key,ri.key_len,
prefixes[i]->ptr,sdslen(prefixes[i]->ptr)))
{
sds collision = sdsnewlen(ri.key,ri.key_len);
addReplyErrorFormat(c,
"Prefix '%s' overlaps with an existing prefix '%s'. "
"Prefixes for a single client must not overlap.",
(unsigned char *)prefixes[i]->ptr,
(unsigned char *)collision);
sdsfree(collision);
raxStop(&ri);
return 0;
}
}
raxStop(&ri);
}
/* Check input has no overlap with itself. */
for (size_t j = i + 1; j < numprefix; j++) {
if (stringCheckPrefix(prefixes[i]->ptr,sdslen(prefixes[i]->ptr),
prefixes[j]->ptr,sdslen(prefixes[j]->ptr)))
{
addReplyErrorFormat(c,
"Prefix '%s' overlaps with another provided prefix '%s'. "
"Prefixes for a single client must not overlap.",
(unsigned char *)prefixes[i]->ptr,
(unsigned char *)prefixes[j]->ptr);
return i;
}
}
}
return -1;
}
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is /* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
* already registered for the specified prefix, no operation is performed. */ * already registered for the specified prefix, no operation is performed. */
void enableBcastTrackingForPrefix(client *c, char *prefix, size_t plen) { void enableBcastTrackingForPrefix(client *c, char *prefix, size_t plen) {
...@@ -350,19 +401,22 @@ void trackingInvalidateKey(client *c, robj *keyobj) { ...@@ -350,19 +401,22 @@ void trackingInvalidateKey(client *c, robj *keyobj) {
} }
/* This function is called when one or all the Redis databases are /* This function is called when one or all the Redis databases are
* flushed (dbid == -1 in case of FLUSHALL). Caching keys are not * flushed. Caching keys are not specific for each DB but are global:
* specific for each DB but are global: currently what we do is send a * currently what we do is send a special notification to clients with
* special notification to clients with tracking enabled, sending a * tracking enabled, sending a RESP NULL, which means, "all the keys",
* RESP NULL, which means, "all the keys", in order to avoid flooding * in order to avoid flooding clients with many invalidation messages
* clients with many invalidation messages for all the keys they may * for all the keys they may hold.
* hold.
*/ */
void freeTrackingRadixTree(void *rt) { void freeTrackingRadixTreeCallback(void *rt) {
raxFree(rt); raxFree(rt);
} }
void freeTrackingRadixTree(rax *rt) {
raxFreeWithCallback(rt,freeTrackingRadixTreeCallback);
}
/* A RESP NULL is sent to indicate that all keys are invalid */ /* A RESP NULL is sent to indicate that all keys are invalid */
void trackingInvalidateKeysOnFlush(int dbid) { void trackingInvalidateKeysOnFlush(int async) {
if (server.tracking_clients) { if (server.tracking_clients) {
listNode *ln; listNode *ln;
listIter li; listIter li;
...@@ -376,8 +430,12 @@ void trackingInvalidateKeysOnFlush(int dbid) { ...@@ -376,8 +430,12 @@ void trackingInvalidateKeysOnFlush(int dbid) {
} }
/* In case of FLUSHALL, reclaim all the memory used by tracking. */ /* In case of FLUSHALL, reclaim all the memory used by tracking. */
if (dbid == -1 && TrackingTable) { if (TrackingTable) {
raxFreeWithCallback(TrackingTable,freeTrackingRadixTree); if (async) {
freeTrackingRadixTreeAsync(TrackingTable);
} else {
freeTrackingRadixTree(TrackingTable);
}
TrackingTable = raxNew(); TrackingTable = raxNew();
TrackingTableTotalItems = 0; TrackingTableTotalItems = 0;
} }
......
...@@ -431,19 +431,21 @@ unsigned int zipStoreEntryEncoding(unsigned char *p, unsigned char encoding, uns ...@@ -431,19 +431,21 @@ unsigned int zipStoreEntryEncoding(unsigned char *p, unsigned char encoding, uns
/* Encode the length of the previous entry and write it to "p". This only /* Encode the length of the previous entry and write it to "p". This only
* uses the larger encoding (required in __ziplistCascadeUpdate). */ * uses the larger encoding (required in __ziplistCascadeUpdate). */
int zipStorePrevEntryLengthLarge(unsigned char *p, unsigned int len) { int zipStorePrevEntryLengthLarge(unsigned char *p, unsigned int len) {
uint32_t u32;
if (p != NULL) { if (p != NULL) {
p[0] = ZIP_BIG_PREVLEN; p[0] = ZIP_BIG_PREVLEN;
memcpy(p+1,&len,sizeof(len)); u32 = len;
memcpy(p+1,&u32,sizeof(u32));
memrev32ifbe(p+1); memrev32ifbe(p+1);
} }
return 1+sizeof(len); return 1 + sizeof(uint32_t);
} }
/* Encode the length of the previous entry and write it to "p". Return the /* Encode the length of the previous entry and write it to "p". Return the
* number of bytes needed to encode this length if "p" is NULL. */ * number of bytes needed to encode this length if "p" is NULL. */
unsigned int zipStorePrevEntryLength(unsigned char *p, unsigned int len) { unsigned int zipStorePrevEntryLength(unsigned char *p, unsigned int len) {
if (p == NULL) { if (p == NULL) {
return (len < ZIP_BIG_PREVLEN) ? 1 : sizeof(len)+1; return (len < ZIP_BIG_PREVLEN) ? 1 : sizeof(uint32_t) + 1;
} else { } else {
if (len < ZIP_BIG_PREVLEN) { if (len < ZIP_BIG_PREVLEN) {
p[0] = len; p[0] = len;
...@@ -1711,7 +1713,7 @@ int ziplistTest(int argc, char **argv) { ...@@ -1711,7 +1713,7 @@ int ziplistTest(int argc, char **argv) {
if (p == NULL) { if (p == NULL) {
printf("No entry\n"); printf("No entry\n");
} else { } else {
printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl); printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", (long)(p-zl));
return 1; return 1;
} }
printf("\n"); printf("\n");
...@@ -1761,7 +1763,7 @@ int ziplistTest(int argc, char **argv) { ...@@ -1761,7 +1763,7 @@ int ziplistTest(int argc, char **argv) {
if (p == NULL) { if (p == NULL) {
printf("No entry\n"); printf("No entry\n");
} else { } else {
printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl); printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", (long)(p-zl));
return 1; return 1;
} }
printf("\n"); printf("\n");
......
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