We plan to spend one hour learning Redis source code every day. Make a record on the blog. -------- June 18 ----------- the redis dictionary dict mainly involves several data structures. dictEntry: The specific k-v linked list node dictht: Hash Table dict: The dictionary relationship is 1 typedefstructdict {2dictType * type; 3void * privda
We plan to spend one hour learning Redis source code every day. Make a record on the blog. -------- June 18 ----------- redis dictionary dict mainly involves several data structures, dictEntry: The specific k-v linked list node dictht: Hash Table dict: the specific dictionary relationship is 1 typedef struct dict {2 dictType * type; 3 void * privda
We plan to spend one hour learning Redis source code every day. Make a record on the blog.
-------- June 18 -----------
The redis dictionary dict mainly involves several data structures,
DictEntry: The specific k-v linked list Node
Dictht: hash table
Dict: Dictionary
The specific link is
1 typedef struct dict {2 dictType * type; 3 void * privdata; 4 dictht ht [2]; iterators;} dict;
1 typedef struct dictht {2 dictEntry ** table; 3 unsigned long size; 4 unsigned long sizemask; 5 unsigned long used; 6} dictht;
1 typedef struct dictEntry {2 void * key; 3 union {4 void * val; 5 uint64_t u64; 6 int64_t s64; 7} v; 8 struct dictEntry * next; 9} dictEntry;
A dictionary has two hash tables. The link address method is used after conflicts, which is easy to understand.
Some simple operations use macros.
# Define dictGetKey (he)-> key) # define dictGetVal (he)-> v. val) # define dictGetSignedIntegerVal (he)-> v. s64) # define dictGetUnsignedIntegerVal (he)-> v. u64)
------------ June 19 ----------------------
The dictionary uses two hash algorithms. I only read the simple one. I didn't expect that the code could be so small. The algorithm name is djb2,
Unsigned int dictGenCaseHashFunction (const unsigned char * buf, int len) {3 unsigned int hash = (unsigned int) dict_hash_function_seed; (len --) hash; 8}
Dict_hash_function_seed is a global variable, which is 5381.
The magic of number 33 (why it works better than extends other constants, prime or not) has never been adequately explained.
JDK uses the hash algorithm to obtain 31 digits, a prime number.
Create a new dictionary and initialize it:
1 dict * dictCreate (dictType * type, void * privDataPtr) {2 dict * d = malloc (sizeof (* d); 3 _ dictInit (d, type, privDataPtr ); 4 return d; 5} _ dictInit (dict * d, dictType * type, void * privDataPtr) {8_dictReset (& d-> ht [0]); 9_dictReset (& d-> ht [1]); 10 11d-> type = type; 12d-> privdata = privDataPtr; 13d-> rehashidx =-1; 14d-> iterators = 0; DICT_ OK; 17} _ dictReset (dictht * ht) {20ht-> table = NULL; 21ht-> size = 0; 22ht-> sizemask = 0; 23ht-> used = 0; 24}
After learning the C language for so many years, I saw malloc (sizeof (* d) for the first time.
Speaking of sizeof, I would also like to mention that after c99, sizeof is determined at runtime, and c99 also adds the concept of dynamic array. The answer on csdn is wrong.
Compress the dictionary so that the length of the number/hash table in the hash table is close to 1:
1 int dictResize (dict * d) {2int minimal ;(! Dict_can_resize | dictIsRehashing (d) return DICT_ERR; 5 6 minimal = d-> ht [0]. used; (minimal <DICT_HT_INITIAL_SIZE) 9 minimal = DICT_HT_INITIAL_SIZE; dictExpand (d, minimal); 12} dictIsRehashing (ht)-> rehashidx! =-1) 15 # define DICT_HT_INITIAL_SIZE4
When the dictionary is Rehash, the Resize operation cannot be performed. The hash table size is 4 at the beginning, and the hash table size is generally the power of 2.
If minimal is 5, after dictExpand, the hash table size changes to 8.
1 static unsigned long _ dictNextPower (unsigned long size) {2 unsigned long I = DICT_HT_INITIAL_SIZE; (size> = LONG_MAX) return LONG_MAX; 5 while (1) {6if (I> = size) 7 return I; 8i * = 2; 9} 10} dictExpand (dict * d, unsigned long size) {unsigned long realsize = _ dictNextPower (size); the size is invalid if it is smaller than the number of (dictIsRehashing (d) | d-> ht [0]. used> size) 20 return DICT_ERR; n. size = Realsize; 24n. sizemask = realsize-1; 25n. table = zcalloc (realsize * sizeof (dictEntry *); 26n. used = 0; Is this the first initialization? If so it's not really a rehashing (d-> ht [0]. table = NULL) {31d-> ht [0] = n; 32 return DICT_ OK; 33} d-> ht [1] = n; 37d-> rehashidx = 0; DICT_ OK; 40}
A new hash table n is created. The size is the extended size. If the ht [0]. table is empty, this is the first initialization. If it is not an extension, it is assigned a value directly.
Ht [0]. table is not empty. This indicates that this is an extension. n is assigned to ht [1]. The ReHash mark rehashix is also set to 0.
The above section is not very easy to understand. Let's first look at the later section. I will return it later to study the dictExpand function.
-------------------- June 20 --------------------------
To add an element to a dictionary, call the dictAdd function: