当前位置: 首页 > news >正文

Redis源码学习 -- 数据类型编码 -- List - -蓝蜗牛

1. 什么是List?

List​​是Redis的数据类型之一,给用户提供一个双向链表的功能。核心优势是头尾操作O(1)

2. List的编码模式

List的编码模式有两种:LISTPACKQUICKLIST(下文用全大写表示编码名称,首字母大写表示数据结构)
Quicklist本身就是节点为Listpack的链表,所以实际上LISTPACK编码可以看成只有一个节点的QUICKLIST编码,没有本质区别。
单独设计一个LISTPACK编码的目的是,在元素较少的时候可以节省Quicklist结构体的内存空间。

3. List的编码策略

  • 默认编码是LISTPACK,当元素大小或数量超过Listpack阈值时切换到QUICKLIST
  • 当元素删除后,减少到Listpack上限阈值的一半时,切换到LISTPACK。减少到一半再切换的目的是:避免刚好在Listpack上限阈值边界频繁增删的时候反复触发切换编码。

缩容代码如下:

static void listTypeTryConvertQuicklist(robj *o, int shrinking, beforeConvertCB fn, void *data) {serverAssert(o->encoding == OBJ_ENCODING_QUICKLIST); // 必须是QUICKLIST编码才允许转换size_t sz_limit;unsigned int count_limit;quicklist *ql = o->ptr;   // QUICKLIST 编码下, ptr指向quicklist/***************************************************************1. 只有单节点的 Quicklist 才允许转换到 Listpack 2. 如果 Quicklist 里面的元素是超过大小阈值的元素, 只能用Quicklist  ****************************************************************/if (ql->len != 1 || ql->head->container != QUICKLIST_NODE_CONTAINER_PACKED)return;/* 读取配置文件设置的大小阈值和数量阈值并减半,小于一半才转换 */quicklistNodeLimit(server.list_max_listpack_size, &sz_limit, &count_limit);if (shrinking) {sz_limit /= 2;count_limit /= 2;}if (ql->head->sz > sz_limit || ql->count > count_limit) return;if (fn) fn(data); // 如果参数有回调则调用回调/* 从 quicklist 唯一的一个节点中取出 listpack 然后删除 quicklist */o->ptr = ql->head->entry;ql->head->entry = NULL;quicklistRelease(ql);o->encoding = OBJ_ENCODING_LISTPACK;
}

扩容代码如下:

static void listTypeTryConvertListpack(robj *o, robj **argv, int start, int end,beforeConvertCB fn, void *data)
{serverAssert(o->encoding == OBJ_ENCODING_LISTPACK);  // 必须是LISTPACK编码才允许转换size_t add_bytes = 0;size_t add_length = 0;/* 如果是PUSH命令,遍历计算需要新增的元素大小和个数 */if (argv) {for (int i = start; i <= end; i++) {if (!sdsEncodedObject(argv[i]))continue;add_bytes += sdslen(argv[i]->ptr);}add_length = end - start + 1;}// 判断新的元素大小和个数是否会超过配置文件设置的阈值if (quicklistNodeExceedsLimit(server.list_max_listpack_size,lpBytes(o->ptr) + add_bytes, lpLength(o->ptr) + add_length)){if (fn) fn(data); // 如果参数有回调则调用回调/* 创建一个空quicklist,并设置配置文件的 listpack上限阈值 和 quicklist压缩深度 */quicklist *ql = quicklistNew(server.list_max_listpack_size, server.list_compress_depth);if (lpLength(o->ptr))quicklistAppendListpack(ql, o->ptr); // listpack 有元素则直接添加指针作为节点elselpFree(o->ptr); // listpack 没有有元素则直接释放o->ptr = ql;o->encoding = OBJ_ENCODING_QUICKLIST;}
}

4. 添加元素

根据不同的编码类型头尾插入节点代码如下:

void listTypePush(robj *subject, robj *value, int where) {if (subject->encoding == OBJ_ENCODING_QUICKLIST) {int pos = (where == LIST_HEAD) ? QUICKLIST_HEAD : QUICKLIST_TAIL;if (value->encoding == OBJ_ENCODING_INT) {char buf[32];ll2string(buf, 32, (long)value->ptr);quicklistPush(subject->ptr, buf, strlen(buf), pos);} else {quicklistPush(subject->ptr, value->ptr, sdslen(value->ptr), pos);}} else if (subject->encoding == OBJ_ENCODING_LISTPACK) {if (value->encoding == OBJ_ENCODING_INT) {subject->ptr = (where == LIST_HEAD) ?lpPrependInteger(subject->ptr, (long)value->ptr) :lpAppendInteger(subject->ptr, (long)value->ptr);} else {subject->ptr = (where == LIST_HEAD) ?lpPrepend(subject->ptr, value->ptr, sdslen(value->ptr)) :lpAppend(subject->ptr, value->ptr, sdslen(value->ptr));}} else {serverPanic("Unknown list encoding");}
}

Listpack内部本身就有检测数据是否是整数的功能,QUICKLIST编码时只保留了统一的插入string接口,导致了:
插入数字使用ll2string()转成string,到了底层的Listpack又转回数字,是一个浪费性能的点。

http://www.wxhsa.cn/company.asp?id=6622

相关文章:

  • 乌班图无法登录桌面,只能终端登录用户。且有网拉不了包(DNS问题)
  • 事半功倍是蠢蛋53 tornado接口报错
  • 完整教程:云手机的技术架构可分为哪些
  • AI提示词遇见精密算法:TimeGuessr如何用数学魔法打造文化游戏新体验
  • Arkime:大规模开源网络分析与数据包捕获系统
  • kylin SP2安装mysql 8.0.41
  • SAP采购订单数据获取
  • get和post如何理解
  • me and my girlfriend WP复盘
  • 顺序表
  • 能源管理的数字神经:MyEMS如何重塑能效认知
  • 开源・数据・能效:MyEMS 如何成为能源管理革新的核心引擎
  • mysql回表,为什么你的查询总是慢半拍?
  • HMCL 3.6.17 Minecraft我的世界启动器
  • 用自带的Nginx为gitlab做白名单
  • XHR/Fetch请求介绍与安全测试
  • 能流新智:MyEMS与开源时代的能源感知
  • ​​普科科技罗氏线圈应用指南:精准掌控电流测量的艺术​​
  • go mod基础
  • go 变量作用域
  • Oracle笔记:测试update语句关联表扫描的次数
  • ​​电流互感器选型指南:以普科科技产品为例
  • .NET驾驭Word之力:玩转文本与格式
  • 读书笔记:白话解读位图索引:什么时候该用,什么时候千万别用?
  • 泰克CT-6交流电流探头测量原理
  • 结构体成员赋值问题
  • RepositoryItemGridLookUpEdit 使用 ok
  • wso2~系统端口总结
  • 故障处理:19C RAC改私网IP后重建集群时报网络找不到
  • 谈谈程序猿的职业方向