文章目录

  • hset 主函数
  • 1,首先创建hash对象(hashTypeLookupWriteOrCreate)
  • 2、尝试转换存储空间的编码格式(hashTypeTryConversion)
  • 3、遍历把键值对根据存储空间格式(ziplist,hashtable)的不同分别 存储起来

hset 主函数

void hsetCommand(client *c) {int i, created = 0;robj *o;if ((c->argc % 2) == 1) {addReplyErrorFormat(c,"wrong number of arguments for '%s' command",c->cmd->name);return;}//查找key,不存在则新建if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;// 尝试转换底层编码hashTypeTryConversion(o,c->argv,2,c->argc-1);//依次写入field-value对for (i = 2; i < c->argc; i += 2)created += !hashTypeSet(o,c->argv[i]->ptr,c->argv[i+1]->ptr,HASH_SET_COPY);/* HMSET (deprecated) and HSET return value is different. HMSET(已弃用)和 HSET 返回值不同*/char *cmdname = c->argv[0]->ptr;//找命令是hset还是hmset,if (cmdname[1] == 's' || cmdname[1] == 'S') {/* HSET */addReplyLongLong(c, created);} else {/* HMSET */addReply(c, shared.ok);}signalModifiedKey(c,c->db,c->argv[1]);notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id);server.dirty += (c->argc - 2)/2;
}

1,首先创建hash对象(hashTypeLookupWriteOrCreate)

//取出或新创建哈希对象,如果是新建相当于创建了一个hashMap
robj *hashTypeLookupWriteOrCreate(client *c, robj *key) {//首先根据key去取robj *o = lookupKeyWrite(c->db,key);if (checkType(c,o,OBJ_HASH)) return NULL;//如果不存在则会新创建一个hash对象if (o == NULL) {o = createHashObject();dbAdd(c->db,key,o);}return o;
}

2、尝试转换存储空间的编码格式(hashTypeTryConversion)

比较的规则就是hash中value对象长度是否大于server.hash_max_ziplist_value这个值作为判断依据

/* Check the length of a number of objects to see if we need to convert a* ziplist to a real hash. Note that we only check string encoded objects* as their string length can be queried in constant time.检查argv数组中多个对象的长度,看看我们是否需要将 * ziplist 转换为真正的哈希。请注意,我们只检查字符串编码的对象 * 因为它们的字符串长度可以在恒定时间内查询*/
void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {int i;//如果对象不是 ziplist 编码,那么直接返回if (o->encoding != OBJ_ENCODING_ZIPLIST) return;//遍历所有对象,一个一个比较长度,字符串值是否超过指定长度,记住这里是比较链表中每一个值的长度,如果有一个大于server.hash_max_ziplist_value,则把ziplist转换成hashtablefor (i = start; i <= end; i++) {if (sdsEncodedObject(argv[i]) &&sdslen(argv[i]->ptr) > server.hash_max_ziplist_value){hashTypeConvert(o, OBJ_ENCODING_HT);break;}}
}

3、遍历把键值对根据存储空间格式(ziplist,hashtable)的不同分别 存储起来

但是会根据原来的存储空间结构,比如ziplist或者hashtable选择不同的方式

/* Add a new field, overwrite the old with the new value if it already exists.* Return 0 on insert and 1 on update.*添加一个新字段,如果它已经存在,则用新值覆盖旧字段。* 插入时返回 0,更新时返回 1* By default, the key and value SDS strings are copied if needed, so the* caller retains ownership of the strings passed. However this behavior* can be effected by passing appropriate flags (possibly bitwise OR-ed):*默认情况下,如果需要,会复制键和值 SDS 字符串,因此* 调用者保留传递的字符串的所有权。然而,这种行为* 可以通过传递适当的标志来实现(可能是按位 OR-ed)* HASH_SET_TAKE_FIELD -- The SDS field ownership passes to the function.* HASH_SET_TAKE_FIELD     SDS 字段所有权传递给函数** When the flags are used the caller does not need to release the passed* SDS string(s). It's up to the function to use the string to create a new* entry or to free the SDS string before returning to the caller.*当使用标志时,调用者不需要释放传递的SDS 字符串。*在返回给调用者之前,由函数使用字符串来创建新的条目或释放 SDS 字符串** HASH_SET_COPY corresponds to no flags passed, and means the default* semantics of copying the values if needed.*HASH_SET_COPY 对应于没有传递标志,并且意味着如果需要复制值的默认语义*/
#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;//添加到 ziplistif (o->encoding == OBJ_ENCODING_ZIPLIST) {unsigned char *zl, *fptr, *vptr;zl = o->ptr;//从ziplist中取指定的字段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)抓取指向值的指针(fptr 指向字段)*/vptr = ziplistNext(zl, fptr);serverAssert(vptr != NULL);update = 1;/* Replace value替换掉值*/zl = ziplistReplace(zl, vptr, (unsigned char*)value,sdslen(value));}}//创建新的而不是修改旧的value值if (!update) {/* Push new field/value pair onto the tail of the ziplist将新的字段/值对推送到 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再检查ziplist是否需要转换为哈希表 ,这里比较的是整个ziplist的长度,大于某个值则整个ziplist转换成hashtable存储*/if (hashTypeLength(o) > serverR.hash_max_ziplist_entries)hashTypeConvert(o, OBJ_ENCODING_HT);} else if (o->encoding == OBJ_ENCODING_HT) {//添加到hash表dictEntry *de = dictFind(o->ptr,field);if (de) {//把键值对中旧的value替换掉sdsfree(dictGetVal(de));if (flags & HASH_SET_TAKE_VALUE) {dictGetVal(de) = value;value = NULL;} else {dictGetVal(de) = sdsdup(value);}update = 1;} else { //往hashTable中加入新的键值对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;
}

Redis 6.2 执行hset 操作(源码)相关推荐

  1. 字符串固定长度 易语言_易语言字符串操作源码

    易语言字符串操作源码 系统结构:字符串_取长度,字符串_取中间,字符串_取左边,字符串_取右边,字符串_替换,到宽字符,到多字节,取文本数据地址,取字节集数据地址,MultiByteToWideCha ...

  2. 使用 Redis 实现语音社交聊天室源码中的排行榜功能

    在语音社交聊天室源码中,排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般语音社交聊天室源码的排行榜都是有实效性的,比如"用户积分榜&quo ...

  3. Java文件操作源码大全

    Java文件操作源码大全 1.创建文件夹 5 2.创建文件 5 3.删除文件 5 4.删除文件夹 6 5.删除一个文件下夹所有的文件夹 7 6.清空文件夹 8 7.读取文件 8 8.写入文件 9 9. ...

  4. 分享一套开源的springboot制造执行MES系统源码,带本地部署搭建教程+运行文档

    全开源的一套超有价值的JAVA制造执行MES系统源码 亲测 带本地部署搭建教程 教你如何在本地运行运行起来. 开发环境:jdk1./1.8 tomcat mysql5.6+springmvc+mave ...

  5. 单机redis工具类的使用附源码

    单机redis工具类的使用附源码 问题背景 项目搭建 代码测试 总结 Lyric: 怎么隐藏我的悲伤 问题背景 redis常用的工具类 注意事项: 默认已安装redis,可以使用安装包安装看这篇文章, ...

  6. 关于执行git克隆源码包fatal:无法访问“https://***“之类的问题

    关于执行git克隆源码包fatal:无法访问"https://***"之类的问题 问题分析:出现的错误大概是这个样子(我用的是kali虚拟机,Ubuntu出现这样的错误一样可以解决 ...

  7. 汇编 debug调试没有执行对应文件源码指令---》失灵---》正确使用debug第一步

    汇编 debug调试时 没有执行 对应文件源码指令 果然不认真听课就是这样 把调试命令 debug test.exe 错误写成 debug test.asm 并一直使用多达两周时长 我真是个人才Σ( ...

  8. 数据库 记录php 全屏编辑,Thinkphp5数据库操作源码

    后台直接操作数据库,实现新建.编辑.删除数据表,新建.编辑.删除数据库字段,Thinkphp5数据库管理操作源码 下载资源 下载积分: 300 积分 1.使用前请配置虚拟主机:将整个文件放在根目录下面 ...

  9. 实时编译、动态执行C/C++源码函数

    实时编译.动态执行C/C++源码函数 语法格式:fileCLASS *pObj = <file.cpp> 该语法获得源代码file.cpp的函数接口对象指针pObj,通过pObj调用fil ...

最新文章

  1. mysql之select查询
  2. 从青铜到王者的路线,java不同系统间数据同步
  3. 刷爆了!GitHub标星1.6W,这个 Python 项目太实用!
  4. CCF 201703-2 学生排队
  5. Keras之模型拼接
  6. 为什么越来越少的人用 jQuery?
  7. Django项目实践2 - Django模板语言(常用语法规则)
  8. jar编译成exe可执行文件【图文教程】
  9. 为什么打印机打印照片模糊_家用喷墨打印机打印照片不清楚怎么办 是什么原因?...
  10. mandriva2010 xp ubuntu10.04 三系统的安装
  11. matlab自带的音乐,MATLAB乐器(如何用matlab演奏音乐)
  12. 音乐 美术 劳技 计算机教研组工作总结,小班教研组工作总结
  13. 浅谈游戏数据分析------留存篇一---留存折损
  14. 天载优配简述指数放量轰动
  15. 全国省市数据 sql语句+json格式数据
  16. 加密解密五种算法的实现
  17. 海思Hi3518EV200(1)简介
  18. linux环境下的c编程指南,C语言Socket简单编程指南PDF
  19. 记:《洛克菲勒留给儿子的38封信》-- 34
  20. 代码随想录——Dota2参议院

热门文章

  1. Windows 系统API 函数快速查找
  2. android 三星调用拍照功能吗,Android 相机开发 三星拍照崩溃修改解决 详细
  3. 与孩童家长的一段奇异的对话:父母视觉正常,孩子却患色盲
  4. 关于“高速网络链路,提高的是数据发送速率而不是传播速率“笔记
  5. 太阳能充电调节代码_“中国Kcar” 无需充电的薄膜太阳能动力汽车
  6. [POJ3155]Hard Life
  7. buuctf GWCTF 2019 pyre
  8. IDEA maven项目变灰
  9. 来了,来了!孙正义出手之“软银22.5亿美金砸向通用Cruise”
  10. 寒假算法学习 I (9). 宇宙总统 (重载运算赋 >)