From 94364d53b4746e8cd9e3da633162cb1e34f0bdb6 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 26 Aug 2010 14:05:14 +0200 Subject: [PATCH 01/17] Verify that the blocking pop timeout value is a non-negative integer --- src/t_list.c | 14 +++++++++++++- tests/unit/type/list.tcl | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/t_list.c b/src/t_list.c index 2a981033..43d292b6 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -782,9 +782,20 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) { /* Blocking RPOP/LPOP */ void blockingPopGenericCommand(redisClient *c, int where) { robj *o; + long long lltimeout; time_t timeout; int j; + /* Make sure timeout is an integer value */ + if (getLongLongFromObjectOrReply(c,c->argv[c->argc-1],&lltimeout, + "timeout is not an integer") != REDIS_OK) return; + + /* Make sure the timeout is not negative */ + if (lltimeout < 0) { + addReplySds(c,sdsnew("-ERR timeout is negative\r\n")); + return; + } + for (j = 1; j < c->argc-1; j++) { o = lookupKeyWrite(c->db,c->argv[j]); if (o != NULL) { @@ -823,8 +834,9 @@ void blockingPopGenericCommand(redisClient *c, int where) { } } } + /* If the list is empty or the key does not exists we must block */ - timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10); + timeout = lltimeout; if (timeout > 0) timeout += time(NULL); blockForKeys(c,c->argv+1,c->argc-2,timeout); } diff --git a/tests/unit/type/list.tcl b/tests/unit/type/list.tcl index d3ed90ec..1a85c809 100644 --- a/tests/unit/type/list.tcl +++ b/tests/unit/type/list.tcl @@ -139,6 +139,28 @@ start_server { assert_equal 0 [r exists blist1] } + test "$pop: with negative timeout" { + set rd [redis_deferring_client] + $rd $pop blist1 -1 + assert_error "ERR*is negative*" {$rd read} + } + + test "$pop: with non-integer timeout" { + set rd [redis_deferring_client] + $rd $pop blist1 1.1 + assert_error "ERR*not an integer*" {$rd read} + } + + test "$pop: with zero timeout should block indefinitely" { + # To test this, use a timeout of 0 and wait a second. + # The blocking pop should still be waiting for a push. + set rd [redis_deferring_client] + $rd $pop blist1 0 + after 1000 + r rpush blist1 foo + assert_equal {blist1 foo} [$rd read] + } + test "$pop: second argument is not a list" { set rd [redis_deferring_client] r del blist1 blist2 From 8fedd04dccd08e9a25652a22c2034d3f38f72d0f Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 30 Aug 2010 11:37:17 +0200 Subject: [PATCH 02/17] Makefile deps updated --- src/Makefile | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5fe3971e..38007e8d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,6 +33,7 @@ CHECKAOFPRGNAME = redis-check-aof all: redis-server redis-benchmark redis-cli redis-check-dump redis-check-aof + # Deps (use make dep to generate this) adlist.o: adlist.c adlist.h zmalloc.h ae.o: ae.c ae.h zmalloc.h config.h ae_kqueue.c @@ -40,25 +41,61 @@ ae_epoll.o: ae_epoll.c ae_kqueue.o: ae_kqueue.c ae_select.o: ae_select.c anet.o: anet.c fmacros.h anet.h +aof.o: aof.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +config.o: config.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +db.o: db.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +debug.o: debug.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h sha1.h dict.o: dict.c fmacros.h dict.h zmalloc.h +intset.o: intset.c intset.h zmalloc.h linenoise.o: linenoise.c fmacros.h lzf_c.o: lzf_c.c lzfP.h lzf_d.o: lzf_d.c lzfP.h +multi.o: multi.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +networking.o: networking.c redis.h fmacros.h config.h ae.h sds.h dict.h \ + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +object.o: object.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h pqsort.o: pqsort.c +pubsub.o: pubsub.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +rdb.o: rdb.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h lzf.h redis-benchmark.o: redis-benchmark.c fmacros.h ae.h anet.h sds.h adlist.h \ zmalloc.h redis-check-aof.o: redis-check-aof.c fmacros.h config.h redis-check-dump.o: redis-check-dump.c lzf.h -redis-cli.o: redis-cli.c fmacros.h anet.h sds.h adlist.h zmalloc.h \ - linenoise.h -redis.o: redis.c fmacros.h config.h redis.h ae.h sds.h anet.h dict.h \ - adlist.h zmalloc.h lzf.h pqsort.h zipmap.h ziplist.h sha1.h +redis-cli.o: redis-cli.c fmacros.h version.h anet.h sds.h adlist.h \ + zmalloc.h linenoise.h +redis.o: redis.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h release.o: release.c release.h +replication.o: replication.c redis.h fmacros.h config.h ae.h sds.h dict.h \ + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h sds.o: sds.c sds.h zmalloc.h sha1.o: sha1.c sha1.h +sort.o: sort.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h pqsort.h +t_hash.o: t_hash.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +t_list.o: t_list.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +t_set.o: t_set.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +t_string.o: t_string.c redis.h fmacros.h config.h ae.h sds.h dict.h \ + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +t_zset.o: t_zset.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +util.o: util.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h +vm.o: vm.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h ziplist.o: ziplist.c zmalloc.h ziplist.h zipmap.o: zipmap.c zmalloc.h -intset.o: intset.c zmalloc.h zmalloc.o: zmalloc.c config.h redis-server: $(OBJ) From e0e1c195202dd74ab22554dd4293672cc95368ee Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 30 Aug 2010 11:51:45 +0200 Subject: [PATCH 03/17] Fixed MONITOR mode and Issue 296 --- src/db.c | 6 +++--- src/redis-cli.c | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/db.c b/src/db.c index 6d287d72..f380bf6e 100644 --- a/src/db.c +++ b/src/db.c @@ -221,19 +221,19 @@ void keysCommand(redisClient *c) { dictIterator *di; dictEntry *de; sds pattern = c->argv[1]->ptr; - int plen = sdslen(pattern); + int plen = sdslen(pattern), allkeys; unsigned long numkeys = 0; robj *lenobj = createObject(REDIS_STRING,NULL); di = dictGetIterator(c->db->dict); addReply(c,lenobj); decrRefCount(lenobj); + allkeys = (pattern[0] == '*' && pattern[1] == '\0'); while((de = dictNext(di)) != NULL) { sds key = dictGetEntryKey(de); robj *keyobj; - if ((pattern[0] == '*' && pattern[1] == '\0') || - stringmatchlen(pattern,plen,key,sdslen(key),0)) { + if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) { keyobj = createStringObject(key,sdslen(key)); if (expireIfNeeded(c->db,keyobj) == 0) { addReplyBulk(c,keyobj); diff --git a/src/redis-cli.c b/src/redis-cli.c index 8b7d0777..3a6b0a90 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -96,7 +96,7 @@ static sds cliReadLine(int fd) { ssize_t ret; ret = read(fd,&c,1); - if (ret == -1) { + if (ret <= 0) { sdsfree(line); return NULL; } else if ((ret == 0) || (c == '\n')) { @@ -282,7 +282,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) { while(repeat--) { anetWrite(fd,cmd,sdslen(cmd)); while (config.monitor_mode) { - cliReadSingleLineReply(fd,0); + if (cliReadSingleLineReply(fd,0)) exit(1); + printf("\n"); } if (config.pubsub_mode) { From 93b2a7718eefd73cdd1b3b221cfc38be83fca0b5 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 30 Aug 2010 15:36:13 +0200 Subject: [PATCH 04/17] It is now possible to use authentication and DB selection options at the same time in redis-cli (Issue 298) --- src/redis-cli.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index 3a6b0a90..0b2fd0c1 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -478,10 +478,16 @@ int main(int argc, char **argv) { if (config.auth != NULL) { char *authargv[2]; + int dbnum = config.dbnum; + /* We need to save the real configured database number and set it to + * zero here, otherwise cliSendCommand() will try to perform the + * SELECT command before the authentication, and it will fail. */ + config.dbnum = 0; authargv[0] = "AUTH"; authargv[1] = config.auth; cliSendCommand(2, convertToSds(2, authargv), 1); + config.dbnum = dbnum; /* restore the right DB number */ } /* Start interactive mode when no command is provided */ From 8079656a8ea7c379815366c6f89f9954e86a57be Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 30 Aug 2010 15:57:03 +0200 Subject: [PATCH 05/17] Now redis-cli replies to help showing some basic usage information (Issue 291) --- src/redis-cli.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index 0b2fd0c1..761c025e 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -251,12 +251,32 @@ static int selectDb(int fd) { return 0; } +static void showInteractiveHelp(void) { + printf( + "\n" + "Welcome to redis-cli " REDIS_VERSION "!\n" + "Just type any valid Redis command to see a pretty printed output.\n" + "\n" + "It is possible to quote strings, like in:\n" + " set \"my key\" \"some string \\xff\\n\"\n" + "\n" + "You can find a list of valid Redis commands at\n" + " http://code.google.com/p/redis/wiki/CommandReference\n" + "\n" + "Note: redis-cli supports line editing, use up/down arrows for history." + "\n\n"); +} + static int cliSendCommand(int argc, char **argv, int repeat) { char *command = argv[0]; int fd, j, retval = 0; sds cmd; config.raw_output = !strcasecmp(command,"info"); + if (!strcasecmp(command,"help")) { + showInteractiveHelp(); + return 0; + } if (!strcasecmp(command,"shutdown")) config.shutdown = 1; if (!strcasecmp(command,"monitor")) config.monitor_mode = 1; if (!strcasecmp(command,"subscribe") || From fb92ecece75ec48efb927fa6c2f2f86a58f73609 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 30 Aug 2010 16:31:03 +0200 Subject: [PATCH 06/17] BLPOP inside MULTI/EXEC block no longer crashes, instead if the list is empty the behavior is like if the timeout is reached. This fixes Issue 285 --- src/t_list.c | 7 +++++++ tests/unit/type/list.tcl | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/t_list.c b/src/t_list.c index 2a981033..6b4a611e 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -823,6 +823,13 @@ void blockingPopGenericCommand(redisClient *c, int where) { } } } + /* If we are inside a MULTI/EXEC and the list is empty the only thing + * we can do is treating it as a timeout (even with timeout 0). */ + if (c->flags & REDIS_MULTI) { + addReply(c,shared.nullmultibulk); + return; + } + /* If the list is empty or the key does not exists we must block */ timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10); if (timeout > 0) timeout += time(NULL); diff --git a/tests/unit/type/list.tcl b/tests/unit/type/list.tcl index d3ed90ec..ca0da764 100644 --- a/tests/unit/type/list.tcl +++ b/tests/unit/type/list.tcl @@ -172,6 +172,17 @@ start_server { } } + test {BLPOP inside a transaction} { + r del xlist + r lpush xlist foo + r lpush xlist bar + r multi + r blpop xlist 0 + r blpop xlist 0 + r blpop xlist 0 + r exec + } {{xlist bar} {xlist foo} {}} + test {LPUSHX, RPUSHX - generic} { r del xlist assert_equal 0 [r lpushx xlist a] From 1eb13e4913622927b17b9c2922754f864d520710 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Tue, 31 Aug 2010 09:37:25 +0200 Subject: [PATCH 07/17] Fix set tests to make sets have a deterministic encoding --- tests/unit/type/set.tcl | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/unit/type/set.tcl b/tests/unit/type/set.tcl index 056ed27c..0f9f6abe 100644 --- a/tests/unit/type/set.tcl +++ b/tests/unit/type/set.tcl @@ -106,14 +106,17 @@ start_server { } r sadd set5 0 - # it is possible that a hashtable encoded only contains integers, - # because it is converted from an intset to a hashtable when a - # non-integer element is added and then removed. + # To make sure the sets are encoded as the type we are testing -- also + # when the VM is enabled and the values may be swapped in and out + # while the tests are running -- an extra element is added to every + # set that determines its encoding. + set large 200 if {$type eq "hashtable"} { - for {set i 1} {$i <= 5} {incr i} { - r sadd [format "set%d" $i] foo - r srem [format "set%d" $i] foo - } + set large foo + } + + for {set i 1} {$i <= 5} {incr i} { + r sadd [format "set%d" $i] $large } test "Generated sets must be encoded as $type" { @@ -123,20 +126,20 @@ start_server { } test "SINTER with two sets - $type" { - assert_equal {195 196 197 198 199} [lsort [r sinter set1 set2]] + assert_equal [list 195 196 197 198 199 $large] [lsort [r sinter set1 set2]] } test "SINTERSTORE with two sets - $type" { r sinterstore setres set1 set2 - assert_encoding intset setres - assert_equal {195 196 197 198 199} [lsort [r smembers setres]] + assert_encoding $type setres + assert_equal [list 195 196 197 198 199 $large] [lsort [r smembers setres]] } test "SINTERSTORE with two sets, after a DEBUG RELOAD - $type" { r debug reload r sinterstore setres set1 set2 - assert_encoding intset setres - assert_equal {195 196 197 198 199} [lsort [r smembers setres]] + assert_encoding $type setres + assert_equal [list 195 196 197 198 199 $large] [lsort [r smembers setres]] } test "SUNION with two sets - $type" { @@ -146,18 +149,18 @@ start_server { test "SUNIONSTORE with two sets - $type" { r sunionstore setres set1 set2 - assert_encoding intset setres + assert_encoding $type setres set expected [lsort -uniq "[r smembers set1] [r smembers set2]"] assert_equal $expected [lsort [r smembers setres]] } test "SINTER against three sets - $type" { - assert_equal {195 199} [lsort [r sinter set1 set2 set3]] + assert_equal [list 195 199 $large] [lsort [r sinter set1 set2 set3]] } test "SINTERSTORE with three sets - $type" { r sinterstore setres set1 set2 set3 - assert_equal {195 199} [r smembers setres] + assert_equal [list 195 199 $large] [lsort [r smembers setres]] } test "SUNION with non existing keys - $type" { @@ -175,7 +178,9 @@ start_server { test "SDIFFSTORE with three sets - $type" { r sdiffstore setres set1 set4 set5 - assert_encoding intset setres + # The type is determined by type of the first key to diff against. + # See the implementation for more information. + assert_encoding $type setres assert_equal {1 2 3 4} [lsort [r smembers setres]] } } From 7b30cc3a7bed6ea1d5b4131f977d554d78791bf7 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Tue, 31 Aug 2010 10:21:35 +0200 Subject: [PATCH 08/17] Fix issue 300 by upgrading variable types to 64-bit --- src/redis-check-dump.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/redis-check-dump.c b/src/redis-check-dump.c index 0b002790..a7e85973 100644 --- a/src/redis-check-dump.c +++ b/src/redis-check-dump.c @@ -65,8 +65,8 @@ /* data type to hold offset in file and size */ typedef struct { void *data; - unsigned long size; - unsigned long offset; + uint64_t size; + uint64_t offset; } pos; static unsigned char level = 0; @@ -77,8 +77,8 @@ static pos positions[16]; /* Hold a stack of errors */ typedef struct { char error[16][1024]; - unsigned long offset[16]; - unsigned int level; + uint64_t offset[16]; + uint32_t level; } errors_t; static errors_t errors; @@ -494,15 +494,15 @@ void printCentered(int indent, int width, char* body) { printf("%s %s %s\n", head, body, tail); } -void printValid(int ops, int bytes) { +void printValid(uint64_t ops, uint64_t bytes) { char body[80]; - sprintf(body, "Processed %d valid opcodes (in %d bytes)", ops, bytes); + sprintf(body, "Processed %llu valid opcodes (in %llu bytes)", ops, bytes); printCentered(4, 80, body); } -void printSkipped(int bytes, int offset) { +void printSkipped(uint64_t bytes, uint64_t offset) { char body[80]; - sprintf(body, "Skipped %d bytes (resuming at 0x%08x)", bytes, offset); + sprintf(body, "Skipped %llu bytes (resuming at 0x%08llx)", bytes, offset); printCentered(4, 80, body); } @@ -536,12 +536,12 @@ void printErrorStack(entry *e) { /* display error stack */ for (i = 0; i < errors.level; i++) { - printf("0x%08lx - %s\n", errors.offset[i], errors.error[i]); + printf("0x%08llx - %s\n", errors.offset[i], errors.error[i]); } } void process() { - int i, num_errors = 0, num_valid_ops = 0, num_valid_bytes = 0; + uint64_t num_errors = 0, num_valid_ops = 0, num_valid_bytes = 0; entry entry; processHeader(); @@ -558,7 +558,9 @@ void process() { num_valid_bytes = 0; /* search for next valid entry */ - unsigned long offset = positions[0].offset + 1; + uint64_t offset = positions[0].offset + 1; + int i = 0; + while (!entry.success && offset < positions[0].size) { positions[1].offset = offset; @@ -606,9 +608,9 @@ void process() { } /* print summary on errors */ - if (num_errors > 0) { + if (num_errors) { printf("\n"); - printf("Total unprocessable opcodes: %d\n", num_errors); + printf("Total unprocessable opcodes: %llu\n", num_errors); } } @@ -620,7 +622,7 @@ int main(int argc, char **argv) { } int fd; - unsigned long size; + size_t size; struct stat stat; void *data; From 08f55b786b58b3e0f8310e02683a0e1761c5b6bf Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 31 Aug 2010 11:17:06 +0200 Subject: [PATCH 09/17] faster server starting in Redis tests --- tests/support/server.tcl | 29 +++++++++++++++++++++++++---- tests/unit/other.tcl | 2 +- tests/unit/protocol.tcl | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tests/support/server.tcl b/tests/support/server.tcl index 24fef467..e5ca6c6c 100644 --- a/tests/support/server.tcl +++ b/tests/support/server.tcl @@ -83,7 +83,9 @@ proc ping_server {host port} { } close $fd } e]} { - puts "Can't PING server at $host:$port... $e" + puts -nonewline "." + } else { + puts -nonewline "ok" } return $retval } @@ -170,14 +172,33 @@ proc start_server {options {code undefined}} { if {$::valgrind} { exec valgrind src/redis-server $config_file > $stdout 2> $stderr & - after 2000 } else { exec src/redis-server $config_file > $stdout 2> $stderr & - after 500 } # check that the server actually started - if {$code ne "undefined" && ![ping_server $::host $::port]} { + # ugly but tries to be as fast as possible... + set retrynum 20 + set serverisup 0 + + puts -nonewline "=== ($tags) Starting server ${::host}:${::port} " + after 10 + if {$code ne "undefined"} { + while {[incr retrynum -1]} { + catch { + if {[ping_server $::host $::port]} { + set serverisup 1 + } + } + if {$serverisup} break + after 50 + } + } else { + set serverisup 1 + } + puts {} + + if {!$serverisup} { error_and_quit $config_file [exec cat $stderr] } diff --git a/tests/unit/other.tcl b/tests/unit/other.tcl index f0497b62..5967c722 100644 --- a/tests/unit/other.tcl +++ b/tests/unit/other.tcl @@ -1,4 +1,4 @@ -start_server {} { +start_server {tags {"other"}} { test {SAVE - make sure there are all the types as values} { # Wait for a background saving in progress to terminate waitForBgsave r diff --git a/tests/unit/protocol.tcl b/tests/unit/protocol.tcl index 9eebf77f..5bf42d7f 100644 --- a/tests/unit/protocol.tcl +++ b/tests/unit/protocol.tcl @@ -1,4 +1,4 @@ -start_server {} { +start_server {tags {"protocol"}} { test {Handle an empty query well} { set fd [r channel] puts -nonewline $fd "\r\n" From d320764706cce1b4339043eb2ee9240d5fe3f2d2 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 31 Aug 2010 11:42:52 +0200 Subject: [PATCH 10/17] We finally have an half decent README! (Issue 277) --- README | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/README b/README index a810a7c0..5eeabf74 100644 --- a/README +++ b/README @@ -1 +1,68 @@ -Check the 'doc' directory. doc/README.html is a good starting point :) +Where to find complete Redis documentation? +------------------------------------------- + +This README is just a fast "quick start" document. You can find more detailed +documentation here: + +1) http://code.google.com/p/redis +2) Check the 'doc' directory. doc/README.html is a good starting point :) + +Building Redis +-------------- + +It is as simple as: + + % make + +Redis is just a single binary, but if you want to install it you can use +the "make install" target that will copy the binary in /usr/local/bin +for default. + +You can run a 32 bit Redis binary using: + + % make 32bit + +After you build Redis is a good idea to test it, using: + + % make test + +Running Redis +------------- + +To run Redis with the default configuration just type: + + % cd src + % ./redis-server + +If you want to provide your redis.conf, you have to run it using an additional +parameter (the path of the configuration file): + + % cd src + % ./redis-server /path/to/redis.conf + +Playing with Redis +------------------ + +You can use redis-cli to play with Redis. Start a redis-server instance, +then in another terminal try the following: + + % cd src + % ./redis-cli + redis> ping + PONG + redis> set foo bar + OK + redis> get foo + "bar" + redis> incr mycounter + (integer) 1 + redis> incr mycounter + (integer) 2 + redis> + +You can find the list of all the available commands here: + + http://code.google.com/p/redis/wiki/CommandReference + +Enjoy! + From f85202c3dc6213bffdc3ccf998e4ea85a36ad9a8 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Tue, 31 Aug 2010 13:06:26 +0200 Subject: [PATCH 11/17] Fix compilation errors and add warning for 32-bit platforms --- src/redis-check-dump.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/redis-check-dump.c b/src/redis-check-dump.c index a7e85973..959ecf8d 100644 --- a/src/redis-check-dump.c +++ b/src/redis-check-dump.c @@ -65,8 +65,8 @@ /* data type to hold offset in file and size */ typedef struct { void *data; - uint64_t size; - uint64_t offset; + size_t size; + size_t offset; } pos; static unsigned char level = 0; @@ -77,8 +77,8 @@ static pos positions[16]; /* Hold a stack of errors */ typedef struct { char error[16][1024]; - uint64_t offset[16]; - uint32_t level; + size_t offset[16]; + size_t level; } errors_t; static errors_t errors; @@ -112,7 +112,7 @@ int readBytes(void *target, long num) { if (p.offset + num > p.size) { return 0; } else { - memcpy(target, (void*)((unsigned long)p.data + p.offset), num); + memcpy(target, (void*)((size_t)p.data + p.offset), num); if (!peek) positions[level].offset += num; } return 1; @@ -536,7 +536,7 @@ void printErrorStack(entry *e) { /* display error stack */ for (i = 0; i < errors.level; i++) { - printf("0x%08llx - %s\n", errors.offset[i], errors.error[i]); + printf("0x%08lx - %s\n", errors.offset[i], errors.error[i]); } } @@ -622,7 +622,7 @@ int main(int argc, char **argv) { } int fd; - size_t size; + off_t size; struct stat stat; void *data; @@ -636,6 +636,10 @@ int main(int argc, char **argv) { size = stat.st_size; } + if (sizeof(size_t) == sizeof(int32_t) && size >= INT_MAX) { + ERROR("Cannot check dump files >2GB on a 32-bit platform\n"); + } + data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { ERROR("Cannot mmap: %s\n", argv[1]); From dbebd395ebc897275ec84edb143b1067aef8d882 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 31 Aug 2010 18:34:34 +0200 Subject: [PATCH 12/17] Version is now 2.1.4 -- AKA 2.2-alpha1 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index b570fe04..80decef1 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define REDIS_VERSION "2.1.3" +#define REDIS_VERSION "2.1.4" From a047bf52a4fed963a434c6e7e7376880cf17abcf Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 1 Sep 2010 18:31:30 +0200 Subject: [PATCH 13/17] fixed a few harmless warnings complining on Linux --- src/redis-check-dump.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/redis-check-dump.c b/src/redis-check-dump.c index 959ecf8d..987e1db3 100644 --- a/src/redis-check-dump.c +++ b/src/redis-check-dump.c @@ -496,13 +496,15 @@ void printCentered(int indent, int width, char* body) { void printValid(uint64_t ops, uint64_t bytes) { char body[80]; - sprintf(body, "Processed %llu valid opcodes (in %llu bytes)", ops, bytes); + sprintf(body, "Processed %llu valid opcodes (in %llu bytes)", + (unsigned long long) ops, (unsigned long long) bytes); printCentered(4, 80, body); } void printSkipped(uint64_t bytes, uint64_t offset) { char body[80]; - sprintf(body, "Skipped %llu bytes (resuming at 0x%08llx)", bytes, offset); + sprintf(body, "Skipped %llu bytes (resuming at 0x%08llx)", + (unsigned long long) bytes, (unsigned long long) offset); printCentered(4, 80, body); } @@ -610,7 +612,8 @@ void process() { /* print summary on errors */ if (num_errors) { printf("\n"); - printf("Total unprocessable opcodes: %llu\n", num_errors); + printf("Total unprocessable opcodes: %llu\n", + (unsigned long long) num_errors); } } From eddb388ef90258be406bdf1355f7c65bdd71bbe8 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 2 Sep 2010 10:34:39 +0200 Subject: [PATCH 14/17] memory fragmentation ratio in INFO output --- src/config.h | 5 +++++ src/redis.c | 2 ++ src/zmalloc.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/zmalloc.h | 1 + 4 files changed, 50 insertions(+) diff --git a/src/config.h b/src/config.h index 6e98fbb2..acc95cf5 100644 --- a/src/config.h +++ b/src/config.h @@ -21,6 +21,11 @@ #define redis_stat stat #endif +/* test for proc filesystem */ +#ifdef __linux__ +#define HAVE_PROCFS 1 +#endif + /* test for backtrace() */ #if defined(__APPLE__) || defined(__linux__) #define HAVE_BACKTRACE 1 diff --git a/src/redis.c b/src/redis.c index 77e67c58..8206b5d3 100644 --- a/src/redis.c +++ b/src/redis.c @@ -1166,6 +1166,7 @@ sds genRedisInfoString(void) { "blocked_clients:%d\r\n" "used_memory:%zu\r\n" "used_memory_human:%s\r\n" + "mem_fragmentation_ratio:%.2f\r\n" "changes_since_last_save:%lld\r\n" "bgsave_in_progress:%d\r\n" "last_save_time:%ld\r\n" @@ -1192,6 +1193,7 @@ sds genRedisInfoString(void) { server.blpop_blocked_clients, zmalloc_used_memory(), hmem, + zmalloc_get_fragmentation_ratio(), server.dirty, server.bgsavechildpid != -1, server.lastsave, diff --git a/src/zmalloc.c b/src/zmalloc.c index 5c1b5e9a..81fc4c04 100644 --- a/src/zmalloc.c +++ b/src/zmalloc.c @@ -32,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include "config.h" #if defined(__sun) @@ -170,3 +174,41 @@ size_t zmalloc_used_memory(void) { void zmalloc_enable_thread_safeness(void) { zmalloc_thread_safe = 1; } + +/* Fragmentation = RSS / allocated-bytes */ +float zmalloc_get_fragmentation_ratio(void) { +#ifdef HAVE_PROCFS + size_t allocated = zmalloc_used_memory(); + int page = sysconf(_SC_PAGESIZE); + size_t rss; + char buf[4096]; + char filename[256]; + int fd, count; + char *p, *x; + + snprintf(filename,256,"/proc/%d/stat",getpid()); + if ((fd = open(filename,O_RDONLY)) == -1) return 0; + if (read(fd,buf,4096) <= 0) { + close(fd); + return 0; + } + close(fd); + + p = buf; + count = 23; /* RSS is the 24th field in /proc//stat */ + while(p && count--) { + p = strchr(p,' '); + if (p) p++; + } + if (!p) return 0; + x = strchr(p,' '); + if (!x) return 0; + *x = '\0'; + + rss = strtoll(p,NULL,10); + rss *= page; + return (float)rss/allocated; +#else + return 0; +#endif +} diff --git a/src/zmalloc.h b/src/zmalloc.h index db858bba..281aa3a8 100644 --- a/src/zmalloc.h +++ b/src/zmalloc.h @@ -38,5 +38,6 @@ void zfree(void *ptr); char *zstrdup(const char *s); size_t zmalloc_used_memory(void); void zmalloc_enable_thread_safeness(void); +float zmalloc_get_fragmentation_ratio(void); #endif /* _ZMALLOC_H */ From 73db2acc374c99ca8224e44a7383f69e7ca24a4f Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 2 Sep 2010 10:57:58 +0200 Subject: [PATCH 15/17] memory fragmentation reporting in INFO also added for Mac OS X --- src/config.h | 5 +++++ src/zmalloc.c | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/config.h b/src/config.h index acc95cf5..e2d84818 100644 --- a/src/config.h +++ b/src/config.h @@ -26,6 +26,11 @@ #define HAVE_PROCFS 1 #endif +/* test for task_info() */ +#if defined(__APPLE__) +#define HAVE_TASKINFO 1 +#endif + /* test for backtrace() */ #if defined(__APPLE__) || defined(__linux__) #define HAVE_BACKTRACE 1 diff --git a/src/zmalloc.c b/src/zmalloc.c index 81fc4c04..544155e7 100644 --- a/src/zmalloc.c +++ b/src/zmalloc.c @@ -32,10 +32,7 @@ #include #include #include -#include -#include -#include -#include + #include "config.h" #if defined(__sun) @@ -176,8 +173,14 @@ void zmalloc_enable_thread_safeness(void) { } /* Fragmentation = RSS / allocated-bytes */ + +#if defined(HAVE_PROCFS) +#include +#include +#include +#include + float zmalloc_get_fragmentation_ratio(void) { -#ifdef HAVE_PROCFS size_t allocated = zmalloc_used_memory(); int page = sysconf(_SC_PAGESIZE); size_t rss; @@ -208,7 +211,29 @@ float zmalloc_get_fragmentation_ratio(void) { rss = strtoll(p,NULL,10); rss *= page; return (float)rss/allocated; -#else - return 0; -#endif } +#elif defined(HAVE_TASKINFO) +#include +#include +#include +#include +#include +#include +#include + +float zmalloc_get_fragmentation_ratio(void) { + task_t task = MACH_PORT_NULL; + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS) + return 0; + task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); + + return (float)t_info.resident_size/zmalloc_used_memory(); +} +#else +float zmalloc_get_fragmentation_ratio(void) { + return 0; +} +#endif From b435f64510a032528c42fc1cfc4eca15a4474a1b Mon Sep 17 00:00:00 2001 From: Anko painting Date: Thu, 2 Sep 2010 21:13:27 -0700 Subject: [PATCH 16/17] fix for issue 237 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vm.c b/src/vm.c index 50fb326d..635016b8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -110,6 +110,9 @@ void vmInit(void) { /* LZF requires a lot of stack */ pthread_attr_init(&server.io_threads_attr); pthread_attr_getstacksize(&server.io_threads_attr, &stacksize); + if(!stacksize) { + stacksize = 1; + } while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2; pthread_attr_setstacksize(&server.io_threads_attr, stacksize); /* Listen for events in the threaded I/O pipe */ From 556bdfbab9062d472e19d882ae045fece36a25ab Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 3 Sep 2010 10:24:18 +0200 Subject: [PATCH 17/17] added some comment and changed coding style for fix for 237 --- src/vm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vm.c b/src/vm.c index 635016b8..ee831fb9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -110,9 +110,11 @@ void vmInit(void) { /* LZF requires a lot of stack */ pthread_attr_init(&server.io_threads_attr); pthread_attr_getstacksize(&server.io_threads_attr, &stacksize); - if(!stacksize) { - stacksize = 1; - } + + /* Solaris may report a stacksize of 0, let's set it to 1 otherwise + * multiplying it by 2 in the while loop later will not really help ;) */ + if (!stacksize) stacksize = 1; + while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2; pthread_attr_setstacksize(&server.io_threads_attr, stacksize); /* Listen for events in the threaded I/O pipe */