diff options
author | Yossi Gottlieb <yossigo@gmail.com> | 2013-01-27 09:49:15 +0200 |
---|---|---|
committer | Yossi Gottlieb <yossigo@gmail.com> | 2013-01-27 09:49:15 +0200 |
commit | acb73e8a972adadd31450dca9ab8cf74cc82a029 (patch) | |
tree | ccd1ca55a85aec0af719c8ed1012f13883cd6c15 | |
parent | d195e8bb8225bae62b8a714b9c02a472bc601e2f (diff) | |
parent | c17a7f6fbc82dc6ab34a788f65adc16e84b5777c (diff) | |
download | redis-2.6.9-1.tar.gz |
Merge upstream Redis 2.6.9.2.6.9-1
46 files changed, 512 insertions, 225 deletions
diff --git a/00-RELEASENOTES b/00-RELEASENOTES index 5471baa3f..2c5010660 100644 --- a/00-RELEASENOTES +++ b/00-RELEASENOTES @@ -14,6 +14,20 @@ HIGH: There is a critical bug that may affect a subset of users. Upgrade! CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP. -------------------------------------------------------------------------------- +--[ Redis 2.6.9 ] + +UPGRADE URGENCY: MODERATE if you use replication. + +* [BUGFIX] Changing master at runtime (SLAVEOF command) in presence of + network problems, or in very rapid succession, could result + in non-critical problems (GitHub Issue #828). +* [IMPROVED] CLINGET GETNAME and SETNAME to set and query connection names + reported by CLIENT LIST. Very useful for debugging of + problems. +* [IMPROVED] redis-cli is now able to transfer an RDB file from a remote + server to a local file using the --rdb <filename> command + line option. + --[ Redis 2.6.8 ] UPGRADE URGENCY: MODERATE if you use Lua scripting. Otherwise LOW. diff --git a/deps/lua/src/lua_struct.c b/deps/lua/src/lua_struct.c index 6807c8387..ec78bcbc0 100644 --- a/deps/lua/src/lua_struct.c +++ b/deps/lua/src/lua_struct.c @@ -1,18 +1,7 @@ - -#include <assert.h> -#include <ctype.h> -#include <limits.h> -#include <string.h> - - -#include "lua.h" -#include "lauxlib.h" - - /* ** {====================================================== ** Library for packing/unpacking structures. -** $Id: struct.c,v 1.2 2008/04/18 20:06:01 roberto Exp $ +** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $ ** See Copyright Notice at the end of this file ** ======================================================= */ @@ -25,6 +14,7 @@ ** b/B - signed/unsigned byte ** h/H - signed/unsigned short ** l/L - signed/unsigned long +** T - size_t ** i/In - signed/unsigned integer with size `n' (default is size of int) ** cn - sequence of `n' chars (from/to a string); when packing, n==0 means the whole string; when unpacking, n==0 means use the previous @@ -36,6 +26,38 @@ */ +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <stddef.h> +#include <string.h> + + +#include "lua.h" +#include "lauxlib.h" + + +#if (LUA_VERSION_NUM >= 502) + +#define luaL_register(L,n,f) luaL_newlib(L,f) + +#endif + + +/* basic integer type */ +#if !defined(STRUCT_INT) +#define STRUCT_INT long +#endif + +typedef STRUCT_INT Inttype; + +/* corresponding unsigned version */ +typedef unsigned STRUCT_INT Uinttype; + + +/* maximum size (in bytes) for integral types */ +#define MAXINTSIZE 32 + /* is 'x' a power of 2? */ #define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0) @@ -67,11 +89,11 @@ typedef struct Header { } Header; -static size_t getnum (const char **fmt, size_t df) { +static int getnum (const char **fmt, int df) { if (!isdigit(**fmt)) /* no number? */ return df; /* return default value */ else { - size_t a = 0; + int a = 0; do { a = a*10 + *((*fmt)++) - '0'; } while (isdigit(**fmt)); @@ -89,33 +111,40 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) { case 'B': case 'b': return sizeof(char); case 'H': case 'h': return sizeof(short); case 'L': case 'l': return sizeof(long); + case 'T': return sizeof(size_t); case 'f': return sizeof(float); case 'd': return sizeof(double); case 'x': return 1; case 'c': return getnum(fmt, 1); - case 's': case ' ': case '<': case '>': case '!': return 0; case 'i': case 'I': { int sz = getnum(fmt, sizeof(int)); - if (!isp2(sz)) - luaL_error(L, "integral size %d is not a power of 2", sz); + if (sz > MAXINTSIZE) + luaL_error(L, "integral size %d is larger than limit of %d", + sz, MAXINTSIZE); return sz; } - default: { - const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt); - return luaL_argerror(L, 1, msg); - } + default: return 0; /* other cases do not need alignment */ } } +/* +** return number of bytes needed to align an element of size 'size' +** at current position 'len' +*/ static int gettoalign (size_t len, Header *h, int opt, size_t size) { if (size == 0 || opt == 'c') return 0; - if (size > (size_t)h->align) size = h->align; /* respect max. alignment */ - return (size - (len & (size - 1))) & (size - 1); + if (size > (size_t)h->align) + size = h->align; /* respect max. alignment */ + return (size - (len & (size - 1))) & (size - 1); } -static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) { +/* +** options to control endianess and alignment +*/ +static void controloptions (lua_State *L, int opt, const char **fmt, + Header *h) { switch (opt) { case ' ': return; /* ignore white spaces */ case '>': h->endian = BIG; return; @@ -127,7 +156,10 @@ static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) { h->align = a; return; } - default: assert(0); + default: { + const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt); + luaL_argerror(L, 1, msg); + } } } @@ -135,21 +167,27 @@ static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) { static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian, int size) { lua_Number n = luaL_checknumber(L, arg); - unsigned long value; - if (n < (lua_Number)LONG_MAX) - value = (long)n; + Uinttype value; + char buff[MAXINTSIZE]; + if (n < 0) + value = (Uinttype)(Inttype)n; else - value = (unsigned long)n; + value = (Uinttype)n; if (endian == LITTLE) { int i; - for (i = 0; i < size; i++) - luaL_addchar(b, (value >> 8*i) & 0xff); + for (i = 0; i < size; i++) { + buff[i] = (value & 0xff); + value >>= 8; + } } else { int i; - for (i = size - 1; i >= 0; i--) - luaL_addchar(b, (value >> 8*i) & 0xff); + for (i = size - 1; i >= 0; i--) { + buff[i] = (value & 0xff); + value >>= 8; + } } + luaL_addlstring(b, buff, size); } @@ -179,15 +217,15 @@ static int b_pack (lua_State *L) { size_t size = optsize(L, opt, &fmt); int toalign = gettoalign(totalsize, &h, opt, size); totalsize += toalign; - while (toalign-- > 0) luaL_putchar(&b, '\0'); + while (toalign-- > 0) luaL_addchar(&b, '\0'); switch (opt) { case 'b': case 'B': case 'h': case 'H': - case 'l': case 'L': case 'i': case 'I': { /* integer types */ + case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ putinteger(L, &b, arg++, h.endian, size); break; } case 'x': { - luaL_putchar(&b, '\0'); + luaL_addchar(&b, '\0'); break; } case 'f': { @@ -209,12 +247,12 @@ static int b_pack (lua_State *L) { luaL_argcheck(L, l >= (size_t)size, arg, "string too short"); luaL_addlstring(&b, s, size); if (opt == 's') { - luaL_putchar(&b, '\0'); /* add zero at the end */ + luaL_addchar(&b, '\0'); /* add zero at the end */ size++; } break; } - default: commoncases(L, opt, &fmt, &h); + default: controloptions(L, opt, &fmt, &h); } totalsize += size; } @@ -225,24 +263,27 @@ static int b_pack (lua_State *L) { static lua_Number getinteger (const char *buff, int endian, int issigned, int size) { - unsigned long l = 0; + Uinttype l = 0; + int i; if (endian == BIG) { - int i; - for (i = 0; i < size; i++) - l |= (unsigned long)(unsigned char)buff[size - i - 1] << (i*8); + for (i = 0; i < size; i++) { + l <<= 8; + l |= (Uinttype)(unsigned char)buff[i]; + } } else { - int i; - for (i = 0; i < size; i++) - l |= (unsigned long)(unsigned char)buff[i] << (i*8); + for (i = size - 1; i >= 0; i--) { + l <<= 8; + l |= (Uinttype)(unsigned char)buff[i]; + } } if (!issigned) return (lua_Number)l; else { /* signed format */ - unsigned long mask = ~(0UL) << (size*8 - 1); + Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1); if (l & mask) /* negative value? */ l |= mask; /* signal extension */ - return (lua_Number)(long)l; + return (lua_Number)(Inttype)l; } } @@ -260,9 +301,10 @@ static int b_unpack (lua_State *L) { size_t size = optsize(L, opt, &fmt); pos += gettoalign(pos, &h, opt, size); luaL_argcheck(L, pos+size <= ld, 2, "data string too short"); + luaL_checkstack(L, 1, "too many results"); switch (opt) { case 'b': case 'B': case 'h': case 'H': - case 'l': case 'L': case 'i': case 'I': { /* integer types */ + case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ int issigned = islower(opt); lua_Number res = getinteger(data+pos, h.endian, issigned, size); lua_pushnumber(L, res); @@ -304,7 +346,7 @@ static int b_unpack (lua_State *L) { lua_pushlstring(L, data+pos, size - 1); break; } - default: commoncases(L, opt, &fmt, &h); + default: controloptions(L, opt, &fmt, &h); } pos += size; } @@ -312,26 +354,50 @@ static int b_unpack (lua_State *L) { return lua_gettop(L) - 2; } + +static int b_size (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t pos = 0; + defaultoptions(&h); + while (*fmt) { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + pos += gettoalign(pos, &h, opt, size); + if (opt == 's') + luaL_argerror(L, 1, "option 's' has no fixed size"); + else if (opt == 'c' && size == 0) + luaL_argerror(L, 1, "option 'c0' has no fixed size"); + if (!isalnum(opt)) + controloptions(L, opt, &fmt, &h); + pos += size; + } + lua_pushinteger(L, pos); + return 1; +} + /* }====================================================== */ -static const struct luaL_reg thislib[] = { +static const struct luaL_Reg thislib[] = { {"pack", b_pack}, {"unpack", b_unpack}, + {"size", b_size}, {NULL, NULL} }; +LUALIB_API int luaopen_struct (lua_State *L); + LUALIB_API int luaopen_struct (lua_State *L) { luaL_register(L, "struct", thislib); return 1; } - /****************************************************************************** -* Copyright (C) 2010 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -352,3 +418,4 @@ LUALIB_API int luaopen_struct (lua_State *L) { * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ + diff --git a/redis.conf b/redis.conf index e3531927c..6da381361 100755 --- a/redis.conf +++ b/redis.conf @@ -257,7 +257,7 @@ slave-priority 100 # Set the max number of connected clients at the same time. By default # this limit is set to 10000 clients, however if the Redis server is not -# able ot configure the process file limit to allow for the specified limit +# able to configure the process file limit to allow for the specified limit # the max number of allowed clients is set to the current file limit # minus 32 (as Redis reserves a few file descriptors for internal uses). # diff --git a/sentinel.conf b/sentinel.conf index 94169ee8f..ac687b535 100644 --- a/sentinel.conf +++ b/sentinel.conf @@ -71,7 +71,7 @@ sentinel parallel-syncs mymaster 1 # Default is 15 minutes. sentinel failover-timeout mymaster 900000 -# SCRIPTS EXECTION +# SCRIPTS EXECUTION # # sentinel notification-script and sentinel reconfig-script are used in order # to configure scripts that are called to notify the system administrator diff --git a/src/adlist.c b/src/adlist.c index e48957e3a..f075e1bda 100644 --- a/src/adlist.c +++ b/src/adlist.c @@ -97,7 +97,7 @@ list *listAddNodeHead(list *list, void *value) return list; } -/* Add a new node to the list, to tail, contaning the specified 'value' +/* Add a new node to the list, to tail, containing the specified 'value' * pointer as value. * * On error, NULL is returned and no operation is performed (i.e. the @@ -308,7 +308,7 @@ listNode *listSearchKey(list *list, void *key) /* Return the element at the specified zero-based index * where 0 is the head, 1 is the element next to head * and so on. Negative integers are used in order to count - * from the tail, -1 is the last element, -2 the penultimante + * from the tail, -1 is the last element, -2 the penultimate * and so on. If the index is out of range NULL is returned. */ listNode *listIndex(list *list, long index) { listNode *n; @@ -330,7 +330,7 @@ void listRotate(list *list) { if (listLength(list) <= 1) return; - /* Detatch current tail */ + /* Detach current tail */ list->tail = tail->prev; list->tail->next = NULL; /* Move it as head */ @@ -309,7 +309,7 @@ static int processTimeEvents(aeEventLoop *eventLoop) { /* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * Without special flags the function sleeps until some file event - * fires, or when the next time event occurrs (if any). + * fires, or when the next time event occurs (if any). * * If flags is 0, the function does nothing and returns. * if flags has AE_ALL_EVENTS set, all the kind of events are processed. @@ -356,7 +356,7 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags) if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { /* If we have to check for events but need to return - * ASAP because of AE_DONT_WAIT we need to se the timeout + * ASAP because of AE_DONT_WAIT we need to set the timeout * to zero */ if (flags & AE_DONT_WAIT) { tv.tv_sec = tv.tv_usec = 0; @@ -395,7 +395,7 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags) return processed; /* return the number of processed file/time events */ } -/* Wait for millseconds until the given file descriptor becomes +/* Wait for milliseconds until the given file descriptor becomes * writable/readable/exception */ int aeWait(int fd, int mask, long long milliseconds) { struct pollfd pfd; diff --git a/src/ae_evport.c b/src/ae_evport.c index 0196dccf4..94413c132 100644 --- a/src/ae_evport.c +++ b/src/ae_evport.c @@ -50,15 +50,15 @@ static int evport_debug = 0; * aeApiPoll, the corresponding file descriptors become dissociated from the * port. This is necessary because poll events are level-triggered, so if the * fd didn't become dissociated, it would immediately fire another event since - * the underlying state hasn't changed yet. We must reassociate the file + * the underlying state hasn't changed yet. We must re-associate the file * descriptor, but only after we know that our caller has actually read from it. * The ae API does not tell us exactly when that happens, but we do know that * it must happen by the time aeApiPoll is called again. Our solution is to - * keep track of the last fds returned by aeApiPoll and reassociate them next + * keep track of the last fds returned by aeApiPoll and re-associate them next * time aeApiPoll is invoked. * * To summarize, in this module, each fd association is EITHER (a) represented - * only via the in-kernel assocation OR (b) represented by pending_fds and + * only via the in-kernel association OR (b) represented by pending_fds and * pending_masks. (b) is only true for the last fds we returned from aeApiPoll, * and only until we enter aeApiPoll again (at which point we restore the * in-kernel association). @@ -164,7 +164,7 @@ static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { * This fd was recently returned from aeApiPoll. It should be safe to * assume that the consumer has processed that poll event, but we play * it safer by simply updating pending_mask. The fd will be - * reassociated as usual when aeApiPoll is called again. + * re-associated as usual when aeApiPoll is called again. */ if (evport_debug) fprintf(stderr, "aeApiAddEvent: adding to pending fd %d\n", fd); @@ -228,7 +228,7 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { * ENOMEM is a potentially transient condition, but the kernel won't * generally return it unless things are really bad. EAGAIN indicates * we've reached an resource limit, for which it doesn't make sense to - * retry (counterintuitively). All other errors indicate a bug. In any + * retry (counter-intuitively). All other errors indicate a bug. In any * of these cases, the best we can do is to abort. */ abort(); /* will not return */ @@ -243,7 +243,7 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { port_event_t event[MAX_EVENT_BATCHSZ]; /* - * If we've returned fd events before, we must reassociate them with the + * If we've returned fd events before, we must re-associate them with the * port now, before calling port_get(). See the block comment at the top of * this file for an explanation of why. */ diff --git a/src/anet.c b/src/anet.c index ae8e9a658..4da3e28db 100644 --- a/src/anet.c +++ b/src/anet.c @@ -61,7 +61,7 @@ int anetNonBlock(char *err, int fd) { int flags; - /* Set the socket nonblocking. + /* Set the socket non-blocking. * Note that fcntl(2) for F_GETFL and F_SETFL can't be * interrupted by a signal. */ if ((flags = fcntl(fd, F_GETFL)) == -1) { @@ -132,7 +132,7 @@ static int anetCreateSocket(char *err, int domain) { return ANET_ERR; } - /* Make sure connection-intensive things like the redis benckmark + /* Make sure connection-intensive things like the redis benchmark * will be able to close/open sockets a zillion of times */ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno)); @@ -177,7 +177,7 @@ void stopAppendOnly(void) { redisLog(REDIS_NOTICE,"Killing running AOF rewrite child: %ld", (long) server.aof_child_pid); - if (kill(server.aof_child_pid,SIGKILL) != -1) + if (kill(server.aof_child_pid,SIGUSR1) != -1) wait4(server.aof_child_pid,&statloc,0,NULL); /* reset the buffer accumulating changes while the child saves */ aofRewriteBufferReset(); @@ -385,7 +385,7 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a sds buf = sdsempty(); robj *tmpargv[3]; - /* The DB this command was targetting is not the same as the last command + /* The DB this command was targeting is not the same as the last command * we appendend. To issue a SELECT command is needed. */ if (dictid != server.aof_selected_db) { char seldb[64]; @@ -442,6 +442,7 @@ struct redisClient *createFakeClient(void) { selectDb(c,0); c->fd = -1; + c->name = NULL; c->querybuf = sdsempty(); c->querybuf_peak = 0; c->argc = 0; @@ -73,7 +73,7 @@ static list *bio_jobs[REDIS_BIO_NUM_OPS]; static unsigned long long bio_pending[REDIS_BIO_NUM_OPS]; /* This structure represents a background Job. It is only used locally to this - * file as the API deos not expose the internals at all. */ + * file as the API does not expose the internals at all. */ struct bio_job { time_t time; /* Time at which the job was created. */ /* Job specific arguments pointers. If we need to pass more than three diff --git a/src/bitops.c b/src/bitops.c index 3ef0a8f3d..75f3317a9 100644 --- a/src/bitops.c +++ b/src/bitops.c @@ -34,7 +34,7 @@ * Helpers and low level bit functions. * -------------------------------------------------------------------------- */ -/* This helper function used by GETBIT / SETBIT parses the bit offset arguemnt +/* This helper function used by GETBIT / SETBIT parses the bit offset argument * making sure an error is returned if it is negative or if it overflows * Redis 512 MB limit for the string value. */ static int getBitOffsetFromArgument(redisClient *c, robj *o, size_t *offset) { @@ -189,7 +189,7 @@ void bitopCommand(redisClient *c) { char *opname = c->argv[1]->ptr; robj *o, *targetkey = c->argv[2]; long op, j, numkeys; - robj **objects; /* Array of soruce objects. */ + robj **objects; /* Array of source objects. */ unsigned char **src; /* Array of source strings pointers. */ long *len, maxlen = 0; /* Array of length of src strings, and max len. */ long minlen = 0; /* Min len among the input keys. */ diff --git a/src/config.c b/src/config.c index 43c042698..71157313c 100755 --- a/src/config.c +++ b/src/config.c @@ -348,7 +348,7 @@ void loadServerConfigFromString(char *config) { goto loaderr; } - /* If the target command name is the emtpy string we just + /* If the target command name is the empty string we just * remove it from the command table. */ retval = dictDelete(server.commands, argv[1]); redisAssert(retval == DICT_OK); @@ -386,7 +386,7 @@ void loadServerConfigFromString(char *config) { soft = memtoll(argv[3],NULL); soft_seconds = atoi(argv[4]); if (soft_seconds < 0) { - err = "Negative number of seconds in soft limt is invalid"; + err = "Negative number of seconds in soft limit is invalid"; goto loaderr; } server.client_obuf_limits[class].hard_limit_bytes = hard; @@ -431,7 +431,7 @@ loaderr: * in the 'options' string to the config file before loading. * * Both filename and options can be NULL, in such a case are considered - * emtpy. This way loadServerConfig can be used to just load a file or + * empty. This way loadServerConfig can be used to just load a file or * just load a string. */ void loadServerConfig(char *filename, char *options) { sds config = sdsempty(); diff --git a/src/config.h b/src/config.h index b5c8284a0..c1fcaf6d4 100644 --- a/src/config.h +++ b/src/config.h @@ -54,7 +54,7 @@ #endif /* Test for backtrace() */ -#if defined(__APPLE__) || defined(__linux__) || defined(__sun) +#if defined(__APPLE__) || defined(__linux__) #define HAVE_BACKTRACE 1 #endif @@ -44,7 +44,7 @@ robj *lookupKey(redisDb *db, robj *key) { if (de) { robj *val = dictGetVal(de); - /* Update the access time for the aging algorithm. + /* Update the access time for the ageing algorithm. * Don't do it if we have a saving child, as this will trigger * a copy on write madness. */ if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) @@ -96,7 +96,7 @@ robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) { } /* Add the key to the DB. It's up to the caller to increment the reference - * counte of the value if needed. + * counter of the value if needed. * * The program is aborted if the key already exists. */ void dbAdd(redisDb *db, robj *key, robj *val) { @@ -230,7 +230,7 @@ void flushallCommand(redisClient *c) { server.dirty += emptyDb(); addReply(c,shared.ok); if (server.rdb_child_pid != -1) { - kill(server.rdb_child_pid,SIGKILL); + kill(server.rdb_child_pid,SIGUSR1); rdbRemoveTempFile(server.rdb_child_pid); } if (server.saveparamslen > 0) { @@ -549,7 +549,7 @@ int expireIfNeeded(redisDb *db, robj *key) { * for *AT variants of the command, or the current time for relative expires). * * unit is either UNIT_SECONDS or UNIT_MILLISECONDS, and is only used for - * the argv[2] parameter. The basetime is always specified in milliesconds. */ + * the argv[2] parameter. The basetime is always specified in milliseconds. */ void expireGenericCommand(redisClient *c, long long basetime, int unit) { dictEntry *de; robj *key = c->argv[1], *param = c->argv[2]; diff --git a/src/debug.c b/src/debug.c index 9af6a6cc1..45364a292 100644 --- a/src/debug.c +++ b/src/debug.c @@ -42,7 +42,7 @@ /* ================================= Debugging ============================== */ /* Compute the sha1 of string at 's' with 'len' bytes long. - * The SHA1 is then xored againt the string pointed by digest. + * The SHA1 is then xored against the string pointed by digest. * Since xor is commutative, this operation is used in order to * "add" digests relative to unordered elements. * @@ -67,7 +67,7 @@ void xorObjectDigest(unsigned char *digest, robj *o) { } /* This function instead of just computing the SHA1 and xoring it - * against diget, also perform the digest of "digest" itself and + * against digest, also perform the digest of "digest" itself and * replace the old value with the new one. * * So the final digest will be: diff --git a/src/dict.c b/src/dict.c index 1e7d7609d..4bb60e0af 100644 --- a/src/dict.c +++ b/src/dict.c @@ -610,7 +610,7 @@ static int _dictExpandIfNeeded(dict *d) /* Incremental rehashing already in progress. Return. */ if (dictIsRehashing(d)) return DICT_OK; - /* If the hash table is empty expand it to the intial size. */ + /* If the hash table is empty expand it to the initial size. */ if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE); /* If we reached the 1:1 ratio, and we are allowed to resize the hash diff --git a/src/lzfP.h b/src/lzfP.h index d533f1829..10d804e04 100644 --- a/src/lzfP.h +++ b/src/lzfP.h @@ -93,7 +93,7 @@ /* * Avoid assigning values to errno variable? for some embedding purposes - * (linux kernel for example), this is neccessary. NOTE: this breaks + * (linux kernel for example), this is necessary. NOTE: this breaks * the documentation in lzf.h. */ #ifndef AVOID_ERRNO @@ -101,7 +101,7 @@ #endif /* - * Wether to pass the LZF_STATE variable as argument, or allocate it + * Whether to pass the LZF_STATE variable as argument, or allocate it * on the stack. For small-stack environments, define this to 1. * NOTE: this breaks the prototype in lzf.h. */ @@ -110,11 +110,11 @@ #endif /* - * Wether to add extra checks for input validity in lzf_decompress + * Whether to add extra checks for input validity in lzf_decompress * and return EINVAL if the input stream has been corrupted. This * only shields against overflowing the input buffer and will not * detect most corrupted streams. - * This check is not normally noticable on modern hardware + * This check is not normally noticeable on modern hardware * (<1% slowdown), but might slow down older cpus considerably. */ #ifndef CHECK_INPUT diff --git a/src/memtest.c b/src/memtest.c index 56162ff4f..a0b99f98b 100644 --- a/src/memtest.c +++ b/src/memtest.c @@ -78,10 +78,8 @@ void memtest_progress_end(void) { void memtest_progress_step(size_t curr, size_t size, char c) { size_t chars = ((unsigned long long)curr*progress_full)/size, j; - for (j = 0; j < chars-progress_printed; j++) { - printf("%c",c); - progress_printed++; - } + for (j = 0; j < chars-progress_printed; j++) printf("%c",c); + progress_printed = chars; fflush(stdout); } diff --git a/src/mkreleasehdr.sh b/src/mkreleasehdr.sh index 30984160e..dbf948c8a 100755 --- a/src/mkreleasehdr.sh +++ b/src/mkreleasehdr.sh @@ -3,7 +3,7 @@ GIT_SHA1=`(git show-ref --head --hash=8 2> /dev/null || echo 00000000) | head -n GIT_DIRTY=`git diff 2> /dev/null | wc -l` test -f release.h || touch release.h (cat release.h | grep SHA1 | grep $GIT_SHA1) && \ -(cat release.h | grep DIRTY | grep $GIT_DIRTY) && exit 0 # Already uptodate +(cat release.h | grep DIRTY | grep $GIT_DIRTY) && exit 0 # Already up-to-date echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h touch release.c # Force recompile of release.c diff --git a/src/multi.c b/src/multi.c index bcd263236..2b7e6b552 100755 --- a/src/multi.c +++ b/src/multi.c @@ -102,7 +102,7 @@ void discardCommand(redisClient *c) { } /* Send a MULTI command to all the slaves and AOF file. Check the execCommand - * implememntation for more information. */ + * implementation for more information. */ void execCommandReplicateMulti(redisClient *c) { robj *multistring = createStringObject("MULTI",5); @@ -223,7 +223,7 @@ void watchForKey(redisClient *c, robj *key) { incrRefCount(key); } listAddNodeTail(clients,c); - /* Add the new key to the lits of keys watched by this client */ + /* Add the new key to the list of keys watched by this client */ wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; diff --git a/src/networking.c b/src/networking.c index c23939c5c..6e5d32489 100644 --- a/src/networking.c +++ b/src/networking.c @@ -70,6 +70,7 @@ redisClient *createClient(int fd) { selectDb(c,0); c->fd = fd; + c->name = NULL; c->bufpos = 0; c->querybuf = sdsempty(); c->querybuf_peak = 0; @@ -377,7 +378,7 @@ void *addDeferredMultiBulkLength(redisClient *c) { return listLast(c->reply); } -/* Populate the length object and try glueing it to the next chunk. */ +/* Populate the length object and try gluing it to the next chunk. */ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) { listNode *ln = (listNode*)node; robj *len, *next; @@ -403,7 +404,7 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) { asyncCloseClientOnOutputBufferLimitReached(c); } -/* Add a duble as a bulk reply */ +/* Add a double as a bulk reply */ void addReplyDouble(redisClient *c, double d) { char dbuf[128], sbuf[128]; int dlen, slen; @@ -525,7 +526,7 @@ static void acceptCommonHandler(int fd, int flags) { } /* If maxclient directive is set and this is one client more... close the * connection. Note that we create the client instead to check before - * for this condition, since now the socket is already set in nonblocking + * for this condition, since now the socket is already set in non-blocking * mode and we can send an error for free using the Kernel I/O */ if (listLength(server.clients) > server.maxclients) { char *err = "-ERR max number of clients reached\r\n"; @@ -668,6 +669,7 @@ void freeClient(redisClient *c) { } /* Release memory */ + if (c->name) decrRefCount(c->name); zfree(c->argv); freeClientMultiState(c); zfree(c); @@ -939,7 +941,7 @@ int processMultibulkBuffer(redisClient *c) { /* Not enough data (+2 == trailing \r\n) */ break; } else { - /* Optimization: if the buffer contanins JUST our bulk element + /* Optimization: if the buffer contains JUST our bulk element * instead of creating a new object by *copying* the sds we * just use the current sds string. */ if (pos == 0 && @@ -1123,9 +1125,11 @@ sds getClientInfoString(redisClient *client) { if (emask & AE_WRITABLE) *p++ = 'w'; *p = '\0'; return sdscatprintf(sdsempty(), - "addr=%s:%d fd=%d age=%ld idle=%ld flags=%s db=%d sub=%d psub=%d multi=%d qbuf=%lu qbuf-free=%lu obl=%lu oll=%lu omem=%lu events=%s cmd=%s", + "addr=%s:%d fd=%d name=%s age=%ld idle=%ld flags=%s db=%d sub=%d psub=%d multi=%d qbuf=%lu qbuf-free=%lu obl=%lu oll=%lu omem=%lu events=%s cmd=%s", (client->flags & REDIS_UNIX_SOCKET) ? server.unixsocket : ip, - port,client->fd, + port, + client->fd, + client->name ? (char*)client->name->ptr : "", (long)(server.unixtime - client->ctime), (long)(server.unixtime - client->lastinteraction), flags, @@ -1190,8 +1194,41 @@ void clientCommand(redisClient *c) { } } addReplyError(c,"No such client"); + } else if (!strcasecmp(c->argv[1]->ptr,"setname") && c->argc == 3) { + int j, len = sdslen(c->argv[2]->ptr); + char *p = c->argv[2]->ptr; + + /* Setting the client name to an empty string actually removes + * the current name. */ + if (len == 0) { + if (c->name) decrRefCount(c->name); + c->name = NULL; + addReply(c,shared.ok); + return; + } + + /* Otherwise check if the charset is ok. We need to do this otherwise + * CLIENT LIST format will break. You should always be able to + * split by space to get the different fields. */ + for (j = 0; j < len; j++) { + if (p[j] < '!' || p[j] > '~') { /* ASCII is assumed. */ + addReplyError(c, + "Client names cannot contain spaces, " + "newlines or special characters."); + return; + } + } + if (c->name) decrRefCount(c->name); + c->name = c->argv[2]; + incrRefCount(c->name); + addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"getname") && c->argc == 2) { + if (c->name) + addReplyBulk(c,c->name); + else + addReply(c,shared.nullbulk); } else { - addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port)"); + addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port | GETNAME | SETNAME connection-name)"); } } diff --git a/src/object.c b/src/object.c index c2b89709d..00cf023b0 100644 --- a/src/object.c +++ b/src/object.c @@ -72,7 +72,7 @@ robj *createStringObjectFromLongDouble(long double value) { int len; /* We use 17 digits precision since with 128 bit floats that precision - * after rouding is able to represent most small decimal numbers in a way + * after rounding is able to represent most small decimal numbers in a way * that is "non surprising" for the user (that is, most small decimal * numbers will be represented in a way that when converted back into * a string are exactly the same as what the user typed.) */ diff --git a/src/pubsub.c b/src/pubsub.c index 5e8cef0ae..ece32445d 100644 --- a/src/pubsub.c +++ b/src/pubsub.c @@ -118,7 +118,7 @@ int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) { return retval; } -/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */ +/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. */ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; @@ -180,6 +180,14 @@ int pubsubUnsubscribeAllChannels(redisClient *c, int notify) { count += pubsubUnsubscribeChannel(c,channel,notify); } + /* We were subscribed to nothing? Still reply to the client. */ + if (notify && count == 0) { + addReply(c,shared.mbulkhdr[3]); + addReply(c,shared.unsubscribebulk); + addReply(c,shared.nullbulk); + addReplyLongLong(c,dictSize(c->pubsub_channels)+ + listLength(c->pubsub_patterns)); + } dictReleaseIterator(di); return count; } @@ -197,6 +205,14 @@ int pubsubUnsubscribeAllPatterns(redisClient *c, int notify) { count += pubsubUnsubscribePattern(c,pattern,notify); } + if (notify && count == 0) { + /* We were subscribed to nothing? Still reply to the client. */ + addReply(c,shared.mbulkhdr[3]); + addReply(c,shared.punsubscribebulk); + addReply(c,shared.nullbulk); + addReplyLongLong(c,dictSize(c->pubsub_channels)+ + listLength(c->pubsub_patterns)); + } return count; } @@ -266,7 +266,7 @@ err: return NULL; } -/* Save a string objet as [len][data] on disk. If the object is a string +/* Save a string object as [len][data] on disk. If the object is a string * representation of an integer value we try to save it in a special form */ int rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) { int enclen; @@ -322,7 +322,7 @@ int rdbSaveLongLongAsStringObject(rio *rdb, long long value) { /* Like rdbSaveStringObjectRaw() but handle encoded objects */ int rdbSaveStringObject(rio *rdb, robj *obj) { /* Avoid to decode the object, then encode it again, if the - * object is alrady integer encoded. */ + * object is already integer encoded. */ if (obj->encoding == REDIS_ENCODING_INT) { return rdbSaveLongLongAsStringObject(rdb,(long)obj->ptr); } else { @@ -368,7 +368,7 @@ robj *rdbLoadEncodedStringObject(rio *rdb) { } /* Save a double value. Doubles are saved as strings prefixed by an unsigned - * 8 bit integer specifing the length of the representation. + * 8 bit integer specifying the length of the representation. * This 8 bit integer has special values in order to specify the following * conditions: * 253: not a number @@ -607,7 +607,7 @@ off_t rdbSavedObjectLen(robj *o) { /* Save a key-value pair, with expire time, type, key, value. * On error -1 is returned. - * On success if the key was actaully saved 1 is returned, otherwise 0 + * On success if the key was actually saved 1 is returned, otherwise 0 * is returned (the key was already expired). */ int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, long long expiretime, long long now) @@ -1177,7 +1177,7 @@ int rdbLoad(char *filename) { /* We read the time so we need to read the object type again. */ if ((type = rdbLoadType(&rdb)) == -1) goto eoferr; /* the EXPIRETIME opcode specifies time in seconds, so convert - * into milliesconds. */ + * into milliseconds. */ expiretime *= 1000; } else if (type == REDIS_RDB_OPCODE_EXPIRETIME_MS) { /* Milliseconds precision expire times introduced with RDB @@ -1453,6 +1453,11 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) { "Background saving terminated by signal %d", bysignal); rdbRemoveTempFile(server.rdb_child_pid); if (update_status) server.lastbgsave_status = REDIS_ERR; + + /* SIGUSR1 is whitelisted, so we have a way to kill a child without + * tirggering an error conditon. */ + if (bysignal != SIGUSR1) + server.lastbgsave_status = REDIS_ERR; } server.rdb_child_pid = -1; server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start; @@ -57,7 +57,7 @@ * number specify the kind of object that follows. * See the REDIS_RDB_ENC_* defines. * - * Lenghts up to 63 are stored using a single byte, most DB keys, and may + * Lengths up to 63 are stored using a single byte, most DB keys, and may * values, will fit inside. */ #define REDIS_RDB_6BITLEN 0 #define REDIS_RDB_14BITLEN 1 diff --git a/src/redis-check-dump.c b/src/redis-check-dump.c index 7efecb1a3..85ab9b96c 100644 --- a/src/redis-check-dump.c +++ b/src/redis-check-dump.c @@ -78,7 +78,7 @@ * number specify the kind of object that follows. * See the REDIS_RDB_ENC_* defines. * - * Lenghts up to 63 are stored using a single byte, most DB keys, and may + * Lengths up to 63 are stored using a single byte, most DB keys, and may * values, will fit inside. */ #define REDIS_RDB_6BITLEN 0 #define REDIS_RDB_14BITLEN 1 @@ -132,7 +132,7 @@ typedef struct { char success; } entry; -/* Global vars that are actally used as constants. The following double +/* Global vars that are actually used as constants. The following double * values are used for double on-disk serialization, and are initialized * at runtime to avoid strange compiler optimizations. */ static double R_Zero, R_PosInf, R_NegInf, R_Nan; diff --git a/src/redis-cli.c b/src/redis-cli.c index 3969fbab5..c182ac17d 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -41,6 +41,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <assert.h> +#include <fcntl.h> #include "hiredis.h" #include "sds.h" @@ -73,6 +74,8 @@ static struct config { int cluster_reissue_command; int slave_mode; int pipe_mode; + int getrdb_mode; + char *rdb_filename; int bigkeys; int stdinarg; /* get last arg from stdin. (-x option) */ char *auth; @@ -305,7 +308,7 @@ static int cliSelect() { return REDIS_ERR; } -/* Connect to the client. If force is not zero the connection is performed +/* Connect to the server. If force is not zero the connection is performed * even if there is already a connected socket. */ static int cliConnect(int force) { if (context == NULL || force) { @@ -660,6 +663,9 @@ static int parseOptions(int argc, char **argv) { config.latency_mode = 1; } else if (!strcmp(argv[i],"--slave")) { config.slave_mode = 1; + } else if (!strcmp(argv[i],"--rdb") && !lastarg) { + config.getrdb_mode = 1; + config.rdb_filename = argv[++i]; } else if (!strcmp(argv[i],"--pipe")) { config.pipe_mode = 1; } else if (!strcmp(argv[i],"--bigkeys")) { @@ -720,6 +726,7 @@ static void usage() { " --raw Use raw formatting for replies (default when STDOUT is not a tty)\n" " --latency Enter a special mode continuously sampling latency\n" " --slave Simulate a slave showing commands received from the master\n" +" --rdb <filename> Transfer an RDB dump from remote server to local file.\n" " --pipe Transfer raw Redis protocol from stdin to server\n" " --bigkeys Sample Redis keys looking for big keys\n" " --eval <file> Send an EVAL command using the Lua script at <file>\n" @@ -794,6 +801,7 @@ static void repl() { sdsfree(config.hostip); config.hostip = sdsnew(argv[1]); config.hostport = atoi(argv[2]); + cliRefreshPrompt(); cliConnect(1); } else if (argc == 1 && !strcasecmp(argv[0],"clear")) { linenoiseClearScreen(); @@ -927,15 +935,15 @@ static void latencyMode(void) { } } -static void slaveMode(void) { +/* Sends SYNC and reads the number of bytes in the payload. Used both by + * slaveMode() and getRDB(). */ +unsigned long long sendSync(int fd) { /* To start we need to send the SYNC command and return the payload. * The hiredis client lib does not understand this part of the protocol * and we don't want to mess with its buffers, so everything is performed * using direct low-level I/O. */ - int fd = context->fd; - char buf[1024], *p; + char buf[4096], *p; ssize_t nread; - unsigned long long payload; /* Send the SYNC command. */ if (write(fd,"SYNC\r\n",6) != 6) { @@ -951,16 +959,29 @@ static void slaveMode(void) { fprintf(stderr,"Error reading bulk length while SYNCing\n"); exit(1); } - if (*p == '\n') break; - p++; + if (*p == '\n' && p != buf) break; + if (*p != '\n') p++; } *p = '\0'; - payload = strtoull(buf+1,NULL,10); - fprintf(stderr,"SYNC with master, discarding %lld bytes of bulk tranfer...\n", - payload); + if (buf[0] == '-') { + printf("SYNC with master failed: %s\n", buf); + exit(1); + } + return strtoull(buf+1,NULL,10); +} + +static void slaveMode(void) { + int fd = context->fd; + unsigned long long payload = sendSync(fd); + char buf[1024]; + + fprintf(stderr,"SYNC with master, discarding %llu " + "bytes of bulk transfer...\n", payload); /* Discard the payload. */ while(payload) { + ssize_t nread; + nread = read(fd,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); if (nread <= 0) { fprintf(stderr,"Error reading RDB payload while SYNCing\n"); @@ -970,11 +991,56 @@ static void slaveMode(void) { } fprintf(stderr,"SYNC done. Logging commands from master.\n"); - /* Now we can use the hiredis to read the incoming protocol. */ + /* Now we can use hiredis to read the incoming protocol. */ config.output = OUTPUT_CSV; while (cliReadReply(0) == REDIS_OK); } +/* This function implements --rdb, so it uses the replication protocol in order + * to fetch the RDB file from a remote server. */ +static void getRDB(void) { + int s = context->fd; + int fd; + unsigned long long payload = sendSync(s); + char buf[4096]; + + fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n", + payload, config.rdb_filename); + + /* Write to file. */ + if (!strcmp(config.rdb_filename,"-")) { + fd = STDOUT_FILENO; + } else { + fd = open(config.rdb_filename, O_CREAT|O_WRONLY, 0644); + if (fd == -1) { + fprintf(stderr, "Error opening '%s': %s\n", config.rdb_filename, + strerror(errno)); + exit(1); + } + } + + while(payload) { + ssize_t nread, nwritten; + + nread = read(s,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); + if (nread <= 0) { + fprintf(stderr,"I/O Error reading RDB payload from socket\n"); + exit(1); + } + nwritten = write(fd, buf, nread); + if (nwritten != nread) { + fprintf(stderr,"Error writing data to file: %s\n", + strerror(errno)); + exit(1); + } + payload -= nread; + } + close(s); /* Close the file descriptor ASAP as fsync() may take time. */ + fsync(fd); + fprintf(stderr,"Transfer finished with success.\n"); + exit(0); +} + static void pipeMode(void) { int fd = context->fd; long long errors = 0, replies = 0, obuf_len = 0, obuf_pos = 0; @@ -1075,7 +1141,7 @@ static void pipeMode(void) { int j; eof = 1; - /* Everything transfered, so we queue a special + /* Everything transferred, so we queue a special * ECHO command that we can match in the replies * to make sure everything was read from the server. */ for (j = 0; j < 20; j++) @@ -1117,6 +1183,7 @@ static void findBigKeys(void) { unsigned long long samples = 0; redisReply *reply1, *reply2, *reply3 = NULL; char *sizecmd, *typename[] = {"string","list","set","hash","zset"}; + char *typeunit[] = {"bytes","items","members","fields","members"}; int type; printf("\n# Press ctrl+c when you have had enough of it... :)\n"); @@ -1168,9 +1235,10 @@ static void findBigKeys(void) { reply3 = redisCommand(context,"%s %s", sizecmd, reply1->str); if (reply3 && reply3->type == REDIS_REPLY_INTEGER) { if (biggest[type] < reply3->integer) { - printf("[%6s] %s | biggest so far with size %llu\n", + printf("Biggest %-6s found so far '%s' with %llu %s.\n", typename[type], reply1->str, - (unsigned long long) reply3->integer); + (unsigned long long) reply3->integer, + typeunit[type]); biggest[type] = reply3->integer; } } @@ -1203,6 +1271,8 @@ int main(int argc, char **argv) { config.latency_mode = 0; config.cluster_mode = 0; config.slave_mode = 0; + config.getrdb_mode = 0; + config.rdb_filename = NULL; config.pipe_mode = 0; config.bigkeys = 0; config.stdinarg = 0; @@ -1221,16 +1291,22 @@ int main(int argc, char **argv) { /* Latency mode */ if (config.latency_mode) { - cliConnect(0); + if (cliConnect(0) == REDIS_ERR) exit(1); latencyMode(); } /* Slave mode */ if (config.slave_mode) { - cliConnect(0); + if (cliConnect(0) == REDIS_ERR) exit(1); slaveMode(); } + /* Get RDB mode. */ + if (config.getrdb_mode) { + if (cliConnect(0) == REDIS_ERR) exit(1); + getRDB(); + } + /* Pipe mode */ if (config.pipe_mode) { if (cliConnect(0) == REDIS_ERR) exit(1); @@ -1239,7 +1315,7 @@ int main(int argc, char **argv) { /* Find big keys */ if (config.bigkeys) { - cliConnect(0); + if (cliConnect(0) == REDIS_ERR) exit(1); findBigKeys(); } diff --git a/src/redis.c b/src/redis.c index 04289db23..9b4e1ac28 100755 --- a/src/redis.c +++ b/src/redis.c @@ -99,7 +99,7 @@ struct redisCommand *commandTable; * m: may increase memory usage once called. Don't allow if out of memory. * a: admin command, like SAVE or SHUTDOWN. * p: Pub/Sub related command. - * f: force replication of this command, regarless of server.dirty. + * f: force replication of this command, regardless of server.dirty. * s: command not allowed in scripts. * R: random command. Command is not deterministic, that is, the same command * with the same arguments, with the same key space, may have different @@ -292,7 +292,7 @@ void redisLogRaw(int level, const char *msg) { if (server.syslog_enabled) syslog(syslogLevelMap[level], "%s", msg); } -/* Like redisLogRaw() but with printf-alike support. This is the funciton that +/* Like redisLogRaw() but with printf-alike support. This is the function that * is used across the code. The raw version is only used in order to dump * the INFO output on crash. */ void redisLog(int level, const char *fmt, ...) { @@ -367,7 +367,7 @@ void exitFromChild(int retcode) { /*====================== Hash table type implementation ==================== */ -/* This is an hash table type that uses the SDS dynamic strings libary as +/* This is an hash table type that uses the SDS dynamic strings library as * keys and radis objects as values (objects can hold SDS strings, * lists, sets). */ @@ -541,7 +541,7 @@ dictType commandTableDictType = { NULL /* val destructor */ }; -/* Hash type hash table (note that small hashes are represented with zimpaps) */ +/* Hash type hash table (note that small hashes are represented with zipmaps) */ dictType hashDictType = { dictEncObjHash, /* hash function */ NULL, /* key dup */ @@ -742,7 +742,7 @@ int clientsCronHandleTimeout(redisClient *c) { /* The client query buffer is an sds.c string that can end with a lot of * free space not used, this function reclaims space if needed. * - * The funciton always returns 0 as it never terminates the client. */ + * The function always returns 0 as it never terminates the client. */ int clientsCronResizeQueryBuffer(redisClient *c) { size_t querybuf_size = sdsAllocSize(c->querybuf); time_t idletime = server.unixtime - c->lastinteraction; @@ -878,11 +878,11 @@ void checkOSMemory(void) { * * - Active expired keys collection (it is also performed in a lazy way on * lookup). - * - Software watchdong. + * - Software watchdog. * - Update some statistic. * - Incremental rehashing of the DBs hash tables. * - Triggering BGSAVE / AOF rewrite, and handling of terminated children. - * - Clients timeout of differnet kinds. + * - Clients timeout of different kinds. * - Replication reconnection. * - Many more... * @@ -911,7 +911,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { /* We have just 22 bits per object for LRU information. * So we use an (eventually wrapping) LRU clock with 10 seconds resolution. - * 2^22 bits with 10 seconds resoluton is more or less 1.5 years. + * 2^22 bits with 10 seconds resolution is more or less 1.5 years. * * Note that even if this will wrap after 1.5 years it's not a problem, * everything will still work but just some object will appear younger @@ -932,6 +932,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { if (server.shutdown_asap) { if (prepareForShutdown(0) == REDIS_OK) exit(0); redisLog(REDIS_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information"); + server.shutdown_asap = 0; } /* Try to evict if OS memory is low */ @@ -958,7 +959,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { } } - /* We don't want to resize the hash tables while a bacground saving + /* We don't want to resize the hash tables while a background saving * is in progress: the saving child is created using fork() that is * implemented with a copy-on-write semantic in most modern systems, so * if we resize the HT while there is the saving child at work actually @@ -1274,7 +1275,7 @@ void initServerConfig() { R_NegInf = -1.0/R_Zero; R_Nan = R_Zero/R_Zero; - /* Command table -- we intiialize it here as it is part of the + /* Command table -- we initiialize it here as it is part of the * initial configuration, since command names may be changed via * redis.conf using the rename-command directive. */ server.commands = dictCreate(&commandTableDictType,NULL); @@ -1609,7 +1610,7 @@ void call(redisClient *c, int flags) { long long dirty, start = ustime(), duration; /* Sent the command to clients in MONITOR mode, only if the commands are - * not geneated from reading an AOF. */ + * not generated from reading an AOF. */ if (!(c->flags & REDIS_HIDDEN) && listLength(server.monitors) && !server.loading && @@ -1633,7 +1634,7 @@ void call(redisClient *c, int flags) { /* Log the command into the Slow log if needed, and populate the * per-command statistics that we show in INFO commandstats. */ - if (flags & REDIS_CALL_SLOWLOG) + if (flags & REDIS_CALL_SLOWLOG && c->cmd->proc != execCommand) slowlogPushEntryIfNeeded(c->argv,c->argc,duration); if (dirty > 0 && server.conditional_sync) { update_dbversion(c); @@ -1677,8 +1678,8 @@ void call(redisClient *c, int flags) { * server for a bulk read from the client. * * If 1 is returned the client is still alive and valid and - * and other operations can be performed by the caller. Otherwise - * if 0 is returned the client was destroied (i.e. after QUIT). */ + * other operations can be performed by the caller. Otherwise + * if 0 is returned the client was destroyed (i.e. after QUIT). */ int processCommand(redisClient *c) { /* The QUIT command is handled separately. Normal command procs will * go through checking for replication and QUIT will cause trouble @@ -1831,7 +1832,7 @@ int prepareForShutdown(int flags) { overwrite the synchronous saving did by SHUTDOWN. */ if (server.rdb_child_pid != -1) { redisLog(REDIS_WARNING,"There is a child saving an .rdb. Killing it!"); - kill(server.rdb_child_pid,SIGKILL); + kill(server.rdb_child_pid,SIGUSR1); rdbRemoveTempFile(server.rdb_child_pid); } if (server.aof_state != REDIS_AOF_OFF) { @@ -1840,7 +1841,7 @@ int prepareForShutdown(int flags) { if (server.aof_child_pid != -1) { redisLog(REDIS_WARNING, "There is a child rewriting the AOF. Killing it!"); - kill(server.aof_child_pid,SIGKILL); + kill(server.aof_child_pid,SIGUSR1); } /* Append only file: fsync() the AOF and exit */ redisLog(REDIS_NOTICE,"Calling fsync() on the AOF file."); @@ -1942,7 +1943,7 @@ void echoCommand(redisClient *c) { void timeCommand(redisClient *c) { struct timeval tv; - /* gettimeofday() can only fail if &tv is a bad addresss so we + /* gettimeofday() can only fail if &tv is a bad address so we * don't check for errors. */ gettimeofday(&tv,NULL); addReplyMultiBulkLen(c,2); diff --git a/src/redis.h b/src/redis.h index 39066074c..3319aa87b 100755 --- a/src/redis.h +++ b/src/redis.h @@ -143,12 +143,12 @@ * * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte - * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow + * 10|000000 [32 bit integer] => if it's 10, a full 32 bit len will follow * 11|000000 this means: specially encoded object will follow. The six bits * number specify the kind of object that follows. * See the REDIS_RDB_ENC_* defines. * - * Lenghts up to 63 are stored using a single byte, most DB keys, and may + * Lengths up to 63 are stored using a single byte, most DB keys, and may * values, will fit inside. */ #define REDIS_RDB_6BITLEN 0 #define REDIS_RDB_14BITLEN 1 @@ -328,7 +328,7 @@ typedef struct redisObject { void *ptr; } robj; -/* Macro used to initalize a Redis object allocated on the stack. +/* Macro used to initialize a Redis object allocated on the stack. * Note that this macro is taken near the structure definition to make sure * we'll update it when the structure is changed, to avoid bugs like * bug #85 introduced exactly in this way. */ @@ -385,12 +385,13 @@ typedef struct readyList { robj *key; } readyList; -/* With multiplexing we need to take per-clinet state. +/* With multiplexing we need to take per-client state. * Clients are taken in a liked list. */ typedef struct redisClient { int fd; redisDb *db; int dictid; + robj *name; /* As set by CLIENT SETNAME */ sds querybuf; size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */ int argc; @@ -556,7 +557,7 @@ struct redisServer { size_t stat_peak_memory; /* Max used memory record */ long long stat_aof_rewrites; /* number of aof file rewrites performed */ long long stat_rdb_saves; /* number of rdb saves performed */ - long long stat_fork_time; /* Time needed to perform latets fork() */ + long long stat_fork_time; /* Time needed to perform latest fork() */ long long stat_rejected_conn; /* Clients rejected because of maxclients */ list *slowlog; /* SLOWLOG list of commands */ long long slowlog_entry_id; /* SLOWLOG current entry ID */ @@ -613,7 +614,7 @@ struct redisServer { int rdb_bgsavetype; /* Type of BGSAVE operation now in progress */ int rdb_compression; /* Use compression in RDB? */ int rdb_checksum; /* Use RDB checksum? */ - time_t lastsave; /* Unix time of last save succeeede */ + time_t lastsave; /* Unix time of last successful save */ time_t rdb_save_time_last; /* Time used by last RDB save run. */ time_t rdb_save_time_start; /* Current RDB save start time. */ int lastbgsave_status; /* REDIS_OK or REDIS_ERR */ @@ -651,7 +652,7 @@ struct redisServer { unsigned int maxclients; /* Max number of simultaneous clients */ unsigned long long maxmemory; /* Max number of memory bytes to use */ unsigned long long minmemory_os; /* OS Free memory threshold that */ - int maxmemory_policy; /* Policy for key evition */ + int maxmemory_policy; /* Policy for key eviction */ int maxmemory_samples; /* Pricision of random sampling */ /* Blocked clients */ unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */ @@ -688,7 +689,7 @@ struct redisServer { int lua_timedout; /* True if we reached the time limit for script execution. */ int lua_kill; /* Kill the script if true. */ - /* Assert & bug reportign */ + /* Assert & bug reporting */ char *assert_failed; char *assert_file; int assert_line; @@ -707,13 +708,13 @@ struct redisCommand { char *name; redisCommandProc *proc; int arity; - char *sflags; /* Flags as string represenation, one char per flag. */ + char *sflags; /* Flags as string representation, one char per flag. */ int flags; /* The actual flags, obtained from the 'sflags' field. */ /* Use a function to determine keys arguments in a command line. */ redisGetKeysProc *getkeys_proc; /* What keys should be loaded in background when calling this command? */ int firstkey; /* The first argument that's a key (0 = no keys) */ - int lastkey; /* THe last argument that's a key */ + int lastkey; /* The last argument that's a key */ int keystep; /* The step between first and last key */ long long microseconds, calls; }; @@ -760,7 +761,7 @@ typedef struct { dictIterator *di; } setTypeIterator; -/* Structure to hold hash iteration abstration. Note that iteration over +/* Structure to hold hash iteration abstraction. Note that iteration over * hashes involves both fields and values. Because it is possible that * not both are required, store pointers in the iterator to avoid * unnecessary memory allocation for fields/values. */ diff --git a/src/release.c b/src/release.c index 46761448c..296db67b3 100644 --- a/src/release.c +++ b/src/release.c @@ -27,8 +27,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* Every time the Redis Git SHA1 or Dirty status changes only this file - * small file is recompiled, as we access this information in all the other +/* Every time the Redis Git SHA1 or Dirty status changes only this small + * file is recompiled, as we access this information in all the other * files using this functions. */ #include "release.h" diff --git a/src/replication.c b/src/replication.c index 0a4321095..9c6d4dff7 100755 --- a/src/replication.c +++ b/src/replication.c @@ -75,7 +75,7 @@ void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) { if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue; /* Feed slaves that are waiting for the initial SYNC (so these commands - * are queued in the output buffer until the intial SYNC completes), + * are queued in the output buffer until the initial SYNC completes), * or are already in sync with the master. */ if (slave->slaveseldb != dictid) { robj *selectcmd; @@ -202,7 +202,7 @@ void syncnowCommand(redisClient *c) { void syncCommand(redisClient *c) { int bgsave_required = 1; - /* ignore SYNC if aleady slave or in monitor mode */ + /* ignore SYNC if already slave or in monitor mode */ if (c->flags & REDIS_SLAVE) return; /* Refuse SYNC requests if we are a slave but the link with our master @@ -333,7 +333,7 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) { if (slave->repldboff == 0) { /* Write the bulk write count before to transfer the DB. In theory here * we don't know how much room there is in the output buffer of the - * socket, but in pratice SO_SNDLOWAT (the minimum count for output + * socket, but in practice SO_SNDLOWAT (the minimum count for output * operations) will never be smaller than the few bytes we need. */ sds bulkcount; @@ -376,7 +376,7 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) { } } -/* This function is called at the end of every backgrond saving. +/* This function is called at the end of every background saving. * The argument bgsaveerr is REDIS_OK if the background saving succeeded * otherwise REDIS_ERR is passed to the function. * @@ -567,7 +567,7 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) { stopAppendOnly(); while (retry-- && startAppendOnly() == REDIS_ERR) { - redisLog(REDIS_WARNING,"Failed enabling the AOF after successful master synchrnization! Trying it again in one second."); + redisLog(REDIS_WARNING,"Failed enabling the AOF after successful master synchronization! Trying it again in one second."); sleep(1); } if (!retry) { @@ -817,6 +817,27 @@ void undoConnectWithMaster(void) { server.repl_state = REDIS_REPL_CONNECT; } +/* This function aborts a non blocking replication attempt if there is one + * in progress, by canceling the non-blocking connect attempt or + * the initial bulk transfer. + * + * If there was a replication handshake in progress 1 is returned and + * the replication state (server.repl_state) set to REDIS_REPL_CONNECT. + * + * Otherwise zero is returned and no operation is perforemd at all. */ +int cancelReplicationHandshake(void) { + if (server.repl_state == REDIS_REPL_TRANSFER) { + replicationAbortSyncTransfer(); + } else if (server.repl_state == REDIS_REPL_CONNECTING || + server.repl_state == REDIS_REPL_RECEIVE_PONG) + { + undoConnectWithMaster(); + } else { + return 0; + } + return 1; +} + void slaveofCommand(redisClient *c) { if (!strcasecmp(c->argv[1]->ptr,"no") && !strcasecmp(c->argv[2]->ptr,"one")) { @@ -824,11 +845,7 @@ void slaveofCommand(redisClient *c) { sdsfree(server.masterhost); server.masterhost = NULL; if (server.master) freeClient(server.master); - if (server.repl_state == REDIS_REPL_TRANSFER) - replicationAbortSyncTransfer(); - else if (server.repl_state == REDIS_REPL_CONNECTING || - server.repl_state == REDIS_REPL_RECEIVE_PONG) - undoConnectWithMaster(); + cancelReplicationHandshake(); server.repl_state = REDIS_REPL_NONE; redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)"); } @@ -852,8 +869,7 @@ void slaveofCommand(redisClient *c) { server.masterport = port; if (server.master) freeClient(server.master); disconnectSlaves(); /* Force our slaves to resync with us as well. */ - if (server.repl_state == REDIS_REPL_TRANSFER) - replicationAbortSyncTransfer(); + cancelReplicationHandshake(); server.repl_state = REDIS_REPL_CONNECT; redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)", server.masterhost, server.masterport); diff --git a/src/scripting.c b/src/scripting.c index e3f810815..ee3d0405b 100755 --- a/src/scripting.c +++ b/src/scripting.c @@ -48,7 +48,7 @@ void sha1hex(char *digest, char *script, size_t len); /* Take a Redis reply in the Redis protocol format and convert it into a * Lua type. Thanks to this function, and the introduction of not connected - * clients, it is trvial to implement the redis() lua function. + * clients, it is trivial to implement the redis() lua function. * * Basically we take the arguments, execute the Redis command in the context * of a non connected client, then take the generated reply and convert it @@ -58,7 +58,7 @@ void sha1hex(char *digest, char *script, size_t len); * * Note: in this function we do not do any sanity check as the reply is * generated by Redis directly. This allows us to go faster. - * The reply string can be altered during the parsing as it is discared + * The reply string can be altered during the parsing as it is discarded * after the conversion is completed. * * Errors are returned as a table with a single 'err' field set to the @@ -597,7 +597,7 @@ void scriptingInit(void) { lua_setglobal(lua,"math"); - /* Add a helper funciton that we use to sort the multi bulk output of non + /* Add a helper function that we use to sort the multi bulk output of non * deterministic commands, when containing 'false' elements. */ { char *compare_func = "function __redis__compare_helper(a,b)\n" @@ -638,7 +638,7 @@ void scriptingReset(void) { scriptingInit(); } -/* Perform the SHA1 of the input string. We use this both for hasing script +/* Perform the SHA1 of the input string. We use this both for hashing script * bodies in order to obtain the Lua function name, and in the implementation * of redis.sha1(). * @@ -677,7 +677,7 @@ void luaReplyToRedisReply(redisClient *c, lua_State *lua) { case LUA_TTABLE: /* We need to check if it is an array, an error, or a status reply. * Error are returned as a single element table with 'err' field. - * Status replies are returned as single elment table with 'ok' field */ + * Status replies are returned as single element table with 'ok' field */ lua_pushstring(lua,"err"); lua_gettable(lua,-2); t = lua_type(lua,-1); @@ -838,7 +838,7 @@ void evalGenericCommand(redisClient *c, int evalsha) { if (lua_isnil(lua,1)) { lua_pop(lua,1); /* remove the nil from the stack */ /* Function not defined... let's define it if we have the - * body of the funciton. If this is an EVALSHA call we can just + * body of the function. If this is an EVALSHA call we can just * return an error. */ if (evalsha) { addReply(c, shared.noscripterr); @@ -141,7 +141,7 @@ size_t sdsAllocSize(sds s) { * right-trim the string. * * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the - * following schema to cat bytes coming from the kerenl to the end of an + * following schema to cat bytes coming from the kernel to the end of an * sds string new things without copying into an intermediate buffer: * * oldlen = sdslen(s); @@ -596,7 +596,7 @@ void sdssplitargs_free(sds *argv, int argc) { } /* Modify the string substituting all the occurrences of the set of - * characters specifed in the 'from' string to the corresponding character + * characters specified in the 'from' string to the corresponding character * in the 'to' array. * * For instance: sdsmapchars(mystring, "ho", "01", 2) diff --git a/src/sentinel.c b/src/sentinel.c index d8a960713..8009e5ed9 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -969,9 +969,9 @@ const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance *ri) { * a master's Sentinels dictionary, we want to be very sure about not * having duplicated instances for any reason. This is so important because * we use those other sentinels in order to run our quorum protocol to - * understand if it's time to proceeed with the fail over. + * understand if it's time to proceed with the fail over. * - * Making sure no duplication is possible we greately improve the robustness + * Making sure no duplication is possible we greatly improve the robustness * of the quorum (otherwise we may end counting the same instance multiple * times for some reason). * @@ -1238,7 +1238,7 @@ void sentinelKillLink(sentinelRedisInstance *ri, redisAsyncContext *c) { * cleanup needed. * * Note: we don't free the hiredis context as hiredis will do it for us - * for async conenctions. */ + * for async connections. */ void sentinelDisconnectInstanceFromContext(const redisAsyncContext *c) { sentinelRedisInstance *ri = c->data; int pubsub; @@ -1647,7 +1647,7 @@ void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privd /* Update the last activity in the pubsub channel. Note that since we * receive our messages as well this timestamp can be used to detect - * if the link is probably diconnected even if it seems otherwise. */ + * if the link is probably disconnected even if it seems otherwise. */ ri->pc_last_activity = mstime(); /* Sanity check in the reply we expect, so that the code that follows @@ -1939,7 +1939,7 @@ void addReplySentinelRedisInstance(redisClient *c, sentinelRedisInstance *ri) { setDeferredMultiBulkLength(c,mbl,fields*2); } -/* Output a number of instances contanined inside a dictionary as +/* Output a number of instances contained inside a dictionary as * Redis protocol. */ void addReplyDictOfRedisInstances(redisClient *c, dict *instances) { dictIterator *di; @@ -2535,7 +2535,7 @@ void sentinelStartFailoverIfNeeded(sentinelRedisInstance *master) { * 3) info_refresh more recent than SENTINEL_INFO_VALIDITY_TIME. * 4) master_link_down_time no more than: * (now - master->s_down_since_time) + (master->down_after_period * 10). - * 5) Slave priority can't be zero, otherwise the slave is discareded. + * 5) Slave priority can't be zero, otherwise the slave is discarded. * * Among all the slaves matching the above conditions we select the slave * with lower slave_priority. If priority is the same we select the slave @@ -2611,10 +2611,10 @@ void sentinelFailoverWaitStart(sentinelRedisInstance *ri) { /* If we in "wait start" but the master is no longer in ODOWN nor in * SDOWN condition we abort the failover. This is important as it * prevents a useless failover in a a notable case of netsplit, where - * the senitnels are split from the redis instances. In this case + * the sentinels are split from the redis instances. In this case * the failover will not start while there is the split because no * good slave can be reached. However when the split is resolved, we - * can go to waitstart if the slave is back rechable a few milliseconds + * can go to waitstart if the slave is back reachable a few milliseconds * before the master is. In that case when the master is back online * we cancel the failover. */ if ((ri->flags & (SRI_S_DOWN|SRI_O_DOWN|SRI_FORCE_FAILOVER)) == 0) { @@ -3026,13 +3026,13 @@ void sentinelHandleDictOfRedisInstances(dict *instances) { * following conditions happen: * * 1) The Sentiel process for some time is blocked, for every kind of - * random reason: the load is huge, the computer was freezed for some time + * random reason: the load is huge, the computer was frozen for some time * in I/O or alike, the process was stopped by a signal. Everything. * 2) The system clock was altered significantly. * * Under both this conditions we'll see everything as timed out and failing * without good reasons. Instead we enter the TILT mode and wait - * for SENTIENL_TILT_PERIOD to elapse before starting to act again. + * for SENTINEL_TILT_PERIOD to elapse before starting to act again. * * During TILT time we still collect information, we just do not act. */ void sentinelCheckTiltCondition(void) { diff --git a/src/sha1.c b/src/sha1.c index 26a5565ee..59e6f461d 100644 --- a/src/sha1.c +++ b/src/sha1.c @@ -57,13 +57,13 @@ A million repetitions of "a" void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) { -u_int32_t a, b, c, d, e; -typedef union { - unsigned char c[64]; - u_int32_t l[16]; -} CHAR64LONG16; + u_int32_t a, b, c, d, e; + typedef union { + unsigned char c[64]; + u_int32_t l[16]; + } CHAR64LONG16; #ifdef SHA1HANDSOFF -CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ memcpy(block, buffer, 64); #else /* The following had better never be used because it causes the @@ -71,7 +71,7 @@ CHAR64LONG16 block[1]; /* use array to appear as a pointer */ * And the result is written through. I threw a "const" in, hoping * this will cause a diagnostic. */ -CHAR64LONG16* block = (const CHAR64LONG16*)buffer; + CHAR64LONG16* block = (const CHAR64LONG16*)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; @@ -132,12 +132,11 @@ void SHA1Init(SHA1_CTX* context) void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len) { -u_int32_t i; -u_int32_t j; + u_int32_t i, j; j = context->count[0]; if ((context->count[0] += len << 3) < j) - context->count[1]++; + context->count[1]++; context->count[1] += (len>>29); j = (j >> 3) & 63; if ((j + len) > 63) { @@ -157,9 +156,9 @@ u_int32_t j; void SHA1Final(unsigned char digest[20], SHA1_CTX* context) { -unsigned i; -unsigned char finalcount[8]; -unsigned char c; + unsigned i; + unsigned char finalcount[8]; + unsigned char c; #if 0 /* untested "improvement" by DHR */ /* Convert context->count to a sequence of bytes @@ -170,12 +169,12 @@ unsigned char c; unsigned char *fcp = &finalcount[8]; for (i = 0; i < 2; i++) - { - u_int32_t t = context->count[i]; - int j; + { + u_int32_t t = context->count[i]; + int j; - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char) t + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t; } #else for (i = 0; i < 8; i++) { @@ -226,3 +225,4 @@ main(int argc, char **argv) } #endif + diff --git a/src/sort.c b/src/sort.c index 17db30bba..7f056ea21 100644 --- a/src/sort.c +++ b/src/sort.c @@ -46,7 +46,7 @@ redisSortOperation *createSortOperation(int type, robj *pattern) { /* Return the value associated to the key with a name obtained using * the following rules: * - * 1) The first occurence of '*' in 'pattern' is substituted with 'subst'. + * 1) The first occurrence of '*' in 'pattern' is substituted with 'subst'. * * 2) If 'pattern' matches the "->" string, everything on the left of * the arrow is treated as the name of an hash field, and the part on the @@ -148,7 +148,7 @@ int sortCompare(const void *s1, const void *s2) { cmp = -1; } else { /* Objects have the same score, but we don't want the comparison - * to be undefined, so we compare objects lexicographycally. + * to be undefined, so we compare objects lexicographically. * This way the result of SORT is deterministic. */ cmp = compareStringObjects(so1->obj,so2->obj); } @@ -206,7 +206,7 @@ void sortCommand(redisClient *c) { /* Now we need to protect sortval incrementing its count, in the future * SORT may have options able to overwrite/delete keys during the sorting - * and the sorted key itself may get destroied */ + * and the sorted key itself may get destroyed */ if (sortval) incrRefCount(sortval); else diff --git a/src/t_list.c b/src/t_list.c index 1693f0ac1..63e788afd 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -46,10 +46,10 @@ void listTypeTryConversion(robj *subject, robj *value) { listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST); } -/* The function pushes an elmenet to the specified list object 'subject', +/* The function pushes an element to the specified list object 'subject', * at head or tail position as specified by 'where'. * - * There is no need for the caller to incremnet the refcount of 'value' as + * There is no need for the caller to increment the refcount of 'value' as * the function takes care of it if needed. */ void listTypePush(robj *subject, robj *value, int where) { /* Check if we need to convert the ziplist */ @@ -833,7 +833,7 @@ void unblockClientWaitingData(redisClient *c) { /* If the specified key has clients blocked waiting for list pushes, this * function will put the key reference into the server.ready_keys list. * Note that db->ready_keys is an hash table that allows us to avoid putting - * the same key agains and again in the list in case of multiple pushes + * the same key again and again in the list in case of multiple pushes * made by a script or in the context of MULTI/EXEC. * * The list will be finally processed by handleClientsBlockedOnLists() */ @@ -866,7 +866,7 @@ void signalListAsReady(redisClient *c, robj *key) { * * 1) Provide the client with the 'value' element. * 2) If the dstkey is not NULL (we are serving a BRPOPLPUSH) also push the - * 'value' element on the destionation list (the LPUSH side of the command). + * 'value' element on the destination list (the LPUSH side of the command). * 3) Propagate the resulting BRPOP, BLPOP and additional LPUSH if any into * the AOF and replication channel. * @@ -876,7 +876,7 @@ void signalListAsReady(redisClient *c, robj *key) { * * The function returns REDIS_OK if we are able to serve the client, otherwise * REDIS_ERR is returned to signal the caller that the list POP operation - * should be undoed as the client was not served: This only happens for + * should be undone as the client was not served: This only happens for * BRPOPLPUSH that fails to push the value to the destination key as it is * of the wrong type. */ int serveClientBlockedOnList(redisClient *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where) diff --git a/src/t_set.c b/src/t_set.c index 2baef7ffe..f384dc76c 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -189,7 +189,7 @@ robj *setTypeNextObject(setTypeIterator *si) { * The caller provides both pointers to be populated with the right * object. The return value of the function is the object->encoding * field of the object and is used by the caller to check if the - * int64_t pointer or the redis object pointere was populated. + * int64_t pointer or the redis object pointer was populated. * * When an object is returned (the set was a real set) the ref count * of the object is not incremented so this function can be considered @@ -599,7 +599,7 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum, sets[j] = setobj; } /* Sort sets from the smallest to largest, this will improve our - * algorithm's performace */ + * algorithm's performance */ qsort(sets,setnum,sizeof(robj*),qsortCompareSetsByCardinality); slowlogAddComplexityParam('N', setTypeSize(sets[0])); diff --git a/src/t_string.c b/src/t_string.c index 00510c710..0a7f22583 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -43,7 +43,7 @@ static int checkStringLength(redisClient *c, long long size) { } void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire, int unit) { - long long milliseconds = 0; /* initialized to avoid an harmness warning */ + long long milliseconds = 0; /* initialized to avoid any harmness warning */ if (expire) { if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK) @@ -340,7 +340,7 @@ void incrbyfloatCommand(redisClient *c) { addReplyBulk(c,new); /* Always replicate INCRBYFLOAT as a SET command with the final value - * in order to make sure that differences in float pricision or formatting + * in order to make sure that differences in float precision or formatting * will not create differences in replicas or after an AOF restart. */ aux = createStringObject("SET",3); rewriteClientCommandArgument(c,0,aux); diff --git a/src/t_zset.c b/src/t_zset.c index 8d676fa1f..3f57284e5 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -126,7 +126,7 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) { } /* we assume the key is not already inside, since we allow duplicated * scores, and the re-insertion of score and redis object should never - * happpen since the caller of zslInsert() should test in the hash table + * happen since the caller of zslInsert() should test in the hash table * if the element is already inside or not. */ level = zslRandomLevel(); if (level > zsl->level) { @@ -286,7 +286,7 @@ zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec range) { } /* Delete all the elements with score between min and max from the skiplist. - * Min and mx are inclusive, so a score >= min || score <= max is deleted. + * Min and max are inclusive, so a score >= min || score <= max is deleted. * Note that this function takes the reference to the hash table view of the * sorted set, in order to remove the elements from the hash table too. */ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec range, dict *dict) { diff --git a/src/version.h b/src/version.h index c0881950f..293bd1bfb 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define REDIS_VERSION "2.6.8" +#define REDIS_VERSION "2.6.9" diff --git a/src/zmalloc.c b/src/zmalloc.c index 1f8c7f08e..71e9e0820 100644 --- a/src/zmalloc.c +++ b/src/zmalloc.c @@ -250,7 +250,7 @@ void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) { * * For this kind of "fast RSS reporting" usages use instead the * function RedisEstimateRSS() that is a much faster (and less precise) - * version of the funciton. */ + * version of the function. */ #if defined(HAVE_PROCFS) #include <unistd.h> diff --git a/tests/unit/introspection.tcl b/tests/unit/introspection.tcl index 9db0395a2..a6c2130f5 100644 --- a/tests/unit/introspection.tcl +++ b/tests/unit/introspection.tcl @@ -19,4 +19,37 @@ start_server {tags {"introspection"}} { assert_match {*eval*} [$rd read] assert_match {*lua*"set"*"foo"*"bar"*} [$rd read] } + + test {CLIENT GETNAME should return NIL if name is not assigned} { + r client getname + } {} + + test {CLIENT LIST shows empty fields for unassigned names} { + r client list + } {*name= *} + + test {CLIENT SETNAME does not accept spaces} { + catch {r client setname "foo bar"} e + set e + } {ERR*} + + test {CLIENT SETNAME can assign a name to this connection} { + assert_equal [r client setname myname] {OK} + r client list + } {*name=myname*} + + test {CLIENT SETNAME can change the name of an existing connection} { + assert_equal [r client setname someothername] {OK} + r client list + } {*name=someothername*} + + test {After CLIENT SETNAME, connection can still be closed} { + set rd [redis_deferring_client] + $rd client setname foobar + assert_equal [$rd read] "OK" + assert_match {*foobar*} [r client list] + $rd close + # Now the client should no longer be listed + string match {*foobar*} [r client list] + } {0} } diff --git a/tests/unit/pubsub.tcl b/tests/unit/pubsub.tcl index c8b547b4f..769151600 100644 --- a/tests/unit/pubsub.tcl +++ b/tests/unit/pubsub.tcl @@ -192,4 +192,14 @@ start_server {tags {"pubsub"}} { # clean up clients $rd1 close } -}
\ No newline at end of file + + test "PUNSUBSCRIBE and UNSUBSCRIBE should always reply." { + # Make sure we are not subscribed to any channel at all. + r punsubscribe + r unsubscribe + # Now check if the commands still reply correctly. + set reply1 [r punsubscribe] + set reply2 [r unsubscribe] + concat $reply1 $reply2 + } {punsubscribe {} 0 unsubscribe {} 0} +} diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl index 4333fb64e..64cf00d55 100644 --- a/tests/unit/scripting.tcl +++ b/tests/unit/scripting.tcl @@ -34,7 +34,7 @@ start_server {tags {"scripting"}} { r eval {return {1,2,3,'ciao',{1,2}}} 0 } {1 2 3 ciao {1 2}} - test {EVAL - Are the KEYS and ARGS arrays populated correctly?} { + test {EVAL - Are the KEYS and ARGV arrays populated correctly?} { r eval {return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}} 2 a b c d } {a b c d} diff --git a/tests/unit/slowlog.tcl b/tests/unit/slowlog.tcl index e15ddf5ff..bc1e70d85 100644 --- a/tests/unit/slowlog.tcl +++ b/tests/unit/slowlog.tcl @@ -55,4 +55,16 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} { set e [lindex [r slowlog get] 0] lindex $e 4 } {sadd set foo {AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... (1 more bytes)}} + + test {SLOWLOG - EXEC is not logged, just executed commands} { + r config set slowlog-log-slower-than 100000 + r slowlog reset + assert_equal [r slowlog len] 0 + r multi + r debug sleep 0.2 + r exec + assert_equal [r slowlog len] 1 + set e [lindex [r slowlog get] 0] + assert_equal [lindex $e 4] {debug sleep 0.2} + } } |