redis object 对象系统

redis object对象系统

概述

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

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;
  • 对象类型api

    • // 对象类型
      // 字符串
      #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 种类型, 可是在使用上每种类型根据不一样的使用场景会采用不一样的编码, 不一样的对象编码会使用不一样的底层存储结构, 这样作是为了性能考虑, 因为数据量的不一样, 使用不一样的结构对效率的影响不一样dom

    对象类型函数

    名称 类型
    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)
相关文章
相关标签/搜索