]>
git.saurik.com Git - redis.git/blob - src/t_hash.c
   4 /*----------------------------------------------------------------------------- 
   6  *----------------------------------------------------------------------------*/ 
   8 /* Check the length of a number of objects to see if we need to convert a 
   9  * ziplist to a real hash. Note that we only check string encoded objects 
  10  * as their string length can be queried in constant time. */ 
  11 void hashTypeTryConversion(robj 
*o
, robj 
**argv
, int start
, int end
) { 
  14     if (o
->encoding 
!= REDIS_ENCODING_ZIPLIST
) return; 
  16     for (i 
= start
; i 
<= end
; i
++) { 
  17         if (argv
[i
]->encoding 
== REDIS_ENCODING_RAW 
&& 
  18             sdslen(argv
[i
]->ptr
) > server
.hash_max_ziplist_value
) 
  20             hashTypeConvert(o
, REDIS_ENCODING_HT
); 
  26 /* Encode given objects in-place when the hash uses a dict. */ 
  27 void hashTypeTryObjectEncoding(robj 
*subject
, robj 
**o1
, robj 
**o2
) { 
  28     if (subject
->encoding 
== REDIS_ENCODING_HT
) { 
  29         if (o1
) *o1 
= tryObjectEncoding(*o1
); 
  30         if (o2
) *o2 
= tryObjectEncoding(*o2
); 
  34 /* Get the value from a ziplist encoded hash, identified by field. 
  35  * Returns -1 when the field cannot be found. */ 
  36 int hashTypeGetFromZiplist(robj 
*o
, robj 
*field
, 
  41     unsigned char *zl
, *fptr 
= NULL
, *vptr 
= NULL
; 
  44     redisAssert(o
->encoding 
== REDIS_ENCODING_ZIPLIST
); 
  46     field 
= getDecodedObject(field
); 
  49     fptr 
= ziplistIndex(zl
, ZIPLIST_HEAD
); 
  50     while (fptr 
!= NULL
) { 
  51         /* Grab pointer to the value (fptr points to the field) */ 
  52         vptr 
= ziplistNext(zl
, fptr
); 
  53         redisAssert(vptr 
!= NULL
); 
  55         /* Compare field in ziplist with specified field */ 
  56         if (ziplistCompare(fptr
, field
->ptr
, sdslen(field
->ptr
))) { 
  61         fptr 
= ziplistNext(zl
, vptr
); 
  67         ret 
= ziplistGet(vptr
, vstr
, vlen
, vll
); 
  75 /* Get the value from a hash table encoded hash, identified by field. 
  76  * Returns -1 when the field cannot be found. */ 
  77 int hashTypeGetFromHashTable(robj 
*o
, robj 
*field
, robj 
**value
) { 
  80     redisAssert(o
->encoding 
== REDIS_ENCODING_HT
); 
  82     de 
= dictFind(o
->ptr
, field
); 
  87     *value 
= dictGetVal(de
); 
  91 /* Higher level function of hashTypeGet*() that always returns a Redis 
  92  * object (either new or with refcount incremented), so that the caller 
  93  * can retain a reference or call decrRefCount after the usage. 
  95  * The lower level function can prevent copy on write so it is 
  96  * the preferred way of doing read operations. */ 
  97 robj 
*hashTypeGetObject(robj 
*o
, robj 
*field
) { 
 100     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 101         unsigned char *vstr 
= NULL
; 
 102         unsigned int vlen 
= UINT_MAX
; 
 103         long long vll 
= LLONG_MAX
; 
 105         if (hashTypeGetFromZiplist(o
, field
, &vstr
, &vlen
, &vll
) == 0) { 
 107                 value 
= createStringObject((char*)vstr
, vlen
); 
 109                 value 
= createStringObjectFromLongLong(vll
); 
 113     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 116         if (hashTypeGetFromHashTable(o
, field
, &aux
) == 0) { 
 122         redisPanic("Unknown hash encoding"); 
 128 /* Test if the specified field exists in the given hash. Returns 1 if the field 
 129  * exists, and 0 when it doesn't. */ 
 130 int hashTypeExists(robj 
*o
, robj 
*field
) { 
 131     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 132         unsigned char *vstr 
= NULL
; 
 133         unsigned int vlen 
= UINT_MAX
; 
 134         long long vll 
= LLONG_MAX
; 
 136         if (hashTypeGetFromZiplist(o
, field
, &vstr
, &vlen
, &vll
) == 0) { 
 140     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 143         if (hashTypeGetFromHashTable(o
, field
, &aux
) == 0) { 
 148         redisPanic("Unknown hash encoding"); 
 154 /* Add an element, discard the old if the key already exists. 
 155  * Return 0 on insert and 1 on update. */ 
 156 int hashTypeSet(robj 
*o
, robj 
*field
, robj 
*value
) { 
 159     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 160         unsigned char *zl
, *fptr
, *vptr
; 
 162         field 
= getDecodedObject(field
); 
 163         value 
= getDecodedObject(value
); 
 166         fptr 
= ziplistIndex(zl
, ZIPLIST_HEAD
); 
 167         while (fptr 
!= NULL
) { 
 168             /* Compare field in ziplist with specified field */ 
 169             if (ziplistCompare(fptr
, field
->ptr
, sdslen(field
->ptr
))) { 
 170                 zl 
= ziplistDelete(zl
,&fptr
); 
 171                 zl 
= ziplistDelete(zl
,&fptr
); 
 177             /* Grab pointer to the value (fptr points to the field) */ 
 178             vptr 
= ziplistNext(zl
, fptr
); 
 179             redisAssert(vptr 
!= NULL
); 
 181             /* Grab pointer (if any) to the next field */ 
 182             fptr 
= ziplistNext(zl
, vptr
); 
 185         /* Push new field/value pair onto the tail of the ziplist */ 
 186         zl 
= ziplistPush(zl
, field
->ptr
, sdslen(field
->ptr
), ZIPLIST_TAIL
); 
 187         zl 
= ziplistPush(zl
, value
->ptr
, sdslen(value
->ptr
), ZIPLIST_TAIL
); 
 193         /* Check if the ziplist needs to be converted to a hash table */ 
 194         if (hashTypeLength(o
) > server
.hash_max_ziplist_entries
) { 
 195             hashTypeConvert(o
, REDIS_ENCODING_HT
); 
 198     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 199         if (dictReplace(o
->ptr
, field
, value
)) { /* Insert */ 
 201         } else { /* Update */ 
 208         redisPanic("Unknown hash encoding"); 
 214 /* Delete an element from a hash. 
 215  * Return 1 on deleted and 0 on not found. */ 
 216 int hashTypeDelete(robj 
*o
, robj 
*field
) { 
 219     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 220         unsigned char *zl
, *fptr
, *vptr
; 
 222         field 
= getDecodedObject(field
); 
 225         fptr 
= ziplistIndex(zl
, ZIPLIST_HEAD
); 
 226         while (fptr 
!= NULL
) { 
 227             /* Compare field in ziplist with specified field */ 
 228             if (ziplistCompare(fptr
, field
->ptr
, sdslen(field
->ptr
))) { 
 229                 zl 
= ziplistDelete(zl
,&fptr
); 
 230                 zl 
= ziplistDelete(zl
,&fptr
); 
 236             /* Grab pointer to the value (fptr points to the field) */ 
 237             vptr 
= ziplistNext(zl
, fptr
); 
 238             redisAssert(vptr 
!= NULL
); 
 240             /* Grab pointer (if any) to the next field */ 
 241             fptr 
= ziplistNext(zl
, vptr
); 
 246     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 247         if (dictDelete((dict
*)o
->ptr
, field
) == REDIS_OK
) { 
 250             /* Always check if the dictionary needs a resize after a delete. */ 
 251             if (htNeedsResize(o
->ptr
)) dictResize(o
->ptr
); 
 255         redisPanic("Unknown hash encoding"); 
 261 /* Return the number of elements in a hash. */ 
 262 unsigned long hashTypeLength(robj 
*o
) { 
 263     unsigned long length 
= ULONG_MAX
; 
 265     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 266         length 
= ziplistLen(o
->ptr
) / 2; 
 267     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 268         length 
= dictSize((dict
*)o
->ptr
); 
 270         redisPanic("Unknown hash encoding"); 
 276 hashTypeIterator 
*hashTypeInitIterator(robj 
*subject
) { 
 277     hashTypeIterator 
*hi 
= zmalloc(sizeof(hashTypeIterator
)); 
 278     hi
->subject 
= subject
; 
 279     hi
->encoding 
= subject
->encoding
; 
 281     if (hi
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 284     } else if (hi
->encoding 
== REDIS_ENCODING_HT
) { 
 285         hi
->di 
= dictGetIterator(subject
->ptr
); 
 287         redisPanic("Unknown hash encoding"); 
 293 void hashTypeReleaseIterator(hashTypeIterator 
*hi
) { 
 294     if (hi
->encoding 
== REDIS_ENCODING_HT
) { 
 295         dictReleaseIterator(hi
->di
); 
 301 /* Move to the next entry in the hash. Return REDIS_OK when the next entry 
 302  * could be found and REDIS_ERR when the iterator reaches the end. */ 
 303 int hashTypeNext(hashTypeIterator 
*hi
) { 
 304     if (hi
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 306         unsigned char *fptr
, *vptr
; 
 308         zl 
= hi
->subject
->ptr
; 
 313             /* Initialize cursor */ 
 314             redisAssert(vptr 
== NULL
); 
 315             fptr 
= ziplistIndex(zl
, 0); 
 318             redisAssert(vptr 
!= NULL
); 
 319             fptr 
= ziplistNext(zl
, vptr
); 
 326         /* Grab pointer to the value (fptr points to the field) */ 
 327         vptr 
= ziplistNext(zl
, fptr
); 
 328         redisAssert(vptr 
!= NULL
); 
 330         /* fptr, vptr now point to the first or next pair */ 
 334     } else if (hi
->encoding 
== REDIS_ENCODING_HT
) { 
 335         if ((hi
->de 
= dictNext(hi
->di
)) == NULL
) { 
 340         redisPanic("Unknown hash encoding"); 
 346 /* Get the field or value at iterator cursor, for an iterator on a hash value 
 347  * encoded as a ziplist. Prototype is similar to `hashTypeGetFromZiplist`. */ 
 348 void hashTypeCurrentFromZiplist(hashTypeIterator 
*hi
, int what
, 
 349                                 unsigned char **vstr
, 
 355     redisAssert(hi
->encoding 
== REDIS_ENCODING_ZIPLIST
); 
 357     if (what 
& REDIS_HASH_KEY
) { 
 358         ret 
= ziplistGet(hi
->fptr
, vstr
, vlen
, vll
); 
 361         ret 
= ziplistGet(hi
->vptr
, vstr
, vlen
, vll
); 
 366 /* Get the field or value at iterator cursor, for an iterator on a hash value 
 367  * encoded as a ziplist. Prototype is similar to `hashTypeGetFromHashTable`. */ 
 368 void hashTypeCurrentFromHashTable(hashTypeIterator 
*hi
, int what
, robj 
**dst
) { 
 369     redisAssert(hi
->encoding 
== REDIS_ENCODING_HT
); 
 371     if (what 
& REDIS_HASH_KEY
) { 
 372         *dst 
= dictGetKey(hi
->de
); 
 374         *dst 
= dictGetVal(hi
->de
); 
 378 /* A non copy-on-write friendly but higher level version of hashTypeCurrent*() 
 379  * that returns an object with incremented refcount (or a new object). It is up 
 380  * to the caller to decrRefCount() the object if no reference is retained. */ 
 381 robj 
*hashTypeCurrentObject(hashTypeIterator 
*hi
, int what
) { 
 384     if (hi
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 385         unsigned char *vstr 
= NULL
; 
 386         unsigned int vlen 
= UINT_MAX
; 
 387         long long vll 
= LLONG_MAX
; 
 389         hashTypeCurrentFromZiplist(hi
, what
, &vstr
, &vlen
, &vll
); 
 391             dst 
= createStringObject((char*)vstr
, vlen
); 
 393             dst 
= createStringObjectFromLongLong(vll
); 
 396     } else if (hi
->encoding 
== REDIS_ENCODING_HT
) { 
 397         hashTypeCurrentFromHashTable(hi
, what
, &dst
); 
 401         redisPanic("Unknown hash encoding"); 
 407 robj 
*hashTypeLookupWriteOrCreate(redisClient 
*c
, robj 
*key
) { 
 408     robj 
*o 
= lookupKeyWrite(c
->db
,key
); 
 410         o 
= createHashObject(); 
 413         if (o
->type 
!= REDIS_HASH
) { 
 414             addReply(c
,shared
.wrongtypeerr
); 
 421 void hashTypeConvertZiplist(robj 
*o
, int enc
) { 
 422     redisAssert(o
->encoding 
== REDIS_ENCODING_ZIPLIST
); 
 424     if (enc 
== REDIS_ENCODING_ZIPLIST
) { 
 425         /* Nothing to do... */ 
 427     } else if (enc 
== REDIS_ENCODING_HT
) { 
 428         hashTypeIterator 
*hi
; 
 432         hi 
= hashTypeInitIterator(o
); 
 433         dict 
= dictCreate(&hashDictType
, NULL
); 
 435         while (hashTypeNext(hi
) != REDIS_ERR
) { 
 438             field 
= hashTypeCurrentObject(hi
, REDIS_HASH_KEY
); 
 439             field 
= tryObjectEncoding(field
); 
 440             value 
= hashTypeCurrentObject(hi
, REDIS_HASH_VALUE
); 
 441             value 
= tryObjectEncoding(value
); 
 442             ret 
= dictAdd(dict
, field
, value
); 
 443             redisAssert(ret 
== DICT_OK
); 
 446         hashTypeReleaseIterator(hi
); 
 449         o
->encoding 
= REDIS_ENCODING_HT
; 
 453         redisPanic("Unknown hash encoding"); 
 457 void hashTypeConvert(robj 
*o
, int enc
) { 
 458     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 459         hashTypeConvertZiplist(o
, enc
); 
 460     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 461         redisPanic("Not implemented"); 
 463         redisPanic("Unknown hash encoding"); 
 467 /*----------------------------------------------------------------------------- 
 469  *----------------------------------------------------------------------------*/ 
 471 void hsetCommand(redisClient 
*c
) { 
 475     if ((o 
= hashTypeLookupWriteOrCreate(c
,c
->argv
[1])) == NULL
) return; 
 476     hashTypeTryConversion(o
,c
->argv
,2,3); 
 477     hashTypeTryObjectEncoding(o
,&c
->argv
[2], &c
->argv
[3]); 
 478     update 
= hashTypeSet(o
,c
->argv
[2],c
->argv
[3]); 
 479     addReply(c
, update 
? shared
.czero 
: shared
.cone
); 
 480     signalModifiedKey(c
->db
,c
->argv
[1]); 
 484 void hsetnxCommand(redisClient 
*c
) { 
 486     if ((o 
= hashTypeLookupWriteOrCreate(c
,c
->argv
[1])) == NULL
) return; 
 487     hashTypeTryConversion(o
,c
->argv
,2,3); 
 489     if (hashTypeExists(o
, c
->argv
[2])) { 
 490         addReply(c
, shared
.czero
); 
 492         hashTypeTryObjectEncoding(o
,&c
->argv
[2], &c
->argv
[3]); 
 493         hashTypeSet(o
,c
->argv
[2],c
->argv
[3]); 
 494         addReply(c
, shared
.cone
); 
 495         signalModifiedKey(c
->db
,c
->argv
[1]); 
 500 void hmsetCommand(redisClient 
*c
) { 
 504     if ((c
->argc 
% 2) == 1) { 
 505         addReplyError(c
,"wrong number of arguments for HMSET"); 
 509     if ((o 
= hashTypeLookupWriteOrCreate(c
,c
->argv
[1])) == NULL
) return; 
 510     hashTypeTryConversion(o
,c
->argv
,2,c
->argc
-1); 
 511     for (i 
= 2; i 
< c
->argc
; i 
+= 2) { 
 512         hashTypeTryObjectEncoding(o
,&c
->argv
[i
], &c
->argv
[i
+1]); 
 513         hashTypeSet(o
,c
->argv
[i
],c
->argv
[i
+1]); 
 515     addReply(c
, shared
.ok
); 
 516     signalModifiedKey(c
->db
,c
->argv
[1]); 
 520 void hincrbyCommand(redisClient 
*c
) { 
 521     long long value
, incr
; 
 522     robj 
*o
, *current
, *new; 
 524     if (getLongLongFromObjectOrReply(c
,c
->argv
[3],&incr
,NULL
) != REDIS_OK
) return; 
 525     if ((o 
= hashTypeLookupWriteOrCreate(c
,c
->argv
[1])) == NULL
) return; 
 526     if ((current 
= hashTypeGetObject(o
,c
->argv
[2])) != NULL
) { 
 527         if (getLongLongFromObjectOrReply(c
,current
,&value
, 
 528             "hash value is not an integer") != REDIS_OK
) { 
 529             decrRefCount(current
); 
 532         decrRefCount(current
); 
 538     new = createStringObjectFromLongLong(value
); 
 539     hashTypeTryObjectEncoding(o
,&c
->argv
[2],NULL
); 
 540     hashTypeSet(o
,c
->argv
[2],new); 
 542     addReplyLongLong(c
,value
); 
 543     signalModifiedKey(c
->db
,c
->argv
[1]); 
 547 void hincrbyfloatCommand(redisClient 
*c
) { 
 548     double long value
, incr
; 
 549     robj 
*o
, *current
, *new; 
 551     if (getLongDoubleFromObjectOrReply(c
,c
->argv
[3],&incr
,NULL
) != REDIS_OK
) return; 
 552     if ((o 
= hashTypeLookupWriteOrCreate(c
,c
->argv
[1])) == NULL
) return; 
 553     if ((current 
= hashTypeGetObject(o
,c
->argv
[2])) != NULL
) { 
 554         if (getLongDoubleFromObjectOrReply(c
,current
,&value
, 
 555             "hash value is not a valid float") != REDIS_OK
) { 
 556             decrRefCount(current
); 
 559         decrRefCount(current
); 
 565     new = createStringObjectFromLongDouble(value
); 
 566     hashTypeTryObjectEncoding(o
,&c
->argv
[2],NULL
); 
 567     hashTypeSet(o
,c
->argv
[2],new); 
 570     signalModifiedKey(c
->db
,c
->argv
[1]); 
 574 static void addHashFieldToReply(redisClient 
*c
, robj 
*o
, robj 
*field
) { 
 578         addReply(c
, shared
.nullbulk
); 
 582     if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 583         unsigned char *vstr 
= NULL
; 
 584         unsigned int vlen 
= UINT_MAX
; 
 585         long long vll 
= LLONG_MAX
; 
 587         ret 
= hashTypeGetFromZiplist(o
, field
, &vstr
, &vlen
, &vll
); 
 589             addReply(c
, shared
.nullbulk
); 
 592                 addReplyBulkCBuffer(c
, vstr
, vlen
); 
 594                 addReplyBulkLongLong(c
, vll
); 
 598     } else if (o
->encoding 
== REDIS_ENCODING_HT
) { 
 601         ret 
= hashTypeGetFromHashTable(o
, field
, &value
); 
 603             addReply(c
, shared
.nullbulk
); 
 605             addReplyBulk(c
, value
); 
 609         redisPanic("Unknown hash encoding"); 
 613 void hgetCommand(redisClient 
*c
) { 
 616     if ((o 
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL 
|| 
 617         checkType(c
,o
,REDIS_HASH
)) return; 
 619     addHashFieldToReply(c
, o
, c
->argv
[2]); 
 622 void hmgetCommand(redisClient 
*c
) { 
 626     /* Don't abort when the key cannot be found. Non-existing keys are empty 
 627      * hashes, where HMGET should respond with a series of null bulks. */ 
 628     o 
= lookupKeyRead(c
->db
, c
->argv
[1]); 
 629     if (o 
!= NULL 
&& o
->type 
!= REDIS_HASH
) { 
 630         addReply(c
, shared
.wrongtypeerr
); 
 634     addReplyMultiBulkLen(c
, c
->argc
-2); 
 635     for (i 
= 2; i 
< c
->argc
; i
++) { 
 636         addHashFieldToReply(c
, o
, c
->argv
[i
]); 
 640 void hdelCommand(redisClient 
*c
) { 
 644     if ((o 
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL 
|| 
 645         checkType(c
,o
,REDIS_HASH
)) return; 
 647     for (j 
= 2; j 
< c
->argc
; j
++) { 
 648         if (hashTypeDelete(o
,c
->argv
[j
])) { 
 650             if (hashTypeLength(o
) == 0) { 
 651                 dbDelete(c
->db
,c
->argv
[1]); 
 657         signalModifiedKey(c
->db
,c
->argv
[1]); 
 658         server
.dirty 
+= deleted
; 
 660     addReplyLongLong(c
,deleted
); 
 663 void hlenCommand(redisClient 
*c
) { 
 665     if ((o 
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL 
|| 
 666         checkType(c
,o
,REDIS_HASH
)) return; 
 668     addReplyLongLong(c
,hashTypeLength(o
)); 
 671 static void addHashIteratorCursorToReply(redisClient 
*c
, hashTypeIterator 
*hi
, int what
) { 
 672     if (hi
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 673         unsigned char *vstr 
= NULL
; 
 674         unsigned int vlen 
= UINT_MAX
; 
 675         long long vll 
= LLONG_MAX
; 
 677         hashTypeCurrentFromZiplist(hi
, what
, &vstr
, &vlen
, &vll
); 
 679             addReplyBulkCBuffer(c
, vstr
, vlen
); 
 681             addReplyBulkLongLong(c
, vll
); 
 684     } else if (hi
->encoding 
== REDIS_ENCODING_HT
) { 
 687         hashTypeCurrentFromHashTable(hi
, what
, &value
); 
 688         addReplyBulk(c
, value
); 
 691         redisPanic("Unknown hash encoding"); 
 695 void genericHgetallCommand(redisClient 
*c
, int flags
) { 
 697     hashTypeIterator 
*hi
; 
 699     int length
, count 
= 0; 
 701     if ((o 
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.emptymultibulk
)) == NULL
 
 702         || checkType(c
,o
,REDIS_HASH
)) return; 
 704     if (flags 
& REDIS_HASH_KEY
) multiplier
++; 
 705     if (flags 
& REDIS_HASH_VALUE
) multiplier
++; 
 707     length 
= hashTypeLength(o
) * multiplier
; 
 708     addReplyMultiBulkLen(c
, length
); 
 710     hi 
= hashTypeInitIterator(o
); 
 711     while (hashTypeNext(hi
) != REDIS_ERR
) { 
 712         if (flags 
& REDIS_HASH_KEY
) { 
 713             addHashIteratorCursorToReply(c
, hi
, REDIS_HASH_KEY
); 
 716         if (flags 
& REDIS_HASH_VALUE
) { 
 717             addHashIteratorCursorToReply(c
, hi
, REDIS_HASH_VALUE
); 
 722     hashTypeReleaseIterator(hi
); 
 723     redisAssert(count 
== length
); 
 726 void hkeysCommand(redisClient 
*c
) { 
 727     genericHgetallCommand(c
,REDIS_HASH_KEY
); 
 730 void hvalsCommand(redisClient 
*c
) { 
 731     genericHgetallCommand(c
,REDIS_HASH_VALUE
); 
 734 void hgetallCommand(redisClient 
*c
) { 
 735     genericHgetallCommand(c
,REDIS_HASH_KEY
|REDIS_HASH_VALUE
); 
 738 void hexistsCommand(redisClient 
*c
) { 
 740     if ((o 
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL 
|| 
 741         checkType(c
,o
,REDIS_HASH
)) return; 
 743     addReply(c
, hashTypeExists(o
,c
->argv
[2]) ? shared
.cone 
: shared
.czero
);