summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2014-08-25 10:27:53 +0200
committerantirez <antirez@gmail.com>2014-08-25 10:27:53 +0200
commit209f266cc534471daa03501b2802f08e4fca4fe6 (patch)
treedc5a9dbe07eb684a8a11730ed3d427afbe2e641b
parentc951c3ee5a12110f1c0c1270c45ab663c04e0f77 (diff)
parent1f8a6d806cc25ece4d092fb3d49af9ccc1443102 (diff)
downloadredis-209f266cc534471daa03501b2802f08e4fca4fe6.tar.gz
Merge branch '1906-merge' into unstable
-rw-r--r--deps/Makefile7
-rw-r--r--deps/hiredis/fmacros.h4
-rw-r--r--deps/hiredis/net.h2
-rw-r--r--deps/hiredis/sds.c9
-rw-r--r--deps/hiredis/sds.h4
-rw-r--r--redis.conf2
-rw-r--r--src/Makefile14
-rw-r--r--src/ae.c4
-rw-r--r--src/anet.c6
-rw-r--r--src/anet.h6
-rw-r--r--src/aof.c9
-rw-r--r--src/bitops.c20
-rw-r--r--src/cluster.c94
-rw-r--r--src/config.c4
-rw-r--r--src/config.h7
-rw-r--r--src/db.c20
-rw-r--r--src/dict.c10
-rw-r--r--src/dict.h4
-rw-r--r--src/fmacros.h4
-rw-r--r--src/hyperloglog.c4
-rw-r--r--src/intset.c2
-rw-r--r--src/latency.c1
-rw-r--r--src/memtest.c1
-rw-r--r--src/multi.c2
-rw-r--r--src/networking.c2
-rw-r--r--src/pubsub.c2
-rw-r--r--src/rand.c4
-rw-r--r--src/rdb.c6
-rw-r--r--src/redis-benchmark.c29
-rw-r--r--src/redis-check-dump.c11
-rw-r--r--src/redis-cli.c62
-rw-r--r--src/redis.c84
-rw-r--r--src/redis.h18
-rw-r--r--src/scripting.c5
-rw-r--r--src/sds.c8
-rw-r--r--src/sds.h4
-rw-r--r--src/sentinel.c29
-rw-r--r--src/t_string.c4
-rw-r--r--src/t_zset.c2
-rw-r--r--src/ziplist.c26
-rw-r--r--tests/support/util.tcl2
-rw-r--r--tests/unit/basic.tcl11
-rw-r--r--tests/unit/pubsub.tcl4
-rw-r--r--tests/unit/scripting.tcl5
-rw-r--r--tests/unit/sort.tcl8
-rwxr-xr-xutils/generate-command-help.rb2
-rwxr-xr-xutils/install_server.sh4
47 files changed, 375 insertions, 197 deletions
diff --git a/deps/Makefile b/deps/Makefile
index 5a95545de..e183ede9c 100644
--- a/deps/Makefile
+++ b/deps/Makefile
@@ -60,10 +60,15 @@ endif
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI $(CFLAGS)
LUA_LDFLAGS+= $(LDFLAGS)
+# lua's Makefile defines AR="ar rcu", which is unusual, and makes it more
+# challenging to cross-compile lua (and redis). These defines make it easier
+# to fit redis into cross-compilation environments, which typically set AR.
+AR=ar
+ARFLAGS=rcu
lua: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
- cd lua/src && $(MAKE) all CFLAGS="$(LUA_CFLAGS)" MYLDFLAGS="$(LUA_LDFLAGS)"
+ cd lua/src && $(MAKE) all CFLAGS="$(LUA_CFLAGS)" MYLDFLAGS="$(LUA_LDFLAGS)" AR="$(AR) $(ARFLAGS)"
.PHONY: lua
diff --git a/deps/hiredis/fmacros.h b/deps/hiredis/fmacros.h
index 9e5fec0ce..6a41aa176 100644
--- a/deps/hiredis/fmacros.h
+++ b/deps/hiredis/fmacros.h
@@ -5,6 +5,10 @@
#define _BSD_SOURCE
#endif
+#if defined(_AIX)
+#define _ALL_SOURCE
+#endif
+
#if defined(__sun__)
#define _POSIX_C_SOURCE 200112L
#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__)
diff --git a/deps/hiredis/net.h b/deps/hiredis/net.h
index 5e742f577..3763ab089 100644
--- a/deps/hiredis/net.h
+++ b/deps/hiredis/net.h
@@ -35,7 +35,7 @@
#include "hiredis.h"
-#if defined(__sun)
+#if defined(__sun) || defined(_AIX)
#define AF_LOCAL AF_UNIX
#endif
diff --git a/deps/hiredis/sds.c b/deps/hiredis/sds.c
index 47b9823ea..4af9961ad 100644
--- a/deps/hiredis/sds.c
+++ b/deps/hiredis/sds.c
@@ -123,7 +123,7 @@ void sdsclear(sds s) {
/* Enlarge the free space at the end of the sds string so that the caller
* is sure that after calling this function can overwrite up to addlen
* bytes after the end of the string, plus one more byte for nul term.
- *
+ *
* Note: this does not change the *length* of the sds string as returned
* by sdslen(), but only the free buffer space we have. */
sds sdsMakeRoomFor(sds s, size_t addlen) {
@@ -200,7 +200,10 @@ size_t sdsAllocSize(sds s) {
void sdsIncrLen(sds s, int incr) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
- assert(sh->free >= incr);
+ if (incr >= 0)
+ assert(sh->free >= (unsigned int)incr);
+ else
+ assert(sh->len >= (unsigned int)(-incr));
sh->len += incr;
sh->free -= incr;
assert(sh->free >= 0);
@@ -457,7 +460,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
i = initlen; /* Position of the next byte to write to dest str. */
while(*f) {
char next, *str;
- int l;
+ unsigned int l;
long long num;
unsigned long long unum;
diff --git a/deps/hiredis/sds.h b/deps/hiredis/sds.h
index 9a604021c..37aaf7a28 100644
--- a/deps/hiredis/sds.h
+++ b/deps/hiredis/sds.h
@@ -39,8 +39,8 @@
typedef char *sds;
struct sdshdr {
- int len;
- int free;
+ unsigned int len;
+ unsigned int free;
char buf[];
};
diff --git a/redis.conf b/redis.conf
index 33f28a5bb..ae774d6fe 100644
--- a/redis.conf
+++ b/redis.conf
@@ -68,7 +68,7 @@ tcp-backlog 511
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
-# unixsocketperm 755
+# unixsocketperm 700
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
diff --git a/src/Makefile b/src/Makefile
index 4ccc6d367..96af74afa 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -19,7 +19,7 @@ DEPENDENCY_TARGETS=hiredis linenoise lua
# Default settings
STD=-std=c99 -pedantic
-WARN=-Wall
+WARN=-Wall -W
OPT=$(OPTIMIZATION)
PREFIX?=/usr/local
@@ -58,17 +58,23 @@ ifeq ($(uname_S),SunOS)
# SunOS
INSTALL=cp -pf
FINAL_CFLAGS+= -D__EXTENSIONS__ -D_XPG6
- FINAL_LIBS+= -ldl -lnsl -lsocket -lpthread
+ FINAL_LIBS+= -ldl -lnsl -lsocket -lresolv -lpthread
else
ifeq ($(uname_S),Darwin)
# Darwin (nothing to do)
else
+ifeq ($(uname_S),AIX)
+ # AIX
+ FINAL_LDFLAGS+= -Wl,-bexpall
+ FINAL_LIBS+= -pthread -lcrypt -lbsd
+
+else
# All the other OSes (notably Linux)
FINAL_LDFLAGS+= -rdynamic
FINAL_LIBS+= -pthread
endif
endif
-
+endif
# Include paths to dependencies
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
@@ -119,7 +125,7 @@ REDIS_CHECK_AOF_OBJ=redis-check-aof.o
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_DUMP_NAME) $(REDIS_CHECK_AOF_NAME)
@echo ""
- @echo "Hint: To run 'make test' is a good idea ;)"
+ @echo "Hint: It's a good idea to run 'make test' ;)"
@echo ""
.PHONY: all
diff --git a/src/ae.c b/src/ae.c
index 164f8fdeb..63a1ab4eb 100644
--- a/src/ae.c
+++ b/src/ae.c
@@ -156,8 +156,9 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
{
if (fd >= eventLoop->setsize) return;
aeFileEvent *fe = &eventLoop->events[fd];
-
if (fe->mask == AE_NONE) return;
+
+ aeApiDelEvent(eventLoop, fd, mask);
fe->mask = fe->mask & (~mask);
if (fd == eventLoop->maxfd && fe->mask == AE_NONE) {
/* Update the max fd */
@@ -167,7 +168,6 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
if (eventLoop->events[j].mask != AE_NONE) break;
eventLoop->maxfd = j;
}
- aeApiDelEvent(eventLoop, fd, mask);
}
int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
diff --git a/src/anet.c b/src/anet.c
index 87cc3ea25..76915326f 100644
--- a/src/anet.c
+++ b/src/anet.c
@@ -117,6 +117,8 @@ int anetKeepAlive(char *err, int fd, int interval)
anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno));
return ANET_ERR;
}
+#else
+ ((void) interval); /* Avoid unused var warning for non Linux systems. */
#endif
return ANET_OK;
@@ -262,7 +264,8 @@ static int anetTcpGenericConnect(char *err, char *addr, int port,
if (source_addr) {
int bound = 0;
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
- if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) {
+ if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0)
+ {
anetSetError(err, "%s", gai_strerror(rv));
goto end;
}
@@ -272,6 +275,7 @@ static int anetTcpGenericConnect(char *err, char *addr, int port,
break;
}
}
+ freeaddrinfo(bservinfo);
if (!bound) {
anetSetError(err, "bind: %s", strerror(errno));
goto end;
diff --git a/src/anet.h b/src/anet.h
index c4659cd35..5191c4b69 100644
--- a/src/anet.h
+++ b/src/anet.h
@@ -39,10 +39,14 @@
#define ANET_NONE 0
#define ANET_IP_ONLY (1<<0)
-#if defined(__sun)
+#if defined(__sun) || defined(_AIX)
#define AF_LOCAL AF_UNIX
#endif
+#ifdef _AIX
+#undef ip_len
+#endif
+
int anetTcpConnect(char *err, char *addr, int port);
int anetTcpNonBlockConnect(char *err, char *addr, int port);
int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr);
diff --git a/src/aof.c b/src/aof.c
index a2ef2df93..5d46a21c4 100644
--- a/src/aof.c
+++ b/src/aof.c
@@ -95,6 +95,10 @@ void aofChildWriteDiffData(aeEventLoop *el, int fd, void *privdata, int mask) {
listNode *ln;
aofrwblock *block;
ssize_t nwritten;
+ REDIS_NOTUSED(el);
+ REDIS_NOTUSED(fd);
+ REDIS_NOTUSED(privdata);
+ REDIS_NOTUSED(mask);
while(1) {
ln = listFirst(server.aof_rewrite_buf_blocks);
@@ -177,7 +181,7 @@ ssize_t aofRewriteBufferWrite(int fd) {
if (block->used) {
nwritten = write(fd,block->buf,block->used);
- if (nwritten != block->used) {
+ if (nwritten != (ssize_t)block->used) {
if (nwritten == 0) errno = EIO;
return -1;
}
@@ -1128,6 +1132,9 @@ werr:
* parent sends a '!' as well to acknowledge. */
void aofChildPipeReadable(aeEventLoop *el, int fd, void *privdata, int mask) {
char byte;
+ REDIS_NOTUSED(el);
+ REDIS_NOTUSED(privdata);
+ REDIS_NOTUSED(mask);
if (read(fd,&byte,1) == 1 && byte == '!') {
redisLog(REDIS_NOTICE,"AOF rewrite child asks to stop sending diffs.");
diff --git a/src/bitops.c b/src/bitops.c
index 28f772430..94c7f3537 100644
--- a/src/bitops.c
+++ b/src/bitops.c
@@ -107,12 +107,12 @@ size_t redisPopcount(void *s, long count) {
* no zero bit is found, it returns count*8 assuming the string is zero
* padded on the right. However if 'bit' is 1 it is possible that there is
* not a single set bit in the bitmap. In this special case -1 is returned. */
-long redisBitpos(void *s, long count, int bit) {
+long redisBitpos(void *s, unsigned long count, int bit) {
unsigned long *l;
unsigned char *c;
unsigned long skipval, word = 0, one;
long pos = 0; /* Position of bit, to return to the caller. */
- int j;
+ unsigned long j;
/* Process whole words first, seeking for first word that is not
* all ones or all zeros respectively if we are lookig for zeros
@@ -276,11 +276,12 @@ void getbitCommand(redisClient *c) {
void bitopCommand(redisClient *c) {
char *opname = c->argv[1]->ptr;
robj *o, *targetkey = c->argv[2];
- long op, j, numkeys;
+ unsigned long op, j, numkeys;
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. */
+ unsigned long *len, maxlen = 0; /* Array of length of src strings,
+ and max len. */
+ unsigned long minlen = 0; /* Min len among the input keys. */
unsigned char *res = NULL; /* Resulting string. */
/* Parse the operation name. */
@@ -320,9 +321,10 @@ void bitopCommand(redisClient *c) {
}
/* Return an error if one of the keys is not a string. */
if (checkType(c,o,REDIS_STRING)) {
- for (j = j-1; j >= 0; j--) {
- if (objects[j])
- decrRefCount(objects[j]);
+ unsigned long i;
+ for (i = 0; i < j; i++) {
+ if (objects[i])
+ decrRefCount(objects[i]);
}
zfree(src);
zfree(len);
@@ -340,7 +342,7 @@ void bitopCommand(redisClient *c) {
if (maxlen) {
res = (unsigned char*) sdsnewlen(NULL,maxlen);
unsigned char output, byte;
- long i;
+ unsigned long i;
/* Fast path: as far as we have data for all the input bitmaps we
* can take a fast path that performs much better than the
diff --git a/src/cluster.c b/src/cluster.c
index 0d908349c..07eaa637c 100644
--- a/src/cluster.c
+++ b/src/cluster.c
@@ -72,6 +72,7 @@ void resetManualFailover(void);
void clusterCloseAllSlots(void);
void clusterSetNodeAsMaster(clusterNode *n);
void clusterDelNode(clusterNode *delnode);
+sds representRedisNodeFlags(sds ci, uint16_t flags);
/* -----------------------------------------------------------------------------
* Initialization
@@ -163,9 +164,13 @@ int clusterLoadConfig(char *filename) {
argv[j]);
}
}
+ sdsfreesplitres(argv,argc);
continue;
}
+ /* Regular config lines have at least eight fields */
+ if (argc < 8) goto fmterr;
+
/* Create this node if it does not exist */
n = clusterLookupNode(argv[0]);
if (!n) {
@@ -266,11 +271,12 @@ int clusterLoadConfig(char *filename) {
sdsfreesplitres(argv,argc);
}
+ /* Config sanity check */
+ if (server.cluster->myself == NULL) goto fmterr;
+
zfree(line);
fclose(fp);
- /* Config sanity check */
- redisAssert(server.cluster->myself != NULL);
redisLog(REDIS_NOTICE,"Node configuration loaded, I'm %.40s", myself->name);
/* Something that should never happen: currentEpoch smaller than
@@ -284,7 +290,8 @@ int clusterLoadConfig(char *filename) {
fmterr:
redisLog(REDIS_WARNING,
"Unrecoverable error: corrupted cluster config file.");
- fclose(fp);
+ zfree(line);
+ if (fp) fclose(fp);
exit(1);
}
@@ -321,7 +328,7 @@ int clusterSaveConfig(int do_fsync) {
/* Pad the new payload if the existing file length is greater. */
if (fstat(fd,&sb) != -1) {
- if (sb.st_size > content_size) {
+ if (sb.st_size > (off_t)content_size) {
ci = sdsgrowzero(ci,sb.st_size);
memset(ci+content_size,'\n',sb.st_size-content_size);
}
@@ -1144,20 +1151,11 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
clusterNode *sender = link->node ? link->node : clusterLookupNode(hdr->sender);
while(count--) {
- sds ci = sdsempty();
uint16_t flags = ntohs(g->flags);
clusterNode *node;
+ sds ci;
- if (flags == 0) ci = sdscat(ci,"noflags,");
- if (flags & REDIS_NODE_MYSELF) ci = sdscat(ci,"myself,");
- if (flags & REDIS_NODE_MASTER) ci = sdscat(ci,"master,");
- if (flags & REDIS_NODE_SLAVE) ci = sdscat(ci,"slave,");
- if (flags & REDIS_NODE_PFAIL) ci = sdscat(ci,"fail?,");
- if (flags & REDIS_NODE_FAIL) ci = sdscat(ci,"fail,");
- if (flags & REDIS_NODE_HANDSHAKE) ci = sdscat(ci,"handshake,");
- if (flags & REDIS_NODE_NOADDR) ci = sdscat(ci,"noaddr,");
- if (ci[sdslen(ci)-1] == ',') ci[sdslen(ci)-1] = ' ';
-
+ ci = representRedisNodeFlags(sdsempty(), flags);
redisLog(REDIS_DEBUG,"GOSSIP %.40s %s:%d %s",
g->nodename,
g->ip,
@@ -1914,7 +1912,7 @@ void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
ssize_t nread;
clusterMsg *hdr;
clusterLink *link = (clusterLink*) privdata;
- int readlen, rcvbuflen;
+ unsigned int readlen, rcvbuflen;
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
@@ -3296,14 +3294,13 @@ int verifyClusterConfigWithData(void) {
update_config++;
/* Case A: slot is unassigned. Take responsability for it. */
if (server.cluster->slots[j] == NULL) {
- redisLog(REDIS_WARNING, "I've keys about slot %d that is "
- "unassigned. Taking responsability "
- "for it.",j);
+ redisLog(REDIS_WARNING, "I have keys for unassigned slot %d. "
+ "Taking responsibility for it.",j);
clusterAddSlot(myself,j);
} else {
- redisLog(REDIS_WARNING, "I've keys about slot %d that is "
- "already assigned to a different node. "
- "Setting it in importing state.",j);
+ redisLog(REDIS_WARNING, "I have keys for slot %d, but the slot is "
+ "assigned to another node. "
+ "Setting it to importing state.",j);
server.cluster->importing_slots_from[j] = server.cluster->slots[j];
}
}
@@ -3336,9 +3333,40 @@ void clusterSetMaster(clusterNode *n) {
}
/* -----------------------------------------------------------------------------
- * CLUSTER command
+ * Nodes to string representation functions.
* -------------------------------------------------------------------------- */
+struct redisNodeFlags {
+ uint16_t flag;
+ char *name;
+};
+
+static struct redisNodeFlags redisNodeFlagsTable[] = {
+ {REDIS_NODE_MYSELF, "myself,"},
+ {REDIS_NODE_MASTER, "master,"},
+ {REDIS_NODE_SLAVE, "slave,"},
+ {REDIS_NODE_PFAIL, "fail?,"},
+ {REDIS_NODE_FAIL, "fail,"},
+ {REDIS_NODE_HANDSHAKE, "handshake,"},
+ {REDIS_NODE_NOADDR, "noaddr,"}
+};
+
+/* Concatenate the comma separated list of node flags to the given SDS
+ * string 'ci'. */
+sds representRedisNodeFlags(sds ci, uint16_t flags) {
+ if (flags == 0) {
+ ci = sdscat(ci,"noflags,");
+ } else {
+ int i, size = sizeof(redisNodeFlagsTable)/sizeof(struct redisNodeFlags);
+ for (i = 0; i < size; i++) {
+ struct redisNodeFlags *nodeflag = redisNodeFlagsTable + i;
+ if (flags & nodeflag->flag) ci = sdscat(ci, nodeflag->name);
+ }
+ }
+ sdsIncrLen(ci,-1); /* Remove trailing comma. */
+ return ci;
+}
+
/* Generate a csv-alike representation of the specified cluster node.
* See clusterGenNodesDescription() top comment for more information.
*
@@ -3354,21 +3382,13 @@ sds clusterGenNodeDescription(clusterNode *node) {
node->port);
/* Flags */
- if (node->flags == 0) ci = sdscat(ci,"noflags,");
- if (node->flags & REDIS_NODE_MYSELF) ci = sdscat(ci,"myself,");
- if (node->flags & REDIS_NODE_MASTER) ci = sdscat(ci,"master,");
- if (node->flags & REDIS_NODE_SLAVE) ci = sdscat(ci,"slave,");
- if (node->flags & REDIS_NODE_PFAIL) ci = sdscat(ci,"fail?,");
- if (node->flags & REDIS_NODE_FAIL) ci = sdscat(ci,"fail,");
- if (node->flags & REDIS_NODE_HANDSHAKE) ci =sdscat(ci,"handshake,");
- if (node->flags & REDIS_NODE_NOADDR) ci = sdscat(ci,"noaddr,");
- if (ci[sdslen(ci)-1] == ',') ci[sdslen(ci)-1] = ' ';
+ ci = representRedisNodeFlags(ci, node->flags);
/* Slave of... or just "-" */
if (node->slaveof)
- ci = sdscatprintf(ci,"%.40s ",node->slaveof->name);
+ ci = sdscatprintf(ci," %.40s ",node->slaveof->name);
else
- ci = sdscatprintf(ci,"- ");
+ ci = sdscatlen(ci," - ",3);
/* Latency from the POV of this node, link status */
ci = sdscatprintf(ci,"%lld %lld %llu %s",
@@ -3446,6 +3466,10 @@ sds clusterGenNodesDescription(int filter) {
return ci;
}
+/* -----------------------------------------------------------------------------
+ * CLUSTER command
+ * -------------------------------------------------------------------------- */
+
int getSlotOrReply(redisClient *c, robj *o) {
long long slot;
@@ -3962,7 +3986,7 @@ void clusterCommand(redisClient *c) {
"configEpoch set to %llu via CLUSTER SET-CONFIG-EPOCH",
(unsigned long long) myself->configEpoch);
- if (server.cluster->currentEpoch < epoch)
+ if (server.cluster->currentEpoch < (uint64_t)epoch)
server.cluster->currentEpoch = epoch;
/* No need to fsync the config here since in the unlucky event
* of a failure to persist the config, the conflict resolution code
diff --git a/src/config.c b/src/config.c
index b0fc50b9d..2aff1351f 100644
--- a/src/config.c
+++ b/src/config.c
@@ -73,7 +73,7 @@ void appendServerSaveParams(time_t seconds, int changes) {
server.saveparamslen++;
}
-void resetServerSaveParams() {
+void resetServerSaveParams(void) {
zfree(server.saveparams);
server.saveparams = NULL;
server.saveparamslen = 0;
@@ -629,7 +629,7 @@ void configSetCommand(redisClient *c) {
server.maxclients = orig_value;
return;
}
- if (aeGetSetSize(server.el) <
+ if ((unsigned int) aeGetSetSize(server.el) <
server.maxclients + REDIS_EVENTLOOP_FDSET_INCR)
{
if (aeResizeSetSize(server.el,
diff --git a/src/config.h b/src/config.h
index 1bc70a13e..57d07599a 100644
--- a/src/config.h
+++ b/src/config.h
@@ -187,9 +187,14 @@ void setproctitle(const char *fmt, ...);
#if (__i386 || __amd64 || __powerpc__) && __GNUC__
#define GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-#if (GNUC_VERSION >= 40100) || defined(__clang__)
+#if defined(__clang__)
#define HAVE_ATOMIC
#endif
+#if (defined(__GLIBC__) && defined(__GLIBC_PREREQ))
+#if (GNUC_VERSION >= 40100 && __GLIBC_PREREQ(2, 6))
+#define HAVE_ATOMIC
+#endif
+#endif
#endif
#endif
diff --git a/src/db.c b/src/db.c
index c83ab2ee6..8eb1b89a7 100644
--- a/src/db.c
+++ b/src/db.c
@@ -421,9 +421,7 @@ int parseScanCursorOrReply(redisClient *c, robj *o, unsigned long *cursor) {
* In the case of a Hash object the function returns both the field and value
* of every element on the Hash. */
void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor) {
- int rv;
int i, j;
- char buf[REDIS_LONGSTR_SIZE];
list *keys = listCreate();
listNode *node, *nextnode;
long count = 10;
@@ -503,7 +501,7 @@ void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor) {
privdata[1] = o;
do {
cursor = dictScan(ht, cursor, scanCallback, privdata);
- } while (cursor && listLength(keys) < count);
+ } while (cursor && listLength(keys) < (unsigned long)count);
} else if (o->type == REDIS_SET) {
int pos = 0;
int64_t ll;
@@ -577,9 +575,7 @@ void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor) {
/* Step 4: Reply to the client. */
addReplyMultiBulkLen(c, 2);
- rv = snprintf(buf, sizeof(buf), "%lu", cursor);
- redisAssert(rv < sizeof(buf));
- addReplyBulkCBuffer(c, buf, rv);
+ addReplyBulkLongLong(c,cursor);
addReplyMultiBulkLen(c, listLength(keys));
while ((node = listFirst(keys)) != NULL) {
@@ -707,6 +703,7 @@ void moveCommand(redisClient *c) {
robj *o;
redisDb *src, *dst;
int srcid;
+ long long dbid;
if (server.cluster_enabled) {
addReplyError(c,"MOVE is not allowed in cluster mode");
@@ -716,7 +713,11 @@ void moveCommand(redisClient *c) {
/* Obtain source and target DB pointers */
src = c->db;
srcid = c->db->id;
- if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
+
+ if (getLongLongFromObject(c->argv[2],&dbid) == REDIS_ERR ||
+ dbid < INT_MIN || dbid > INT_MAX ||
+ selectDb(c,dbid) == REDIS_ERR)
+ {
addReply(c,shared.outofrangeerr);
return;
}
@@ -1076,7 +1077,7 @@ int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
* follow in SQL-alike style. Here we parse just the minimum in order to
* correctly identify keys in the "STORE" option. */
int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) {
- int i, j, num, *keys;
+ int i, j, num, *keys, found_store = 0;
REDIS_NOTUSED(cmd);
num = 0;
@@ -1107,12 +1108,13 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
/* Note: we don't increment "num" here and continue the loop
* to be sure to process the *last* "STORE" option if multiple
* ones are provided. This is same behavior as SORT. */
+ found_store = 1;
keys[num] = i+1; /* <store-key> */
break;
}
}
}
- *numkeys = num;
+ *numkeys = num + found_store;
return keys;
}
diff --git a/src/dict.c b/src/dict.c
index b27920a44..17818b853 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -79,12 +79,6 @@ unsigned int dictIntHashFunction(unsigned int key)
return key;
}
-/* Identity hash function for integer keys */
-unsigned int dictIdentityHashFunction(unsigned int key)
-{
- return key;
-}
-
static uint32_t dict_hash_function_seed = 5381;
void dictSetHashFunctionSeed(uint32_t seed) {
@@ -668,9 +662,9 @@ dictEntry *dictGetRandomKey(dict *d)
* statistics. However the function is much faster than dictGetRandomKey()
* at producing N elements, and the elements are guaranteed to be non
* repeating. */
-int dictGetRandomKeys(dict *d, dictEntry **des, int count) {
+unsigned int dictGetRandomKeys(dict *d, dictEntry **des, unsigned int count) {
int j; /* internal hash table id, 0 or 1. */
- int stored = 0;
+ unsigned int stored = 0;
if (dictSize(d) < count) count = dictSize(d);
while(stored < count) {
diff --git a/src/dict.h b/src/dict.h
index 905330f5d..b82e137f9 100644
--- a/src/dict.h
+++ b/src/dict.h
@@ -142,7 +142,7 @@ typedef void (dictScanFunction)(void *privdata, const dictEntry *de);
#define dictGetDoubleVal(he) ((he)->v.d)
#define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size)
#define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used)
-#define dictIsRehashing(ht) ((ht)->rehashidx != -1)
+#define dictIsRehashing(d) ((d)->rehashidx != -1)
/* API */
dict *dictCreate(dictType *type, void *privDataPtr);
@@ -162,7 +162,7 @@ dictIterator *dictGetSafeIterator(dict *d);
dictEntry *dictNext(dictIterator *iter);
void dictReleaseIterator(dictIterator *iter);
dictEntry *dictGetRandomKey(dict *d);
-int dictGetRandomKeys(dict *d, dictEntry **des, int count);
+unsigned int dictGetRandomKeys(dict *d, dictEntry **des, unsigned int count);
void dictPrintStats(dict *d);
unsigned int dictGenHashFunction(const void *key, int len);
unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);
diff --git a/src/fmacros.h b/src/fmacros.h
index 44e378a68..e49735ce5 100644
--- a/src/fmacros.h
+++ b/src/fmacros.h
@@ -36,6 +36,10 @@
#define _GNU_SOURCE
#endif
+#if defined(_AIX)
+#define _ALL_SOURCE
+#endif
+
#if defined(__linux__) || defined(__OpenBSD__)
#define _XOPEN_SOURCE 700
/*
diff --git a/src/hyperloglog.c b/src/hyperloglog.c
index 63052a789..005beb18f 100644
--- a/src/hyperloglog.c
+++ b/src/hyperloglog.c
@@ -1349,7 +1349,7 @@ void pfmergeCommand(redisClient *c) {
* Something that is not easy to test from within the outside. */
#define HLL_TEST_CYCLES 1000
void pfselftestCommand(redisClient *c) {
- int j, i;
+ unsigned int j, i;
sds bitcounters = sdsnewlen(NULL,HLL_DENSE_SIZE);
struct hllhdr *hdr = (struct hllhdr*) bitcounters, *hdr2;
robj *o = NULL;
@@ -1431,7 +1431,7 @@ void pfselftestCommand(redisClient *c) {
if (j == 10) maxerr = 1;
if (abserr < 0) abserr = -abserr;
- if (abserr > maxerr) {
+ if (abserr > (int64_t)maxerr) {
addReplyErrorFormat(c,
"TESTFAILED Too big error. card:%llu abserr:%llu",
(unsigned long long) checkpoint,
diff --git a/src/intset.c b/src/intset.c
index b61530e45..5d894e3cd 100644
--- a/src/intset.c
+++ b/src/intset.c
@@ -133,7 +133,7 @@ static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
}
while(max >= min) {
- mid = (min+max)/2;
+ mid = ((unsigned int)min + (unsigned int)max) >> 1;
cur = _intsetGet(is,mid);
if (value > cur) {
min = mid+1;
diff --git a/src/latency.c b/src/latency.c
index fdc88210e..b7845ca29 100644
--- a/src/latency.c
+++ b/src/latency.c
@@ -37,6 +37,7 @@
/* Dictionary type for latency events. */
int dictStringKeyCompare(void *privdata, const void *key1, const void *key2) {
+ REDIS_NOTUSED(privdata);
return strcmp(key1,key2) == 0;
}
diff --git a/src/memtest.c b/src/memtest.c
index cabfb5c89..18d821b10 100644
--- a/src/memtest.c
+++ b/src/memtest.c
@@ -237,6 +237,7 @@ void memtest_test(size_t megabytes, int passes) {
memtest_progress_end();
memtest_compare_times(m,bytes,pass,4);
}
+ free(m);
}
void memtest_non_destructive_invert(void *addr, size_t size) {
diff --git a/src/multi.c b/src/multi.c
index 3d78e1488..c82876456 100644
--- a/src/multi.c
+++ b/src/multi.c
@@ -72,7 +72,7 @@ void queueMultiCommand(redisClient *c) {
void discardTransaction(redisClient *c) {
freeClientMultiState(c);
initClientMultiState(c);
- c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);;
+ c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);
unwatchAllKeys(c);
}
diff --git a/src/networking.c b/src/networking.c
index 9c100db19..fb49b7964 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -1051,7 +1051,7 @@ int processMultibulkBuffer(redisClient *c) {
qblen = sdslen(c->querybuf);
/* Hint the sds library about the amount of bytes this string is
* going to contain. */
- if (qblen < ll+2)
+ if (qblen < (size_t)ll+2)
c->querybuf = sdsMakeRoomFor(c->querybuf,ll+2-qblen);
}
c->bulklen = ll;
diff --git a/src/pubsub.c b/src/pubsub.c
index 720cd5185..d6cfbdf3c 100644
--- a/src/pubsub.c
+++ b/src/pubsub.c
@@ -358,7 +358,7 @@ void pubsubCommand(redisClient *c) {
list *l = dictFetchValue(server.pubsub_channels,c->argv[j]);
addReplyBulk(c,c->argv[j]);
- addReplyBulkLongLong(c,l ? listLength(l) : 0);
+ addReplyLongLong(c,l ? listLength(l) : 0);
}
} else if (!strcasecmp(c->argv[1]->ptr,"numpat") && c->argc == 2) {
/* PUBSUB NUMPAT */
diff --git a/src/rand.c b/src/rand.c
index 36cb417cf..09b0508f1 100644
--- a/src/rand.c
+++ b/src/rand.c
@@ -66,7 +66,7 @@
#define HI_BIT (1L << (2 * N - 1))
static uint32_t x[3] = { X0, X1, X2 }, a[3] = { A0, A1, A2 }, c = C;
-static void next();
+static void next(void);
int32_t redisLrand48() {
next();
@@ -77,7 +77,7 @@ void redisSrand48(int32_t seedval) {
SEED(X0, LOW(seedval), HIGH(seedval));
}
-static void next() {
+static void next(void) {
uint32_t p[2], q[2], r[2], carry0, carry1;
MUL(a[0], x[0], p);
diff --git a/src/rdb.c b/src/rdb.c
index ce5f99c9a..afaef2681 100644
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -688,7 +688,7 @@ int rdbSave(char *filename) {
* loading code skips the check in this case. */
cksum = rdb.cksum;
memrev64ifbe(&cksum);
- rioWrite(&rdb,&cksum,8);
+ if (rioWrite(&rdb,&cksum,8) == 0) goto werr;
/* Make sure data will not remain on the OS's output buffers */
if (fflush(fp) == EOF) goto werr;
@@ -766,7 +766,7 @@ int rdbSaveBackground(char *filename) {
void rdbRemoveTempFile(pid_t childpid) {
char tmpfile[256];
- snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
+ snprintf(tmpfile,sizeof(tmpfile),"temp-%d.rdb", (int) childpid);
unlink(tmpfile);
}
@@ -943,7 +943,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* Add pair to hash table */
ret = dictAdd((dict*)o->ptr, field, value);
- redisAssert(ret == REDIS_OK);
+ redisAssert(ret == DICT_OK);
}
/* All pairs should be read by now */
diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c
index 5ab2625d2..2e67f1021 100644
--- a/src/redis-benchmark.c
+++ b/src/redis-benchmark.c
@@ -77,6 +77,7 @@ static struct config {
int dbnum;
sds dbnumstr;
char *tests;
+ char *auth;
} config;
typedef struct _client {
@@ -213,7 +214,7 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
freeReplyObject(reply);
if (c->selectlen) {
- int j;
+ size_t j;
/* This is the OK from SELECT. Just discard the SELECT
* from the buffer. */
@@ -325,6 +326,13 @@ static client createClient(char *cmd, size_t len, client from) {
* the example client buffer. */
c->obuf = sdsempty();
+ if (config.auth) {
+ char *buf = NULL;
+ int len = redisFormatCommand(&buf, "AUTH %s", config.auth);
+ c->obuf = sdscatlen(c->obuf, buf, len);
+ free(buf);
+ }
+
/* If a DB number different than zero is selected, prefix our request
* buffer with the SELECT command, that will be discarded the first
* time the replies are received, so if the client is reused the
@@ -346,6 +354,7 @@ static client createClient(char *cmd, size_t len, client from) {
for (j = 0; j < config.pipeline; j++)
c->obuf = sdscatlen(c->obuf,cmd,len);
}
+
c->written = 0;
c->pending = config.pipeline;
c->randptr = NULL;
@@ -359,7 +368,7 @@ static client createClient(char *cmd, size_t len, client from) {
c->randfree = 0;
c->randptr = zmalloc(sizeof(char*)*c->randlen);
/* copy the offsets. */
- for (j = 0; j < c->randlen; j++) {
+ for (j = 0; j < (int)c->randlen; j++) {
c->randptr[j] = c->obuf + (from->randptr[j]-from->obuf);
/* Adjust for the different select prefix length. */
c->randptr[j] += c->selectlen - from->selectlen;
@@ -389,15 +398,6 @@ static client createClient(char *cmd, size_t len, client from) {
static void createMissingClients(client c) {
int n = 0;
- char *buf = c->obuf;
- size_t buflen = sdslen(c->obuf);
-
- /* If we are cloning from a client with a SELECT prefix, skip it since the
- * client will be created with the prefixed SELECT if needed. */
- if (c->selectlen) {
- buf += c->selectlen;
- buflen -= c->selectlen;
- }
while(config.liveclients < config.numclients) {
createClient(NULL,0,c);
@@ -489,6 +489,9 @@ int parseOptions(int argc, const char **argv) {
} else if (!strcmp(argv[i],"-s")) {
if (lastarg) goto invalid;
config.hostsocket = strdup(argv[++i]);
+ } else if (!strcmp(argv[i],"-a") ) {
+ if (lastarg) goto invalid;
+ config.auth = strdup(argv[++i]);
} else if (!strcmp(argv[i],"-d")) {
if (lastarg) goto invalid;
config.datasize = atoi(argv[++i]);
@@ -550,6 +553,7 @@ usage:
" -h <hostname> Server hostname (default 127.0.0.1)\n"
" -p <port> Server port (default 6379)\n"
" -s <socket> Server socket (overrides host and port)\n"
+" -a <password> Password for Redis Auth\n"
" -c <clients> Number of parallel connections (default 50)\n"
" -n <requests> Total number of requests (default 10000)\n"
" -d <size> Data size of SET/GET value in bytes (default 2)\n"
@@ -593,7 +597,7 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
REDIS_NOTUSED(clientData);
if (config.liveclients == 0) {
- fprintf(stderr,"All clients disconnected... aborting.");
+ fprintf(stderr,"All clients disconnected... aborting.\n");
exit(1);
}
@@ -651,6 +655,7 @@ int main(int argc, const char **argv) {
config.hostsocket = NULL;
config.tests = NULL;
config.dbnum = 0;
+ config.auth = NULL;
i = parseOptions(argc,argv);
argc -= i;
diff --git a/src/redis-check-dump.c b/src/redis-check-dump.c
index a4f103fdd..546462001 100644
--- a/src/redis-check-dump.c
+++ b/src/redis-check-dump.c
@@ -138,8 +138,10 @@ typedef struct {
* at runtime to avoid strange compiler optimizations. */
static double R_Zero, R_PosInf, R_NegInf, R_Nan;
+#define MAX_TYPES_NUM 256
+#define MAX_TYPE_NAME_LEN 16
/* store string types for output */
-static char types[256][16];
+static char types[MAX_TYPES_NUM][MAX_TYPE_NAME_LEN];
/* Return true if 't' is a valid object type. */
int checkType(unsigned char t) {
@@ -166,7 +168,7 @@ int readBytes(void *target, long num) {
return 1;
}
-int processHeader() {
+int processHeader(void) {
char buf[10] = "_________";
int dump_version;
@@ -335,6 +337,7 @@ char* loadStringObject() {
if (len == REDIS_RDB_LENERR) return NULL;
char *buf = malloc(sizeof(char) * (len+1));
+ if (buf == NULL) return NULL;
buf[len] = '\0';
if (!readBytes(buf, len)) {
free(buf);
@@ -600,7 +603,7 @@ void printErrorStack(entry *e) {
}
}
-void process() {
+void process(void) {
uint64_t num_errors = 0, num_valid_ops = 0, num_valid_bytes = 0;
entry entry;
int dump_version = processHeader();
@@ -611,7 +614,7 @@ void process() {
printf("RDB version >= 5 but no room for checksum.\n");
exit(1);
}
- positions[0].size -= 8;;
+ positions[0].size -= 8;
}
level = 1;
diff --git a/src/redis-cli.c b/src/redis-cli.c
index 907e62b74..3526319d5 100644
--- a/src/redis-cli.c
+++ b/src/redis-cli.c
@@ -94,10 +94,11 @@ static struct config {
sds mb_delim;
char prompt[128];
char *eval;
+ int last_cmd_type;
} config;
static volatile sig_atomic_t force_cancel_loop = 0;
-static void usage();
+static void usage(void);
static void slaveMode(void);
char *redisGitSHA1(void);
char *redisGitDirty(void);
@@ -131,7 +132,7 @@ static void cliRefreshPrompt(void) {
strchr(config.hostip,':') ? "[%s]:%d" : "%s:%d",
config.hostip, config.hostport);
/* Add [dbnum] if needed */
- if (config.dbnum != 0)
+ if (config.dbnum != 0 && config.last_cmd_type != REDIS_REPLY_ERROR)
len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]",
config.dbnum);
snprintf(config.prompt+len,sizeof(config.prompt)-len,"> ");
@@ -157,7 +158,7 @@ typedef struct {
static helpEntry *helpEntries;
static int helpEntriesLen;
-static sds cliVersion() {
+static sds cliVersion(void) {
sds version;
version = sdscatprintf(sdsempty(), "%s", REDIS_VERSION);
@@ -171,7 +172,7 @@ static sds cliVersion() {
return version;
}
-static void cliInitHelp() {
+static void cliInitHelp(void) {
int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
int groupslen = sizeof(commandGroups)/sizeof(char*);
int i, len, pos = 0;
@@ -210,7 +211,7 @@ static void cliOutputCommandHelp(struct commandHelp *help, int group) {
}
/* Print generic help. */
-static void cliOutputGenericHelp() {
+static void cliOutputGenericHelp(void) {
sds version = cliVersion();
printf(
"redis-cli %s\r\n"
@@ -320,8 +321,10 @@ static int cliSelect() {
reply = redisCommand(context,"SELECT %d",config.dbnum);
if (reply != NULL) {
+ int result = REDIS_OK;
+ if (reply->type == REDIS_REPLY_ERROR) result = REDIS_ERR;
freeReplyObject(reply);
- return REDIS_OK;
+ return result;
}
return REDIS_ERR;
}
@@ -365,7 +368,7 @@ static int cliConnect(int force) {
return REDIS_OK;
}
-static void cliPrintContextError() {
+static void cliPrintContextError(void) {
if (context == NULL) return;
fprintf(stderr,"Error: %s\n",context->errstr);
}
@@ -514,8 +517,11 @@ static int cliReadReply(int output_raw_strings) {
int output = 1;
if (redisGetReply(context,&_reply) != REDIS_OK) {
- if (config.shutdown)
+ if (config.shutdown) {
+ redisFree(context);
+ context = NULL;
return REDIS_OK;
+ }
if (config.interactive) {
/* Filter cases where we should reconnect */
if (context->err == REDIS_ERR_IO && errno == ECONNRESET)
@@ -530,6 +536,8 @@ static int cliReadReply(int output_raw_strings) {
reply = (redisReply*)_reply;
+ config.last_cmd_type = reply->type;
+
/* Check if we need to connect to a different node and reissue the
* request. */
if (config.cluster_mode && reply->type == REDIS_REPLY_ERROR &&
@@ -639,6 +647,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
printf("Entering slave output mode... (press Ctrl-C to quit)\n");
slaveMode();
config.slave_mode = 0;
+ free(argvlen);
return REDIS_ERR; /* Error = slaveMode lost connection to master */
}
@@ -650,6 +659,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
if (!strcasecmp(command,"select") && argc == 2) {
config.dbnum = atoi(argv[1]);
cliRefreshPrompt();
+ } else if (!strcasecmp(command,"auth") && argc == 2) {
+ cliSelect();
}
}
if (config.interval) usleep(config.interval);
@@ -724,6 +735,8 @@ static int parseOptions(int argc, char **argv) {
config.auth = argv[++i];
} else if (!strcmp(argv[i],"--raw")) {
config.output = OUTPUT_RAW;
+ } else if (!strcmp(argv[i],"--no-raw")) {
+ config.output = OUTPUT_STANDARD;
} else if (!strcmp(argv[i],"--csv")) {
config.output = OUTPUT_CSV;
} else if (!strcmp(argv[i],"--latency")) {
@@ -795,7 +808,7 @@ static sds readArgFromStdin(void) {
return arg;
}
-static void usage() {
+static void usage(void) {
sds version = cliVersion();
fprintf(stderr,
"redis-cli %s\n"
@@ -814,6 +827,7 @@ static void usage() {
" -c Enable cluster mode (follow -ASK and -MOVED redirections).\n"
" --raw Use raw formatting for replies (default when STDOUT is\n"
" not a tty).\n"
+" --no-raw Force formatted output even when STDOUT is not a tty.\n"
" --csv Output in CSV format.\n"
" --latency Enter a special mode continuously sampling latency.\n"
" --latency-history Like --latency but tracking latency changes over time.\n"
@@ -862,8 +876,7 @@ static char **convertToSds(int count, char** args) {
return sds;
}
-#define LINE_BUFLEN 4096
-static void repl() {
+static void repl(void) {
sds historyfile = NULL;
int history = 0;
char *line;
@@ -1406,7 +1419,7 @@ static int toIntType(char *key, char *type) {
static void getKeyTypes(redisReply *keys, int *types) {
redisReply *reply;
- int i;
+ unsigned int i;
/* Pipeline TYPE commands */
for(i=0;i<keys->elements;i++) {
@@ -1435,7 +1448,7 @@ static void getKeySizes(redisReply *keys, int *types,
{
redisReply *reply;
char *sizecmds[] = {"STRLEN","LLEN","SCARD","HLEN","ZCARD"};
- int i;
+ unsigned int i;
/* Pipeline size commands */
for(i=0;i<keys->elements;i++) {
@@ -1482,7 +1495,8 @@ static void findBigKeys(void) {
char *typename[] = {"string","list","set","hash","zset"};
char *typeunit[] = {"bytes","items","members","fields","members"};
redisReply *reply, *keys;
- int type, *types=NULL, arrsize=0, i;
+ unsigned int arrsize=0, i;
+ int type, *types=NULL;
double pct;
/* Total keys pre scanning */
@@ -1666,7 +1680,7 @@ void bytesToHuman(char *s, long long n) {
}
}
-static void statMode() {
+static void statMode(void) {
redisReply *reply;
long aux, requests = 0;
int i = 0;
@@ -1752,7 +1766,7 @@ static void statMode() {
* Scan mode
*--------------------------------------------------------------------------- */
-static void scanMode() {
+static void scanMode(void) {
redisReply *reply;
unsigned long long cur = 0;
@@ -1769,7 +1783,7 @@ static void scanMode() {
printf("ERROR: %s\n", reply->str);
exit(1);
} else {
- int j;
+ unsigned int j;
cur = strtoull(reply->element[0]->str,NULL,10);
for (j = 0; j < reply->element[1]->elements; j++)
@@ -1840,11 +1854,15 @@ static void intrinsicLatencyMode(void) {
printf("Max latency so far: %lld microseconds.\n", max_latency);
}
+ double avg_us = (double)run_time/runs;
+ double avg_ns = avg_us * 10e3;
if (force_cancel_loop || end > test_end) {
- printf("\n%lld total runs (avg %lld microseconds per run).\n",
- runs, run_time/runs);
- printf("Worst run took %.02fx times the average.\n",
- (double) max_latency / (run_time/runs));
+ printf("\n%lld total runs "
+ "(avg latency: "
+ "%.4f microseconds / %.2f nanoseconds per run).\n",
+ runs, avg_us, avg_ns);
+ printf("Worst run took %.0fx longer than the average latency.\n",
+ max_latency / avg_us);
exit(0);
}
}
@@ -1883,6 +1901,8 @@ int main(int argc, char **argv) {
config.stdinarg = 0;
config.auth = NULL;
config.eval = NULL;
+ config.last_cmd_type = -1;
+
if (!isatty(fileno(stdout)) && (getenv("FAKETTY") == NULL))
config.output = OUTPUT_RAW;
else
diff --git a/src/redis.c b/src/redis.c
index 5ddbc9250..e58ceb047 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -66,7 +66,6 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
/* Global vars */
struct redisServer server; /* server global state */
-struct redisCommand *commandTable;
/* Our command table.
*
@@ -267,7 +266,7 @@ struct redisCommand redisCommandTable[] = {
{"readwrite",readwriteCommand,1,"rF",0,NULL,0,0,0,0,0},
{"dump",dumpCommand,2,"ar",0,NULL,1,1,1,0,0},
{"object",objectCommand,3,"r",0,NULL,2,2,2,0,0},
- {"client",clientCommand,-2,"ar",0,NULL,0,0,0,0,0},
+ {"client",clientCommand,-2,"ars",0,NULL,0,0,0,0,0},
{"eval",evalCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
{"evalsha",evalShaCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
{"slowlog",slowlogCommand,-2,"r",0,NULL,0,0,0,0,0},
@@ -760,8 +759,8 @@ void activeExpireCycle(int type) {
static int timelimit_exit = 0; /* Time limit hit in previous call? */
static long long last_fast_cycle = 0; /* When last fast cycle ran. */
- unsigned int j, iteration = 0;
- unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
+ int j, iteration = 0;
+ int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
long long start = ustime(), timelimit;
if (type == ACTIVE_EXPIRE_CYCLE_FAST) {
@@ -1000,8 +999,8 @@ void databasesCron(void) {
* cron loop iteration. */
static unsigned int resize_db = 0;
static unsigned int rehash_db = 0;
- unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
- unsigned int j;
+ int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
+ int j;
/* Don't test more DBs than we have. */
if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;
@@ -1376,7 +1375,7 @@ void createSharedObjects(void) {
shared.maxstring = createStringObject("maxstring",9);
}
-void initServerConfig() {
+void initServerConfig(void) {
int j;
getRandomHexChars(server.runid,REDIS_RUN_ID_SIZE);
@@ -1557,7 +1556,7 @@ void adjustOpenFilesLimit(void) {
* to the higher value supported less than maxfiles. */
f = maxfiles;
while(f > oldlimit) {
- int decr_step = 16;
+ rlim_t decr_step = 16;
limit.rlim_cur = f;
limit.rlim_max = f;
@@ -1696,7 +1695,7 @@ void resetServerStats(void) {
server.ops_sec_last_sample_ops = 0;
}
-void initServer() {
+void initServer(void) {
int j;
signal(SIGHUP, SIG_IGN);
@@ -2359,9 +2358,9 @@ int time_independent_strcmp(char *a, char *b) {
* a or b are fixed (our password) length, and the difference is only
* relative to the length of the user provided string, so no information
* leak is possible in the following two lines of code. */
- int alen = strlen(a);
- int blen = strlen(b);
- int j;
+ unsigned int alen = strlen(a);
+ unsigned int blen = strlen(b);
+ unsigned int j;
int diff = 0;
/* We can't compare strings longer than our static buffers.
@@ -2547,6 +2546,15 @@ void bytesToHuman(char *s, unsigned long long n) {
} else if (n < (1024LL*1024*1024*1024)) {
d = (double)n/(1024LL*1024*1024);
sprintf(s,"%.2fG",d);
+ } else if (n < (1024LL*1024*1024*1024*1024)) {
+ d = (double)n/(1024LL*1024*1024*1024);
+ sprintf(s,"%.2fT",d);
+ } else if (n < (1024LL*1024*1024*1024*1024*1024)) {
+ d = (double)n/(1024LL*1024*1024*1024*1024);
+ sprintf(s,"%.2fP",d);
+ } else {
+ /* Let's hope we never need this */
+ sprintf(s,"%lluB",n);
}
}
@@ -2562,10 +2570,9 @@ sds genRedisInfoString(char *section) {
int allsections = 0, defsections = 0;
int sections = 0;
- if (section) {
- allsections = strcasecmp(section,"all") == 0;
- defsections = strcasecmp(section,"default") == 0;
- }
+ if (section == NULL) section = "default";
+ allsections = strcasecmp(section,"all") == 0;
+ defsections = strcasecmp(section,"default") == 0;
getrusage(RUSAGE_SELF, &self_ru);
getrusage(RUSAGE_CHILDREN, &c_ru);
@@ -3350,7 +3357,7 @@ void daemonize(void) {
}
}
-void version() {
+void version(void) {
printf("Redis server v=%s sha=%s:%d malloc=%s bits=%d build=%llx\n",
REDIS_VERSION,
redisGitSHA1(),
@@ -3361,7 +3368,7 @@ void version() {
exit(0);
}
-void usage() {
+void usage(void) {
fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf] [options]\n");
fprintf(stderr," ./redis-server - (read config from stdin)\n");
fprintf(stderr," ./redis-server -v or --version\n");
@@ -3399,10 +3406,33 @@ void redisAsciiArt(void) {
zfree(buf);
}
-static void sigtermHandler(int sig) {
- REDIS_NOTUSED(sig);
-
- redisLogFromHandler(REDIS_WARNING,"Received SIGTERM, scheduling shutdown...");
+static void sigShutdownHandler(int sig) {
+ char *msg;
+
+ switch (sig) {
+ case SIGINT:
+ msg = "Received SIGINT scheduling shutdown...";
+ break;
+ case SIGTERM:
+ msg = "Received SIGTERM scheduling shutdown...";
+ break;
+ default:
+ msg = "Received shutdown signal, scheduling shutdown...";
+ };
+
+ /* SIGINT is often delivered via Ctrl+C in an interactive session.
+ * If we receive the signal the second time, we interpret this as
+ * the user really wanting to quit ASAP without waiting to persist
+ * on disk. */
+ if (server.shutdown_asap && sig == SIGINT) {
+ redisLogFromHandler(REDIS_WARNING, "You insist... exiting now.");
+ rdbRemoveTempFile(getpid());
+ exit(1); /* Exit with an error since this was not a clean shutdown. */
+ } else if (server.loading) {
+ exit(0);
+ }
+
+ redisLogFromHandler(REDIS_WARNING, msg);
server.shutdown_asap = 1;
}
@@ -3413,8 +3443,9 @@ void setupSignalHandlers(void) {
* Otherwise, sa_handler is used. */
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
- act.sa_handler = sigtermHandler;
+ act.sa_handler = sigShutdownHandler;
sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
#ifdef HAVE_BACKTRACE
sigemptyset(&act.sa_mask);
@@ -3545,6 +3576,13 @@ int main(int argc, char **argv) {
}
j++;
}
+ if (server.sentinel_mode && configfile && *configfile == '-') {
+ redisLog(REDIS_WARNING,
+ "Sentinel config from STDIN not allowed.");
+ redisLog(REDIS_WARNING,
+ "Sentinel needs config file on disk to save state. Exiting...");
+ exit(1);
+ }
if (configfile) server.configfile = getAbsolutePath(configfile);
resetServerSaveParams();
loadServerConfig(configfile,options);
diff --git a/src/redis.h b/src/redis.h
index d2b00bff5..c352cd79a 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -626,6 +626,12 @@ typedef struct redisOpArray {
struct clusterState;
+/* AIX defines hz to __hz, we don't use this define and in order to allow
+ * Redis build on AIX we need to undef it. */
+#ifdef _AIX
+#undef hz
+#endif
+
struct redisServer {
/* General */
pid_t pid; /* Main process pid. */
@@ -808,12 +814,12 @@ struct redisServer {
/* Replication script cache. */
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */
- int repl_scriptcache_size; /* Max number of elements. */
+ unsigned int repl_scriptcache_size; /* Max number of elements. */
/* Synchronous replication. */
list *clients_waiting_acks; /* Clients waiting in WAIT command. */
int get_ack_from_slaves; /* If true we send REPLCONF GETACK. */
/* Limits */
- int maxclients; /* Max number of simultaneous clients */
+ unsigned int maxclients; /* Max number of simultaneous clients */
unsigned long long maxmemory; /* Max number of memory bytes to use */
int maxmemory_policy; /* Policy for key eviction */
int maxmemory_samples; /* Pricision of random sampling */
@@ -993,11 +999,10 @@ void freeClient(redisClient *c);
void freeClientAsync(redisClient *c);
void resetClient(redisClient *c);
void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask);
-void addReply(redisClient *c, robj *obj);
void *addDeferredMultiBulkLength(redisClient *c);
void setDeferredMultiBulkLength(redisClient *c, void *node, long length);
-void addReplySds(redisClient *c, sds s);
void processInputBuffer(redisClient *c);
+void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask);
@@ -1005,7 +1010,6 @@ void addReplyBulk(redisClient *c, robj *obj);
void addReplyBulkCString(redisClient *c, char *s);
void addReplyBulkCBuffer(redisClient *c, void *p, size_t len);
void addReplyBulkLongLong(redisClient *c, long long ll);
-void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void addReply(redisClient *c, robj *obj);
void addReplySds(redisClient *c, sds s);
void addReplyError(redisClient *c, char *err);
@@ -1210,7 +1214,7 @@ void redisLog(int level, const char *fmt, ...);
#endif
void redisLogRaw(int level, const char *msg);
void redisLogFromHandler(int level, const char *msg);
-void usage();
+void usage(void);
void updateDictResizePolicy(void);
int htNeedsResize(dict *dict);
void oom(const char *msg);
@@ -1270,7 +1274,7 @@ sds keyspaceEventsFlagsToString(int flags);
/* Configuration */
void loadServerConfig(char *filename, char *options);
void appendServerSaveParams(time_t seconds, int changes);
-void resetServerSaveParams();
+void resetServerSaveParams(void);
struct rewriteConfigState; /* Forward declaration to export API. */
void rewriteConfigRewriteLine(struct rewriteConfigState *state, char *option, sds line, int force);
int rewriteConfig(char *path);
diff --git a/src/scripting.c b/src/scripting.c
index ef00eede6..a0c88742f 100644
--- a/src/scripting.c
+++ b/src/scripting.c
@@ -212,7 +212,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
static robj **argv = NULL;
static int argv_size = 0;
static robj *cached_objects[LUA_CMD_OBJCACHE_SIZE];
- static int cached_objects_len[LUA_CMD_OBJCACHE_SIZE];
+ static size_t cached_objects_len[LUA_CMD_OBJCACHE_SIZE];
/* Require at least one argument */
if (argc == 0) {
@@ -910,6 +910,9 @@ void evalGenericCommand(redisClient *c, int evalsha) {
if (numkeys > (c->argc - 3)) {
addReplyError(c,"Number of keys can't be greater than number of args");
return;
+ } else if (numkeys < 0) {
+ addReplyError(c,"Number of keys can't be negative");
+ return;
}
/* We obtain the script SHA1, then check if this function is already
diff --git a/src/sds.c b/src/sds.c
index dc07d0d3a..4adcc06a8 100644
--- a/src/sds.c
+++ b/src/sds.c
@@ -200,7 +200,10 @@ size_t sdsAllocSize(sds s) {
void sdsIncrLen(sds s, int incr) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
- assert(sh->free >= incr);
+ if (incr >= 0)
+ assert(sh->free >= (unsigned int)incr);
+ else
+ assert(sh->len >= (unsigned int)(-incr));
sh->len += incr;
sh->free -= incr;
assert(sh->free >= 0);
@@ -388,6 +391,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
buf[buflen-2] = '\0';
va_copy(cpy,ap);
vsnprintf(buf, buflen, fmt, cpy);
+ va_end(ap);
if (buf[buflen-2] != '\0') {
if (buf != staticbuf) zfree(buf);
buflen *= 2;
@@ -457,7 +461,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
i = initlen; /* Position of the next byte to write to dest str. */
while(*f) {
char next, *str;
- int l;
+ unsigned int l;
long long num;
unsigned long long unum;
diff --git a/src/sds.h b/src/sds.h
index 9a604021c..37aaf7a28 100644
--- a/src/sds.h
+++ b/src/sds.h
@@ -39,8 +39,8 @@
typedef char *sds;
struct sdshdr {
- int len;
- int free;
+ unsigned int len;
+ unsigned int free;
char buf[];
};
diff --git a/src/sentinel.c b/src/sentinel.c
index 48e1de8dd..603cdd404 100644
--- a/src/sentinel.c
+++ b/src/sentinel.c
@@ -159,7 +159,7 @@ typedef struct sentinelRedisInstance {
/* Master specific. */
dict *sentinels; /* Other sentinels monitoring the same master. */
dict *slaves; /* Slaves for this master instance. */
- int quorum; /* Number of sentinels that need to agree on failure. */
+ unsigned int quorum;/* Number of sentinels that need to agree on failure. */
int parallel_syncs; /* How many slaves to reconfigure at same time. */
char *auth_pass; /* Password to use for AUTH against master & slaves. */
@@ -345,6 +345,7 @@ int dictSdsKeyCompare(void *privdata, const void *key1, const void *key2);
void releaseSentinelRedisInstance(sentinelRedisInstance *ri);
void dictInstancesValDestructor (void *privdata, void *obj) {
+ REDIS_NOTUSED(privdata);
releaseSentinelRedisInstance(obj);
}
@@ -403,7 +404,7 @@ void initSentinelConfig(void) {
/* Perform the Sentinel mode initialization. */
void initSentinel(void) {
- int j;
+ unsigned int j;
/* Remove usual Redis commands from the command table, then just add
* the SENTINEL command. */
@@ -455,19 +456,19 @@ void sentinelIsRunning(void) {
* EINVAL: Invalid port number.
*/
sentinelAddr *createSentinelAddr(char *hostname, int port) {
- char buf[32];
+ char ip[REDIS_IP_STR_LEN];
sentinelAddr *sa;
if (port <= 0 || port > 65535) {
errno = EINVAL;
return NULL;
}
- if (anetResolve(NULL,hostname,buf,sizeof(buf)) == ANET_ERR) {
+ if (anetResolve(NULL,hostname,ip,sizeof(ip)) == ANET_ERR) {
errno = ENOENT;
return NULL;
}
sa = zmalloc(sizeof(*sa));
- sa->ip = sdsnew(buf);
+ sa->ip = sdsnew(ip);
sa->port = port;
return sa;
}
@@ -1634,6 +1635,7 @@ void sentinelLinkEstablishedCallback(const redisAsyncContext *c, int status) {
}
void sentinelDisconnectCallback(const redisAsyncContext *c, int status) {
+ REDIS_NOTUSED(status);
sentinelDisconnectInstanceFromContext(c);
}
@@ -1998,6 +2000,7 @@ void sentinelRefreshInstanceInfo(sentinelRedisInstance *ri, const char *info) {
void sentinelInfoReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
sentinelRedisInstance *ri = c->data;
redisReply *r;
+ REDIS_NOTUSED(privdata);
if (ri) ri->pending_commands--;
if (!reply || !ri) return;
@@ -2012,6 +2015,8 @@ void sentinelInfoReplyCallback(redisAsyncContext *c, void *reply, void *privdata
* value of the command but its effects directly. */
void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
sentinelRedisInstance *ri = c->data;
+ REDIS_NOTUSED(reply);
+ REDIS_NOTUSED(privdata);
if (ri) ri->pending_commands--;
}
@@ -2019,6 +2024,7 @@ void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privd
void sentinelPingReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
sentinelRedisInstance *ri = c->data;
redisReply *r;
+ REDIS_NOTUSED(privdata);
if (ri) ri->pending_commands--;
if (!reply || !ri) return;
@@ -2057,6 +2063,7 @@ void sentinelPingReplyCallback(redisAsyncContext *c, void *reply, void *privdata
void sentinelPublishReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
sentinelRedisInstance *ri = c->data;
redisReply *r;
+ REDIS_NOTUSED(privdata);
if (ri) ri->pending_commands--;
if (!reply || !ri) return;
@@ -2166,6 +2173,7 @@ cleanup:
void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privdata) {
sentinelRedisInstance *ri = c->data;
redisReply *r;
+ REDIS_NOTUSED(privdata);
if (!reply || !ri) return;
r = reply;
@@ -2559,7 +2567,7 @@ sentinelRedisInstance *sentinelGetMasterByNameOrReplyError(redisClient *c,
{
sentinelRedisInstance *ri;
- ri = dictFetchValue(sentinel.masters,c->argv[2]->ptr);
+ ri = dictFetchValue(sentinel.masters,name->ptr);
if (!ri) {
addReplyError(c,"No such master with that name");
return NULL;
@@ -2682,7 +2690,7 @@ void sentinelCommand(redisClient *c) {
/* SENTINEL MONITOR <name> <ip> <port> <quorum> */
sentinelRedisInstance *ri;
long quorum, port;
- char buf[32];
+ char ip[REDIS_IP_STR_LEN];
if (c->argc != 6) goto numargserr;
if (getLongFromObjectOrReply(c,c->argv[5],&quorum,"Invalid quorum")
@@ -2692,7 +2700,7 @@ void sentinelCommand(redisClient *c) {
/* Make sure the IP field is actually a valid IP before passing it
* to createSentinelRedisInstance(), otherwise we may trigger a
* DNS lookup at runtime. */
- if (anetResolveIP(NULL,c->argv[3]->ptr,buf,sizeof(buf)) == ANET_ERR) {
+ if (anetResolveIP(NULL,c->argv[3]->ptr,ip,sizeof(ip)) == ANET_ERR) {
addReplyError(c,"Invalid IP address specified");
return;
}
@@ -2997,7 +3005,7 @@ void sentinelCheckSubjectivelyDown(sentinelRedisInstance *ri) {
void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
dictIterator *di;
dictEntry *de;
- int quorum = 0, odown = 0;
+ unsigned int quorum = 0, odown = 0;
if (master->flags & SRI_S_DOWN) {
/* Is down for enough sentinels? */
@@ -3034,6 +3042,7 @@ void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *privdata) {
sentinelRedisInstance *ri = c->data;
redisReply *r;
+ REDIS_NOTUSED(privdata);
if (ri) ri->pending_commands--;
if (!reply || !ri) return;
@@ -3057,7 +3066,7 @@ void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *p
/* If the runid in the reply is not "*" the Sentinel actually
* replied with a vote. */
sdsfree(ri->leader);
- if (ri->leader_epoch != r->element[2]->integer)
+ if ((long long)ri->leader_epoch != r->element[2]->integer)
redisLog(REDIS_WARNING,
"%s voted for %s %llu", ri->name,
r->element[1]->str,
diff --git a/src/t_string.c b/src/t_string.c
index 41e4b3b71..8a4d5f166 100644
--- a/src/t_string.c
+++ b/src/t_string.c
@@ -69,7 +69,7 @@ void setGenericCommand(redisClient *c, int flags, robj *key, robj *val, robj *ex
if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK)
return;
if (milliseconds <= 0) {
- addReplyError(c,"invalid expire time in SETEX");
+ addReplyErrorFormat(c,"invalid expire time in %s",c->cmd->name);
return;
}
if (unit == UNIT_SECONDS) milliseconds *= 1000;
@@ -255,7 +255,7 @@ void getrangeCommand(redisClient *c) {
if (end < 0) end = strlen+end;
if (start < 0) start = 0;
if (end < 0) end = 0;
- if ((unsigned)end >= strlen) end = strlen-1;
+ if ((size_t)end >= strlen) end = strlen-1;
/* Precondition: end >= 0 && end < strlen, so the only condition where
* nothing can be returned is: start > end. */
diff --git a/src/t_zset.c b/src/t_zset.c
index 20ef62e27..d3c7214bd 100644
--- a/src/t_zset.c
+++ b/src/t_zset.c
@@ -205,8 +205,6 @@ int zslDelete(zskiplist *zsl, double score, robj *obj) {
zslDeleteNode(zsl, x, update);
zslFreeNode(x);
return 1;
- } else {
- return 0; /* not found */
}
return 0; /* not found */
}
diff --git a/src/ziplist.c b/src/ziplist.c
index d78f8f5da..4a0111105 100644
--- a/src/ziplist.c
+++ b/src/ziplist.c
@@ -576,19 +576,19 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig
/* Insert item at "p". */
static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
- size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen, prevlen = 0;
+ size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen;
+ unsigned int prevlensize, prevlen = 0;
size_t offset;
int nextdiff = 0;
unsigned char encoding = 0;
long long value = 123456789; /* initialized to avoid warning. Using a value
that is easy to see if for some reason
we use it uninitialized. */
- zlentry entry, tail;
+ zlentry tail;
/* Find out prevlen for the entry that is inserted. */
if (p[0] != ZIP_END) {
- entry = zipEntry(p);
- prevlen = entry.prevrawlen;
+ ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);
} else {
unsigned char *ptail = ZIPLIST_ENTRY_TAIL(zl);
if (ptail[0] != ZIP_END) {
@@ -676,15 +676,15 @@ unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int sle
* doesn't contain an element at the provided index, NULL is returned. */
unsigned char *ziplistIndex(unsigned char *zl, int index) {
unsigned char *p;
- zlentry entry;
+ unsigned int prevlensize, prevlen = 0;
if (index < 0) {
index = (-index)-1;
p = ZIPLIST_ENTRY_TAIL(zl);
if (p[0] != ZIP_END) {
- entry = zipEntry(p);
- while (entry.prevrawlen > 0 && index--) {
- p -= entry.prevrawlen;
- entry = zipEntry(p);
+ ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);
+ while (prevlen > 0 && index--) {
+ p -= prevlen;
+ ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);
}
}
} else {
@@ -722,7 +722,7 @@ unsigned char *ziplistNext(unsigned char *zl, unsigned char *p) {
/* Return pointer to previous entry in ziplist. */
unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p) {
- zlentry entry;
+ unsigned int prevlensize, prevlen = 0;
/* Iterating backwards from ZIP_END should return the tail. When "p" is
* equal to the first element of the list, we're already at the head,
@@ -733,9 +733,9 @@ unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p) {
} else if (p == ZIPLIST_ENTRY_HEAD(zl)) {
return NULL;
} else {
- entry = zipEntry(p);
- assert(entry.prevrawlen > 0);
- return p-entry.prevrawlen;
+ ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);
+ assert(prevlen > 0);
+ return p-prevlen;
}
}
diff --git a/tests/support/util.tcl b/tests/support/util.tcl
index 7774dd99a..4b9caced8 100644
--- a/tests/support/util.tcl
+++ b/tests/support/util.tcl
@@ -353,7 +353,7 @@ proc colorstr {color str} {
default {set colorcode {37}}
}
if {$colorcode ne {}} {
- return "\033\[$b;${colorcode};40m$str\033\[0m"
+ return "\033\[$b;${colorcode};49m$str\033\[0m"
}
} else {
return $str
diff --git a/tests/unit/basic.tcl b/tests/unit/basic.tcl
index 6f7fe292c..110376087 100644
--- a/tests/unit/basic.tcl
+++ b/tests/unit/basic.tcl
@@ -404,6 +404,12 @@ start_server {tags {"basic"}} {
r move mykey 10
} {0}
+ test {MOVE against non-integer DB (#1428)} {
+ r set mykey hello
+ catch {r move mykey notanumber} e
+ set e
+ } {*ERR*index out of range}
+
test {SET/GET keys in different DBs} {
r set a hello
r set b world
@@ -769,4 +775,9 @@ start_server {tags {"basic"}} {
r keys *
r keys *
} {dlskeriewrioeuwqoirueioqwrueoqwrueqw}
+
+ test {GETRANGE with huge ranges, Github issue #1844} {
+ r set foo bar
+ r getrange foo 0 4294967297
+ } {bar}
}
diff --git a/tests/unit/pubsub.tcl b/tests/unit/pubsub.tcl
index 18033bdf2..9c7a43bf0 100644
--- a/tests/unit/pubsub.tcl
+++ b/tests/unit/pubsub.tcl
@@ -196,6 +196,10 @@ start_server {tags {"pubsub"}} {
$rd1 close
}
+ test "NUMSUB returns numbers, not strings (#1561)" {
+ r pubsub numsub abc def
+ } {abc 0 def 0}
+
test "Mix SUBSCRIBE and PSUBSCRIBE" {
set rd1 [redis_deferring_client]
assert_equal {1} [subscribe $rd1 {foo.bar}]
diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl
index 4190a0a49..d0c6f5d7a 100644
--- a/tests/unit/scripting.tcl
+++ b/tests/unit/scripting.tcl
@@ -358,6 +358,11 @@ start_server {tags {"scripting"}} {
return redis.call("get", "key")
} 0
} {12039611435714932082}
+
+ test {Verify negative arg count is error instead of crash (issue #1842)} {
+ catch { r eval { return "hello" } -12 } e
+ set e
+ } {ERR Number of keys can't be negative}
}
# Start a new server since the last test in this stanza will kill the
diff --git a/tests/unit/sort.tcl b/tests/unit/sort.tcl
index f48f88b5d..54b0cc7e2 100644
--- a/tests/unit/sort.tcl
+++ b/tests/unit/sort.tcl
@@ -95,6 +95,14 @@ start_server {
assert_encoding ziplist sort-res
}
+ test "SORT extracts STORE correctly" {
+ r command getkeys sort abc store def
+ } {abc def}
+
+ test "SORT extracts multiple STORE correctly" {
+ r command getkeys sort abc store invalid store stillbad store def
+ } {abc def}
+
test "SORT DESC" {
assert_equal [lsort -decreasing -integer $result] [r sort tosort DESC]
}
diff --git a/utils/generate-command-help.rb b/utils/generate-command-help.rb
index 47fbc645c..068953198 100755
--- a/utils/generate-command-help.rb
+++ b/utils/generate-command-help.rb
@@ -50,7 +50,7 @@ def commands
require "json"
require "uri"
- url = URI.parse "https://raw.github.com/antirez/redis-doc/master/commands.json"
+ url = URI.parse "https://raw.githubusercontent.com/antirez/redis-doc/master/commands.json"
client = Net::HTTP.new url.host, url.port
client.use_ssl = true
response = client.get url.path
diff --git a/utils/install_server.sh b/utils/install_server.sh
index 15b60a08e..98e047e3d 100755
--- a/utils/install_server.sh
+++ b/utils/install_server.sh
@@ -152,7 +152,7 @@ rm -f $TMP_FILE
#we hard code the configs here to avoid issues with templates containing env vars
#kinda lame but works!
REDIS_INIT_HEADER=\
-"#/bin/sh\n
+"#!/bin/sh\n
#Configurations injected by install_server below....\n\n
EXEC=$REDIS_EXECUTABLE\n
CLIEXEC=$CLI_EXEC\n
@@ -193,7 +193,7 @@ fi
# warning if init info is not available.
cat > ${TMP_FILE} <<EOT
-#/bin/sh
+#!/bin/sh
#Configurations injected by install_server below....
EXEC=$REDIS_EXECUTABLE