From acfc19633dbd522de4571d7ca9cbc629987b39b6 Mon Sep 17 00:00:00 2001 From: xiaost Date: Tue, 9 Sep 2014 17:53:30 +0800 Subject: [PATCH] Limit the *SCAN command `dictScan` iterations *SCAN will cause redis server to hang for seconds after millions of keys was deleted by SCAN/DEL pairs --- src/db.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/db.c b/src/db.c index 8eb1b89a..d5a381da 100644 --- a/src/db.c +++ b/src/db.c @@ -493,6 +493,11 @@ void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor) { if (ht) { void *privdata[2]; + /* We set the max number of iterations to ten times the specified + * COUNT, so if the hash table is in a pathological state (very + * sparsely populated) we avoid to block too much time at the cost + * of returning no or very few elements. */ + long maxiterations = count*10; /* We pass two pointers to the callback: the list to which it will * add new elements, and the object containing the dictionary so that @@ -501,7 +506,9 @@ void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor) { privdata[1] = o; do { cursor = dictScan(ht, cursor, scanCallback, privdata); - } while (cursor && listLength(keys) < (unsigned long)count); + } while (cursor && + maxiterations-- && + listLength(keys) < (unsigned long)count); } else if (o->type == REDIS_SET) { int pos = 0; int64_t ll;