add noshrink flag to stop dict from shrinking during mass insertions

Former-commit-id: 5e0c994ec82f4adb437a31f8d89eee7a09145576
This commit is contained in:
Malavan Sotheeswaran 2021-08-05 20:07:31 +00:00
parent 81639cd0a6
commit e2abe4f1a0
2 changed files with 26 additions and 19 deletions

View File

@ -131,19 +131,6 @@ int _dictInit(dict *d, dictType *type,
return DICT_OK;
}
/* Resize the table to the minimal size that contains all the elements,
* but with the invariant of a USED/BUCKETS ratio near to <= 1 */
int dictResize(dict *d)
{
unsigned long minimal;
if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR;
minimal = d->ht[0].used;
if (minimal < DICT_HT_INITIAL_SIZE)
minimal = DICT_HT_INITIAL_SIZE;
return dictExpand(d, minimal, false /*fShirnk*/);
}
/* Expand or create the hash table,
* when malloc_failed is non-NULL, it'll avoid panic if malloc fails (in which case it'll be set to 1).
* Returns DICT_OK if expand was performed, and DICT_ERR if skipped. */
@ -189,6 +176,19 @@ int _dictExpand(dict *d, unsigned long size, bool fShrink, int* malloc_failed)
return DICT_OK;
}
/* Resize the table to the minimal size that contains all the elements,
* but with the invariant of a USED/BUCKETS ratio near to <= 1 */
int dictResize(dict *d)
{
unsigned long minimal;
if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR;
minimal = d->ht[0].used;
if (minimal < DICT_HT_INITIAL_SIZE)
minimal = DICT_HT_INITIAL_SIZE;
return _dictExpand(d, minimal, false /*fShirnk*/, nullptr);
}
int dictMerge(dict *dst, dict *src)
{
#define MERGE_BLOCK_SIZE 4
@ -273,7 +273,7 @@ int dictMerge(dict *dst, dict *src)
return DICT_OK;
}
dictExpand(dst, dictSize(dst)+dictSize(src), false /* fShrink */); // start dst rehashing if necessary
_dictExpand(dst, dictSize(dst)+dictSize(src), false /* fShrink */, nullptr); // start dst rehashing if necessary
auto &htDst = dictIsRehashing(dst) ? dst->ht[1] : dst->ht[0];
for (int iht = 0; iht < 2; ++iht)
{
@ -328,12 +328,16 @@ int dictMerge(dict *dst, dict *src)
/* return DICT_ERR if expand was not performed */
int dictExpand(dict *d, unsigned long size, bool fShrink) {
// External expand likely means mass insertion, and we don't want to shrink during that
d->noshrink = true;
return _dictExpand(d, size, fShrink, NULL);
}
/* return DICT_ERR if expand failed due to memory allocation failure */
int dictTryExpand(dict *d, unsigned long size, bool fShrink) {
int malloc_failed;
// External expand likely means mass insertion, and we don't want to shrink during that
d->noshrink = true;
_dictExpand(d, size, fShrink, &malloc_failed);
return malloc_failed? DICT_ERR : DICT_OK;
}
@ -677,6 +681,9 @@ static dictEntry *dictGenericDelete(dict *d, const void *key, int nofree) {
dictEntry *he, *prevHe;
int table;
// if we are deleting elements we probably aren't mass inserting anymore and it is safe to shrink
d->noshrink = false;
if (d->ht[0].used == 0 && d->ht[1].used == 0) return NULL;
if (dictIsRehashing(d)) _dictRehashStep(d);
@ -713,7 +720,6 @@ static dictEntry *dictGenericDelete(dict *d, const void *key, int nofree) {
}
if (!dictIsRehashing(d)) break;
}
_dictExpandIfNeeded(d);
return NULL; /* not found */
}
@ -1317,7 +1323,7 @@ static int _dictExpandIfNeeded(dict *d)
if (dictIsRehashing(d)) return DICT_OK;
/* If the hash table is empty expand it to the initial size. */
if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE, false /*fShrink*/);
if (d->ht[0].size == 0) return _dictExpand(d, DICT_HT_INITIAL_SIZE, false /*fShrink*/, nullptr);
/* 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
@ -1328,12 +1334,12 @@ static int _dictExpandIfNeeded(dict *d)
d->ht[0].used/d->ht[0].size > dict_force_resize_ratio) &&
dictTypeExpandAllowed(d))
{
return dictExpand(d, d->ht[0].used + 1, false /*fShrink*/);
return _dictExpand(d, d->ht[0].used + 1, false /*fShrink*/, nullptr);
}
else if (d->ht[0].used > 0 && d->ht[0].size >= (1024*SHRINK_FACTOR) && (d->ht[0].used * 16) < d->ht[0].size && dict_can_resize)
else if (d->ht[0].used > 0 && d->ht[0].size >= (1024*SHRINK_FACTOR) && (d->ht[0].used * 16) < d->ht[0].size && dict_can_resize && !d->noshrink)
{
// If the dictionary has shurnk a lot we'll need to shrink the hash table instead
return dictExpand(d, d->ht[0].size/SHRINK_FACTOR, true /*fShrink*/);
return _dictExpand(d, d->ht[0].size/SHRINK_FACTOR, true /*fShrink*/, nullptr);
}
return DICT_OK;
}

View File

@ -124,6 +124,7 @@ typedef struct dict {
unsigned refcount;
dictAsyncRehashCtl *asyncdata;
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
uint8_t noshrink = false;
} dict;
/* If safe is set to 1 this is a safe iterator, that means, you can call