diff --git a/dict.h b/dict.h index 90d46f488..bd935d5f4 100644 --- a/dict.h +++ b/dict.h @@ -73,7 +73,7 @@ typedef struct dictIterator { } dictIterator; /* This is the initial size of every hash table */ -#define DICT_HT_INITIAL_SIZE 16 +#define DICT_HT_INITIAL_SIZE 4 /* ------------------------------- Macros ------------------------------------*/ #define dictFreeEntryVal(ht, entry) \ diff --git a/doc/Credits.html b/doc/Credits.html index e4e35fa43..fefc44400 100644 --- a/doc/Credits.html +++ b/doc/Credits.html @@ -26,7 +26,7 @@
Return the members of a set resulting from the intersection of all thesets hold at the specified keys. Like in LRANGE the result is sent tothe client as a multi-bulk reply (see the protocol specification formore information). If just a single key is specified, then this commandproduces the same result as SELEMENTS. Actually SELEMENTS is just syntaxsugar for SINTERSECT.+Time complexity O(NM) worst case where N is the cardinality of the smallest set and M the number of sets_
Return the members of a set resulting from the intersection of all thesets hold at the specified keys. Like in LRANGE the result is sent tothe client as a multi-bulk reply (see the protocol specification formore information). If just a single key is specified, then this commandproduces the same result as SMEMBERS. Actually SMEMBERS is just syntaxsugar for SINTERSECT.
Non existing keys are considered like empty sets, so if one of the keys ismissing an empty set is returned (since the intersection with an emptyset always is an empty set).
* SADD* SREM* SISMEMBER* SCARD* SMEMBERS* SINTERSTORE* SUNION* SUNIONSTORE* SMOVEdiff --git a/redis-cli.c b/redis-cli.c index 343ee0a14..9acf92dc2 100644 --- a/redis-cli.c +++ b/redis-cli.c @@ -79,6 +79,7 @@ static struct redisCommand cmdTable[] = { {"smove",4,REDIS_CMD_BULK}, {"sismember",3,REDIS_CMD_BULK}, {"scard",2,REDIS_CMD_INLINE}, + {"spop",2,REDIS_CMD_INLINE}, {"sinter",-2,REDIS_CMD_INLINE}, {"sinterstore",-3,REDIS_CMD_INLINE}, {"sunion",-2,REDIS_CMD_INLINE}, diff --git a/redis.c b/redis.c index 2caf06c34..fa653d21e 100644 --- a/redis.c +++ b/redis.c @@ -85,7 +85,6 @@ /* Hash table parameters */ #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */ -#define REDIS_HT_MINSLOTS 16384 /* Never resize the HT under this */ /* Command flags */ #define REDIS_CMD_BULK 1 /* Bulk write command */ @@ -370,6 +369,7 @@ static void sremCommand(redisClient *c); static void smoveCommand(redisClient *c); static void sismemberCommand(redisClient *c); static void scardCommand(redisClient *c); +static void spopCommand(redisClient *c); static void sinterCommand(redisClient *c); static void sinterstoreCommand(redisClient *c); static void sunionCommand(redisClient *c); @@ -417,6 +417,7 @@ static struct redisCommand cmdTable[] = { {"smove",smoveCommand,4,REDIS_CMD_BULK}, {"sismember",sismemberCommand,3,REDIS_CMD_BULK}, {"scard",scardCommand,2,REDIS_CMD_INLINE}, + {"spop",spopCommand,2,REDIS_CMD_INLINE}, {"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM}, {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM}, {"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM}, @@ -691,22 +692,28 @@ static void closeTimedoutClients(void) { } } +static int htNeedsResize(dict *dict) { + long long size, used; + + size = dictSlots(dict); + used = dictSize(dict); + return (size && used && size > DICT_HT_INITIAL_SIZE && + (used*100/size < REDIS_HT_MINFILL)); +} + /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL * we resize the hash table to save memory */ static void tryResizeHashTables(void) { int j; for (j = 0; j < server.dbnum; j++) { - long long size, used; - - size = dictSlots(server.db[j].dict); - used = dictSize(server.db[j].dict); - if (size && used && size > REDIS_HT_MINSLOTS && - (used*100/size < REDIS_HT_MINFILL)) { - redisLog(REDIS_NOTICE,"The hash table %d is too sparse, resize it...",j); + if (htNeedsResize(server.db[j].dict)) { + redisLog(REDIS_DEBUG,"The hash table %d is too sparse, resize it...",j); dictResize(server.db[j].dict); - redisLog(REDIS_NOTICE,"Hash table %d resized.",j); + redisLog(REDIS_DEBUG,"Hash table %d resized.",j); } + if (htNeedsResize(server.db[j].expires)) + dictResize(server.db[j].expires); } } @@ -2961,6 +2968,7 @@ static void sremCommand(redisClient *c) { } if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) { server.dirty++; + if (htNeedsResize(set->ptr)) dictResize(set->ptr); addReply(c,shared.cone); } else { addReply(c,shared.czero); @@ -3040,6 +3048,34 @@ static void scardCommand(redisClient *c) { } } +static void spopCommand(redisClient *c) { + robj *set; + dictEntry *de; + + set = lookupKeyWrite(c->db,c->argv[1]); + if (set == NULL) { + addReply(c,shared.nullbulk); + } else { + if (set->type != REDIS_SET) { + addReply(c,shared.wrongtypeerr); + return; + } + de = dictGetRandomKey(set->ptr); + if (de == NULL) { + addReply(c,shared.nullbulk); + } else { + robj *ele = dictGetEntryKey(de); + + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele->ptr))); + addReply(c,ele); + addReply(c,shared.crlf); + dictDelete(set->ptr,ele); + if (htNeedsResize(set->ptr)) dictResize(set->ptr); + server.dirty++; + } + } +} + static int qsortCompareSetsByCardinality(const void *s1, const void *s2) { dict **d1 = (void*) s1, **d2 = (void*) s2; @@ -4170,6 +4206,7 @@ static struct redisFunctionSym symsTable[] = { {"smoveCommand", (unsigned long)smoveCommand}, {"sismemberCommand", (unsigned long)sismemberCommand}, {"scardCommand", (unsigned long)scardCommand}, +{"spopCommand", (unsigned long)spopCommand}, {"sinterCommand", (unsigned long)sinterCommand}, {"sinterstoreCommand", (unsigned long)sinterstoreCommand}, {"sunionCommand", (unsigned long)sunionCommand}, @@ -4296,6 +4333,9 @@ static void setupSigSegvAction(void) { act.sa_sigaction = segvHandler; sigaction (SIGSEGV, &act, NULL); sigaction (SIGBUS, &act, NULL); + sigaction (SIGFPE, &act, NULL); + sigaction (SIGILL, &act, NULL); + sigaction (SIGBUS, &act, NULL); return; } #else /* HAVE_BACKTRACE */ diff --git a/test-redis.tcl b/test-redis.tcl index bd58cb2e7..f5a03161a 100644 --- a/test-redis.tcl +++ b/test-redis.tcl @@ -515,6 +515,14 @@ proc main {server port} { lsort [$r smembers sres] } {1 2 3 4} + test {SPOP basics} { + $r del myset + $r sadd myset 1 + $r sadd myset 2 + $r sadd myset 3 + list [lsort [list [$r spop myset] [$r spop myset] [$r spop myset]]] [$r scard myset] + } {{1 2 3} 0} + test {SAVE - make sure there are all the types as values} { $r lpush mysavelist hello $r lpush mysavelist world