diff --git a/src/dict.cpp b/src/dict.cpp index fda797363..184e01ca8 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -179,6 +179,9 @@ int dictExpand(dict *d, unsigned long size) int dictMerge(dict *dst, dict *src) { +#define MERGE_BLOCK_SIZE 4 + dictEntry *rgdeT[MERGE_BLOCK_SIZE]; + assert(dst != src); if (dictSize(src) == 0) return DICT_OK; @@ -210,6 +213,50 @@ int dictMerge(dict *dst, dict *src) } _dictReset(&src->ht[0]); dst->rehashidx = 0; + assert(dictIsRehashing(dst)); + assert((dictSize(src)+dictSize(dst)) == expectedSize); + return DICT_OK; + } + + if (!dictIsRehashing(src) && dictSize(src) > 0 && + (src->ht[0].size == dst->ht[0].size || src->ht[0].size == dst->ht[1].size)) + { + auto &htDst = (src->ht[0].size == dst->ht[0].size) ? dst->ht[0] : dst->ht[1]; + + assert(src->ht[0].size == htDst.size); + for (size_t ide = 0; ide < src->ht[0].size; ide += MERGE_BLOCK_SIZE) + { + if (src->ht[0].used == 0) + break; + + for (int dde = 0; dde < MERGE_BLOCK_SIZE; ++dde) { + rgdeT[dde] = src->ht[0].table[ide + dde]; + src->ht[0].table[ide + dde] = nullptr; + } + + for (;;) { + bool fAnyFound = false; + for (int dde = 0; dde < MERGE_BLOCK_SIZE; ++dde) { + if (rgdeT[dde] == nullptr) + continue; + dictEntry *deNext = rgdeT[dde]->next; + rgdeT[dde]->next = htDst.table[ide+dde]; + htDst.table[ide+dde] = rgdeT[dde]; + rgdeT[dde] = deNext; + htDst.used++; + src->ht[0].used--; + + fAnyFound = fAnyFound || (deNext != nullptr); + } + + if (!fAnyFound) + break; + } + } + // If we copied to the base hash table of a rehashing dst, reset the rehash + if (dictIsRehashing(dst) && src->ht[0].size == dst->ht[0].size) + dst->rehashidx = 0; + assert(dictSize(src) == 0); assert((dictSize(src)+dictSize(dst)) == expectedSize); return DICT_OK; } @@ -218,10 +265,34 @@ int dictMerge(dict *dst, dict *src) auto &htDst = dictIsRehashing(dst) ? dst->ht[1] : dst->ht[0]; for (int iht = 0; iht < 2; ++iht) { - for (size_t ide = 0; ide < src->ht[iht].size; ++ide) + for (size_t ide = 0; ide < src->ht[iht].size; ide += MERGE_BLOCK_SIZE) { if (src->ht[iht].used == 0) break; + + for (int dde = 0; dde < MERGE_BLOCK_SIZE; ++dde) { + rgdeT[dde] = src->ht[iht].table[ide + dde]; + src->ht[iht].table[ide + dde] = nullptr; + } + + for (;;) { + bool fAnyFound = false; + for (int dde = 0; dde < MERGE_BLOCK_SIZE; ++dde) { + if (rgdeT[dde] == nullptr) + continue; + uint64_t h = dictHashKey(dst, rgdeT[dde]->key) & htDst.sizemask; + dictEntry *deNext = rgdeT[dde]->next; + rgdeT[dde]->next = htDst.table[h]; + htDst.table[h] = rgdeT[dde]; + rgdeT[dde] = deNext; + htDst.used++; + src->ht[iht].used--; + fAnyFound = fAnyFound || (deNext != nullptr); + } + if (!fAnyFound) + break; + } +#if 0 dictEntry *de = src->ht[iht].table[ide]; src->ht[iht].table[ide] = nullptr; while (de != nullptr) @@ -236,6 +307,7 @@ int dictMerge(dict *dst, dict *src) de = deNext; src->ht[iht].used--; } +#endif } } assert((dictSize(src)+dictSize(dst)) == expectedSize);