这里主要是哈希相关的函数,也是基础的内容,任何相关的组件代码必然涉及。
- static uint8_t dict_hash_function_seed[16];
-  
- void dictSetHashFunctionSeed(uint8_t *seed) {
-     memcpy(dict_hash_function_seed,seed,sizeof(dict_hash_function_seed));
- }
-  
- uint8_t *dictGetHashFunctionSeed(void) {
-     return dict_hash_function_seed;
- }
-  
- /* The default hashing function uses SipHash implementation
-  * in siphash.c. */
-  
- uint64_t siphash(const uint8_t *in, const size_t inlen, const uint8_t *k);
- uint64_t siphash_nocase(const uint8_t *in, const size_t inlen, const uint8_t *k);
-  
- uint64_t dictGenHashFunction(const void *key, int len) {
-     return siphash(key,len,dict_hash_function_seed);
- }
-  
- uint64_t dictGenCaseHashFunction(const unsigned char *buf, int len) {
-     return siphash_nocase(buf,len,dict_hash_function_seed);
- }
-  
- /* ----------------------------- API implementation ------------------------- */
-  
- /* Reset a hash table already initialized with ht_init().
-  * NOTE: This function should only be called by ht_destroy(). */
- static void _dictReset(dictht *ht)
- {
-     ht->table = NULL;
-     ht->size = 0;
-     ht->sizemask = 0;
-     ht->used = 0;
- }
-  
- /* Create a new hash table */
- dict *dictCreate(dictType *type,
-         void *privDataPtr)
- {
-     dict *d = zmalloc(sizeof(*d));
-  
-     _dictInit(d,type,privDataPtr);
-     return d;
- }
-  
- /* Initialize the hash table */
- int _dictInit(dict *d, dictType *type,
-         void *privDataPtr)
- {
-     _dictReset(&d->ht[0]);
-     _dictReset(&d->ht[1]);
-     d->type = type;
-     d->privdata = privDataPtr;
-     d->rehashidx = -1;
-     d->pauserehash = 0;
-     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);
- }
-  
- /* 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. */
- int _dictExpand(dict *d, unsigned long size, int* malloc_failed)
- {
-     if (malloc_failed) *malloc_failed = 0;
-  
-     /* the size is invalid if it is smaller than the number of
-      * elements already inside the hash table */
-     if (dictIsRehashing(d) || d->ht[0].used > size)
-         return DICT_ERR;
-  
-     dictht n; /* the new hash table */
-     unsigned long realsize = _dictNextPower(size);
-  
-     /* Detect overflows */
-     if (realsize < size || realsize * sizeof(dictEntry*) < realsize)
-         return DICT_ERR;
-  
-     /* Rehashing to the same table size is not useful. */
-     if (realsize == d->ht[0].size) return DICT_ERR;
-  
-     /* Allocate the new hash table and initialize all pointers to NULL */
-     n.size = realsize;
-     n.sizemask = realsize-1;
-     if (malloc_failed) {
-         n.table = ztrycalloc(realsize*sizeof(dictEntry*));
-         *malloc_failed = n.table == NULL;
-         if (*malloc_failed)
-             return DICT_ERR;
-     } else
-         n.table = zcalloc(realsize*sizeof(dictEntry*));
-  
-     n.used = 0;
-  
-     /* Is this the first initialization? If so it's not really a rehashing
-      * we just set the first hash table so that it can accept keys. */
-     if (d->ht[0].table == NULL) {
-         d->ht[0] = n;
-         return DICT_OK;
-     }
-  
-     /* Prepare a second hash table for incremental rehashing */
-     d->ht[1] = n;
-     d->rehashidx = 0;
-     return DICT_OK;
- }
-  
- /* return DICT_ERR if expand was not performed */
- int dictExpand(dict *d, unsigned long size) {
-     return _dictExpand(d, size, NULL);
- }
-  
- /* return DICT_ERR if expand failed due to memory allocation failure */
- int dictTryExpand(dict *d, unsigned long size) {
-     int malloc_failed;
-     _dictExpand(d, size, &malloc_failed);
-     return malloc_failed? DICT_ERR : DICT_OK;
- }
-  
- /* Performs N steps of incremental rehashing. Returns 1 if there are still
-  * keys to move from the old to the new hash table, otherwise 0 is returned.
-  *
-  * Note that a rehashing step consists in moving a bucket (that may have more
-  * than one key as we use chaining) from the old to the new hash table, however
-  * since part of the hash table may be composed of empty spaces, it is not
-  * guaranteed that this function will rehash even a single bucket, since it
-  * will visit at max N*10 empty buckets in total, otherwise the amount of
-  * work it does would be unbound and the function may block for a long time. */
- int dictRehash(dict *d, int n) {
-     int empty_visits = n*10; /* Max number of empty buckets to visit. */
-     if (!dictIsRehashing(d)) return 0;
-  
-     while(n-- && d->ht[0].used != 0) {
-         dictEntry *de, *nextde;
-  
-         /* Note that rehashidx can't overflow as we are sure there are more
-          * elements because ht[0].used != 0 */
-         assert(d->ht[0].size > (unsigned long)d->rehashidx);
-         while(d->ht[0].table[d->rehashidx] == NULL) {
-             d->rehashidx++;
-             if (--empty_visits == 0) return 1;
-         }
-         de = d->ht[0].table[d->rehashidx];
-         /* Move all the keys in this bucket from the old to the new hash HT */
-         while(de) {
-             uint64_t h;
-  
-             nextde = de->next;
-             /* Get the index in the new hash table */
-             h = dictHashKey(d, de->key) & d->ht[1].sizemask;
-             de->next = d->ht[1].table[h];
-             d->ht[1].table[h] = de;
-             d->ht[0].used--;
-             d->ht[1].used++;
-             de = nextde;
-         }
-         d->ht[0].table[d->rehashidx] = NULL;
-         d->rehashidx++;
-     }
-  
-     /* Check if we already rehashed the whole table... */
-     if (d->ht[0].used == 0) {
-         zfree(d->ht[0].table);
-         d->ht[0] = d->ht[1];
-         _dictReset(&d->ht[1]);
-         d->rehashidx = -1;
-         return 0;
-     }
-  
-     /* More to rehash... */
-     return 1;
- }
-  
- long long timeInMilliseconds(void) {
-     struct timeval tv;
-  
-     gettimeofday(&tv,NULL);
-     return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
- }
-  
- /* Rehash in ms+"delta" milliseconds. The value of "delta" is larger 
-  * than 0, and is smaller than 1 in most cases. The exact upper bound 
-  * depends on the running time of dictRehash(d,100).*/
- int dictRehashMilliseconds(dict *d, int ms) {
-     if (d->pauserehash > 0) return 0;
-  
-     long long start = timeInMilliseconds();
-     int rehashes = 0;
-  
-     while(dictRehash(d,100)) {
-         rehashes += 100;
-         if (timeInMilliseconds()-start > ms) break;
-     }
-     return rehashes;
- }
-  
- /* This function performs just a step of rehashing, and only if hashing has
-  * not been paused for our hash table. When we have iterators in the
-  * middle of a rehashing we can't mess with the two hash tables otherwise
-  * some element can be missed or duplicated.
-  *
-  * This function is called by common lookup or update operations in the
-  * dictionary so that the hash table automatically migrates from H1 to H2
-  * while it is actively used. */
- static void _dictRehashStep(dict *d) {
-     if (d->pauserehash == 0) dictRehash(d,1);
- }
-  
- /* Add an element to the target hash table */
- int dictAdd(dict *d, void *key, void *val)
- {
-     dictEntry *entry = dictAddRaw(d,key,NULL);
-  
-     if (!entry) return DICT_ERR;
-     dictSetVal(d, entry, val);
-     return DICT_OK;
- }
-  
- /* Low level add or find:
-  * This function adds the entry but instead of setting a value returns the
-  * dictEntry structure to the user, that will make sure to fill the value
-  * field as they wish.
-  *
-  * This function is also directly exposed to the user API to be called
-  * mainly in order to store non-pointers inside the hash value, example:
-  *
-  * entry = dictAddRaw(dict,mykey,NULL);
-  * if (entry != NULL) dictSetSignedIntegerVal(entry,1000);
-  *
-  * Return values:
-  *
-  * If key already exists NULL is returned, and "*existing" is populated
-  * with the existing entry if existing is not NULL.
-  *
-  * If key was added, the hash entry is returned to be manipulated by the caller.
-  */
- dictEntry *dictAddRaw(dict *d, void *key, dictEntry **existing)
- {
-     long index;
-     dictEntry *entry;
-     dictht *ht;
-  
-     if (dictIsRehashing(d)) _dictRehashStep(d);
-  
-     /* Get the index of the new element, or -1 if
-      * the element already exists. */
-     if ((index = _dictKeyIndex(d, key, dictHashKey(d,key), existing)) == -1)
-         return NULL;
-  
-     /* Allocate the memory and store the new entry.
-      * Insert the element in top, with the assumption that in a database
-      * system it is more likely that recently added entries are accessed
-      * more frequently. */
-     ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
-     entry = zmalloc(sizeof(*entry));
-     entry->next = ht->table[index];
-     ht->table[index] = entry;
-     ht->used++;
-  
-     /* Set the hash entry fields. */
-     dictSetKey(d, entry, key);
-     return entry;
- }
-  
- /* Add or Overwrite:
-  * Add an element, discarding the old value if the key already exists.
-  * Return 1 if the key was added from scratch, 0 if there was already an
-  * element with such key and dictReplace() just performed a value update
-  * operation. */
- int dictReplace(dict *d, void *key, void *val)
- {
-     dictEntry *entry, *existing, auxentry;
-  
-     /* Try to add the element. If the key
-      * does not exists dictAdd will succeed. */
-     entry = dictAddRaw(d,key,&existing);
-     if (entry) {
-         dictSetVal(d, entry, val);
-         return 1;
-     }
-  
-     /* Set the new value and free the old one. Note that it is important
-      * to do that in this order, as the value may just be exactly the same
-      * as the previous one. In this context, think to reference counting,
-      * you want to increment (set), and then decrement (free), and not the
-      * reverse. */
-     auxentry = *existing;
-     dictSetVal(d, existing, val);
-     dictFreeVal(d, &auxentry);
-     return 0;
- }
-  
- /* Add or Find:
-  * dictAddOrFind() is simply a version of dictAddRaw() that always
-  * returns the hash entry of the specified key, even if the key already
-  * exists and can't be added (in that case the entry of the already
-  * existing key is returned.)
-  *
-  * See dictAddRaw() for more information. */
- dictEntry *dictAddOrFind(dict *d, void *key) {
-     dictEntry *entry, *existing;
-     entry = dictAddRaw(d,key,&existing);
-     return entry ? entry : existing;
- }
-  
- /* Search and remove an element. This is an helper function for
-  * dictDelete() and dictUnlink(), please check the top comment
-  * of those functions. */
- static dictEntry *dictGenericDelete(dict *d, const void *key, int nofree) {
-     uint64_t h, idx;
-     dictEntry *he, *prevHe;
-     int table;
-  
-     if (d->ht[0].used == 0 && d->ht[1].used == 0) return NULL;
-  
-     if (dictIsRehashing(d)) _dictRehashStep(d);
-     h = dictHashKey(d, key);
-  
-     for (table = 0; table <= 1; table++) {
-         idx = h & d->ht[table].sizemask;
-         he = d->ht[table].table[idx];
-         prevHe = NULL;
-         while(he) {
-             if (key==he->key || dictCompareKeys(d, key, he->key)) {
-                 /* Unlink the element from the list */
-                 if (prevHe)
-                     prevHe->next = he->next;
-                 else
-                     d->ht[table].table[idx] = he->next;
-                 if (!nofree) {
-                     dictFreeKey(d, he);
-                     dictFreeVal(d, he);
-                     zfree(he);
-                 }
-                 d->ht[table].used--;
-                 return he;
-             }
-             prevHe = he;
-             he = he->next;
-         }
-         if (!dictIsRehashing(d)) break;
-     }
-     return NULL; /* not found */
- }
-  
- /* Remove an element, returning DICT_OK on success or DICT_ERR if the
-  * element was not found. */
- int dictDelete(dict *ht, const void *key) {
-     return dictGenericDelete(ht,key,0) ? DICT_OK : DICT_ERR;
- }
-  
- /* Remove an element from the table, but without actually releasing
-  * the key, value and dictionary entry. The dictionary entry is returned
-  * if the element was found (and unlinked from the table), and the user
-  * should later call `dictFreeUnlinkedEntry()` with it in order to release it.
-  * Otherwise if the key is not found, NULL is returned.
-  *
-  * This function is useful when we want to remove something from the hash
-  * table but want to use its value before actually deleting the entry.
-  * Without this function the pattern would require two lookups:
-  *
-  *  entry = dictFind(...);
-  *  // Do something with entry
-  *  dictDelete(dictionary,entry);
-  *
-  * Thanks to this function it is possible to avoid this, and use
-  * instead:
-  *
-  * entry = dictUnlink(dictionary,entry);
-  * // Do something with entry
-  * dictFreeUnlinkedEntry(entry); // <- This does not need to lookup again.
-  */
- dictEntry *dictUnlink(dict *ht, const void *key) {
-     return dictGenericDelete(ht,key,1);
- }

 
                

















