Implementation of redis hset hget dictionary

operation command

  • If the hset key does not exist, execute the creation operation, and if it exists, execute the update operation
  • Execute the command only if the hsetnx key does not exist
  • hget Gets the value on the field
  • How much data is added to HINCRBY, when the value can be interpreted as a number
  • HINCRBYFLOAT increments floating point numbers
  • Hstrlen counts the length of the value of filed
  • Does the hexists key exist in this field
  • hdel Delete the field, if you want to delete the key, use del to delete the key
  • hlen counts the number of filed in the key
  • hmset set multiple filed for a key
  • hkeys Get all the filed values ​​​​of the key
  • hvals gets the value of the field
  • hgetall field and value are obtained together

some principle knowledge

redis:6.2.1
dict位置: src/dict.h srcdict.c src/t_hash.c

The dictionary adopts the method of progressive rehash, and the hash algorithm adopts the murmurHashX algorithm (X represents the version number). Hash factor = used / size.

When to expand?

  • When the redis server does not start the BGSAVE or BGWRITEAOF command and the hash factor is >=1
  • Open the above command, hash factor>=5

Because these two commands will start the child process, and copy-on-write will take up a lot of memory, this is also a detailed optimization

progressive hashing

When checking and adding, it will be judged whether it is in rehash. If it is, it will be slightly moved from the old hash table to the new hash table. The linked list behind the index is moved to the new hash table. Find the index and give 10 opportunities. If all 10 opportunities are used up and a suitable opportunity is not found, it will return.
insert image description here

source code

This part of the source code is okay and can be understood. Let me introduce these struct member variables, which can be found in src/dich.h

dict is a dictionary, and type can be understood as a callback function. privdata is not used for the time being, dicttht is two hash tables. When rehashidx is not equal to 1, it means that in progressive rehash, rehashidx means the subscript hashed there in the first hash table. pauserehash looks at the name guess to determine whether the progressive hashing is terminated.

typedef struct dict {
    
    
    dictType *type;// 设置哈希函数的
    void *privdata;
    dictht ht[2];// 两块哈希表
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
} dict;

The dictht table is for storing key-value, size is for opening up capacity, and sizemash = size - 1 is used for calculation of hash value. How many elements used contains, including the elements owned by the open chain method

typedef struct dictht {
    
    
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

dictType stores the series of function pointers

typedef struct dictType {
    
    
    uint64_t (*hashFunction)(const void *key);// 获得hash值
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
    int (*expandAllowed)(size_t moreMem, double usedRatio);// 扩容
} dictType;

In the t_hash.c file, we can see the use of hset and hget that we often use. void hsetCommand(client *c), temporary ability is limited, and you can roughly understand the source code when you first touch it. Because I was curious about how the field of hset is stored at the beginning, today I finally know that
the key is still stored in the hash table, and val is still a hash table, val->key is the field field, and val->val is Stored val.

Guess you like

Origin blog.csdn.net/dxgzg/article/details/121715183