]> git.saurik.com Git - redis.git/commitdiff
resolved conflict merging pietern/bpop-timeout
authorantirez <antirez@gmail.com>
Tue, 31 Aug 2010 09:23:12 +0000 (11:23 +0200)
committerantirez <antirez@gmail.com>
Tue, 31 Aug 2010 09:23:12 +0000 (11:23 +0200)
22 files changed:
src/Makefile
src/aof.c
src/db.c
src/rdb.c
src/redis-check-dump.c
src/redis-cli.c
src/redis.c
src/redis.h
src/replication.c
src/sds.c
src/t_list.c
src/t_set.c
src/util.c
src/version.h
src/vm.c
tests/support/server.tcl
tests/test_helper.tcl
tests/unit/other.tcl
tests/unit/protocol.tcl
tests/unit/sort.tcl
tests/unit/type/list.tcl
tests/unit/type/set.tcl

index 5fe3971ed4171afdbc589a1e57e2d4f927c4ed7d..38007e8d94d635a194446be5670b20d62bae4096 100644 (file)
@@ -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)
index dc806969d5ba5d517e96e38dab67583263bfaf14..8f2dc96f3cd5a22ad0641b3593d5c03ea995d4ce 100644 (file)
--- a/src/aof.c
+++ b/src/aof.c
@@ -468,7 +468,7 @@ int rewriteAppendOnlyFile(char *filename) {
                 /* Emit the SADDs needed to rebuild the set */
                 if (o->encoding == REDIS_ENCODING_INTSET) {
                     int ii = 0;
-                    long long llval;
+                    int64_t llval;
                     while(intsetGet(o->ptr,ii++,&llval)) {
                         if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
                         if (fwriteBulkObject(fp,&key) == 0) goto werr;
index 6d287d72c914762eef4ec17eb08a2f324df71e58..f380bf6ec05882c6e79ec3993608e68d8e96c168 100644 (file)
--- 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);
index 12221b9f3f94189fd4408fee9650e97da701cb69..c15fc6f2fee086655551a4d52142d543903c7c00 100644 (file)
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -273,7 +273,7 @@ int rdbSaveObject(FILE *fp, robj *o) {
             dictReleaseIterator(di);
         } else if (o->encoding == REDIS_ENCODING_INTSET) {
             intset *is = o->ptr;
-            long long llval;
+            int64_t llval;
             int i = 0;
 
             if (rdbSaveLen(fp,intsetLen(is)) == -1) return -1;
@@ -457,6 +457,7 @@ int rdbSaveBackground(char *filename) {
 
     if (server.bgsavechildpid != -1) return REDIS_ERR;
     if (server.vm_enabled) waitEmptyIOJobsQueue();
+    server.dirty_before_bgsave = server.dirty;
     if ((childpid = fork()) == 0) {
         /* Child */
         if (server.vm_enabled) vmReopenSwapFile();
@@ -702,7 +703,7 @@ robj *rdbLoadObject(int type, FILE *fp) {
 
             if (o->encoding == REDIS_ENCODING_INTSET) {
                 /* Fetch integer value from element */
-                if (getLongLongFromObject(ele,&llval) == REDIS_OK) {
+                if (isObjectRepresentableAsLongLong(ele,&llval) == REDIS_OK) {
                     o->ptr = intsetAdd(o->ptr,llval,NULL);
                 } else {
                     setTypeConvert(o,REDIS_ENCODING_HT);
@@ -913,7 +914,7 @@ void backgroundSaveDoneHandler(int statloc) {
     if (!bysignal && exitcode == 0) {
         redisLog(REDIS_NOTICE,
             "Background saving terminated with success");
-        server.dirty = 0;
+        server.dirty = server.dirty - server.dirty_before_bgsave;
         server.lastsave = time(NULL);
     } else if (!bysignal && exitcode != 0) {
         redisLog(REDIS_WARNING, "Background saving error");
index 0b002790db1258d627bb132dc6bd16d6028d5b21..a7e859735de16679413e1e21396792d9c7f01865 100644 (file)
@@ -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;
 
index 8b7d0777dc5f7b4f4c7f8a9819d3d53f632dbf29..761c025e94ffd6bc7747ee6f02fdb68b17a78038 100644 (file)
@@ -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')) {
@@ -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") ||
@@ -282,7 +302,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) {
@@ -477,10 +498,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 */
index 9fbd52f2e19ca1b557fc74912449df67a1ffcf7a..77e67c5839cfdcea732ef5a42037b75f04f3511a 100644 (file)
@@ -1321,7 +1321,8 @@ void freeMemoryIfNeeded(void) {
         if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
         for (j = 0; j < server.dbnum; j++) {
             int minttl = -1;
-            robj *minkey = NULL;
+            sds minkey = NULL;
+            robj *keyobj = NULL;
             struct dictEntry *de;
 
             if (dictSize(server.db[j].expires)) {
@@ -1338,7 +1339,9 @@ void freeMemoryIfNeeded(void) {
                         minttl = t;
                     }
                 }
-                dbDelete(server.db+j,minkey);
+                keyobj = createStringObject(minkey,sdslen(minkey));
+                dbDelete(server.db+j,keyobj);
+                decrRefCount(keyobj);
             }
         }
         if (!freed) return; /* nothing to free... */
index 6156a6ca74187dbb1ee9460f4cf941594e0c48f9..9e27d724854e1788199286f83e9437c81b7df954 100644 (file)
@@ -335,6 +335,7 @@ struct redisServer {
     int fd;
     redisDb *db;
     long long dirty;            /* changes to DB from the last save */
+    long long dirty_before_bgsave; /* used to restore dirty on failed BGSAVE */
     list *clients;
     list *slaves, *monitors;
     char neterr[ANET_ERR_LEN];
@@ -769,6 +770,8 @@ int stringmatch(const char *pattern, const char *string, int nocase);
 long long memtoll(const char *p, int *err);
 int ll2string(char *s, size_t len, long long value);
 int isStringRepresentableAsLong(sds s, long *longval);
+int isStringRepresentableAsLongLong(sds s, long long *longval);
+int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
 
 /* Configuration */
 void loadServerConfig(char *filename);
index 363ce54ac802db07452987d441dc02248ef8aba8..c28460885ecf46c0fd3b4832adffcae254d57f8c 100644 (file)
@@ -138,7 +138,7 @@ int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
     while(size) {
         if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
             nread = read(fd,ptr,size);
-            if (nread == -1) return -1;
+            if (nread <= 0) return -1;
             ptr += nread;
             size -= nread;
             totread += nread;
index d7d23c45a859a7aba07981637d7e25def7df8bf1..a0ebb0591ee17ac9c181a5a89db1a920753227b0 100644 (file)
--- a/src/sds.c
+++ b/src/sds.c
@@ -465,7 +465,7 @@ sds *sdssplitargs(char *line, int *argc) {
     }
 
 err:
-    while(*argc--)
+    while((*argc)--)
         sdsfree(vector[*argc]);
     zfree(vector);
     if (current) sdsfree(current);
index 43d292b6d6642ff7b40a40ac33f2c7191235716b..add1bee167691b1fcc382c1292c728832f6c65bd 100644 (file)
@@ -835,6 +835,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 = lltimeout;
     if (timeout > 0) timeout += time(NULL);
index cb06a6a2e9ee43ba4189189da4107b341350ce83..68e132278f96c938e605490e6ed55aff46177ef8 100644 (file)
@@ -8,7 +8,7 @@
  * an integer-encodable value, an intset will be returned. Otherwise a regular
  * hash table. */
 robj *setTypeCreate(robj *value) {
-    if (getLongLongFromObject(value,NULL) == REDIS_OK)
+    if (isObjectRepresentableAsLongLong(value,NULL) == REDIS_OK)
         return createIntsetObject();
     return createSetObject();
 }
@@ -21,7 +21,7 @@ int setTypeAdd(robj *subject, robj *value) {
             return 1;
         }
     } else if (subject->encoding == REDIS_ENCODING_INTSET) {
-        if (getLongLongFromObject(value,&llval) == REDIS_OK) {
+        if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
             uint8_t success = 0;
             subject->ptr = intsetAdd(subject->ptr,llval,&success);
             if (success) {
@@ -55,7 +55,7 @@ int setTypeRemove(robj *subject, robj *value) {
             return 1;
         }
     } else if (subject->encoding == REDIS_ENCODING_INTSET) {
-        if (getLongLongFromObject(value,&llval) == REDIS_OK) {
+        if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
             uint8_t success;
             subject->ptr = intsetRemove(subject->ptr,llval,&success);
             if (success) return 1;
@@ -71,7 +71,7 @@ int setTypeIsMember(robj *subject, robj *value) {
     if (subject->encoding == REDIS_ENCODING_HT) {
         return dictFind((dict*)subject->ptr,value) != NULL;
     } else if (subject->encoding == REDIS_ENCODING_INTSET) {
-        if (getLongLongFromObject(value,&llval) == REDIS_OK) {
+        if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
             return intsetFind((intset*)subject->ptr,llval);
         }
     } else {
@@ -112,7 +112,7 @@ robj *setTypeNext(setTypeIterator *si) {
             incrRefCount(ret);
         }
     } else if (si->encoding == REDIS_ENCODING_INTSET) {
-        long long llval;
+        int64_t llval;
         if (intsetGet(si->subject->ptr,si->ii++,&llval))
             ret = createStringObjectFromLongLong(llval);
     }
index cc2794f6ab675ae4b88c6f9ae1d2782e802dc603..e304ff839204a5a445542ba5f462db9186803404 100644 (file)
@@ -200,24 +200,44 @@ int ll2string(char *s, size_t len, long long value) {
     return l;
 }
 
-/* Check if the nul-terminated string 's' can be represented by a long
+/* Check if the sds string 's' can be represented by a long long
  * (that is, is a number that fits into long without any other space or
- * character before or after the digits).
+ * character before or after the digits, so that converting this number
+ * back to a string will result in the same bytes as the original string).
  *
- * If so, the function returns REDIS_OK and *longval is set to the value
+ * If so, the function returns REDIS_OK and *llongval is set to the value
  * of the number. Otherwise REDIS_ERR is returned */
-int isStringRepresentableAsLong(sds s, long *longval) {
+int isStringRepresentableAsLongLong(sds s, long long *llongval) {
     char buf[32], *endptr;
-    long value;
+    long long value;
     int slen;
 
-    value = strtol(s, &endptr, 10);
+    value = strtoll(s, &endptr, 10);
     if (endptr[0] != '\0') return REDIS_ERR;
     slen = ll2string(buf,32,value);
 
     /* If the number converted back into a string is not identical
      * then it's not possible to encode the string as integer */
     if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
-    if (longval) *longval = value;
+    if (llongval) *llongval = value;
+    return REDIS_OK;
+}
+
+int isStringRepresentableAsLong(sds s, long *longval) {
+    long long ll;
+
+    if (isStringRepresentableAsLongLong(s,&ll) == REDIS_ERR) return REDIS_ERR;
+    if (ll < LONG_MIN || ll > LONG_MAX) return REDIS_ERR;
+    *longval = (long)ll;
     return REDIS_OK;
 }
+
+int isObjectRepresentableAsLongLong(robj *o, long long *llongval) {
+    redisAssert(o->type == REDIS_STRING);
+    if (o->encoding == REDIS_ENCODING_INT) {
+        if (llongval) *llongval = (long) o->ptr;
+        return REDIS_OK;
+    } else {
+        return isStringRepresentableAsLongLong(o->ptr,llongval);
+    }
+}
index cac597215d3a6b7c9fb54eb729222d3f848a4a17..b570fe04de78d3182d2d02286509af14d2faa530 100644 (file)
@@ -1 +1 @@
-#define REDIS_VERSION "2.1.2"
+#define REDIS_VERSION "2.1.3"
index a34387521d0cac989b73fe9f7021dd53ba917a3b..50fb326dba12ce90dbe817adc5a3661f538807b7 100644 (file)
--- a/src/vm.c
+++ b/src/vm.c
@@ -548,7 +548,15 @@ void freeIOJob(iojob *j) {
 
 /* Every time a thread finished a Job, it writes a byte into the write side
  * of an unix pipe in order to "awake" the main thread, and this function
- * is called. */
+ * is called.
+ *
+ * Note that this is called both by the event loop, when a I/O thread
+ * sends a byte in the notification pipe, and is also directly called from
+ * waitEmptyIOJobsQueue().
+ *
+ * In the latter case we don't want to swap more, so we use the
+ * "privdata" argument setting it to a not NULL value to signal this
+ * condition. */
 void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
             int mask)
 {
@@ -558,6 +566,8 @@ void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
     REDIS_NOTUSED(mask);
     REDIS_NOTUSED(privdata);
 
+    if (privdata != NULL) trytoswap = 0; /* check the comments above... */
+
     /* For every byte we read in the read side of the pipe, there is one
      * I/O job completed to process. */
     while((retval = read(fd,buf,1)) == 1) {
@@ -869,7 +879,8 @@ void waitEmptyIOJobsQueue(void) {
         io_processed_len = listLength(server.io_processed);
         unlockThreadedIO();
         if (io_processed_len) {
-            vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
+            vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,
+                                                        (void*)0xdeadbeef,0);
             usleep(1000); /* 1 millisecond */
         } else {
             usleep(10000); /* 10 milliseconds */
index 24fef4677175cd4202836e48dfdb9a615a8bfacc..e5ca6c6cd69ffb664990c314bbcde90211c0d794 100644 (file)
@@ -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]
     }
     
index d4a0aa140d268bbb87f3ffad220d665baddd6f59..ee7fa3e19597205b0757e667fdb3cf74a401e3d3 100644 (file)
@@ -11,7 +11,7 @@ source tests/support/util.tcl
 
 set ::host 127.0.0.1
 set ::port 16379
-set ::traceleaks 1
+set ::traceleaks 0
 set ::valgrind 0
 set ::denytags {}
 set ::allowtags {}
@@ -95,7 +95,7 @@ proc main {} {
     execute_tests "unit/cas"
     execute_tests "integration/replication"
     execute_tests "integration/aof"
-    execute_tests "integration/redis-cli"
+#    execute_tests "integration/redis-cli"
     execute_tests "unit/pubsub"
 
     # run tests with VM enabled
index f0497b62c6596d870df81c43ae410ad0d2ff53d3..5967c722dd5fc5563d1642c14daa9e3ca5d07d79 100644 (file)
@@ -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
index 9eebf77fdf5d96e3e87cb169ce991c4ec243da96..5bf42d7feeed375b33d27efd81dbf5eef2d4d38d 100644 (file)
@@ -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"
index bca0173799d7ea7fbe46210e6eb8da3cb0509d14..dcc471fb5ba2580beb705490bdfe41c109814514 100644 (file)
@@ -37,9 +37,11 @@ start_server {
 
     foreach {num cmd enc title} {
         16 lpush ziplist "Ziplist"
-        64 lpush linkedlist "Linked list"
+        1000 lpush linkedlist "Linked list"
+        10000 lpush linkedlist "Big Linked list"
         16 sadd intset "Intset"
-        64 sadd hashtable "Hash table"
+        1000 sadd hashtable "Hash table"
+        10000 sadd hashtable "Big Hash table"
     } {
         set result [create_random_dataset $num $cmd]
         assert_encoding $enc tosort
index 1a85c809c7ae3e5e2ac6b3126d8ad4468a194cff..bf188fd709534d366df7d5c79949247a512aca14 100644 (file)
@@ -194,6 +194,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]
index 056ed27c824ce888cec0952693e2ed0f0384707b..0f9f6abebba0bce9a9f149fdf880ac151bb8a9c5 100644 (file)
@@ -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]]
         }
     }