Redis中的对象编码(Object Encoding)是指Redis内部用来表示不同数据类型的具体存储结构和方式。不同的编码方式有其特定的适用场景,以便在不同的使用情况下,能够在性能和内存利用方面做最佳平衡。
Redis支持的对象类型包括:字符串(String)、列表(List)、集合(Set)、有序集合(Sorted Set)和哈希(Hash)。每种对象类型都有多种编码方式。
字符串(String)
编码方式:
- RAW:普通字符串。
- EMBSTR:短字符串(长度小于等于39字节)采用这种编码方式。
- INT:可以表示为64位整数的字符串。
代码实现示例:
c
robj *createStringObject(char *ptr, size_t len) {
robj *o = zmalloc(sizeof(robj));
if (len <= 39) {
o->type = OBJ_STRING;
o->encoding = OBJ_ENCODING_EMBSTR;
o->ptr = zmalloc(sizeof(struct sdshdr) + len + 1);
struct sdshdr *sh = (void*)(o->ptr);
sh->len = len;
sh->alloc = len;
sh->flags = SDS_TYPE_8;
memcpy(sh->buf, ptr, len);
sh->buf[len] = '\0';
} else {
o->type = OBJ_STRING;
o->encoding = OBJ_ENCODING_RAW;
o->ptr = sdsnewlen(ptr, len);
}
o->refcount = 1;
return o;
}
列表(List)
编码方式:
- ZIPLIST:适用于小型列表。
- LINKEDLIST:适用于大型列表。
代码实现示例:
c
robj *createListObject(void) {
list *l = listCreate();
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_LIST;
o->encoding = OBJ_ENCODING_LINKEDLIST;
o->ptr = l;
o->refcount = 1;
return o;
}
robj *createZiplistObject(void) {
unsigned char *zl = ziplistNew();
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_LIST;
o->encoding = OBJ_ENCODING_ZIPLIST;
o->ptr = zl;
o->refcount = 1;
return o;
}
集合(Set)
编码方式:
- INTSET:适用于整数值集合。
- HT(Hash Table):适用于大型集合,或包含非整数值的集合。
代码实现示例:
c
robj *createSetObject(void) {
dict *d = dictCreate(&setDictType, NULL);
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_SET;
o->encoding = OBJ_ENCODING_HT;
o->ptr = d;
o->refcount = 1;
return o;
}
robj *createIntsetObject(void) {
intset *is = intsetNew();
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_SET;
o->encoding = OBJ_ENCODING_INTSET;
o->ptr = is;
o->refcount = 1;
return o;
}
有序集合(Sorted Set)
编码方式:
- ZIPLIST:适用于小型有序集合。
- SKIPLIST:适用于大型有序集合。
代码实现示例:
c
robj *createZsetObject(void) {
zset *zs = zmalloc(sizeof(zset));
zs->dict = dictCreate(&zsetDictType, NULL);
zs->zsl = zslCreate();
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_ZSET;
o->encoding = OBJ_ENCODING_SKIPLIST;
o->ptr = zs;
o->refcount = 1;
return o;
}
robj *createZsetZiplistObject(void) {
unsigned char *zl = ziplistNew();
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_ZSET;
o->encoding = OBJ_ENCODING_ZIPLIST;
o->ptr = zl;
o->refcount = 1;
return o;
}
哈希(Hash)
编码方式:
- ZIPLIST:适用于小型哈希。
- HT(Hash Table):适用于大型哈希。
代码实现示例:
c
robj *createHashObject(void) {
dict *d = dictCreate(&hashDictType, NULL);
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_HASH;
o->encoding = OBJ_ENCODING_HT;
o->ptr = d;
o->refcount = 1;
return o;
}
robj *createHashZiplistObject(void) {
unsigned char *zl = ziplistNew();
robj *o = zmalloc(sizeof(robj));
o->type = OBJ_HASH;
o->encoding = OBJ_ENCODING_ZIPLIST;
o->ptr = zl;
o->refcount = 1;
return o;
}
对象的通用结构
Redis中的对象结构redisObject定义如下:
c
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24;
int refcount;
void *ptr;
} robj;
示例使用
下面是一个简单的示例,展示如何创建和使用不同类型的Redis对象:
c
#include <stdio.h>
#include <string.h>
#include "zmalloc.h"
#include "intset.h"
#include "ziplist.h"
#include "dict.h"
#include "skiplist.h"
#include "robj.h"
int main() {
// 创建字符串对象
robj *strObj = createStringObject("hello", 5);
printf("String object: %s\n", (char*)strObj->ptr);
// 创建整数集合对象
intset *is = intsetNew();
uint8_t success;
is = intsetAdd(is, 100, &success);
is = intsetAdd(is, 200, &success);
robj *setObj = createIntsetObject();
setObj->ptr = is;
printf("Set object with 100 and 200 added.\n");
// 创建压缩列表对象
robj *ziplistObj = createZiplistObject();
unsigned char *zl = ziplistObj->ptr;
zl = ziplistPush(zl, (unsigned char*)"world", 5, ZIPLIST_TAIL);
printf("Ziplist object: %s\n", ziplistIndex(zl, 0));
return 0;
}
总结
Redis对象编码通过多种不同的存储和编码方式,为不同类型的数据提供了灵活高效的存储方案。每种编码方式都有其适用的场景和优点,合理选择合适的编码方式可以有效提升Redis的性能和内存利用率。