Redis Hash Key command Implementation (T_hash)
1. Hash command Introduction
All Redis hash commands are shown in the following table: Redis hash command in detail
Serial Number |
Command and Description |
1 |
Hdel key Field2 [field2]: Delete one or more hash table fields |
2 |
Hexists key field: View Hash table key, whether the specified field exists. |
3 |
Hget key field: Gets the value that is stored in the specified field in the hash table. |
4 |
Hgetall key: Gets all fields and values that specify key in the hash table |
5 |
Hincrby key field Increment: Adds an incremental increment to the integer value of the specified field in the hash table key. |
6 |
Hincrbyfloat key field Increment: Adds an incremental increment to the floating point value of the specified field in the hash table key. |
7 |
Hkeys key: Gets all the fields in the hash table |
8 |
Hlen key: Gets the number of fields in the hash table |
9 |
Hmget key field1 [Field2]: Gets the values of all given fields |
10 |
Hmset key field1 value1 [Field2 value2]: Set multiple field-value (domain-value) pairs to the hash table key at the same time. |
11 |
Hset key field value: Sets the values of field fields in the hash table key to value. |
12 |
Hsetnx key field value: Sets the values of the hash table field only if the fields field does not exist. |
13 |
Hvals key: Gets all the values in the hash table |
14 |
HSCAN key cursor [MATCH pattern][count COUNT]: The key-value pair in the Iteration hash table. |
2. Implementation of the hash type
Previously mentioned in the source anatomy and annotations of the Redis object system, there are two encodings for an object of a hash type, namely Obj_encoding_ziplist and OBJ_ENCODING_HT.
Redis Compression list source code profiling and annotations
REDIS dictionary structure source code anatomy and annotations
Code-encoding |
Object-ptr |
Obj_encoding_ziplist |
A hash object that compresses the list implementation |
Obj_encoding_ht |
Dictionary-Implemented hash object |
However, the default created hash type of an object encoded as Obj_encoding_ziplist,obj_encoding_ht type encoding is obtained by the conversion after the configured threshold condition is reached.
The threshold conditions are:
/* Thresholds in redis.conf file */
Hash-max-ziplist-value max//ziplist maximum stored value length
hash-max-ziplist-entries 512// The maximum number of entry nodes that can be stored in the Ziplist
The structure of a hash object is defined as follows:
typedef struct REDISOBJECT
The data type of the {//object, the string object should be Obj_hash
unsigned type:4;
The encoding type of the object, respectively obj_encoding_ziplist or obj_encoding_ht
unsigned encoding:4;
Do not care about this member
unsigned lru:lru_bits; * * LRU time (relative to Server.lruclock) *
//reference count
int refcount;
Pointer to the underlying data implementation, pointing to a dict dictionary structure
void *ptr;
} robj;
For example, we create a user:info hash key, which has three fields, namely name,sex,passwd.
127.0.0.1:6379> hmset user:info name Mike sex male passwd 123456
OK
127.0.0.1:6379> hgetall user:info< c13/>1) "Name"
2) "Mike"
3) "Sex"
4) "Male"
5) "passwd"
6) "123456"
Let's take this as an example to see the spatial structure of a Redis hash object.
Depending on the size of the information, Redis should create a hash object encoded as obj_encoding_ziplist for it. As shown in the following illustration:
The entry node in the compressed list, 22 to form a key-value pair.
If the hash object stores a key-value pair or the length of the ziplist exceeds the configured limit, it is converted to a dictionary structure, which is listed above, and in order to illustrate the hash object encoded as OBJ_ENCODING_HT type, we still use the above User:info object to represent a hash object of a dictionary structure, and a key-value pair in a hash object is a string-type object. The following figure:
Like the list data type, the hash data type is encapsulated based on ziplist and hash table and implements the interface for the hash data type:
/* Hash Data type *///Convert the encoding type of a hash object, enc specify the new encoding type void Hashtypeconvert (robj *o, int enc);
Check the length of a number object to determine if a type conversion is required, from ziplist to HT type void Hashtypetryconversion (RobJ *subject, robj **argv, int start, int end);
Attempts to optimize encoding of key and value objects to conserve memory void hashtypetryobjectencoding (RobJ *subject, RobJ **o1, RobJ **o2);
Returns a field value object from a hash object RobJ *hashtypegetobject (RobJ *o, RobJ *key);
Determine if the Field object exists in the O object int hashtypeexists (RobJ *o, RobJ *key);
Add Field-value to the hash object, return 1 if field exists update new value, return 0 int hashtypeset (robj *o, RobJ *key, RobJ *value);
Delete field from a hash object, successfully returned 1, no field returned 0 int hashtypedelete (robj *o, RobJ *key);
Returns the number of key-value pairs in a hash object unsigned long hashtypelength (RobJ *o);
Returns an iterator of the initialized hash type hashtypeiterator *hashtypeinititerator (RobJ *subject);
Frees the hash type iterator space void Hashtypereleaseiterator (Hashtypeiterator *hi);
Tells the hash type iterator to the next node in the hash object int Hashtypenext (Hashtypeiterator *hi); Gets the corresponding field or value from the hash type iterator of the ziplist type, saved in the parameter void Hashtypecurrentfromziplist (hashtypeiterator *hi, int what, unsigned char **vSTR, unsigned int *vlen, long long *vll); Gets the corresponding field or value from the hash type iterator of the ziplist type, saved in the parameter void hashtypecurrentfromhashtable (hashtypeiterator *hi, int what, RobJ *
*DST);
Gets the key or value from an iterator of the hash type RobJ *hashtypecurrentobject (hashtypeiterator *hi, int);
Writes a hash object in the database for the corresponding key, and creates a robj *hashtypelookupwriteorcreate (client *c, RobJ *key) If it does not exist;
Comments on these function interfaces are on GitHub view: Hash type function Interface Comment 3. A hash type iterator
Like the list type, the hash data type implements its own iterator, which is also encapsulated by an iterator based on the ziplist and dictionary structure.
typedef struct {
robj *subject; The hash object that the hash type iterator belongs to
int encoding; The encoding type of the hash object
//encoded with ziplist
unsigned char *fptr, *vptr;//point to the address of the current key and value node, ziplist type encoding when used
//For dictionary encoding
dictiterator *di; A dictionary iterator dictentry *de when iterating over a hash object of the HT type
; Points to the current hash table node
} hashtypeiterator;
#define OBJ_HASH_KEY 1 //hashing
key #define OBJ_HASH_VALUE 2 //Hash
Create an iterator
An iterator that returns an initialized hash type
hashtypeiterator *hashtypeinititerator (robj *subject) {
//Allocate space initialization member
Hashtypeiterator *hi = zmalloc (sizeof (Hashtypeiterator));
Hi->subject = subject;
hi->encoding = subject->encoding;
Set different members according to different encodings
if (hi->encoding = = obj_encoding_ziplist) {
hi->fptr = NULL;
Hi->vptr = NULL;
} else if (hi->encoding = = obj_encoding_ht) {
//Initializes a dictionary iterator back to the di member
Hi->di = Dictgetiterator (subject-> PTR);
} else {
serverpanic ("Unknown hash Encoding");
}
return hi;
}
Release iterator
Frees the hash type iterator space
void Hashtypereleaseiterator (Hashtypeiterator *hi) {
///If it is a dictionary, you need to release the space if of the dictionary iterator first
(hi- >encoding = = obj_encoding_ht) {
dictreleaseiterator (hi->di);
}
Zfree (HI);
}
Iteration
/* Move to the next entry in the hash. Return C_OK when the next entry * could is found and c_err when the iterator reaches the end. *///Talk hash type iterator points to the next node in the hash object int Hashtypenext (Hashtypeiterator *hi) {//Iteration ziplist if (hi->encoding = = Obj_encodi
ng_ziplist) {unsigned char *zl;
unsigned char *fptr, *vptr;
Member information for the backup iterator ZL = hi->subject->ptr;
Fptr = hi->fptr;
Vptr = hi->vptr; field pointer is null, point to first entry, initialize pointer if (fptr = = NULL) {/* Initialize cursor */serve on first execution
Rassert (vptr = = NULL);
Fptr = Ziplistindex (Zl, 0); } else {/* Advance cursor *///Gets the next entry address of the value node, which is the address of the next field Serverassert (vptr
! = NULL);
Fptr = Ziplistnext (Zl, Vptr);
}//Iteration Complete or return c_err if (fptr = = NULL) return c_err;
/* Grab pointer to the value (fptr points to the field) *//Save the address of the next valueVptr = Ziplistnext (Zl, Fptr);
Serverassert (vptr! = NULL);
/* fptr, Vptr now point to the first or next pair *///Update iterator member information hi->fptr = FPTR;
Hi->vptr = vptr; If it is an iterative dictionary} else if (hi->encoding = = obj_encoding_ht) {//Gets the address of the next dictionary node if (hi->de = Dictnext (
HI->DI)) = = NULL) return c_err;
} else {serverpanic ("Unknown hash Encoding");
} return C_OK; }
4. Implementation of the hash command
The hash type command is easy to understand, and the hash type command does not have a blocking version.
For all comments, see: Comment on Hash type command Hgetall implementation of a class of commands
Hkeys, Hvals, Hgetall
void Generichgetallcommand (client *c, int flags) {RobJ *o;
Hashtypeiterator *hi;
int multiplier = 0;
int length, count = 0; The hash object is fetched with a write operation, if it fails, or if the object being fetched is not an object of the hash type, then 0 is returned directly if (o = lookupkeyreadorreply (c,c->argv[1],shared.emptymultibulk)) = = NULL | |
Checktype (C,o,obj_hash)) return;
Calculates the number of pairs of key values to return if (Flags & Obj_hash_key) multiplier++;
if (Flags & Obj_hash_value) multiplier++;
Computes the number of all key-value pairs to be returned in the entire hash object length = Hashtypelength (o) * multiplier; Addreplymultibulklen (c, length);
Send the number of get to the client//create a hash type iterator and initialize hi = Hashtypeinititerator (o);
Iterate over all entry nodes while (Hashtypenext (HI)! = c_err) {//If hash key if (Flags & Obj_hash_key) {
Saves the key that the current iterator points to addhashiteratorcursortoreply (c, Hi, Obj_hash_key); count++; Update counter}//If hash value if (Flags & Obj_hash_value) {//Save the value pointed to by the current iterator Addha ShiteratorcursOrtoreply (c, Hi, Obj_hash_value); count++;
Update Counter}}/Release iterator Hashtypereleaseiterator (HI);
Serverassert (count = = length); }
Hstrlen Command Implementation
The newly added Redis 3.2 version
void Hstrlencommand (client *c) {
robj *o;
The hash object is fetched with a write operation, if it fails, or if the object being fetched is not an object of the hash type, the
if ((o = lookupkeyreadorreply (c,c->argv[1],shared.czero)) = = NULL is returned immediately after sending 0 ||
Checktype (C,o,obj_hash)) return;
Send the length of the value of the Field object to client
Addreplylonglong (C,hashtypegetvaluelength (o,c->argv[2]));
}
Hdel Command Implementation
void Hdelcommand (client *c) {RobJ *o;
Int J, deleted = 0, keyremoved = 0;
The hash object is fetched as a write, if it fails, or if the object being fetched is not an object of the hash type, then 0 is returned directly if (o = lookupkeywriteorreply (c,c->argv[1],shared.czero)) = = NULL | |
Checktype (C,o,obj_hash)) return; Traverse all Fields field for (j = 2; J < c->argc; J + +) {//Remove the current field from the hash object if (Hashtypedelete (o,c->argv[ J])) {deleted++; Number of update deletions//If the hash object is empty, delete the object if (Hashtypelength (o) = = 0) {dbdelete (C->DB,C-&G
T;ARGV[1]); keyremoved = 1;
Set Delete flag break; }}}//Just delete the field if (deleted) {//Send signal indicates the key is changed Signalmodifiedkey (c->db,c->argv[1
]);
Send "Hdel" event notification notifykeyspaceevent (Notify_hash, "Hdel", c->argv[1],c->db->id); If the hash object is deleted if (keyremoved)//Send "Hdel" event notification notifykeyspaceevent (Notify_generic, "Del", C-&G
T;ARGV[1], C->DB->ID); Server.dirty + = deleted; Update Dirty Key} addreplylonglong (c,deleted);
Send the number of deletes to client}
Implementation of the Hincrbyfloat command
void Hincrbyfloatcommand (client *c) {Double Long value, incr;
RobJ *o, *current, *new, *aux;
Gets a long double type of increment increment if (getlongdoublefromobjectorreply (c,c->argv[3],&incr,null)! = C_OK) return;
Writes out the hash object, and fails to return directly if ((o = Hashtypelookupwriteorcreate (c,c->argv[1]) = = NULL) return; Returns field value object in hash object o if (current = Hashtypegetobject (o,c->argv[2])! = NULL) {//Gets a long double from the value object Value, if not a floating-point value, sends a "hash value is not a valid float" message to the client if (getlongdoublefromobjectorreply (C,current,&va Lue, "hash value is not a valid float")! = C_OK) {decrrefcount (current);
The value succeeds, releasing the temporary value object space and returning the return directly; } decrrefcount (current); Value failed also free space} else {value = 0; If no value is set to the default of 0} value + = INCR;
Back up the original value//convert value to a string type object new = Createstringobjectfromlongdouble (value,1); Optimizes the encoding of key and value objects to save space by embstr or raw or integer storage HashtypetRyobjectencoding (O,&c->argv[2],null);
Set the original key to the new value object Hashtypeset (o,c->argv[2],new);
Speak new value object sent to client Addreplybulk (c,new);
Modify the database key to send a signal, send "hincrbyfloat" event notification, update dirty key Signalmodifiedkey (c->db,c->argv[1]);
Notifykeyspaceevent (Notify_hash, "Hincrbyfloat", c->argv[1],c->db->id);
server.dirty++; /* Always replicate hincrbyfloat as a hset command with the final value * in order to make sure this differences in float pricision or formatting * would not be create differences in replicas or after an AOF restart.
/////////Use Hset command instead of hincrbyfloat to prevent errors caused by different floating-point accuracy//create Hset string Object aux = Createstringobject ("Hset", 4);
Modify the Hincrbyfloat command to Hset object Rewriteclientcommandargument (C,0,aux);
Free space Decrrefcount (aux);
Modify the increment to a new value object, Rewriteclientcommandargument (c,3,new);
Free space Decrrefcount (new); }
HSCAN Command Implementation
HSCAN key cursor [MATCH pattern] [count count]
//HSCAN command implements
void Hscancommand (client *c) {
robj *o;
unsigned long cursor;
Gets the cursor of the Scan command, cursor
if (parsescancursororreply (c,c->argv[2],&cursor) = = C_err) return;
The hash object is fetched with a write operation, if it fails, or if the object being fetched is not an object of the hash type, then 0 is returned directly
if (o = lookupkeyreadorreply (c,c->argv[1],shared.emptyscan)) = = NULL | |
Checktype (C,o,obj_hash)) return;
Call the underlying implementation
Scangenericcommand (c,o,cursor);
}