From 3856f1475936e58d3caebbb3df317421b263f2e6 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 15 Sep 2010 14:09:41 +0200 Subject: [PATCH] This should fix Issue 332: when there is a background process saving we still allow the hash tables to grow, but only when a critical treshold is reached. Formerly we prevented the resize at all triggering pathological O(N) behavior. Also there is a fix for the statistics in INFO about the number of keys expired --- src/dict.c | 28 +++++++++++++++++++++------- src/redis.c | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/dict.c b/src/dict.c index 2d1e752b..a1060d45 100644 --- a/src/dict.c +++ b/src/dict.c @@ -49,8 +49,13 @@ /* Using dictEnableResize() / dictDisableResize() we make possible to * enable/disable resizing of the hash table as needed. This is very important * for Redis, as we use copy-on-write and don't want to move too much memory - * around when there is a child performing saving operations. */ + * around when there is a child performing saving operations. + * + * Note that even when dict_can_resize is set to 0, not all resizes are + * prevented: an hash table is still allowed to grow if the ratio between + * the number of elements and the buckets > dict_force_resize_ratio. */ static int dict_can_resize = 1; +static unsigned int dict_force_resize_ratio = 5; /* -------------------------- private prototypes ---------------------------- */ @@ -125,7 +130,7 @@ int _dictInit(dict *d, dictType *type, } /* Resize the table to the minimal size that contains all the elements, - * but with the invariant of a USER/BUCKETS ration near to <= 1 */ + * but with the invariant of a USER/BUCKETS ratio near to <= 1 */ int dictResize(dict *d) { int minimal; @@ -493,14 +498,23 @@ dictEntry *dictGetRandomKey(dict *d) /* Expand the hash table if needed */ static int _dictExpandIfNeeded(dict *d) { - /* If the hash table is empty expand it to the intial size, - * if the table is "full" dobule its size. */ + /* Incremental rehashing already in progress. Return. */ if (dictIsRehashing(d)) return DICT_OK; - if (d->ht[0].size == 0) - return dictExpand(d, DICT_HT_INITIAL_SIZE); - if (d->ht[0].used >= d->ht[0].size && dict_can_resize) + + /* If the hash table is empty expand it to the intial size. */ + if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE); + + /* If we reached the 1:1 ratio, and we are allowed to resize the hash + * table (global setting) or we should avoid it but the ratio between + * elements/buckets is over the "safe" threshold, we resize doubling + * the number of buckets. */ + if (d->ht[0].used >= d->ht[0].size && + (dict_can_resize || + d->ht[0].used/d->ht[0].size > dict_force_resize_ratio)) + { return dictExpand(d, ((d->ht[0].size > d->ht[0].used) ? d->ht[0].size : d->ht[0].used)*2); + } return DICT_OK; } diff --git a/src/redis.c b/src/redis.c index 8206b5d3..b6b42521 100644 --- a/src/redis.c +++ b/src/redis.c @@ -1343,6 +1343,7 @@ void freeMemoryIfNeeded(void) { } keyobj = createStringObject(minkey,sdslen(minkey)); dbDelete(server.db+j,keyobj); + server.stat_expiredkeys++; decrRefCount(keyobj); } } -- 2.47.2