Redis 6.2 执行hset 操作(源码)
文章目录
- 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 操作(源码)相关推荐
- 字符串固定长度 易语言_易语言字符串操作源码
易语言字符串操作源码 系统结构:字符串_取长度,字符串_取中间,字符串_取左边,字符串_取右边,字符串_替换,到宽字符,到多字节,取文本数据地址,取字节集数据地址,MultiByteToWideCha ...
- 使用 Redis 实现语音社交聊天室源码中的排行榜功能
在语音社交聊天室源码中,排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般语音社交聊天室源码的排行榜都是有实效性的,比如"用户积分榜&quo ...
- Java文件操作源码大全
Java文件操作源码大全 1.创建文件夹 5 2.创建文件 5 3.删除文件 5 4.删除文件夹 6 5.删除一个文件下夹所有的文件夹 7 6.清空文件夹 8 7.读取文件 8 8.写入文件 9 9. ...
- 分享一套开源的springboot制造执行MES系统源码,带本地部署搭建教程+运行文档
全开源的一套超有价值的JAVA制造执行MES系统源码 亲测 带本地部署搭建教程 教你如何在本地运行运行起来. 开发环境:jdk1./1.8 tomcat mysql5.6+springmvc+mave ...
- 单机redis工具类的使用附源码
单机redis工具类的使用附源码 问题背景 项目搭建 代码测试 总结 Lyric: 怎么隐藏我的悲伤 问题背景 redis常用的工具类 注意事项: 默认已安装redis,可以使用安装包安装看这篇文章, ...
- 关于执行git克隆源码包fatal:无法访问“https://***“之类的问题
关于执行git克隆源码包fatal:无法访问"https://***"之类的问题 问题分析:出现的错误大概是这个样子(我用的是kali虚拟机,Ubuntu出现这样的错误一样可以解决 ...
- 汇编 debug调试没有执行对应文件源码指令---》失灵---》正确使用debug第一步
汇编 debug调试时 没有执行 对应文件源码指令 果然不认真听课就是这样 把调试命令 debug test.exe 错误写成 debug test.asm 并一直使用多达两周时长 我真是个人才Σ( ...
- 数据库 记录php 全屏编辑,Thinkphp5数据库操作源码
后台直接操作数据库,实现新建.编辑.删除数据表,新建.编辑.删除数据库字段,Thinkphp5数据库管理操作源码 下载资源 下载积分: 300 积分 1.使用前请配置虚拟主机:将整个文件放在根目录下面 ...
- 实时编译、动态执行C/C++源码函数
实时编译.动态执行C/C++源码函数 语法格式:fileCLASS *pObj = <file.cpp> 该语法获得源代码file.cpp的函数接口对象指针pObj,通过pObj调用fil ...
最新文章
- mysql之select查询
- 从青铜到王者的路线,java不同系统间数据同步
- 刷爆了!GitHub标星1.6W,这个 Python 项目太实用!
- CCF 201703-2 学生排队
- Keras之模型拼接
- 为什么越来越少的人用 jQuery?
- Django项目实践2 - Django模板语言(常用语法规则)
- jar编译成exe可执行文件【图文教程】
- 为什么打印机打印照片模糊_家用喷墨打印机打印照片不清楚怎么办 是什么原因?...
- mandriva2010 xp ubuntu10.04 三系统的安装
- matlab自带的音乐,MATLAB乐器(如何用matlab演奏音乐)
- 音乐 美术 劳技 计算机教研组工作总结,小班教研组工作总结
- 浅谈游戏数据分析------留存篇一---留存折损
- 天载优配简述指数放量轰动
- 全国省市数据 sql语句+json格式数据
- 加密解密五种算法的实现
- 海思Hi3518EV200(1)简介
- linux环境下的c编程指南,C语言Socket简单编程指南PDF
- 记:《洛克菲勒留给儿子的38封信》-- 34
- 代码随想录——Dota2参议院
热门文章
- Windows 系统API 函数快速查找
- android 三星调用拍照功能吗,Android 相机开发 三星拍照崩溃修改解决 详细
- 与孩童家长的一段奇异的对话:父母视觉正常,孩子却患色盲
- 关于“高速网络链路,提高的是数据发送速率而不是传播速率“笔记
- 太阳能充电调节代码_“中国Kcar” 无需充电的薄膜太阳能动力汽车
- [POJ3155]Hard Life
- buuctf GWCTF 2019 pyre
- IDEA maven项目变灰
- 来了,来了!孙正义出手之“软银22.5亿美金砸向通用Cruise”
- 寒假算法学习 I (9). 宇宙总统 (重载运算赋 >)