sds(简单动态字符串)是redis底层的字符串表示,它具有字符串对象化和替代char*的作用。数据库中的值类型包括字符串,哈希表,列表,集合和有序集合,但是键类型却总是字符串。
typedef char *sds;
struct sdshdr {
// buf 已占用长度
int len;
// buf 剩余可用长度
int free;
// 实际保存字符串数据的地方
char buf[];
};
redis构建了自己的类型系统,所有的键、值、参数都是有类型的,在redis中用redisObject结构表示:
/*
* Redis 对象
*/
typedef struct redisObject {
// 类型
unsigned type:4;
// 对齐位
unsigned notused:2;
// 编码方式
unsigned encoding:4;
// LRU 时间(相对于server.lruclock)
unsigned lru:22;
// 引用计数
int refcount;
// 指向对象的值
void *ptr;
} robj;
string类型的每个具体值都由一个redisObject进行描述,它可以表示一个字符串或整数,分别使用REDIS_ENCODING_INT 和REDIS_ENCODING_RAW 两种编码(redis不直接存储数据结构而是通过编码转化成内存映射模型使用)。前者用于保存long类型数据,后者用来保存sds/char*,long long,long double,double类型数据。字符串类型基本上就是通过sds数据结构的操作函数来实现的,这里仅举个简单例子,其它没啥好说的。
/*
* 在指定字符串后追加字符串并指明增加的内存空间
*/
sds sdscatlen(sds s, const void *t, size_t len) {
//申明字符串sh
struct sdshdr *sh;
//获取参数s的长度
size_t curlen = sdslen(s);
//为s新增内存空间
s = sdsMakeRoomFor(s,len);
//未分配成功则返回null
if (s == NULL) return NULL;
//使sh指向重新分配内存后的s的基址
sh = (void*) (s-(sizeof(struct sdshdr)));
//将t复制到s的结尾
memcpy(s+curlen, t, len);
//设置sh的长度变量和剩余可用长度
sh->len = curlen+len;
sh->free = sh->free-len;
//末尾添加‘\0’结尾符
s[curlen+len] = '\0';
return s;
}