源码链接:https://github.com/redis/redis
一、sds.h
?redis实现动态字符串的方法是定义一个结构体分别指明字符串长度、分配长度、类型和字符数组,其中类型用来表示不同长度的结构,如下:
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
由于使用的是C语言编写,所以不能像C++中声明一个类作为所有结构的基类,这里redis采用了计算指针偏移查找变量首地址的方式来实现,这样对于不同的函数来说只要操作一个字符串地址就可以获取它的结构地址,进而获取得到所有的结构信息。通过以上方式就实现了类似继承类中获取同一函数的方法。
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
这里的全局函数有很多,这里以sdslen为栗子,头文件中其余函数也类似:
typedef char *sds;
/* ... ... */
static inline size_t sdslen(const sds s) {
// 对于每一个结构体来说flag都是一个字节,按定义的顺序取其前一个地址的就是flags了
unsigned char flags = s[-1];
// 根据flag标志来判断类型
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->len;
case SDS_TYPE_16:
return SDS_HDR(16,s)->len;
case SDS_TYPE_32:
return SDS_HDR(32,s)->len;
case SDS_TYPE_64:
return SDS_HDR(64,s)->len;
}
return 0;
}
static inline size_t sdsavail(const sds s) { /* ... */ }
static inline void sdssetlen(sds s, size_t newlen) { /* ... */ }
static inline void sdsinclen(sds s, size_t inc) { /* ... */ }
static inline size_t sdsalloc(const sds s) { /* ... */ }
// 其中alloc = avail + len
static inline void sdssetalloc(sds s, size_t newlen) { /* ... */ }
二、sds.c
?
|