仔细看了一下,这里的hashTypeSet函数的实现挺巧妙,该函数被频繁调用多次,挺重要:
- #define HASH_SET_TAKE_FIELD (1<<0)
- #define HASH_SET_TAKE_VALUE (1<<1)
- #define HASH_SET_COPY 0
- int hashTypeSet(robj *o, sds field, sds value, int flags) {
- int update = 0;
-
- if (o->encoding == OBJ_ENCODING_ZIPLIST) {
- unsigned char *zl, *fptr, *vptr;
-
- zl = o->ptr;
- fptr = ziplistIndex(zl, ZIPLIST_HEAD);
- if (fptr != NULL) {
- fptr = ziplistFind(zl, fptr, (unsigned char*)field, sdslen(field), 1);
- if (fptr != NULL) {
- /* Grab pointer to the value (fptr points to the field) */
- vptr = ziplistNext(zl, fptr);
- serverAssert(vptr != NULL);
- update = 1;
-
- /* Replace value */
- zl = ziplistReplace(zl, vptr, (unsigned char*)value,
- sdslen(value));
- }
- }
-
- if (!update) {
- /* Push new field/value pair onto the tail of the ziplist */
- zl = ziplistPush(zl, (unsigned char*)field, sdslen(field),
- ZIPLIST_TAIL);
- zl = ziplistPush(zl, (unsigned char*)value, sdslen(value),
- ZIPLIST_TAIL);
- }
- o->ptr = zl;
-
- /* Check if the ziplist needs to be converted to a hash table */
- if (hashTypeLength(o) > server.hash_max_ziplist_entries)
- hashTypeConvert(o, OBJ_ENCODING_HT);
- } else if (o->encoding == OBJ_ENCODING_HT) {
- dictEntry *de = dictFind(o->ptr,field);
- if (de) {
- sdsfree(dictGetVal(de));
- if (flags & HASH_SET_TAKE_VALUE) {
- dictGetVal(de) = value;
- value = NULL;
- } else {
- dictGetVal(de) = sdsdup(value);
- }
- update = 1;
- } else {
- sds f,v;
- if (flags & HASH_SET_TAKE_FIELD) {
- f = field;
- field = NULL;
- } else {
- f = sdsdup(field);
- }
- if (flags & HASH_SET_TAKE_VALUE) {
- v = value;
- value = NULL;
- } else {
- v = sdsdup(value);
- }
- dictAdd(o->ptr,f,v);
- }
- } else {
- serverPanic("Unknown hash encoding");
- }
-
- /* Free SDS strings we did not referenced elsewhere if the flags
- * want this function to be responsible. */
- if (flags & HASH_SET_TAKE_FIELD && field) sdsfree(field);
- if (flags & HASH_SET_TAKE_VALUE && value) sdsfree(value);
- return update;
- }
-
- /* Delete an element from a hash.
- * Return 1 on deleted and 0 on not found. */
- int hashTypeDelete(robj *o, sds field) {
- int deleted = 0;
-
- if (o->encoding == OBJ_ENCODING_ZIPLIST) {
- unsigned char *zl, *fptr;
-
- zl = o->ptr;
- fptr = ziplistIndex(zl, ZIPLIST_HEAD);
- if (fptr != NULL) {
- fptr = ziplistFind(zl, fptr, (unsigned char*)field, sdslen(field), 1);
- if (fptr != NULL) {
- zl = ziplistDelete(zl,&fptr); /* Delete the key. */
- zl = ziplistDelete(zl,&fptr); /* Delete the value. */
- o->ptr = zl;
- deleted = 1;
- }
- }
- } else if (o->encoding == OBJ_ENCODING_HT) {
- if (dictDelete((dict*)o->ptr, field) == C_OK) {
- deleted = 1;
-
- /* Always check if the dictionary needs a resize after a delete. */
- if (htNeedsResize(o->ptr)) dictResize(o->ptr);
- }
-
- } else {
- serverPanic("Unknown hash encoding");
- }
- return deleted;
- }