加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Redis系列(十):数据结构Hash之HDEL、HEXISTS、HGETALL、HKEYS

发布时间:2020-12-16 04:38:02 所属栏目:安全 来源:网络整理
导读:1.HDEL 从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。 如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回0。 时间复杂度:O(N)?N是被删除的字段数量 127.0 . 0.1 : 6379 hset myhash field1 " foo " (integer)

1.HDEL

从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。

如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回0。

时间复杂度:O(N)?N是被删除的字段数量

127.0.0.1:6379> hset myhash field1 "foo"
(integer) 1
6379> hdel myhash field1
(integer) 6379>

源码解析

// t_hash.c,
void hdelCommand(client *c) {
    robj *o;
    int j,deleted = 0,keyremoved = 0;

    if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
        checkType(c,o,OBJ_HASH)) return;
     循环删除给定字段列表
    for (j = 2; j < c->argc; j++) {
        if (hashTypeDelete(o,c->argv[j]->ptr)) {
            deleted++;
             当没有任何元素后,直接将key删除
            if (hashTypeLength(o) == ) {
                dbDelete(c->db,1)">1]);
                keyremoved = ;
                break;
            }
        }
    }
    if (deleted) {
        signalModifiedKey(c->db,1)">]);
        notifyKeyspaceEvent(NOTIFY_HASH,hdel",c->db->id);
         (keyremoved)
            notifyKeyspaceEvent(NOTIFY_GENERIC,1)">del],c->db->id);
        server.dirty += deleted;
    }
    addReplyLongLong(c,deleted);
}
 具体删除 field,同样区分编码类型,不同处理逻辑
/* Delete an element from a hash.
 * Return 1 on deleted and 0 on not found. */
int hashTypeDelete(robj *o,sds field) {
    int deleted = if (o->encoding == OBJ_ENCODING_ZIPLIST) {
        unsigned char *zl,*fptr;

        zl = o->ptr;
        fptr = ziplistIndex(zl,ZIPLIST_HEAD);
        if (fptr != NULL) {
             ziplist 删除,依次删除 field,value
            fptr = ziplistFind(fptr,(unsigned char*)field,sdslen(field),);
             NULL) {
                 ziplistDelete 为原地删除,所以只要调用2次,即把kv删除
                zl = ziplistDelete(zl,&fptr);
                zl = ziplistDelete(zl,1)">fptr);
                o->ptr = zl;
                deleted = ;
            }
        }
    } else  OBJ_ENCODING_HT) {
        if (dictDelete((dict*)o->ptr,field) == C_OK) {
            deleted = ;

            /* Always check if the dictionary needs a resize after a delete. */
             hash 删除的,可能需要进行缩容操作,这种处理方法相对特殊些
            if (htNeedsResize(o->ptr)) dictResize(o->ptr);
        }

    } else {
        serverPanic(Unknown hash encoding);
    }
     deleted;
}
 server.c,是否需要进行 resize
int htNeedsResize(dict *dict) {
    long long size,used;

    size = dictSlots(dict);
    used = dictSize(dict);
     HASHTABLE_MIN_FILL=10,即使用率小于 1/10 时,可以进行缩容操作了
    return (size && used && size > DICT_HT_INITIAL_SIZE &&
            (used*100/size < HASHTABLE_MIN_FILL));
}

2.HEXISTS

返回hash里面field是否存在

时间复杂度:O(1)

 hexists myhash field1
(integer)  hexists myhash field2
(integer) 0
void hexistsCommand(client *if ((o = lookupKeyReadOrReply(c,1)">;

    addReply(c,hashTypeExists(o,c->argv[2]->ptr) ? shared.cone : shared.czero);
}
hashTypeExists
int hashTypeExists(robj *char *vstr = NULL;
        unsigned int vlen = UINT_MAX;
        long vll = LLONG_MAX;

        if (hashTypeGetFromZiplist(o,field,&vstr,&vlen,&vll) == 0) return ;
    } if (hashTypeGetFromHashTable(o,field) != NULL) ;
}

ziplist的类型判断

 Get the value from a ziplist encoded hash,identified by field.
 * Returns -1 when the field cannot be found. int hashTypeGetFromZiplist(robj *char **vstr,1)">int *vlen,long *vll)
{
    unsigned  NULL;
    int ret;

    serverAssert(o->encoding == OBJ_ENCODING_ZIPLIST);

    zl = o->ptr;
    fptr = NULL) {
        fptr = ziplistFind(fptr,1)">);
         Grab pointer to the value (fptr points to the field) */
            vptr = ziplistNext(zl,fptr);
            serverAssert(vptr != NULL);
        }
    }

    if (vptr != NULL) {
        ret = ziplistGet(vptr,vstr,vlen,vll);
        serverAssert(ret);
        ;
    }

    return -ziplistFind

 Find pointer to the entry equal to the specified entry. Skip 'skip' entries
 * between every comparison. Returns NULL when the field could not be found. 
unsigned char *ziplistFind(unsigned char *p,unsigned char *vstr,1)">int vlen,1)"> skip) {
    int skipcnt = ;
    unsigned char vencoding = long vll = while (p[0] != ZIP_END) {
        unsigned  prevlensize,encoding,lensize,len;
        unsigned char *q;

        ZIP_DECODE_PREVLENSIZE(p,prevlensize);
        ZIP_DECODE_LENGTH(p + lensize;

        if (skipcnt == ) {
             Compare current entry with specified entry  (ZIP_IS_STR(encoding)) {
                if (len == vlen && memcmp(q,vlen) == ) {
                     p;
                }
            }  {
                 Find out if the searched field can be encoded. Note that
                 * we do it only the first time,once done vencoding is set
                 * to non-zero and vll is set to the integer value. */
                if (vencoding == if (!zipTryEncoding(vstr,&vll,1)">vencoding)) {
                         If the entry can't be encoded we set it to
                         * UCHAR_MAX so that we don't retry again the next
                         * time. 
                        vencoding = UCHAR_MAX;
                    }
                     Must be non-zero by now 
                    assert(vencoding);
                }

                 Compare current entry with specified entry,do it only
                 * if vencoding != UCHAR_MAX because if there is no encoding
                 * possible for the field it can't be a valid integer. if (vencoding != UCHAR_MAX) {
                    long ll = zipLoadInteger(q,encoding);
                    if (ll == vll) {
                         p;
                    }
                }
            }

             Reset skip count 
            skipcnt = skip;
        }  {
             Skip entry 
            skipcnt--;
        }

         Move to next entry 
        p = q + len;
    }

     NULL;
}

hashtable类型的

 Get the value from a hash table encoded hash,identified by field.
 * Returns NULL when the field cannot be found,otherwise the SDS value
 * is returned. 
sds hashTypeGetFromHashTable(robj *de;

    serverAssert(o->encoding == OBJ_ENCODING_HT);

    de = dictFind(o->ptr,field);
    if (de == NULL)  dictGetVal(de);
}

dictFInd

dictEntry *dictFind(dict *d,const void *key)
{
    dictEntry *he;
    uint64_t h,idx,table;

    if (dictSize(d) == return NULL;  dict is empty */
     (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d,key);
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;
        he = d->ht[table].table[idx];
        while(he) {
            if (key==he->key || dictCompareKeys(d,key,he->key))
                 he;
            he = he->next;
        }
        if (!dictIsRehashing(d))  NULL;
    }
     NULL;
}

3.HGETALL、HKEYS、HVALS

HGetAll:返回 key 指定的哈希集中所有的字段和值。返回值中,每个字段名的下一个是它的值,所以返回值的长度是哈希集大小的两倍

时间复杂度:O(N)

HKeys:返回 key 指定的哈希集中所有字段的名字。

HVals:返回 key 指定的哈希集中所有字段的值。

时间复杂度:O(N)

Hello6379> hset myhash field2 World hkeys myhash
1) field1"
2) field2 hgetall myhash
3) 4)  hvals myhash
void hkeysCommand(client *c) {
    genericHgetallCommand(c,OBJ_HASH_KEY);
}

void hvalsCommand(client *void hgetallCommand(client *OBJ_HASH_VALUE);
}

?

void genericHgetallCommand(client *c,1)"> flags) {
    robj *o;
    hashTypeIterator *hi;
    int length,count = resp]))
        == NULL || checkType(c,OBJ_HASH))  We return a map if the user requested keys and values,like in the
     * HGETALL case. Otherwise to use a flat array makes more sense. 
    length = hashTypeLength(o);
    if (flags & OBJ_HASH_KEY && flags & OBJ_HASH_VALUE) {
        addReplyMapLen(c,length);
    }  {
        addReplyArrayLen(c,length);
    }

    hi = hashTypeInitIterator(o);
    while (hashTypeNext(hi) != C_ERR) {
        if (flags & OBJ_HASH_KEY) {
            addHashIteratorCursorToReply(c,hi,OBJ_HASH_KEY);
            count++;
        }
         OBJ_HASH_VALUE) {
            addHashIteratorCursorToReply(c,OBJ_HASH_VALUE);
            count++;
        }
    }

    hashTypeReleaseIterator(hi);

     Make sure we returned the right number of elements. if (flags & OBJ_HASH_KEY && flags & OBJ_HASH_VALUE) count /= 2;
    serverAssert(count == length);
}

4.HLEN

返回?key?指定的哈希集包含的字段的数量。

hlen myhash (integer) 2 6379>

void hlenCommand(client *o;

    ;

    addReplyLongLong(c,hashTypeLength(o));
}

?

 Return the number of elements in a hash. long hashTypeLength(const robj *o) {
    unsigned long length = ULONG_MAX;

     OBJ_ENCODING_ZIPLIST) {
        length = ziplistLen(o->ptr) /  OBJ_ENCODING_HT) {
        length = dictSize((const dict*)o->ptr);
    }  length;
}

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读