Skip to content

Commit 12fea92

Browse files
committed
SPOP implemented. Hash table resizing for Sets and Expires too. Changed the resize policy to play better with RANDOMKEY and SPOP.
1 parent d76412d commit 12fea92

File tree

6 files changed

+61
-12
lines changed

6 files changed

+61
-12
lines changed

dict.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ typedef struct dictIterator {
7373
} dictIterator;
7474

7575
/* This is the initial size of every hash table */
76-
#define DICT_HT_INITIAL_SIZE 16
76+
#define DICT_HT_INITIAL_SIZE 4
7777

7878
/* ------------------------------- Macros ------------------------------------*/
7979
#define dictFreeEntryVal(ht, entry) \

doc/Credits.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ <h1 class="wikiname">Credits</h1>
2626
</div>
2727

2828
<div class="narrow">
29-
<h1><a name="Credits">Credits</a></h1><ul><li> The Redis server was designed and written by <a href="http://invece.org" target="_blank">Salvatore Sanfilippo (aka antirez)</a></li><li> <a href="http://brainspl.at/" target="_blank">Ezra Zygmuntowicz (aka ezmobius)</a> - Ruby client lib initial version and hacking</li><li> <a href="http://qix.it" target="_blank">Ludovico Magnocavallo (aka ludo)</a> - Python clinet lib</li><li> <a href="http://www.adroll.com/" target="_blank">Valentino Volonghi of Adroll</a> - Erlang client lib</li><li> <b>brettbender</b> - found and fixed a bug in sds.c that caused the server to crash at least on 64 bit systems, and anyway to be buggy since we used the same vararg thing against vsprintf without to call va_start and va_end every time.</li><li> <a href="http://www.rot13.org/~dpavlin" target="_blank">Dobrica Pavlinusic</a> - Perl client lib</li><li> Brian Hammond - AUTH command implementation, C++ client lib</li><li> <a href="http://www.clorophilla.net/" target="_blank">Daniele Alessandri</a> - Lua client lib</li><li> Corey Stup - C99 cleanups</li><li> Taylor Weibley - Ruby client improvements</li><li> Bob Potter - Rearrange redisObject struct to reduce memory usage in 64bit environments</li><li> Luca Guidi and Brian McKinney - Ruby client improvements</li><li> Aman Gupta - SDIFF / SDIFFSTORE, other Set operations improvements, ability to disable clients timeout.</li></ul>
29+
<h1><a name="Credits">Credits</a></h1><ul><li> The Redis server was designed and written by <a href="http://invece.org" target="_blank">Salvatore Sanfilippo (aka antirez)</a></li><li> <a href="http://brainspl.at/" target="_blank">Ezra Zygmuntowicz (aka ezmobius)</a> - Ruby client lib initial version and hacking</li><li> <a href="http://qix.it" target="_blank">Ludovico Magnocavallo (aka ludo)</a> - Python clinet lib</li><li> <a href="http://www.adroll.com/" target="_blank">Valentino Volonghi of Adroll</a> - Erlang client lib</li><li> <b>brettbender</b> - found and fixed a bug in sds.c that caused the server to crash at least on 64 bit systems, and anyway to be buggy since we used the same vararg thing against vsprintf without to call va_start and va_end every time.</li><li> <a href="http://www.rot13.org/~dpavlin" target="_blank">Dobrica Pavlinusic</a> - Perl client lib</li><li> Brian Hammond - AUTH command implementation, C++ client lib</li><li> <a href="http://www.clorophilla.net/" target="_blank">Daniele Alessandri</a> - Lua client lib</li><li> Corey Stup - C99 cleanups</li><li> Taylor Weibley - Ruby client improvements</li><li> Bob Potter - Rearrange redisObject struct to reduce memory usage in 64bit environments</li><li> Luca Guidi and Brian McKinney - Ruby client improvements</li><li> Aman Gupta - SDIFF / SDIFFSTORE, other Set operations improvements, ability to disable clients timeout.</li><li> Diego Rosario Brogna - Code and ideas about dumping backtrace on sigsegv and similar error conditions.</li></ul>
3030
p.s. sorry to take this file in sync is hard in this early days. Please drop me an email if I forgot to add your name here!
3131

3232
</div>

doc/SinterCommand.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ <h1 class="wikiname">SinterCommand</h1>
2727

2828
<div class="narrow">
2929
<h1><a name="SINTER _key1_ _key2_ ... _keyN_">SINTER _key1_ _key2_ ... _keyN_</a></h1>
30-
<i>Time complexity O(N<b>M) worst case where N is the cardinality of the smallest set and M the number of sets_<br/><br/><blockquote>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.</blockquote>
30+
<i>Time complexity O(N<b>M) worst case where N is the cardinality of the smallest set and M the number of sets_<br/><br/><blockquote>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.</blockquote>
3131
<blockquote>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).</blockquote>
3232
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Multi bulk reply</a>, specifically the list of common elements.<h2><a name="See also">See also</a></h2>
3333
<blockquote>* <a href="SaddCommand.html">SADD</a>* <a href="SremCommand.html">SREM</a>* <a href="SismemberCommand.html">SISMEMBER</a>* <a href="ScardCommand.html">SCARD</a>* <a href="SmembersCommand.html">SMEMBERS</a>* <a href="SinterstoreCommand.html">SINTERSTORE</a>* <a href="SunionCommand.html">SUNION</a>* <a href="SunionstoreCommand.html">SUNIONSTORE</a>* <a href="SmoveCommand.html">SMOVE</a></blockquote></b></i>

redis-cli.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ static struct redisCommand cmdTable[] = {
7979
{"smove",4,REDIS_CMD_BULK},
8080
{"sismember",3,REDIS_CMD_BULK},
8181
{"scard",2,REDIS_CMD_INLINE},
82+
{"spop",2,REDIS_CMD_INLINE},
8283
{"sinter",-2,REDIS_CMD_INLINE},
8384
{"sinterstore",-3,REDIS_CMD_INLINE},
8485
{"sunion",-2,REDIS_CMD_INLINE},

redis.c

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585

8686
/* Hash table parameters */
8787
#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
88-
#define REDIS_HT_MINSLOTS 16384 /* Never resize the HT under this */
8988

9089
/* Command flags */
9190
#define REDIS_CMD_BULK 1 /* Bulk write command */
@@ -370,6 +369,7 @@ static void sremCommand(redisClient *c);
370369
static void smoveCommand(redisClient *c);
371370
static void sismemberCommand(redisClient *c);
372371
static void scardCommand(redisClient *c);
372+
static void spopCommand(redisClient *c);
373373
static void sinterCommand(redisClient *c);
374374
static void sinterstoreCommand(redisClient *c);
375375
static void sunionCommand(redisClient *c);
@@ -417,6 +417,7 @@ static struct redisCommand cmdTable[] = {
417417
{"smove",smoveCommand,4,REDIS_CMD_BULK},
418418
{"sismember",sismemberCommand,3,REDIS_CMD_BULK},
419419
{"scard",scardCommand,2,REDIS_CMD_INLINE},
420+
{"spop",spopCommand,2,REDIS_CMD_INLINE},
420421
{"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
421422
{"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
422423
{"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
@@ -691,22 +692,28 @@ static void closeTimedoutClients(void) {
691692
}
692693
}
693694

695+
static int htNeedsResize(dict *dict) {
696+
long long size, used;
697+
698+
size = dictSlots(dict);
699+
used = dictSize(dict);
700+
return (size && used && size > DICT_HT_INITIAL_SIZE &&
701+
(used*100/size < REDIS_HT_MINFILL));
702+
}
703+
694704
/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
695705
* we resize the hash table to save memory */
696706
static void tryResizeHashTables(void) {
697707
int j;
698708

699709
for (j = 0; j < server.dbnum; j++) {
700-
long long size, used;
701-
702-
size = dictSlots(server.db[j].dict);
703-
used = dictSize(server.db[j].dict);
704-
if (size && used && size > REDIS_HT_MINSLOTS &&
705-
(used*100/size < REDIS_HT_MINFILL)) {
706-
redisLog(REDIS_NOTICE,"The hash table %d is too sparse, resize it...",j);
710+
if (htNeedsResize(server.db[j].dict)) {
711+
redisLog(REDIS_DEBUG,"The hash table %d is too sparse, resize it...",j);
707712
dictResize(server.db[j].dict);
708-
redisLog(REDIS_NOTICE,"Hash table %d resized.",j);
713+
redisLog(REDIS_DEBUG,"Hash table %d resized.",j);
709714
}
715+
if (htNeedsResize(server.db[j].expires))
716+
dictResize(server.db[j].expires);
710717
}
711718
}
712719

@@ -2961,6 +2968,7 @@ static void sremCommand(redisClient *c) {
29612968
}
29622969
if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
29632970
server.dirty++;
2971+
if (htNeedsResize(set->ptr)) dictResize(set->ptr);
29642972
addReply(c,shared.cone);
29652973
} else {
29662974
addReply(c,shared.czero);
@@ -3040,6 +3048,34 @@ static void scardCommand(redisClient *c) {
30403048
}
30413049
}
30423050

3051+
static void spopCommand(redisClient *c) {
3052+
robj *set;
3053+
dictEntry *de;
3054+
3055+
set = lookupKeyWrite(c->db,c->argv[1]);
3056+
if (set == NULL) {
3057+
addReply(c,shared.nullbulk);
3058+
} else {
3059+
if (set->type != REDIS_SET) {
3060+
addReply(c,shared.wrongtypeerr);
3061+
return;
3062+
}
3063+
de = dictGetRandomKey(set->ptr);
3064+
if (de == NULL) {
3065+
addReply(c,shared.nullbulk);
3066+
} else {
3067+
robj *ele = dictGetEntryKey(de);
3068+
3069+
addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele->ptr)));
3070+
addReply(c,ele);
3071+
addReply(c,shared.crlf);
3072+
dictDelete(set->ptr,ele);
3073+
if (htNeedsResize(set->ptr)) dictResize(set->ptr);
3074+
server.dirty++;
3075+
}
3076+
}
3077+
}
3078+
30433079
static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
30443080
dict **d1 = (void*) s1, **d2 = (void*) s2;
30453081

@@ -4170,6 +4206,7 @@ static struct redisFunctionSym symsTable[] = {
41704206
{"smoveCommand", (unsigned long)smoveCommand},
41714207
{"sismemberCommand", (unsigned long)sismemberCommand},
41724208
{"scardCommand", (unsigned long)scardCommand},
4209+
{"spopCommand", (unsigned long)spopCommand},
41734210
{"sinterCommand", (unsigned long)sinterCommand},
41744211
{"sinterstoreCommand", (unsigned long)sinterstoreCommand},
41754212
{"sunionCommand", (unsigned long)sunionCommand},
@@ -4296,6 +4333,9 @@ static void setupSigSegvAction(void) {
42964333
act.sa_sigaction = segvHandler;
42974334
sigaction (SIGSEGV, &act, NULL);
42984335
sigaction (SIGBUS, &act, NULL);
4336+
sigaction (SIGFPE, &act, NULL);
4337+
sigaction (SIGILL, &act, NULL);
4338+
sigaction (SIGBUS, &act, NULL);
42994339
return;
43004340
}
43014341
#else /* HAVE_BACKTRACE */

test-redis.tcl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,14 @@ proc main {server port} {
515515
lsort [$r smembers sres]
516516
} {1 2 3 4}
517517

518+
test {SPOP basics} {
519+
$r del myset
520+
$r sadd myset 1
521+
$r sadd myset 2
522+
$r sadd myset 3
523+
list [lsort [list [$r spop myset] [$r spop myset] [$r spop myset]]] [$r scard myset]
524+
} {{1 2 3} 0}
525+
518526
test {SAVE - make sure there are all the types as values} {
519527
$r lpush mysavelist hello
520528
$r lpush mysavelist world

0 commit comments

Comments
 (0)