sds.h sds.c 源码阅读 动态字符串
This commit is contained in:
parent
4930d19e70
commit
37273e0dd8
@ -95,7 +95,7 @@ protected-mode yes
|
||||
|
||||
# Accept connections on the specified port, default is 6379 (IANA #815344).
|
||||
# If port 0 is specified Redis will not listen on a TCP socket.
|
||||
port 6379
|
||||
port 16379
|
||||
|
||||
# TCP listen() backlog.
|
||||
#
|
||||
|
78
src/sds.c
78
src/sds.c
@ -38,9 +38,15 @@
|
||||
#include <limits.h>
|
||||
#include "sds.h"
|
||||
#include "sdsalloc.h"
|
||||
|
||||
/**
|
||||
* 常量
|
||||
*/
|
||||
const char *SDS_NOINIT = "SDS_NOINIT";
|
||||
|
||||
/**
|
||||
* 获取sds类型结构占用的内存大小
|
||||
* @param type sds的类型
|
||||
* @return 内存大小
|
||||
*/
|
||||
static inline int sdsHdrSize(char type) {
|
||||
switch(type&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
@ -56,23 +62,39 @@ static inline int sdsHdrSize(char type) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过sds字符串长度获取sds类型
|
||||
* @param string_size 字符串长度
|
||||
* @return 字符串类型
|
||||
*/
|
||||
static inline char sdsReqType(size_t string_size) {
|
||||
//string_size < 2^5 = string_size < 32
|
||||
if (string_size < 1<<5)
|
||||
return SDS_TYPE_5;
|
||||
// 32 <= string_size < 256
|
||||
if (string_size < 1<<8)
|
||||
return SDS_TYPE_8;
|
||||
// 256 <= string_size < 65536(64K)
|
||||
if (string_size < 1<<16)
|
||||
return SDS_TYPE_16;
|
||||
// LONG_MAX == LLONG_MAX = 8 代表64位系统
|
||||
#if (LONG_MAX == LLONG_MAX)
|
||||
if (string_size < 1ll<<32)
|
||||
return SDS_TYPE_32;
|
||||
return SDS_TYPE_64;
|
||||
#else
|
||||
// 65536(64K) <= string_size < 4GB
|
||||
if (string_size < 1ll<<32)
|
||||
return SDS_TYPE_32;
|
||||
// 4G <= string_size
|
||||
return SDS_TYPE_64;
|
||||
#else
|
||||
//32位系统
|
||||
return SDS_TYPE_32;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取sds字符串在该类型中的允许的最大长度
|
||||
* @param type 类型
|
||||
* @return 长度
|
||||
*/
|
||||
static inline size_t sdsTypeMaxSize(char type) {
|
||||
if (type == SDS_TYPE_5)
|
||||
return (1<<5) - 1;
|
||||
@ -81,9 +103,11 @@ static inline size_t sdsTypeMaxSize(char type) {
|
||||
if (type == SDS_TYPE_16)
|
||||
return (1<<16) - 1;
|
||||
#if (LONG_MAX == LLONG_MAX)
|
||||
//预编译命令 代表64位系统
|
||||
if (type == SDS_TYPE_32)
|
||||
return (1ll<<32) - 1;
|
||||
#endif
|
||||
//-1 相当于最大的 SDS_TYPE_64 或者 SDS_TYPE_32
|
||||
return -1; /* this is equivalent to the max SDS_TYPE_64 or SDS_TYPE_32 */
|
||||
}
|
||||
|
||||
@ -100,31 +124,53 @@ static inline size_t sdsTypeMaxSize(char type) {
|
||||
* You can print the string with printf() as there is an implicit \0 at the
|
||||
* end of the string. However the string is binary safe and can contain
|
||||
* \0 characters in the middle, as the length is stored in the sds header. */
|
||||
/**
|
||||
* 用于创建sds字符串
|
||||
* const void *init 代表任何类型的值
|
||||
* @param init init指针 init 代表任何类型的值,值为常量,无法修改其值,但是可以其使指针指向其他对象
|
||||
* @param initlen 字符串长度
|
||||
* @param trymalloc 分配的buf大小
|
||||
* @return sds字符串
|
||||
*/
|
||||
sds _sdsnewlen(const void *init, size_t initlen, int trymalloc) {
|
||||
void *sh;
|
||||
sds s;
|
||||
//通过sds字符串长度获取sds类型
|
||||
char type = sdsReqType(initlen);
|
||||
/* Empty strings are usually created in order to append. Use type 8
|
||||
* since type 5 is not good at this. */
|
||||
// 如果类型SDS_TYPE_5 并且长度位0 则类型设置为 SDS_TYPE_8 ,空的字符串通常使用类型SDS_TYPE_8,以便于追加字符,
|
||||
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
|
||||
//sds 的类型占用的内存的大小
|
||||
int hdrlen = sdsHdrSize(type);
|
||||
//定义flags标识 标识sds的buf属性
|
||||
unsigned char *fp; /* flags pointer. */
|
||||
size_t usable;
|
||||
|
||||
//断言 字符串长度 + 类型占用的长度 + 1 > 字符串长度
|
||||
assert(initlen + hdrlen + 1 > initlen); /* Catch size_t overflow */
|
||||
// 分配内存的大小 sh如果为NULL则分配失败 否则usable为分配的可用内存大小
|
||||
sh = trymalloc?
|
||||
s_trymalloc_usable(hdrlen+initlen+1, &usable) :
|
||||
s_malloc_usable(hdrlen+initlen+1, &usable);
|
||||
//如果分配内存失败则返回 NULL
|
||||
if (sh == NULL) return NULL;
|
||||
// 如果init==SDS_NOINIT(这里判断地址是否相同),设置init为NULL
|
||||
if (init==SDS_NOINIT)
|
||||
init = NULL;
|
||||
else if (!init)
|
||||
// 清空内存内容
|
||||
memset(sh, 0, hdrlen+initlen+1);
|
||||
// c字符串
|
||||
s = (char*)sh+hdrlen;
|
||||
// 标志位(sdshdr_xx中flags)
|
||||
fp = ((unsigned char*)s)-1;
|
||||
//字符串可用内存大小 = 分配的内存大小-sds结构大小-1
|
||||
usable = usable-hdrlen-1;
|
||||
//判断可用内存大小 是否大于该类型最大可用大小
|
||||
if (usable > sdsTypeMaxSize(type))
|
||||
//是的话分配该类型最大可用内存大小
|
||||
usable = sdsTypeMaxSize(type);
|
||||
// 根据得到的sds类型设置头部信息
|
||||
switch(type) {
|
||||
case SDS_TYPE_5: {
|
||||
*fp = type | (initlen << SDS_TYPE_BITS);
|
||||
@ -159,16 +205,28 @@ sds _sdsnewlen(const void *init, size_t initlen, int trymalloc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 拷贝字符串到sds字符串中
|
||||
if (initlen && init)
|
||||
memcpy(s, init, initlen);
|
||||
// 设置标准结束符
|
||||
s[initlen] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建sds字符串
|
||||
* @param init 任意类型的值 常量 值不可更改 但指针可以更改指向的对象
|
||||
* @param initlen
|
||||
* @return 字符串
|
||||
*/
|
||||
sds sdsnewlen(const void *init, size_t initlen) {
|
||||
return _sdsnewlen(init, initlen, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param init 任意类型的值
|
||||
* @param initlen
|
||||
* @return
|
||||
*/
|
||||
sds sdstrynewlen(const void *init, size_t initlen) {
|
||||
return _sdsnewlen(init, initlen, 1);
|
||||
}
|
||||
|
84
src/sds.h
84
src/sds.h
@ -29,7 +29,9 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* redis 动态字符串
|
||||
*/
|
||||
#ifndef __SDS_H
|
||||
#define __SDS_H
|
||||
|
||||
@ -39,57 +41,95 @@ extern const char *SDS_NOINIT;
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* sds 类型是 char * 的别名
|
||||
*/
|
||||
typedef char *sds;
|
||||
|
||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
// 根据存储的内容选择不同数据结构,以节省内存
|
||||
// 这里的 '__attribute__ ((__packed__))' 要求编译器取消内存对齐优化,按照实际的占用字节数进行对齐
|
||||
// string_size < 32
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
/**
|
||||
* 前 5 位保存字符串长度,后 3 位保存类型值
|
||||
*/
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
//实际保存字符串数据的地方以及末尾的一个 \0
|
||||
char buf[];
|
||||
};
|
||||
// 32 <= string_size < 256
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
/* 记录当前 buf 的长度(不包含 '\0') */
|
||||
uint8_t len; /* used */
|
||||
/* 记录当前 buf 总共分配的内存大小(不包含 '\0') */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
/* 记录当前 buf 的属性,用来标识到底是 sdshdr8 还是 sdshdr16 等 */
|
||||
unsigned char flags;
|
||||
// 实际保存字符串数据的地方以及末尾的一个 \0
|
||||
char buf[];
|
||||
};
|
||||
// 256 <= string_size < 65536(64K)
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
// 记录当前 buf 的长度(不包含 '\0')
|
||||
uint16_t len; /* used */
|
||||
// 记录当前 buf 总共分配的内存大小(不包含 '\0'
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
//记录当前 buf 的属性,用来标识到底是 sdshdr8 还是 sdshdr16 等
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
// 实际保存字符串数据的地方以及末尾的一个 \0
|
||||
char buf[];
|
||||
};
|
||||
// 65536(64K) <= string_size < 4GB
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
//记录当前 buf 的长度(不包含 '\0')
|
||||
uint32_t len; /* used */
|
||||
//记录当前 buf 总共分配的内存大小(不包含 '\0')
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
//记录当前 buf 的属性等
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
// 实际保存字符串数据的地方以及末尾的一个 \0
|
||||
char buf[];
|
||||
};
|
||||
// 4G <= string_size
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
//记录当前 buf 的长度(不包含 '\0')
|
||||
uint64_t len; /* used */
|
||||
//记录当前 buf 总共分配的内存大小(不包含 '\0')
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
//记录当前 buf 的属性等
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
// 实际保存字符串数据的地方以及末尾的一个 \0
|
||||
char buf[];
|
||||
};
|
||||
|
||||
// flags 值的定义
|
||||
#define SDS_TYPE_5 0
|
||||
#define SDS_TYPE_8 1
|
||||
#define SDS_TYPE_16 2
|
||||
#define SDS_TYPE_32 3
|
||||
#define SDS_TYPE_64 4
|
||||
// 掩码,flags & SDS_TYPE_MASK 即可获得具体的 flags 值
|
||||
#define SDS_TYPE_MASK 7
|
||||
|
||||
#define SDS_TYPE_BITS 3
|
||||
// 这里的 s 是一个 sds
|
||||
// 可以通过 sds 的头指针进行寻址,拿到整个 struct 的指针
|
||||
// buf[-1]的值是flags的值 存的值再内存中是连续的 (len alloc flags buf)
|
||||
#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))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
//判断字符串长度 inline内联
|
||||
static inline size_t sdslen(const sds s) {
|
||||
// 通过 buf 的 -1 下标获取 flags 的值
|
||||
unsigned char flags = s[-1];
|
||||
//SDS_TYPE_MASK = 7 flags&SDS_TYPE_MASK运算获取flags具体的值
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
//flags的值 flags >> 3
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
//SDS_HDR(8,s) == ((struct sdshdr8 *)((s)-(sizeof(struct sdshdrT8)))->len sdshdr8的len方法
|
||||
return SDS_HDR(8,s)->len;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->len;
|
||||
@ -100,13 +140,16 @@ static inline size_t sdslen(const sds s) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//sds可用长度
|
||||
static inline size_t sdsavail(const sds s) {
|
||||
//s[-1]的值是flags的值, 要求编译器取消内存对齐优化,按照实际的占用字节数进行对齐,buf的前面是flags
|
||||
unsigned char flags = s[-1];
|
||||
//flags&SDS_TYPE_MASK运算获取flags具体的值
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
return 0;
|
||||
}
|
||||
//sh->alloc - sh->len; 分配内存大小减去字符串长度
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
return sh->alloc - sh->len;
|
||||
@ -126,13 +169,19 @@ static inline size_t sdsavail(const sds s) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//给sds设置新的长度
|
||||
static inline void sdssetlen(sds s, size_t newlen) {
|
||||
//获取flags的值
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
/**
|
||||
* 位或| 二进制中只要有一个为1 就位1 10010 | 01100 = 11110
|
||||
* 左移 << newlen << 3 = newlen * 2^3 = newlen * 8
|
||||
*/
|
||||
//0 | newlen * 8 = newlen * 8
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
@ -150,7 +199,11 @@ static inline void sdssetlen(sds s, size_t newlen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加sds字符串长度
|
||||
* @param s 字符串
|
||||
* @param inc 新的长度
|
||||
*/
|
||||
static inline void sdsinclen(sds s, size_t inc) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
@ -175,12 +228,17 @@ static inline void sdsinclen(sds s, size_t inc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*内存占用空间 = 可用空间 + 字符串长度
|
||||
* @param s 字符串
|
||||
* @return
|
||||
*/
|
||||
/* sdsalloc() = sdsavail() + sdslen() */
|
||||
static inline size_t sdsalloc(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
//flags >> 3 = flags / 8
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->alloc;
|
||||
@ -193,14 +251,20 @@ static inline size_t sdsalloc(const sds s) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字符串的分配的内存
|
||||
* @param s 字符串
|
||||
* @param newlen 新的长度
|
||||
*/
|
||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
//选择那种字符串类型
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
//设置字符串buf内存 sds->alloc = newlen
|
||||
SDS_HDR(8,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
|
@ -93,7 +93,12 @@ static void zmalloc_default_oom(size_t size) {
|
||||
}
|
||||
|
||||
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
|
||||
|
||||
/**
|
||||
* 尝试分配内存 返回如果为NULL则分配内存失败,否则*usable设置为可用内存大小
|
||||
* @param size
|
||||
* @param usable
|
||||
* @return
|
||||
*/
|
||||
/* Try allocating memory, and return NULL if failed.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *ztrymalloc_usable(size_t size, size_t *usable) {
|
||||
@ -134,7 +139,12 @@ void *zmalloc_usable(size_t size, size_t *usable) {
|
||||
if (!ptr) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配内存 如果返回值为NULL则分配内存失败 否则*usable 设置为可用内存大小
|
||||
* @param size
|
||||
* @param usable
|
||||
* @return
|
||||
*/
|
||||
/* Allocation and free functions that bypass the thread cache
|
||||
* and go straight to the allocator arena bins.
|
||||
* Currently implemented only for jemalloc. Used for online defragmentation. */
|
||||
|
Loading…
Reference in New Issue
Block a user