From: antirez Date: Tue, 31 Aug 2010 09:23:12 +0000 (+0200) Subject: resolved conflict merging pietern/bpop-timeout X-Git-Url: https://git.saurik.com/redis.git/commitdiff_plain/f7f12a606c39fcb09a203faaaa12c49882409d8f?hp=94364d53b4746e8cd9e3da633162cb1e34f0bdb6 resolved conflict merging pietern/bpop-timeout --- 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) diff --git a/src/aof.c b/src/aof.c index dc806969..8f2dc96f 100644 --- 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; 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/rdb.c b/src/rdb.c index 12221b9f..c15fc6f2 100644 --- 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"); 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; diff --git a/src/redis-cli.c b/src/redis-cli.c index 8b7d0777..761c025e 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')) { @@ -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 */ diff --git a/src/redis.c b/src/redis.c index 9fbd52f2..77e67c58 100644 --- a/src/redis.c +++ b/src/redis.c @@ -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... */ diff --git a/src/redis.h b/src/redis.h index 6156a6ca..9e27d724 100644 --- a/src/redis.h +++ b/src/redis.h @@ -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); diff --git a/src/replication.c b/src/replication.c index 363ce54a..c2846088 100644 --- a/src/replication.c +++ b/src/replication.c @@ -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; diff --git a/src/sds.c b/src/sds.c index d7d23c45..a0ebb059 100644 --- 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); diff --git a/src/t_list.c b/src/t_list.c index 43d292b6..add1bee1 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -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); diff --git a/src/t_set.c b/src/t_set.c index cb06a6a2..68e13227 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -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); } diff --git a/src/util.c b/src/util.c index cc2794f6..e304ff83 100644 --- a/src/util.c +++ b/src/util.c @@ -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); + } +} diff --git a/src/version.h b/src/version.h index cac59721..b570fe04 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define REDIS_VERSION "2.1.2" +#define REDIS_VERSION "2.1.3" diff --git a/src/vm.c b/src/vm.c index a3438752..50fb326d 100644 --- 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 */ 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/test_helper.tcl b/tests/test_helper.tcl index d4a0aa14..ee7fa3e1 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -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 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" diff --git a/tests/unit/sort.tcl b/tests/unit/sort.tcl index bca01737..dcc471fb 100644 --- a/tests/unit/sort.tcl +++ b/tests/unit/sort.tcl @@ -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 diff --git a/tests/unit/type/list.tcl b/tests/unit/type/list.tcl index 1a85c809..bf188fd7 100644 --- a/tests/unit/type/list.tcl +++ b/tests/unit/type/list.tcl @@ -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] 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]] } }