如何自定义数据类型

2021/01/25 posted in  实践

我们需要一个数据类型符合自己的查询但是Redis本身不支持,此时,我们之前学习的这些数据类型就无法满足需求了。那么,自定义的数据类型是一个很好的解决方法

Redis 的基本对象结构

RedisObject 内部包括 type、encoding、lru、refcount 四个元数据以及一个 *ptr 指针

  • type : 表示值类型,涵盖基本 5 大类型
  • encoding : 值的编码方式,表示实行基本类型的底层数据结构
  • lru : 记录对象最后一次被访问的时间,用于淘汰过期数据
  • refconut : 记录对象的引用计数
  • *ptr : 指向数据的指针,通过该指针指向不同的数据类型

开发一个新数据类型

  1. 定义一个新数据类型底层结构、type、encoding 属性值
  2. 实现新数据类型的创建,释放函数和基本操作命令

定义一个新类型 NewTypeNode

定义新数据类型的底层结构

使用newtype.h 定义新类型结构,代码如下

struct NewTypeObject {
    struct NewTypeNode *head; 
    size_t len; 
}NewTypeObject;

其中 NewTypeNode 结构就是自定义的新类型底层结构,包含一个Long类型的value,保存实际数据;一个 *next 指针,指向下一个 NewTypeNode 结构

struct NewTypeNode {
    long value;
    struct NewTypeNode *next;
};

在RedisObject 的 type 属性中增加新类型的定义

定义在Redis中的 server.h 文件中,定义一个 OBJ_NEWTYPE 的宏指代NewTypeObject

#define OBJ_STRING 0    /* String object. */
#define OBJ_LIST 1      /* List object. */
#define OBJ_SET 2       /* Set object. */
#define OBJ_ZSET 3      /* Sorted set object. */
…
#define OBJ_NEWTYPE 7

开发新类型的创建和释放函数

创建函数

robj *createNewTypeObject(void){
   // 初始化内存机构
   NewTypeObject *h = newtypeNew(); 
   // RedisObject 默认的创建函数
   robj *o = createObject(OBJ_NEWTYPE,h);
   return o;
}

初始化内存结构,通过使用zmalloc做底层的结构分配,Redis 默认会为每个数据结构定义一个默认的单独文件 t_newtype.c

NewTypeObject *newtypeNew(void){
    NewTypeObject *n = zmalloc(sizeof(*n));
    n->head = NULL;
    n->len = 0;
    return n;
}

createObject 是 Redis 本身提供的 RedisObject 创建函数,它的参数是数据类型的 type 和指向数据类型实现的指针*ptr


robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;
    o->ptr = ptr;
    ...
    return o;
}

释放函数,是创建函数的反过程,使用 zfree 释放内存空间

开发新类型的命令操作

  • 在 t_newtype.c 文件中增加命令操作的实现
void ntinsertCommand(client *c){
  //基于客户端传递的参数,实现在NewTypeObject链表头插入元素
}
  • 在 server.h 文件中,声明我们已经实现的命令,以便在 server.c 文件引用这个命令
void ntinsertCommand(client *c)
  • 在 server.c 文件中的 redisCommandTable 里面,把新增命令和实现函数关联起来
struct redisCommand redisCommandTable[] = { 
...
{"ntinsert",ntinsertCommand,2,"m",...}
}