sds.h sds.c 源码阅读 动态字符串

This commit is contained in:
zhuyijun 2021-11-06 12:16:21 +08:00
parent 4930d19e70
commit 37273e0dd8
4 changed files with 155 additions and 23 deletions

View File

@ -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.
#

View File

@ -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);
}

View File

@ -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:

View File

@ -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. */