]> git.saurik.com Git - redis.git/blame - src/dict.c
Support EXISTS command queries against MDB archive.
[redis.git] / src / dict.c
CommitLineData
ed9b544e 1/* Hash Tables Implementation.
2 *
3 * This file implements in memory hash tables with insert/del/replace/find/
4 * get-random-element operations. Hash tables will auto resize if needed
5 * tables of power of two in size are used, collisions are handled by
6 * chaining. See the source code for more information... :)
7 *
d288ee65 8 * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
ed9b544e 9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * * Neither the name of Redis nor the names of its contributors may be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
23d4709d 36#include "fmacros.h"
37
ed9b544e 38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <stdarg.h>
42#include <assert.h>
f2923bec 43#include <limits.h>
8ca3e9d1 44#include <sys/time.h>
1b1f47c9 45#include <ctype.h>
ed9b544e 46
47#include "dict.h"
48#include "zmalloc.h"
49
884d4b39 50/* Using dictEnableResize() / dictDisableResize() we make possible to
51 * enable/disable resizing of the hash table as needed. This is very important
52 * for Redis, as we use copy-on-write and don't want to move too much memory
3856f147 53 * around when there is a child performing saving operations.
54 *
55 * Note that even when dict_can_resize is set to 0, not all resizes are
56 * prevented: an hash table is still allowed to grow if the ratio between
57 * the number of elements and the buckets > dict_force_resize_ratio. */
884d4b39 58static int dict_can_resize = 1;
3856f147 59static unsigned int dict_force_resize_ratio = 5;
884d4b39 60
ed9b544e 61/* -------------------------- private prototypes ---------------------------- */
62
63static int _dictExpandIfNeeded(dict *ht);
f2923bec 64static unsigned long _dictNextPower(unsigned long size);
ed9b544e 65static int _dictKeyIndex(dict *ht, const void *key);
66static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
67
68/* -------------------------- hash functions -------------------------------- */
69
70/* Thomas Wang's 32 bit Mix Function */
71unsigned int dictIntHashFunction(unsigned int key)
72{
73 key += ~(key << 15);
74 key ^= (key >> 10);
75 key += (key << 3);
76 key ^= (key >> 6);
77 key += ~(key << 11);
78 key ^= (key >> 16);
79 return key;
80}
81
82/* Identity hash function for integer keys */
83unsigned int dictIdentityHashFunction(unsigned int key)
84{
85 return key;
86}
87
99c3338c 88static uint32_t dict_hash_function_seed = 5381;
a48c8d87 89
99c3338c 90void dictSetHashFunctionSeed(uint32_t seed) {
a48c8d87 91 dict_hash_function_seed = seed;
92}
93
99c3338c 94uint32_t dictGetHashFunctionSeed(void) {
a48c8d87 95 return dict_hash_function_seed;
96}
97
99c3338c 98/* MurmurHash2, by Austin Appleby
99 * Note - This code makes a few assumptions about how your machine behaves -
100 * 1. We can read a 4-byte value from any address without crashing
101 * 2. sizeof(int) == 4
102 *
103 * And it has a few limitations -
104 *
105 * 1. It will not work incrementally.
106 * 2. It will not produce the same results on little-endian and big-endian
107 * machines.
108 */
109unsigned int dictGenHashFunction(const void *key, int len) {
110 /* 'm' and 'r' are mixing constants generated offline.
111 They're not really 'magic', they just happen to work well. */
112 uint32_t seed = dict_hash_function_seed;
113 const uint32_t m = 0x5bd1e995;
114 const int r = 24;
115
116 /* Initialize the hash to a 'random' value */
117 uint32_t h = seed ^ len;
118
119 /* Mix 4 bytes at a time into the hash */
120 const unsigned char *data = (const unsigned char *)key;
121
122 while(len >= 4) {
123 uint32_t k = *(uint32_t*)data;
124
125 k *= m;
126 k ^= k >> r;
127 k *= m;
128
129 h *= m;
130 h ^= k;
131
132 data += 4;
133 len -= 4;
134 }
135
136 /* Handle the last few bytes of the input array */
137 switch(len) {
138 case 3: h ^= data[2] << 16;
139 case 2: h ^= data[1] << 8;
140 case 1: h ^= data[0]; h *= m;
141 };
142
143 /* Do a few final mixes of the hash to ensure the last few
144 * bytes are well-incorporated. */
145 h ^= h >> 13;
146 h *= m;
147 h ^= h >> 15;
148
149 return (unsigned int)h;
ed9b544e 150}
151
99c3338c 152/* And a case insensitive hash function (based on djb hash) */
1b1f47c9 153unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {
99c3338c 154 unsigned int hash = (unsigned int)dict_hash_function_seed;
1b1f47c9 155
156 while (len--)
157 hash = ((hash << 5) + hash) + (tolower(*buf++)); /* hash * 33 + c */
158 return hash;
159}
160
ed9b544e 161/* ----------------------------- API implementation ------------------------- */
162
04779bdf
ED
163/* Reset a hash table already initialized with ht_init().
164 * NOTE: This function should only be called by ht_destroy(). */
5413c40d 165static void _dictReset(dictht *ht)
ed9b544e 166{
167 ht->table = NULL;
168 ht->size = 0;
169 ht->sizemask = 0;
170 ht->used = 0;
171}
172
173/* Create a new hash table */
174dict *dictCreate(dictType *type,
175 void *privDataPtr)
176{
d9dd352b 177 dict *d = zmalloc(sizeof(*d));
ed9b544e 178
5413c40d 179 _dictInit(d,type,privDataPtr);
180 return d;
ed9b544e 181}
182
183/* Initialize the hash table */
5413c40d 184int _dictInit(dict *d, dictType *type,
ed9b544e 185 void *privDataPtr)
186{
5413c40d 187 _dictReset(&d->ht[0]);
188 _dictReset(&d->ht[1]);
189 d->type = type;
190 d->privdata = privDataPtr;
191 d->rehashidx = -1;
192 d->iterators = 0;
ed9b544e 193 return DICT_OK;
194}
195
196/* Resize the table to the minimal size that contains all the elements,
085aaef3 197 * but with the invariant of a USED/BUCKETS ratio near to <= 1 */
5413c40d 198int dictResize(dict *d)
ed9b544e 199{
5413c40d 200 int minimal;
ed9b544e 201
5413c40d 202 if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR;
203 minimal = d->ht[0].used;
ed9b544e 204 if (minimal < DICT_HT_INITIAL_SIZE)
205 minimal = DICT_HT_INITIAL_SIZE;
5413c40d 206 return dictExpand(d, minimal);
ed9b544e 207}
208
04779bdf 209/* Expand or create the hash table */
5413c40d 210int dictExpand(dict *d, unsigned long size)
ed9b544e 211{
04779bdf 212 dictht n; /* the new hash table */
5413c40d 213 unsigned long realsize = _dictNextPower(size);
ed9b544e 214
215 /* the size is invalid if it is smaller than the number of
04779bdf 216 * elements already inside the hash table */
5413c40d 217 if (dictIsRehashing(d) || d->ht[0].used > size)
ed9b544e 218 return DICT_ERR;
219
04779bdf 220 /* Allocate the new hash table and initialize all pointers to NULL */
ed9b544e 221 n.size = realsize;
222 n.sizemask = realsize-1;
399f2f40 223 n.table = zcalloc(realsize*sizeof(dictEntry*));
5413c40d 224 n.used = 0;
ed9b544e 225
5413c40d 226 /* Is this the first initialization? If so it's not really a rehashing
227 * we just set the first hash table so that it can accept keys. */
228 if (d->ht[0].table == NULL) {
229 d->ht[0] = n;
230 return DICT_OK;
231 }
ed9b544e 232
5413c40d 233 /* Prepare a second hash table for incremental rehashing */
234 d->ht[1] = n;
235 d->rehashidx = 0;
236 return DICT_OK;
237}
238
239/* Performs N steps of incremental rehashing. Returns 1 if there are still
240 * keys to move from the old to the new hash table, otherwise 0 is returned.
241 * Note that a rehashing step consists in moving a bucket (that may have more
242 * thank one key as we use chaining) from the old to the new hash table. */
243int dictRehash(dict *d, int n) {
244 if (!dictIsRehashing(d)) return 0;
245
246 while(n--) {
247 dictEntry *de, *nextde;
248
249 /* Check if we already rehashed the whole table... */
250 if (d->ht[0].used == 0) {
d9dd352b 251 zfree(d->ht[0].table);
5413c40d 252 d->ht[0] = d->ht[1];
253 _dictReset(&d->ht[1]);
254 d->rehashidx = -1;
255 return 0;
256 }
257
258 /* Note that rehashidx can't overflow as we are sure there are more
259 * elements because ht[0].used != 0 */
05600eb8 260 assert(d->ht[0].size > (unsigned)d->rehashidx);
5413c40d 261 while(d->ht[0].table[d->rehashidx] == NULL) d->rehashidx++;
262 de = d->ht[0].table[d->rehashidx];
263 /* Move all the keys in this bucket from the old to the new hash HT */
264 while(de) {
ed9b544e 265 unsigned int h;
266
5413c40d 267 nextde = de->next;
268 /* Get the index in the new hash table */
269 h = dictHashKey(d, de->key) & d->ht[1].sizemask;
270 de->next = d->ht[1].table[h];
271 d->ht[1].table[h] = de;
272 d->ht[0].used--;
273 d->ht[1].used++;
274 de = nextde;
ed9b544e 275 }
5413c40d 276 d->ht[0].table[d->rehashidx] = NULL;
277 d->rehashidx++;
ed9b544e 278 }
5413c40d 279 return 1;
280}
ed9b544e 281
8ca3e9d1 282long long timeInMilliseconds(void) {
283 struct timeval tv;
284
285 gettimeofday(&tv,NULL);
286 return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
287}
288
289/* Rehash for an amount of time between ms milliseconds and ms+1 milliseconds */
290int dictRehashMilliseconds(dict *d, int ms) {
291 long long start = timeInMilliseconds();
292 int rehashes = 0;
293
294 while(dictRehash(d,100)) {
295 rehashes += 100;
296 if (timeInMilliseconds()-start > ms) break;
297 }
298 return rehashes;
299}
300
5413c40d 301/* This function performs just a step of rehashing, and only if there are
4b53e736 302 * no safe iterators bound to our hash table. When we have iterators in the
303 * middle of a rehashing we can't mess with the two hash tables otherwise
304 * some element can be missed or duplicated.
5413c40d 305 *
306 * This function is called by common lookup or update operations in the
307 * dictionary so that the hash table automatically migrates from H1 to H2
308 * while it is actively used. */
309static void _dictRehashStep(dict *d) {
310 if (d->iterators == 0) dictRehash(d,1);
ed9b544e 311}
312
313/* Add an element to the target hash table */
5413c40d 314int dictAdd(dict *d, void *key, void *val)
71a50956 315{
316 dictEntry *entry = dictAddRaw(d,key);
317
318 if (!entry) return DICT_ERR;
c0ba9ebe 319 dictSetVal(d, entry, val);
71a50956 320 return DICT_OK;
321}
322
323/* Low level add. This function adds the entry but instead of setting
324 * a value returns the dictEntry structure to the user, that will make
325 * sure to fill the value field as he wishes.
326 *
04779bdf 327 * This function is also directly exposed to user API to be called
71a50956 328 * mainly in order to store non-pointers inside the hash value, example:
329 *
330 * entry = dictAddRaw(dict,mykey);
aa9a61cc 331 * if (entry != NULL) dictSetSignedIntegerVal(entry,1000);
71a50956 332 *
333 * Return values:
334 *
335 * If key already exists NULL is returned.
336 * If key was added, the hash entry is returned to be manipulated by the caller.
337 */
338dictEntry *dictAddRaw(dict *d, void *key)
ed9b544e 339{
340 int index;
341 dictEntry *entry;
5413c40d 342 dictht *ht;
343
344 if (dictIsRehashing(d)) _dictRehashStep(d);
ed9b544e 345
346 /* Get the index of the new element, or -1 if
347 * the element already exists. */
5413c40d 348 if ((index = _dictKeyIndex(d, key)) == -1)
71a50956 349 return NULL;
ed9b544e 350
6a7841eb 351 /* Allocate the memory and store the new entry */
5413c40d 352 ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
d9dd352b 353 entry = zmalloc(sizeof(*entry));
ed9b544e 354 entry->next = ht->table[index];
355 ht->table[index] = entry;
5413c40d 356 ht->used++;
ed9b544e 357
358 /* Set the hash entry fields. */
c0ba9ebe 359 dictSetKey(d, entry, key);
71a50956 360 return entry;
ed9b544e 361}
362
121796f7 363/* Add an element, discarding the old if the key already exists.
364 * Return 1 if the key was added from scratch, 0 if there was already an
365 * element with such key and dictReplace() just performed a value update
366 * operation. */
5413c40d 367int dictReplace(dict *d, void *key, void *val)
ed9b544e 368{
2069d06a 369 dictEntry *entry, auxentry;
ed9b544e 370
371 /* Try to add the element. If the key
372 * does not exists dictAdd will suceed. */
5413c40d 373 if (dictAdd(d, key, val) == DICT_OK)
121796f7 374 return 1;
ed9b544e 375 /* It already exists, get the entry */
5413c40d 376 entry = dictFind(d, key);
2069d06a 377 /* Set the new value and free the old one. Note that it is important
378 * to do that in this order, as the value may just be exactly the same
379 * as the previous one. In this context, think to reference counting,
380 * you want to increment (set), and then decrement (free), and not the
381 * reverse. */
382 auxentry = *entry;
c0ba9ebe 383 dictSetVal(d, entry, val);
384 dictFreeVal(d, &auxentry);
121796f7 385 return 0;
ed9b544e 386}
387
71a50956 388/* dictReplaceRaw() is simply a version of dictAddRaw() that always
389 * returns the hash entry of the specified key, even if the key already
390 * exists and can't be added (in that case the entry of the already
391 * existing key is returned.)
392 *
393 * See dictAddRaw() for more information. */
394dictEntry *dictReplaceRaw(dict *d, void *key) {
395 dictEntry *entry = dictFind(d,key);
396
397 return entry ? entry : dictAddRaw(d,key);
398}
399
ed9b544e 400/* Search and remove an element */
5413c40d 401static int dictGenericDelete(dict *d, const void *key, int nofree)
ed9b544e 402{
5413c40d 403 unsigned int h, idx;
ed9b544e 404 dictEntry *he, *prevHe;
5413c40d 405 int table;
ed9b544e 406
5413c40d 407 if (d->ht[0].size == 0) return DICT_ERR; /* d->ht[0].table is NULL */
408 if (dictIsRehashing(d)) _dictRehashStep(d);
409 h = dictHashKey(d, key);
ed9b544e 410
5413c40d 411 for (table = 0; table <= 1; table++) {
412 idx = h & d->ht[table].sizemask;
413 he = d->ht[table].table[idx];
414 prevHe = NULL;
415 while(he) {
c0ba9ebe 416 if (dictCompareKeys(d, key, he->key)) {
5413c40d 417 /* Unlink the element from the list */
418 if (prevHe)
419 prevHe->next = he->next;
420 else
421 d->ht[table].table[idx] = he->next;
422 if (!nofree) {
c0ba9ebe 423 dictFreeKey(d, he);
424 dictFreeVal(d, he);
5413c40d 425 }
d9dd352b 426 zfree(he);
5413c40d 427 d->ht[table].used--;
428 return DICT_OK;
ed9b544e 429 }
5413c40d 430 prevHe = he;
431 he = he->next;
ed9b544e 432 }
5413c40d 433 if (!dictIsRehashing(d)) break;
ed9b544e 434 }
435 return DICT_ERR; /* not found */
436}
437
438int dictDelete(dict *ht, const void *key) {
439 return dictGenericDelete(ht,key,0);
440}
441
442int dictDeleteNoFree(dict *ht, const void *key) {
443 return dictGenericDelete(ht,key,1);
444}
445
5413c40d 446/* Destroy an entire dictionary */
447int _dictClear(dict *d, dictht *ht)
ed9b544e 448{
f2923bec 449 unsigned long i;
ed9b544e 450
451 /* Free all the elements */
452 for (i = 0; i < ht->size && ht->used > 0; i++) {
453 dictEntry *he, *nextHe;
454
455 if ((he = ht->table[i]) == NULL) continue;
456 while(he) {
457 nextHe = he->next;
c0ba9ebe 458 dictFreeKey(d, he);
459 dictFreeVal(d, he);
d9dd352b 460 zfree(he);
ed9b544e 461 ht->used--;
462 he = nextHe;
463 }
464 }
465 /* Free the table and the allocated cache structure */
d9dd352b 466 zfree(ht->table);
ed9b544e 467 /* Re-initialize the table */
468 _dictReset(ht);
469 return DICT_OK; /* never fails */
470}
471
472/* Clear & Release the hash table */
5413c40d 473void dictRelease(dict *d)
ed9b544e 474{
5413c40d 475 _dictClear(d,&d->ht[0]);
476 _dictClear(d,&d->ht[1]);
d9dd352b 477 zfree(d);
ed9b544e 478}
479
5413c40d 480dictEntry *dictFind(dict *d, const void *key)
ed9b544e 481{
482 dictEntry *he;
5413c40d 483 unsigned int h, idx, table;
484
485 if (d->ht[0].size == 0) return NULL; /* We don't have a table at all */
486 if (dictIsRehashing(d)) _dictRehashStep(d);
487 h = dictHashKey(d, key);
488 for (table = 0; table <= 1; table++) {
489 idx = h & d->ht[table].sizemask;
490 he = d->ht[table].table[idx];
491 while(he) {
c0ba9ebe 492 if (dictCompareKeys(d, key, he->key))
5413c40d 493 return he;
494 he = he->next;
495 }
496 if (!dictIsRehashing(d)) return NULL;
ed9b544e 497 }
498 return NULL;
499}
500
58e1c9c1 501void *dictFetchValue(dict *d, const void *key) {
502 dictEntry *he;
503
504 he = dictFind(d,key);
c0ba9ebe 505 return he ? dictGetVal(he) : NULL;
58e1c9c1 506}
507
5413c40d 508dictIterator *dictGetIterator(dict *d)
ed9b544e 509{
d9dd352b 510 dictIterator *iter = zmalloc(sizeof(*iter));
ed9b544e 511
5413c40d 512 iter->d = d;
513 iter->table = 0;
ed9b544e 514 iter->index = -1;
4b53e736 515 iter->safe = 0;
ed9b544e 516 iter->entry = NULL;
517 iter->nextEntry = NULL;
518 return iter;
519}
520
4b53e736 521dictIterator *dictGetSafeIterator(dict *d) {
522 dictIterator *i = dictGetIterator(d);
523
524 i->safe = 1;
525 return i;
526}
527
ed9b544e 528dictEntry *dictNext(dictIterator *iter)
529{
530 while (1) {
531 if (iter->entry == NULL) {
5413c40d 532 dictht *ht = &iter->d->ht[iter->table];
4b53e736 533 if (iter->safe && iter->index == -1 && iter->table == 0)
534 iter->d->iterators++;
ed9b544e 535 iter->index++;
5413c40d 536 if (iter->index >= (signed) ht->size) {
537 if (dictIsRehashing(iter->d) && iter->table == 0) {
538 iter->table++;
539 iter->index = 0;
540 ht = &iter->d->ht[1];
541 } else {
542 break;
543 }
544 }
545 iter->entry = ht->table[iter->index];
ed9b544e 546 } else {
547 iter->entry = iter->nextEntry;
548 }
549 if (iter->entry) {
550 /* We need to save the 'next' here, the iterator user
551 * may delete the entry we are returning. */
552 iter->nextEntry = iter->entry->next;
553 return iter->entry;
554 }
555 }
556 return NULL;
557}
558
559void dictReleaseIterator(dictIterator *iter)
560{
4b53e736 561 if (iter->safe && !(iter->index == -1 && iter->table == 0))
562 iter->d->iterators--;
d9dd352b 563 zfree(iter);
ed9b544e 564}
565
566/* Return a random entry from the hash table. Useful to
567 * implement randomized algorithms */
5413c40d 568dictEntry *dictGetRandomKey(dict *d)
ed9b544e 569{
5413c40d 570 dictEntry *he, *orighe;
ed9b544e 571 unsigned int h;
572 int listlen, listele;
573
5413c40d 574 if (dictSize(d) == 0) return NULL;
575 if (dictIsRehashing(d)) _dictRehashStep(d);
576 if (dictIsRehashing(d)) {
577 do {
578 h = random() % (d->ht[0].size+d->ht[1].size);
579 he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
580 d->ht[0].table[h];
581 } while(he == NULL);
582 } else {
583 do {
584 h = random() & d->ht[0].sizemask;
585 he = d->ht[0].table[h];
586 } while(he == NULL);
587 }
ed9b544e 588
589 /* Now we found a non empty bucket, but it is a linked
590 * list and we need to get a random element from the list.
5413c40d 591 * The only sane way to do so is counting the elements and
ed9b544e 592 * select a random index. */
593 listlen = 0;
5413c40d 594 orighe = he;
ed9b544e 595 while(he) {
596 he = he->next;
597 listlen++;
598 }
599 listele = random() % listlen;
5413c40d 600 he = orighe;
ed9b544e 601 while(listele--) he = he->next;
602 return he;
603}
604
605/* ------------------------- private functions ------------------------------ */
606
607/* Expand the hash table if needed */
5413c40d 608static int _dictExpandIfNeeded(dict *d)
ed9b544e 609{
3856f147 610 /* Incremental rehashing already in progress. Return. */
5413c40d 611 if (dictIsRehashing(d)) return DICT_OK;
3856f147 612
613 /* If the hash table is empty expand it to the intial size. */
614 if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);
615
616 /* If we reached the 1:1 ratio, and we are allowed to resize the hash
617 * table (global setting) or we should avoid it but the ratio between
618 * elements/buckets is over the "safe" threshold, we resize doubling
619 * the number of buckets. */
620 if (d->ht[0].used >= d->ht[0].size &&
621 (dict_can_resize ||
622 d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
623 {
5413c40d 624 return dictExpand(d, ((d->ht[0].size > d->ht[0].used) ?
625 d->ht[0].size : d->ht[0].used)*2);
3856f147 626 }
ed9b544e 627 return DICT_OK;
628}
629
630/* Our hash table capability is a power of two */
f2923bec 631static unsigned long _dictNextPower(unsigned long size)
ed9b544e 632{
f2923bec 633 unsigned long i = DICT_HT_INITIAL_SIZE;
ed9b544e 634
f2923bec 635 if (size >= LONG_MAX) return LONG_MAX;
ed9b544e 636 while(1) {
637 if (i >= size)
638 return i;
639 i *= 2;
640 }
641}
642
643/* Returns the index of a free slot that can be populated with
644 * an hash entry for the given 'key'.
5413c40d 645 * If the key already exists, -1 is returned.
646 *
647 * Note that if we are in the process of rehashing the hash table, the
648 * index is always returned in the context of the second (new) hash table. */
649static int _dictKeyIndex(dict *d, const void *key)
ed9b544e 650{
8ca3e9d1 651 unsigned int h, idx, table;
ed9b544e 652 dictEntry *he;
653
04779bdf 654 /* Expand the hash table if needed */
5413c40d 655 if (_dictExpandIfNeeded(d) == DICT_ERR)
ed9b544e 656 return -1;
657 /* Compute the key hash value */
5413c40d 658 h = dictHashKey(d, key);
8ca3e9d1 659 for (table = 0; table <= 1; table++) {
660 idx = h & d->ht[table].sizemask;
661 /* Search if this slot does not already contain the given key */
662 he = d->ht[table].table[idx];
663 while(he) {
c0ba9ebe 664 if (dictCompareKeys(d, key, he->key))
8ca3e9d1 665 return -1;
666 he = he->next;
667 }
668 if (!dictIsRehashing(d)) break;
ed9b544e 669 }
8ca3e9d1 670 return idx;
ed9b544e 671}
672
5413c40d 673void dictEmpty(dict *d) {
674 _dictClear(d,&d->ht[0]);
675 _dictClear(d,&d->ht[1]);
676 d->rehashidx = -1;
677 d->iterators = 0;
ed9b544e 678}
679
d54943b7 680void dictEnableResize(void) {
681 dict_can_resize = 1;
682}
683
684void dictDisableResize(void) {
685 dict_can_resize = 0;
686}
687
688#if 0
689
e337b260 690/* The following is code that we don't use for Redis currently, but that is part
691of the library. */
d54943b7 692
693/* ----------------------- Debugging ------------------------*/
694
ed9b544e 695#define DICT_STATS_VECTLEN 50
5413c40d 696static void _dictPrintStatsHt(dictht *ht) {
f2923bec 697 unsigned long i, slots = 0, chainlen, maxchainlen = 0;
698 unsigned long totchainlen = 0;
699 unsigned long clvector[DICT_STATS_VECTLEN];
ed9b544e 700
701 if (ht->used == 0) {
702 printf("No stats available for empty dictionaries\n");
703 return;
704 }
705
706 for (i = 0; i < DICT_STATS_VECTLEN; i++) clvector[i] = 0;
707 for (i = 0; i < ht->size; i++) {
708 dictEntry *he;
709
710 if (ht->table[i] == NULL) {
711 clvector[0]++;
712 continue;
713 }
714 slots++;
715 /* For each hash entry on this slot... */
716 chainlen = 0;
717 he = ht->table[i];
718 while(he) {
719 chainlen++;
720 he = he->next;
721 }
722 clvector[(chainlen < DICT_STATS_VECTLEN) ? chainlen : (DICT_STATS_VECTLEN-1)]++;
723 if (chainlen > maxchainlen) maxchainlen = chainlen;
724 totchainlen += chainlen;
725 }
726 printf("Hash table stats:\n");
f2923bec 727 printf(" table size: %ld\n", ht->size);
728 printf(" number of elements: %ld\n", ht->used);
729 printf(" different slots: %ld\n", slots);
730 printf(" max chain length: %ld\n", maxchainlen);
ed9b544e 731 printf(" avg chain length (counted): %.02f\n", (float)totchainlen/slots);
732 printf(" avg chain length (computed): %.02f\n", (float)ht->used/slots);
733 printf(" Chain length distribution:\n");
734 for (i = 0; i < DICT_STATS_VECTLEN-1; i++) {
735 if (clvector[i] == 0) continue;
f2923bec 736 printf(" %s%ld: %ld (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", i, clvector[i], ((float)clvector[i]/ht->size)*100);
ed9b544e 737 }
738}
739
5413c40d 740void dictPrintStats(dict *d) {
741 _dictPrintStatsHt(&d->ht[0]);
742 if (dictIsRehashing(d)) {
743 printf("-- Rehashing into ht[1]:\n");
744 _dictPrintStatsHt(&d->ht[1]);
745 }
746}
747
ed9b544e 748/* ----------------------- StringCopy Hash Table Type ------------------------*/
749
750static unsigned int _dictStringCopyHTHashFunction(const void *key)
751{
752 return dictGenHashFunction(key, strlen(key));
753}
754
b1e0bd4b 755static void *_dictStringDup(void *privdata, const void *key)
ed9b544e 756{
757 int len = strlen(key);
d9dd352b 758 char *copy = zmalloc(len+1);
ed9b544e 759 DICT_NOTUSED(privdata);
760
761 memcpy(copy, key, len);
762 copy[len] = '\0';
763 return copy;
764}
765
ed9b544e 766static int _dictStringCopyHTKeyCompare(void *privdata, const void *key1,
767 const void *key2)
768{
769 DICT_NOTUSED(privdata);
770
771 return strcmp(key1, key2) == 0;
772}
773
b1e0bd4b 774static void _dictStringDestructor(void *privdata, void *key)
ed9b544e 775{
776 DICT_NOTUSED(privdata);
777
d9dd352b 778 zfree(key);
ed9b544e 779}
780
781dictType dictTypeHeapStringCopyKey = {
b1e0bd4b
BK
782 _dictStringCopyHTHashFunction, /* hash function */
783 _dictStringDup, /* key dup */
784 NULL, /* val dup */
785 _dictStringCopyHTKeyCompare, /* key compare */
786 _dictStringDestructor, /* key destructor */
787 NULL /* val destructor */
ed9b544e 788};
789
790/* This is like StringCopy but does not auto-duplicate the key.
791 * It's used for intepreter's shared strings. */
792dictType dictTypeHeapStrings = {
b1e0bd4b
BK
793 _dictStringCopyHTHashFunction, /* hash function */
794 NULL, /* key dup */
795 NULL, /* val dup */
796 _dictStringCopyHTKeyCompare, /* key compare */
797 _dictStringDestructor, /* key destructor */
798 NULL /* val destructor */
ed9b544e 799};
800
801/* This is like StringCopy but also automatically handle dynamic
802 * allocated C strings as values. */
803dictType dictTypeHeapStringCopyKeyValue = {
b1e0bd4b
BK
804 _dictStringCopyHTHashFunction, /* hash function */
805 _dictStringDup, /* key dup */
806 _dictStringDup, /* val dup */
807 _dictStringCopyHTKeyCompare, /* key compare */
808 _dictStringDestructor, /* key destructor */
809 _dictStringDestructor, /* val destructor */
ed9b544e 810};
e0be2289 811#endif