summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYossi Gottlieb <yossigo@gmail.com>2013-01-27 09:49:15 +0200
committerYossi Gottlieb <yossigo@gmail.com>2013-01-27 09:49:15 +0200
commitacb73e8a972adadd31450dca9ab8cf74cc82a029 (patch)
treeccd1ca55a85aec0af719c8ed1012f13883cd6c15
parentd195e8bb8225bae62b8a714b9c02a472bc601e2f (diff)
parentc17a7f6fbc82dc6ab34a788f65adc16e84b5777c (diff)
downloadredis-2.6.9-1.tar.gz
Merge upstream Redis 2.6.9.2.6.9-1
-rw-r--r--00-RELEASENOTES14
-rw-r--r--deps/lua/src/lua_struct.c171
-rwxr-xr-xredis.conf2
-rw-r--r--sentinel.conf2
-rw-r--r--src/adlist.c6
-rw-r--r--src/ae.c6
-rw-r--r--src/ae_evport.c12
-rw-r--r--src/anet.c4
-rwxr-xr-xsrc/aof.c5
-rw-r--r--src/bio.c2
-rw-r--r--src/bitops.c4
-rwxr-xr-xsrc/config.c6
-rw-r--r--src/config.h2
-rw-r--r--src/db.c8
-rw-r--r--src/debug.c4
-rw-r--r--src/dict.c2
-rw-r--r--src/lzfP.h8
-rw-r--r--src/memtest.c6
-rwxr-xr-xsrc/mkreleasehdr.sh2
-rwxr-xr-xsrc/multi.c4
-rw-r--r--src/networking.c51
-rw-r--r--src/object.c2
-rw-r--r--src/pubsub.c18
-rwxr-xr-xsrc/rdb.c15
-rwxr-xr-xsrc/rdb.h2
-rw-r--r--src/redis-check-dump.c4
-rw-r--r--src/redis-cli.c110
-rwxr-xr-xsrc/redis.c35
-rwxr-xr-xsrc/redis.h23
-rw-r--r--src/release.c4
-rwxr-xr-xsrc/replication.c40
-rwxr-xr-xsrc/scripting.c12
-rw-r--r--src/sds.c4
-rw-r--r--src/sentinel.c20
-rw-r--r--src/sha1.c36
-rw-r--r--src/sort.c6
-rw-r--r--src/t_list.c10
-rw-r--r--src/t_set.c4
-rw-r--r--src/t_string.c4
-rw-r--r--src/t_zset.c4
-rw-r--r--src/version.h2
-rw-r--r--src/zmalloc.c2
-rw-r--r--tests/unit/introspection.tcl33
-rw-r--r--tests/unit/pubsub.tcl12
-rw-r--r--tests/unit/scripting.tcl2
-rw-r--r--tests/unit/slowlog.tcl12
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 */
diff --git a/src/ae.c b/src/ae.c
index 90be4e28f..6ca9a5153 100644
--- a/src/ae.c
+++ b/src/ae.c
@@ -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));
diff --git a/src/aof.c b/src/aof.c
index 36a092397..b0db347ce 100755
--- a/src/aof.c
+++ b/src/aof.c
@@ -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;
diff --git a/src/bio.c b/src/bio.c
index f3ddd6725..744c4c937 100644
--- a/src/bio.c
+++ b/src/bio.c
@@ -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
diff --git a/src/db.c b/src/db.c
index 95f5a2f45..e0d28a4e4 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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;
}
diff --git a/src/rdb.c b/src/rdb.c
index 0de78ab03..17d04743f 100755
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -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;
diff --git a/src/rdb.h b/src/rdb.h
index 2fedfef94..b37ba0338 100755
--- a/src/rdb.h
+++ b/src/rdb.h
@@ -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);
diff --git a/src/sds.c b/src/sds.c
index e8491acfa..85858a4f0 100644
--- a/src/sds.c
+++ b/src/sds.c
@@ -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}
+ }
}