大粨兔奶糖

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

redis object对象系统

概述

redis 当中, sds字符串, adlist双向链表, dict字典, ziplist压缩链表, intset整数集合等均为底层数据结构

redis 并没有使用这些基本数据结构来实现数据库应用, 而是基于这些底层数据结构之上, 构建了一个对象系统, 所有的操作都是基于对象来进行操作

对象结构说明 (src/redis.h)

  • 对象结构

    • // redis 对象结构
      typedef struct redisObject {
          // 类型
          unsigned type:4;
          // 编码
          unsigned encoding:4;
          // 对象最后一次被访问的时间
          unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
          // 引用计数
          int refcount;
          // 指向实际值的指针
          void *ptr;
      } robj;
      
  • 对象类型

    • // 对象类型
      // 字符串
      #define REDIS_STRING 0
      // 链表
      #define REDIS_LIST 1
      // 集合
      #define REDIS_SET 2
      // 有序集合
      #define REDIS_ZSET 3
      // 哈希
      #define REDIS_HASH 4
      
  • 对象编码

    • // 对象编码
      // 普通的 sds 结构
      #define REDIS_ENCODING_RAW 0     /* Raw representation */
      // 整型
      #define REDIS_ENCODING_INT 1     /* Encoded as integer */
      // 哈希
      #define REDIS_ENCODING_HT 2      /* Encoded as hash table */
      // 压缩图, 没看到有应用
      #define REDIS_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
      // 普通链表
      #define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
      // 压缩链表
      #define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
      // 整数集合
      #define REDIS_ENCODING_INTSET 6  /* Encoded as intset */
      // 跳跃表
      #define REDIS_ENCODING_SKIPLIST 7  /* Encoded as skiplist */
      // emb 编码的字符串
      #define REDIS_ENCODING_EMBSTR 8  /* Embedded sds string encoding */
      
  • 引用计数

  • 总结

    redis 的对象系统总共有 5 种类型, 但是在使用上每种类型根据不同的使用场景会采用不同的编码, 不同的对象编码会使用不同的底层存储结构, 这样做是为了性能考虑, 由于数据量的不同, 使用不同的结构对效率的影响不同

    对象类型

    名称 类型
    REDIS_STRING 字符串
    REDIS_LIST 列表
    REDIS_SET 集合
    REDIS_ZSET 有序集合
    REDIS_HASH 哈希

    对象编码

    名称 编码
    REDIS_ENCODING_RAW 普通 sds 字符串
    REDIS_ENCODING_INT 整数
    REDIS_ENCODING_EMBSTR emb 编码的字符串
    REDIS_ENCODING_LINKEDLIST 普通链表
    REDIS_ENCODING_ZIPLIST 压缩链表
    REDIS_ENCODING_HT 哈希
    REDIS_ENCODING_SKIPLIST 跳跃表
    REDIS_ENCODING_INTSET 整数集合
    REDIS_ENCODING_ZIPMAP 压缩图

    对象类型与编码之间的关系

    类型 编码 对象
    REDIS_STRING REDIS_ENCODING_RAW 普通 sds 字符串
    REDIS_STRING REDIS_ENCODING_INT 整数字符串
    REDIS_STRING REDIS_ENCODING_EMBSTR emb 编码字符串
    REDIS_LIST REDIS_ENCODING_LINKEDLIST 普通双向链表
    REDIS_LIST REDIS_ENCODING_ZIPLIST 压缩链表实现的链表结构
    REDIS_SET REDIS_ENCODING_HT 哈希结构实现的集合
    REDIS_SET REDIS_ENCODING_INTSET 整数集合实现的结合
    REDIS_ZSET REDIS_ENCODING_SKIPLIST 跳跃表实现的有序集合
    REDIS_ZSET REDIS_ENCODING_ZIPLIST 压缩链表实现的有序集合
    REDIS_HASH REDIS_ENCODING_HT 哈希表实现的哈希
    REDIS_HASH REDIS_ENCODING_ZIPLIST 压缩链表实现的哈希

各个对象的特性

字符串对象

  • long long 整型在 redis 中是使用字符串存储的

    • // 根据传入的 long long 整数, 创建字符串对象
      robj *createStringObjectFromLongLong(long long value) {
          robj *o;
          /*
          * value 大小符合 REDIS_SHARED_INTEGERS 共享整数范围
          * 返回一个共享对象
          */
          if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
              incrRefCount(shared.integers[value]);
              o = shared.integers[value];
          } else {
              // 不符合共享范围,创建一个新的整数对象
              if (value >= LONG_MIN && value <= LONG_MAX) {
              	// 设置相应的 robj 的值
                  o = createObject(REDIS_STRING, NULL);
                  o->encoding = REDIS_ENCODING_INT;
                  o->ptr = (void*)((long)value);
              // 值不能用 long 类型保存(long long 类型),将值转换为字符串,
              // 并创建一个 REDIS_ENCODING_RAW 的字符串对象来保存值
              } else {
                  o = createObject(REDIS_STRING,sdsfromlonglong(value));
              }
          }
      
          return o;
      }
      
      • 对于整数, redis 有一个共享整数的概念, 用于将一些常用范围的整数在 redis 启动时就创建成对象, 后续所有落在这个范围内的整数, 均使用这个共享对象, 节省了大量整数的对象创建过程

      • 共享整数范围阈值为 10000

        • #define REDIS_SHARED_INTEGERS 10000
          
      • 整数的编码类型不一定都是 REDIS_ENCODING_INT, 当整数值超过了 long 的范围时, 存储的编码类型会变为 REDIS_ENCODING_RAW

  • long double 浮点型在 redis 中也是使用字符串存储的

    • // 将 long double 浮点型存储为字符串
      robj *createStringObjectFromLongDouble(long double value) {
          char buf[256];
          int len;
          // 使用 17 位小数精度,这种精度可以在大部分机器上被 rounding 而不改变
          len = snprintf(buf,sizeof(buf),"%.17Lf", value);
          // 移除尾部的 0 
          if (strchr(buf,'.') != NULL) {
              char *p = buf+len-1;
              while(*p == '0') {
                  p--;
                  len--;
              }
              // 如果不需要小数点,那么移除它
              if (*p == '.') len--;
          }
          // 创建对象
          return createStringObject(buf,len);
      }
      
  • 字符串需要 2 个结构体, robj 和 sdshdr, robj 用来封装成 redis object, sdshdr 用来存储真正的字符串内容

  • 创建 emb 编码与 raw 编码的字符串有一个阈值 REDIS_ENCODING_EMBSTR_SIZE_LIMIT, 当超过这个阈值, 当小于等于这个阈值时, 以 emb 编码; 否则以 raw 编码, REDIS_ENCODING_EMBSTR_SIZE_LIMIT 值为 39

    • #define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
      // 创建字符串对象
      robj *createStringObject(char *ptr, size_t len) {
      	// 当小于等于 REDIS_ENCODING_EMBSTR_SIZE_LIMIT时, 以 emb 编码
          if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
              return createEmbeddedStringObject(ptr,len);
          else
          	// 否则以 raw 编码
              return createRawStringObject(ptr,len);
      }
      
  • 创建 emb 编码的字符串仅需要 1 次内存分配, raw 编码的字符串需要 2 次内存分配, 相应的释放内存时也是如此

  • emb 编码的字符串 robj, sdshdr 内存是连续的, 而 raw 编码的字符串内存是分开的, emb 编码的字符串性能更好

  • 创建 emb 编码字符串

    • // 创建 emb 编码的字符串
      robj *createEmbeddedStringObject(char *ptr, size_t len) {
      	// 分配 robj, sdshdr 内存
          robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
          struct sdshdr *sh = (void*)(o+1);
      	// 设置 robj 的值
          o->type = REDIS_STRING;
          o->encoding = REDIS_ENCODING_EMBSTR;
          o->ptr = sh+1;
          o->refcount = 1;
          o->lru = LRU_CLOCK();
      	// 设置 sdshdr 的值
          sh->len = len;
          sh->free = 0;
          if (ptr) {
              memcpy(sh->buf,ptr,len);
              sh->buf[len] = '\0';
          } else {
              memset(sh->buf,0,len+1);
          }
          return o;
      }
      
  • 创建 raw 编码字符串

    • // 创建 raw 编码字符串
      robj *createRawStringObject(char *ptr, size_t len) {
      	// sdsnewlen 函数分配了 sdshdr 的内存
          return createObject(REDIS_STRING,sdsnewlen(ptr,len));
      }
      
    • robj *createObject(int type, void *ptr) {
      	//  分配 robj 的内存
          robj *o = zmalloc(sizeof(*o));
          // 设置 robj 的值
          o->type = type;
          o->encoding = REDIS_ENCODING_RAW;
          o->ptr = ptr;
          o->refcount = 1;
          o->lru = LRU_CLOCK();
          return o;
      }
      
  • 字符串比较根据不同的 flag 使用不同的比较方法

    • flags

      // 二进制安全的方式, 调用 memcmp 函数
      #define REDIS_COMPARE_BINARY (1<<0)
      // 根据 ascii 码比较, 调用 strcoll 函数
      #define REDIS_COMPARE_COLL (1<<1)
      

链表对象

  • 对象嵌套

    • redis object 里有个对象嵌套的概念, 就是底层存储的数据, 例如字符串, 实际上也是以字符串对象 sdshdr 存在的
      
  • redis 链表对象的编码分为 linkedlist (双端链表), ziplist (压缩链表)

  • redis 链表对象的编码转换

    • 当节点的长度大于 64 字节, 转换为双端链表

      void listTypeTryConversion(robj *subject, robj *value) {
      
          // 确保 subject 为 ZIPLIST 编码
          if (subject->encoding != REDIS_ENCODING_ZIPLIST) return;
      
          if (sdsEncodedObject(value) &&
              // 看字符串是否过长
              sdslen(value->ptr) > server.list_max_ziplist_value)
                  // 将编码转换为双端链表
                  listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
      }
      
    • 当链表存储的节点数量大于等于 512 个, 转换为双端链表

      void listTypePush(robj *subject, robj *value, int where) {
          // 是否需要转换编码?
          listTypeTryConversion(subject,value);
      
          if (subject->encoding == REDIS_ENCODING_ZIPLIST &&
              ziplistLen(subject->ptr) >= server.list_max_ziplist_entries)
                  listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
      
          // 省略 ...
      }
      
    • server.list_max_ziplist_value 值在初始化服务器配置时设置为 REDIS_LIST_MAX_ZIPLIST_VALUE

    • server.list_max_ziplist_entries 值在初始化服务器配置时设置为 REDIS_LIST_MAX_ZIPLIST_ENTRIES

    • // 链表结构从 ziplist 编码转换为 linkedlist 编码的阈值
      // 最大节点数量阈值
      #define REDIS_LIST_MAX_ZIPLIST_ENTRIES 512
      // 最大字符串长度阈值
      #define REDIS_LIST_MAX_ZIPLIST_VALUE 64
      
      void initServerConfig() {
      	// 省略
      
          server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES;
          server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
      
      	// 省略 ...
      }
      

集合对象

  • redis 集合的编码转换

    集合的 intset 编码存储的均为整数

    • 集合的操作 api 在存入 intset 编码时, 均会调用 isObjectRepresentableAsLongLong 函数, 来判断是否是整数
      

    集合保存的元素数量不能超过 512 (REDIS_SET_MAX_INTSET_ENTRIES)

    int setTypeAdd(robj *subject, robj *value) {
    	// 省略 ...
    	
        // 添加成功
        // 检查集合在添加新元素之后是否需要转换为字典
        if (intsetLen(subject->ptr) > server.set_max_intset_entries)
        	setTypeConvert(subject,REDIS_ENCODING_HT);
    
    	// 省略 ...
    }
    
    • server.set_max_intset_entries, 若集合的元素数量大于此值, 会将 intset 编码转换为 ht 编码

      • #define REDIS_SET_MAX_INTSET_ENTRIES 512
        
        void initServerConfig() {
        	// 省略 ...
        	
        	server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES;
        	
        	// 省略 ...
        }
        

有序集合对象

  • 有序集合结构

    • // 有序集合
      typedef struct zset {
          // 字典, 键为成员, 值为分值
          dict *dict;
          // 跳跃表, 按分值排序成员
          zskiplist *zsl;
      } zset;
      
  • ​有序集合 ziplist 编码与 skiplist 编码之间的转换

    • 当执行集合命令时, 判断一些规则, 来决定是否使用 skiplist 编码
      
      • 有序集合保存的元素数量大于 (128) server.zset_max_ziplist_entries

        • #define REDIS_ZSET_MAX_ZIPLIST_ENTRIES 128
          
      • 有序集合保存的元素大小大于 (64) server.zset_max_ziplist_value

        • #define REDIS_ZSET_MAX_ZIPLIST_VALUE 64
          
      • 命令距离

        • void zaddGenericCommand(redisClient *c, int incr) {
          	// 省略 ...
          
              if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries)
              	zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);
          
              if (sdslen(ele->ptr) > server.zset_max_ziplist_value)
              	zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);
          
          	// 省略 ...
          }
          

哈希对象

  • hash 的 ziplist 编码将键和值分别存放在 ziplist 的 2 个节点, 键在前, 值在后

  • redis hash 的编码转换

    • 当满足以下 2 个条件时, redis hash 对象会使用 ziplist 编码

      • 当 hash 的键值对数量小于 512 (server.hash_max_ziplist_entries)

        • #define REDIS_HASH_MAX_ZIPLIST_ENTRIES 512
          
          int hashTypeSet(robj *o, robj *field, robj *value) {
          	// 省略 ...
          	
          	// 检查在添加操作完成之后,是否需要将 ZIPLIST 编码转换成 HT 编码
          	if (hashTypeLength(o) > server.hash_max_ziplist_entries)
          		hashTypeConvert(o, REDIS_ENCODING_HT);
          
          	// 省略 ...
          }
          
      • 当 hash 的所有键和值的字符串长度均小于 64 字节 (server.hash_max_ziplist_value)

        • #define REDIS_HASH_MAX_ZIPLIST_VALUE 64
          
          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;
                  }
              }
          }
          

总结

类型检查

命令多态

内存回收

对象共享

  • 不同键的值指针指向的是同一个值对象
  • 值对象的引用计数 +1

object api (src/object.c)

函数 作用 备注
createObject 创建 robj 对象 robj *createObject(int type, void *ptr)
createRawStringObject 创建 raw 编码的字符串对象 robj *createRawStringObject(char *ptr, size_t len)
createEmbeddedStringObject 创建 emb 压缩算法压缩的字符串对象 robj *createRawStringObject(char *ptr, size_t len)
createStringObject 创建字符串对象, raw 或 emb 编码 robj *createStringObject(char *ptr, size_t len)
createStringObjectFromLongLong 创建 int 编码的字符串对象 robj *createStringObjectFromLongLong(long long value)
createStringObjectFromLongDouble 创建浮点数的字符串对象, raw 或 emb 编码 robj *createStringObjectFromLongDouble(long double value)
dupStringObject 复制字符串对象 robj *dupStringObject(robj *o)
createListObject 创建 linkedlist 编码的列表对象 robj *createListObject(void)
createZiplistObject 创建 ziplist 编码的列表对象 robj *createZiplistObject(void)
createSetObject 创建 ht 编码的集合对象 robj *createSetObject(void)
createIntsetObject 创建 intset 编码的集合对象 robj *createIntsetObject(void)
createHashObject 创建 ziplist 编码的哈希对象 robj *createHashObject(void)
createZsetObject 创建 skiplist 编码的有序集合对象 robj *createZsetObject(void)
createZsetZiplistObject 创建 ziplist 编码的有序集合对象 robj *createZsetZiplistObject(void)
freeStringObject 释放 raw 编码的字符串对象 void freeStringObject(robj *o)
freeListObject 释放链表对象 void freeListObject(robj *o)
freeSetObject 释放集合对象 void freeSetObject(robj *o)
freeZsetObject 释放有序集合对象 void freeZsetObject(robj *o)
freeHashObject 释放哈希对象 void freeHashObject(robj *o)
incrRefCount 为对象的引用加 1 void incrRefCount(robj *o)
decrRefCount 为对象的引用减 1 void decrRefCount(robj *o)
decrRefCountVoid 对象的引用减 1 void decrRefCountVoid(void *o)
resetRefCount 重置对象的 refcount 为 0 robj *resetRefCount(robj *obj)
checkType 检查对象 o 的类型是否符合 type, 并返回客户端信息 int checkType(redisClient *c, robj *o, int type)
isObjectRepresentableAsLongLong 对象 o 是否可以表示为 long long 类型, 将转换后的值存入到 llval int isObjectRepresentableAsLongLong(robj *o, long long *llval)
tryObjectEncoding 尝试对字符串对象进行编码, 以节约内存 robj *tryObjectEncoding(robj *o)
getDecodedObject 将传入的 robj 对象解析为字符串对象 robj *getDecodedObject(robj *o)
compareStringObjectsWithFlags 比较字符串大小, 根据传入的 flag 使用不同的函数比较 int compareStringObjectsWithFlags(robj *a, robj *b, int flags)
compareStringObjects 以二进制安全方式比较字符串大小 int compareStringObjects(robj *a, robj *b)
collateStringObjects 以 strcoll 函数比较字符串大小 int collateStringObjects(robj *a, robj *b)
equalStringObjects 判断两个字符串是否相等 int equalStringObjects(robj *a, robj *b)
stringObjectLen 获取字符串对象中字符串长度 size_t stringObjectLen(robj *o)
getDoubleFromObject 从字符串对象 o 中获取 double 值, 存入 target int getDoubleFromObject(robj *o, double *target)
getDoubleFromObjectOrReply 从对象 o 中获取 double 值, 存入 target; 若失败返回给定信息 int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg)
getLongDoubleFromObject 从对象 o 中获取 long double 值, 存入 target int getLongDoubleFromObject(robj *o, long double *target)
getLongDoubleFromObjectOrReply 从对象 o 中获取 long double 值, 存入 target; 若失败返回给定信息 int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg)
getLongLongFromObject 从对象 o 中获取 long long 值, 存入 target int getLongLongFromObject(robj *o, long long *target)
getLongLongFromObjectOrReply 从对象 o 中获取 long long 值, 存入 target; 若失败返回给定信息 int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg)
getLongFromObjectOrReply 从对象 o 中获取 long 值, 存入 target; 若失败返回给定信息 int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg)
strEncoding 返回给定 encoding 编码的字符串表示 char *strEncoding(int encoding)
estimateObjectIdleTime 计算给定对象的空闲时长 unsigned long long estimateObjectIdleTime(robj *o)
objectCommandLookup OBJECT 命令获取指定 key 的值对象, 不修改 lru robj *objectCommandLookup(redisClient *c, robj *key)
objectCommandLookupOrReply OBJECT 命令获取指定 key 的之对象, 不修改 lru; 若失败返回给定信息 robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply)
objectCommand OBJECT 命令 void objectCommand(redisClient *c)

list api (src/t_list.c)

函数 作用 备注
listTypeTryConversion 根据插入的 value 值, 看是否需要将链表 subject 从 ziplist 转为 linkedlist void listTypeTryConversion(robj *subject, robj *value)
listTypePush 向链表 subject 头部或尾部添加值 value void listTypePush(robj *subject, robj *value, int where)
listTypePop 从链表 subject 头部或尾部弹出节点 robj *listTypePop(robj *subject, int where)
listTypeLength 获取链表 subject 的长度 unsigned long listTypeLength(robj *subject)
listTypeInitIterator 初始化链表迭代器 listTypeIterator *listTypeInitIterator(robj *subject, long index, unsigned char direction)
listTypeReleaseIterator 释放链表迭代器 li void listTypeReleaseIterator(listTypeIterator *li)
listTypeNext 获取迭代器当前指向的节点, 将其存入 entry int listTypeNext(listTypeIterator *li, listTypeEntry *entry)
listTypeGet 返回 entry 结构保存的节点, 转为 robj 结构 robj *listTypeGet(listTypeEntry *entry)
listTypeInsert 将 value 插入 entry 所在链表节点的前面或后面 void listTypeInsert(listTypeEntry *entry, robj *value, int where)
listTypeEqual 判断对象 o 与 entry 节点值是否相等 int listTypeEqual(listTypeEntry *entry, robj *o)
listTypeDelete 删除 entry 节点 void listTypeDelete(listTypeEntry *entry)
listTypeConvert 将 subject 编码转换为 linkedlist void listTypeConvert(robj *subject, int enc)

set api (src/t_set.c)

函数 作用 备注
setTypeCreate 根据 value 值创建集合 robj *setTypeCreate(robj *value)
setTypeAdd 将 value 值添加到 subject 集合中 int setTypeAdd(robj *subject, robj *value)
setTypeRemove 将 value 值从 setobj 集合中删除 int setTypeRemove(robj *setobj, robj *value)
setTypeIsMember 判断 value 值是否在集合 subject 中 int setTypeIsMember(robj *subject, robj *value)
setTypeInitIterator 创建指定 subject 集合的迭代器 setTypeIterator *setTypeInitIterator(robj *subject)
setTypeReleaseIterator 释放集合迭代器 void setTypeReleaseIterator(setTypeIterator *si)
setTypeNext 获取迭代器当前指向的节点, 存入 objele, 返回的对象没有增加引用计数, 对 copy-on-write 友好 int setTypeNext(setTypeIterator *si, robj **objele, int64_t *llele)
setTypeNextObject 获取迭代器当前指向的节点, 总是返回一个新增的, 或者是引用计数增加的对象, 对 copy-on-write 非友好 robj *setTypeNextObject(setTypeIterator *si)
setTypeRandomElement 从集合中随机获取一个元素, 若集合编码是 intset, 存到 llele; 若编码是 ht, 存到 objele int setTypeRandomElement(robj *setobj, robj **objele, int64_t *llele)
setTypeSize 获取集合的元素数量 unsigned long setTypeSize(robj *subject)
setTypeConvert 将集合 setobj 的编码转换为给定的 ht 编码 void setTypeConvert(robj *setobj, int enc)
qsortCompareSetsByCardinality 计算集合 s1 与集合 s2 的元素数量之差 int qsortCompareSetsByCardinality(const void *s1, const void *s2)
qsortCompareSetsByRevCardinality 计算集合 s2 与集合 s1 的元素数量之差 int qsortCompareSetsByRevCardinality(const void *s1, const void *s2)

hash api (src/t_hash.c)

函数 作用 备注
hashTypeTryConversion 尝试将 ziplist 编码的 hash 对象转换成 ht 编码 void hashTypeTryConversion(robj *o, robj ** argv, int start, int end)
hashTypeTryObjectEncoding 尝试将 ht 编码的键值对字符串对象分别进行编码, 以节省内存 void hashTypeTryObjectEncoding(robj *subject, robj ** o1, robj ** o2)
hashTypeGetFromZiplist 从 ziplist 编码的 hash 中获取指定 field 相对应的值 int hashTypeGetFromZiplist(robj *o, robj *field, unsigned char ** vstr, unsigned int *vlen, long long *vll)
hashTypeGetFromHashTable 从 ht 编码的 hash 中获取指定 field 相对应的值 int hashTypeGetFromZiplist(robj *o, robj *field, unsigned char **vstr, unsigned int *vlen, long long *vll)
hashTypeGetObject 从 hash 中获取指定 field 的值, 返回 robj 对象 robj *hashTypeGetObject(robj *o, robj *field)
hashTypeExists 判断 hash 中指定 filed 是否存在 int hashTypeExists(robj *o, robj *field)
hashTypeSet 将键值对添加到 hash 中, 若键已存在, 则使用新值替换旧值 int hashTypeSet(robj *o, robj *field, robj *value)
hashTypeDelete 从 hash 中删除指定 field 的键值对 int hashTypeDelete(robj *o, robj *field)
hashTypeLength 返回 hash 中键值对数量 unsigned long hashTypeLength(robj *o)
hashTypeInitIterator 创建 hash 迭代器 hashTypeIterator *hashTypeInitIterator(robj *subject)
hashTypeReleaseIterator 释放 hash 迭代器 void hashTypeReleaseIterator(hashTypeIterator *hi)
hashTypeNext 获取迭代器下个节点, 存入迭代器 int hashTypeNext(hashTypeIterator *hi)
hashTypeCurrentFromZiplist 从 ziplist 编码的 hash 中, 获取迭代器当前指向的节点的 field 或 value 对象 void hashTypeCurrentFromZiplist(hashTypeIterator *hi, int what, unsigned char **vstr, unsigned int *vlen, long long *vll)
hashTypeCurrentFromHashTable 从 ht 编码的 hash 中, 获取迭代器当前指向的节点的 field 或 value 对象 void hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what, robj **dst)
hashTypeCurrentObject 获取迭代器当前节点的 field 或 value 对象 robj *hashTypeCurrentObject(hashTypeIterator *hi, int what)
hashTypeLookupWriteOrCreate 按 key 在数据库中查找并返回相应 hash 对象, 若对象不存在, 创建新 hash 对象并返回 robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key)
hashTypeConvertZiplist 将 ziplist 编码的 hash 对象转换成 ht 编码 void hashTypeConvertZiplist(robj *o, int enc)
hashTypeConvert 将 hash 对象 o 转换成指定 enc 编码, 目前仅支持将 ziplist 编码转换为 ht 编码 void hashTypeConvert(robj *o, int enc)
posted on 2017-04-13 09:54  大粨兔奶糖  阅读(285)  评论(0编辑  收藏  举报