`

redis之哈希命令源码解析

阅读更多

形象化设计模式实战             HELLO!架构                     redis命令源码解析

 

前面讲过了字典和压缩列表的实现,redis的哈希数据就是存储在这两种结构之中的,如果对这两种结构都非常清楚了,那么对哈希命令的实现的理解将会非常简单。

 

一、hset

void hsetCommand(redisClient *c) {
    int update;
    robj *o;

    // 取出或新创建哈希对象
    if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;

    // 如果需要的话,转换哈希对象的编码
    hashTypeTryConversion(o,c->argv,2,3);

    // 编码 field 和 value 对象以节约空间
    hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);

    // 设置 field 和 value 到 hash
    update = hashTypeSet(o,c->argv[2],c->argv[3]);

    // 返回状态:显示 field-value 对是新添加还是更新
    addReply(c, update ? shared.czero : shared.cone);

    // 发送键修改信号
    signalModifiedKey(c->db,c->argv[1]);

    // 发送事件通知
    notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hset",c->argv[1],c->db->id);

    // 将服务器设为脏
    server.dirty++;
}
这里深入hashTypeTryConversion函数看下是如何进行转换的:
void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
    int i;

    // 如果对象不是 ziplist 编码,那么直接返回
    if (o->encoding != REDIS_ENCODING_ZIPLIST) return;

    // 检查所有输入对象,看它们的字符串值是否超过了指定长度
    for (i = start; i <= end; i++) {
        if (sdsEncodedObject(argv[i]) &&
            sdslen(argv[i]->ptr) > server.hash_max_ziplist_value)
        {
            // 将对象的编码转换成 REDIS_ENCODING_HT
            hashTypeConvert(o, REDIS_ENCODING_HT);
            break;
        }
    }
}
可以看到如果哈希表中的某个键或值大于server.hash_max_ziplist_value,就会被转换为REDIS_ENCODING_HT(字典)类型。
 
再深入hashTypeSet函数中,会发现这么一段代码:
if (hashTypeLength(o) > server.hash_max_ziplist_entries)
            hashTypeConvert(o, REDIS_ENCODING_HT);
可以看出如果压缩列表中的节点数大于server.hash_max_ziplist_entries,也将会被转换为REDIS_ENCODING_HT(字典)类型。
 
 
由上可见:server.hash_max_ziplist_value和server.hash_max_ziplist_entries是影响哈希表选择何种数据结构的重要参数
 
 
 

二、hash_max_ziplist_value与hash_max_ziplist_entries

在redis.conf中,我们可以找到这两参数的定义:
 
大致是说对于数量少的数据来说,使用ziplist的结构全更加节省内存。
我们可以根据自己的需要修改这两参数,但是切勿认为ziplist节省内存就将这两参数修改过大。
 
 

三、hdel命令,转换回REDIS_ENCODING_ZIPLIST?

上面说压缩节点过多就会转换为字典,那么如果hdel命令将节点减少了,会不会又转换回压缩列表呢?
 
int hashTypeDelete(robj *o, robj *field) {
    int deleted = 0;

    // 从 ziplist 中删除
    if (o->encoding == REDIS_ENCODING_ZIPLIST) {
        unsigned char *zl, *fptr;

        field = getDecodedObject(field);

        zl = o->ptr;
        fptr = ziplistIndex(zl, ZIPLIST_HEAD);
        if (fptr != NULL) {
            // 定位到域
            fptr = ziplistFind(fptr, field->ptr, sdslen(field->ptr), 1);
            if (fptr != NULL) {
                // 删除域和值
                zl = ziplistDelete(zl,&fptr);
                zl = ziplistDelete(zl,&fptr);
                o->ptr = zl;
                deleted = 1;
            }
        }

        decrRefCount(field);

    // 从字典中删除
    } else if (o->encoding == REDIS_ENCODING_HT) {
        if (dictDelete((dict*)o->ptr, field) == REDIS_OK) {
            deleted = 1;

            /* Always check if the dictionary needs a resize after a delete. */
            // 删除成功时,看字典是否需要收缩
            if (htNeedsResize(o->ptr)) dictResize(o->ptr);
        }

    } else {
        redisPanic("Unknown hash encoding");
    }

    return deleted;
}
我们看到字典中删除成功并没有检查节点的数量从而选择是否转换为压缩列表,而是对它本身字典进行resize。
由于可见压缩列表转换为字典是不可逆的。至于为什么?这就有点像ziplist的只扩展不收缩,防止哈希表在这种两种结构中转来转去,降低性能。


3
0
分享到:
评论
2 楼 home198979 2014-11-14  
lvwenwen 写道
哥们截图用的什么工具

...就是用qq截的图啊
1 楼 lvwenwen 2014-11-14  
哥们截图用的什么工具

相关推荐

    JAVA上百实例源码以及开源项目源代码

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

    JAVA上百实例源码以及开源项目

    笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此...

    java开源包8

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包1

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包11

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包2

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包3

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包6

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包5

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包10

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包4

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包7

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包9

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    java开源包101

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

    Java资源包01

    SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包...

Global site tag (gtag.js) - Google Analytics