Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xindoo
redis
提交
f15df8ba
R
redis
项目概览
xindoo
/
redis
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
f15df8ba
编写于
4月 09, 2015
作者:
O
Oran Agra
提交者:
antirez
7月 14, 2015
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
sds size classes - memory optimization
上级
0f64080d
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
364 addition
and
139 deletion
+364
-139
src/Makefile
src/Makefile
+1
-1
src/debug.c
src/debug.c
+4
-1
src/networking.c
src/networking.c
+13
-20
src/object.c
src/object.c
+5
-4
src/redis-cli.c
src/redis-cli.c
+2
-2
src/scripting.c
src/scripting.c
+4
-8
src/sds.c
src/sds.c
+195
-94
src/sds.h
src/sds.h
+140
-9
未找到文件。
src/Makefile
浏览文件 @
f15df8ba
...
...
@@ -120,7 +120,7 @@ REDIS_SENTINEL_NAME=redis-sentinel
REDIS_SERVER_OBJ
=
adlist.o quicklist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o geo.o
REDIS_GEOHASH_OBJ
=
../deps/geohash-int/geohash.o ../deps/geohash-int/geohash_helper.o
REDIS_CLI_NAME
=
redis-cli
REDIS_CLI_OBJ
=
anet.o
sds.o
adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_CLI_OBJ
=
anet.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_BENCHMARK_NAME
=
redis-benchmark
REDIS_BENCHMARK_OBJ
=
ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o redis-benchmark.o
REDIS_CHECK_RDB_NAME
=
redis-check-rdb
...
...
src/debug.c
浏览文件 @
f15df8ba
...
...
@@ -423,7 +423,10 @@ void debugCommand(redisClient *c) {
sizes
=
sdscatprintf
(
sizes
,
"bits:%d "
,
(
sizeof
(
void
*
)
==
8
)
?
64
:
32
);
sizes
=
sdscatprintf
(
sizes
,
"robj:%d "
,
(
int
)
sizeof
(
robj
));
sizes
=
sdscatprintf
(
sizes
,
"dictentry:%d "
,
(
int
)
sizeof
(
dictEntry
));
sizes
=
sdscatprintf
(
sizes
,
"sdshdr:%d"
,
(
int
)
sizeof
(
struct
sdshdr
));
sizes
=
sdscatprintf
(
sizes
,
"sdshdr8:%d"
,
(
int
)
sizeof
(
struct
sdshdr8
));
sizes
=
sdscatprintf
(
sizes
,
"sdshdr16:%d"
,
(
int
)
sizeof
(
struct
sdshdr16
));
sizes
=
sdscatprintf
(
sizes
,
"sdshdr32:%d"
,
(
int
)
sizeof
(
struct
sdshdr32
));
sizes
=
sdscatprintf
(
sizes
,
"sdshdr64:%d"
,
(
int
)
sizeof
(
struct
sdshdr64
));
addReplyBulkSds
(
c
,
sizes
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"htstats"
)
&&
c
->
argc
==
3
)
{
long
dbid
;
...
...
src/networking.c
浏览文件 @
f15df8ba
...
...
@@ -33,21 +33,14 @@
static
void
setProtocolError
(
redisClient
*
c
,
int
pos
);
/* To evaluate the output buffer size of a client we need to get size of
* allocated objects, however we can't used zmalloc_size() directly on sds
* strings because of the trick they use to work (the header is before the
* returned pointer), so we use this helper function. */
size_t
zmalloc_size_sds
(
sds
s
)
{
return
zmalloc_size
(
s
-
sizeof
(
struct
sdshdr
));
}
/* Return the amount of memory used by the sds string at object->ptr
* for a string object. */
size_t
getStringObjectSdsUsedMemory
(
robj
*
o
)
{
redisAssertWithInfo
(
NULL
,
o
,
o
->
type
==
REDIS_STRING
);
switch
(
o
->
encoding
)
{
case
REDIS_ENCODING_RAW
:
return
zmalloc_size_sds
(
o
->
ptr
);
case
REDIS_ENCODING_EMBSTR
:
return
sdslen
(
o
->
ptr
);
case
REDIS_ENCODING_RAW
:
return
sdsZmallocSize
(
o
->
ptr
);
case
REDIS_ENCODING_EMBSTR
:
return
zmalloc_size
(
o
)
-
sizeof
(
robj
);
default:
return
0
;
/* Just integer encoding for now. */
}
}
...
...
@@ -235,10 +228,10 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
tail
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
tail
->
ptr
)
+
sdslen
(
o
->
ptr
)
<=
REDIS_REPLY_CHUNK_BYTES
)
{
c
->
reply_bytes
-=
zmalloc_size_sds
(
tail
->
ptr
);
c
->
reply_bytes
-=
sdsZmallocSize
(
tail
->
ptr
);
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
o
->
ptr
,
sdslen
(
o
->
ptr
));
c
->
reply_bytes
+=
zmalloc_size_sds
(
tail
->
ptr
);
c
->
reply_bytes
+=
sdsZmallocSize
(
tail
->
ptr
);
}
else
{
incrRefCount
(
o
);
listAddNodeTail
(
c
->
reply
,
o
);
...
...
@@ -260,7 +253,7 @@ void _addReplySdsToList(redisClient *c, sds s) {
if
(
listLength
(
c
->
reply
)
==
0
)
{
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
c
->
reply_bytes
+=
zmalloc_size_sds
(
s
);
c
->
reply_bytes
+=
sdsZmallocSize
(
s
);
}
else
{
tail
=
listNodeValue
(
listLast
(
c
->
reply
));
...
...
@@ -268,14 +261,14 @@ void _addReplySdsToList(redisClient *c, sds s) {
if
(
tail
->
ptr
!=
NULL
&&
tail
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
tail
->
ptr
)
+
sdslen
(
s
)
<=
REDIS_REPLY_CHUNK_BYTES
)
{
c
->
reply_bytes
-=
zmalloc_size_sds
(
tail
->
ptr
);
c
->
reply_bytes
-=
sdsZmallocSize
(
tail
->
ptr
);
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
s
,
sdslen
(
s
));
c
->
reply_bytes
+=
zmalloc_size_sds
(
tail
->
ptr
);
c
->
reply_bytes
+=
sdsZmallocSize
(
tail
->
ptr
);
sdsfree
(
s
);
}
else
{
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
c
->
reply_bytes
+=
zmalloc_size_sds
(
s
);
c
->
reply_bytes
+=
sdsZmallocSize
(
s
);
}
}
asyncCloseClientOnOutputBufferLimitReached
(
c
);
...
...
@@ -298,10 +291,10 @@ void _addReplyStringToList(redisClient *c, const char *s, size_t len) {
if
(
tail
->
ptr
!=
NULL
&&
tail
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
tail
->
ptr
)
+
len
<=
REDIS_REPLY_CHUNK_BYTES
)
{
c
->
reply_bytes
-=
zmalloc_size_sds
(
tail
->
ptr
);
c
->
reply_bytes
-=
sdsZmallocSize
(
tail
->
ptr
);
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
s
,
len
);
c
->
reply_bytes
+=
zmalloc_size_sds
(
tail
->
ptr
);
c
->
reply_bytes
+=
sdsZmallocSize
(
tail
->
ptr
);
}
else
{
robj
*
o
=
createStringObject
(
s
,
len
);
...
...
@@ -440,16 +433,16 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
len
=
listNodeValue
(
ln
);
len
->
ptr
=
sdscatprintf
(
sdsempty
(),
"*%ld
\r\n
"
,
length
);
len
->
encoding
=
REDIS_ENCODING_RAW
;
/* in case it was an EMBSTR. */
c
->
reply_bytes
+=
zmalloc_size_sds
(
len
->
ptr
);
c
->
reply_bytes
+=
sdsZmallocSize
(
len
->
ptr
);
if
(
ln
->
next
!=
NULL
)
{
next
=
listNodeValue
(
ln
->
next
);
/* Only glue when the next node is non-NULL (an sds in this case) */
if
(
next
->
ptr
!=
NULL
)
{
c
->
reply_bytes
-=
zmalloc_size_sds
(
len
->
ptr
);
c
->
reply_bytes
-=
sdsZmallocSize
(
len
->
ptr
);
c
->
reply_bytes
-=
getStringObjectSdsUsedMemory
(
next
);
len
->
ptr
=
sdscatlen
(
len
->
ptr
,
next
->
ptr
,
sdslen
(
next
->
ptr
));
c
->
reply_bytes
+=
zmalloc_size_sds
(
len
->
ptr
);
c
->
reply_bytes
+=
sdsZmallocSize
(
len
->
ptr
);
listDelNode
(
c
->
reply
,
ln
->
next
);
}
}
...
...
src/object.c
浏览文件 @
f15df8ba
...
...
@@ -58,8 +58,8 @@ robj *createRawStringObject(const char *ptr, size_t len) {
* an object where the sds string is actually an unmodifiable string
* allocated in the same chunk as the object itself. */
robj
*
createEmbeddedStringObject
(
const
char
*
ptr
,
size_t
len
)
{
robj
*
o
=
zmalloc
(
sizeof
(
robj
)
+
sizeof
(
struct
sdshdr
)
+
len
+
1
);
struct
sdshdr
*
sh
=
(
void
*
)(
o
+
1
);
robj
*
o
=
zmalloc
(
sizeof
(
robj
)
+
sizeof
(
struct
sdshdr
8
)
+
len
+
1
);
struct
sdshdr
8
*
sh
=
(
void
*
)(
o
+
1
);
o
->
type
=
REDIS_STRING
;
o
->
encoding
=
REDIS_ENCODING_EMBSTR
;
...
...
@@ -68,7 +68,8 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
o
->
lru
=
LRU_CLOCK
();
sh
->
len
=
len
;
sh
->
free
=
0
;
sh
->
alloc
=
len
;
sh
->
flags
=
SDS_TYPE_8
;
if
(
ptr
)
{
memcpy
(
sh
->
buf
,
ptr
,
len
);
sh
->
buf
[
len
]
=
'\0'
;
...
...
@@ -84,7 +85,7 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
*
* The current limit of 39 is chosen so that the biggest string object
* we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT
39
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT
44
robj
*
createStringObject
(
const
char
*
ptr
,
size_t
len
)
{
if
(
len
<=
REDIS_ENCODING_EMBSTR_SIZE_LIMIT
)
return
createEmbeddedStringObject
(
ptr
,
len
);
...
...
src/redis-cli.c
浏览文件 @
f15df8ba
...
...
@@ -46,8 +46,8 @@
#include <limits.h>
#include <math.h>
#include
"hiredis.h"
#include
"sds.h"
#include
<hiredis.h>
#include
<sds.h>
/* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */
#include "zmalloc.h"
#include "linenoise.h"
#include "help.h"
...
...
src/scripting.c
浏览文件 @
f15df8ba
...
...
@@ -265,14 +265,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
if
(
j
<
LUA_CMD_OBJCACHE_SIZE
&&
cached_objects
[
j
]
&&
cached_objects_len
[
j
]
>=
obj_len
)
{
char
*
s
=
cached_objects
[
j
]
->
ptr
;
struct
sdshdr
*
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
sds
s
=
cached_objects
[
j
]
->
ptr
;
argv
[
j
]
=
cached_objects
[
j
];
cached_objects
[
j
]
=
NULL
;
memcpy
(
s
,
obj_s
,
obj_len
+
1
);
sh
->
free
+=
sh
->
len
-
obj_len
;
sh
->
len
=
obj_len
;
sdssetlen
(
s
,
obj_len
);
}
else
{
argv
[
j
]
=
createStringObject
(
obj_s
,
obj_len
);
}
...
...
@@ -422,11 +419,10 @@ cleanup:
o
->
encoding
==
REDIS_ENCODING_EMBSTR
)
&&
sdslen
(
o
->
ptr
)
<=
LUA_CMD_OBJCACHE_MAX_LEN
)
{
struct
sdshdr
*
sh
=
(
void
*
)(((
char
*
)(
o
->
ptr
))
-
(
sizeof
(
struct
sdshdr
)));
sds
s
=
o
->
ptr
;
if
(
cached_objects
[
j
])
decrRefCount
(
cached_objects
[
j
]);
cached_objects
[
j
]
=
o
;
cached_objects_len
[
j
]
=
s
h
->
free
+
sh
->
len
;
cached_objects_len
[
j
]
=
s
dsalloc
(
s
)
;
}
else
{
decrRefCount
(
o
);
}
...
...
src/sds.c
浏览文件 @
f15df8ba
...
...
@@ -36,6 +36,30 @@
#include "sds.h"
#include "zmalloc.h"
static
inline
int
sdsHdrSize
(
char
type
)
{
switch
(
type
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
return
sizeof
(
struct
sdshdr8
);
case
SDS_TYPE_16
:
return
sizeof
(
struct
sdshdr16
);
case
SDS_TYPE_32
:
return
sizeof
(
struct
sdshdr32
);
case
SDS_TYPE_64
:
return
sizeof
(
struct
sdshdr64
);
}
return
0
;
}
static
inline
char
sdsReqType
(
size_t
string_size
)
{
if
(
string_size
<
0xff
)
return
SDS_TYPE_8
;
if
(
string_size
<
0xffff
)
return
SDS_TYPE_16
;
if
(
string_size
<
0xffffffff
)
return
SDS_TYPE_32
;
return
SDS_TYPE_64
;
}
/* Create a new sds string with the content specified by the 'init' pointer
* and 'initlen'.
* If NULL is used for 'init' the string is initialized with zero bytes.
...
...
@@ -49,20 +73,65 @@
* 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
sdsnewlen
(
const
void
*
init
,
size_t
initlen
)
{
struct
sdshdr
*
sh
;
if
(
init
)
{
sh
=
zmalloc
(
sizeof
(
struct
sdshdr
)
+
initlen
+
1
);
}
else
{
sh
=
zcalloc
(
sizeof
(
struct
sdshdr
)
+
initlen
+
1
);
}
void
*
sh
;
sds
s
;
char
type
=
sdsReqType
(
initlen
);
int
hdrlen
=
sdsHdrSize
(
type
);
sh
=
zmalloc
(
hdrlen
+
initlen
+
1
);
if
(
!
init
)
memset
(
sh
,
0
,
hdrlen
+
initlen
+
1
);
if
(
sh
==
NULL
)
return
NULL
;
sh
->
len
=
initlen
;
sh
->
free
=
0
;
s
=
(
char
*
)
sh
+
hdrlen
;
switch
(
type
)
{
case
SDS_TYPE_8
:
{
SDS_HDR_VAR
(
8
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
break
;
}
case
SDS_TYPE_16
:
{
SDS_HDR_VAR
(
16
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
break
;
}
case
SDS_TYPE_32
:
{
SDS_HDR_VAR
(
32
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
break
;
}
case
SDS_TYPE_64
:
{
SDS_HDR_VAR
(
64
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
break
;
}
}
s
[
-
1
]
=
type
;
if
(
initlen
&&
init
)
memcpy
(
sh
->
buf
,
init
,
initlen
);
sh
->
buf
[
initlen
]
=
'\0'
;
return
(
char
*
)
sh
->
buf
;
memcpy
(
s
,
init
,
initlen
);
s
[
initlen
]
=
'\0'
;
return
s
;
}
void
sdsIncRefcount
(
sds
s
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
refs
=
flags
>>
SDS_TYPE_BITS
;
assert
(
++
refs
);
s
[
-
1
]
=
(
refs
<<
SDS_TYPE_BITS
)
|
(
flags
&
SDS_TYPE_MASK
);
}
void
sdsDecRefcount
(
sds
s
)
{
unsigned
char
flags
=
s
[
-
1
];
void
*
sh
=
(
char
*
)
s
-
sdsHdrSize
(
s
[
-
1
]);
unsigned
refs
=
flags
>>
SDS_TYPE_BITS
;
assert
(
refs
);
if
(
!
(
--
refs
))
zfree
(
sh
);
else
s
[
-
1
]
=
(
refs
<<
SDS_TYPE_BITS
)
|
(
flags
&
SDS_TYPE_MASK
);
}
/* Create an empty (zero length) sds string. Even in this case the string
...
...
@@ -85,7 +154,7 @@ sds sdsdup(const sds s) {
/* Free an sds string. No operation is performed if 's' is NULL. */
void
sdsfree
(
sds
s
)
{
if
(
s
==
NULL
)
return
;
zfree
(
s
-
sizeof
(
struct
sdshdr
));
zfree
(
(
char
*
)
s
-
sdsHdrSize
(
s
[
-
1
]
));
}
/* Set the sds string length to the length as obtained with strlen(), so
...
...
@@ -103,10 +172,8 @@ void sdsfree(sds s) {
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
void
sdsupdatelen
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
int
reallen
=
strlen
(
s
);
sh
->
free
+=
(
sh
->
len
-
reallen
);
sh
->
len
=
reallen
;
sdssetlen
(
s
,
reallen
);
}
/* Modify an sds string in-place to make it empty (zero length).
...
...
@@ -114,10 +181,8 @@ void sdsupdatelen(sds s) {
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
void
sdsclear
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
sh
->
free
+=
sh
->
len
;
sh
->
len
=
0
;
sh
->
buf
[
0
]
=
'\0'
;
sdssetlen
(
s
,
0
);
s
[
0
]
=
'\0'
;
}
/* Enlarge the free space at the end of the sds string so that the caller
...
...
@@ -127,23 +192,41 @@ void sdsclear(sds s) {
* Note: this does not change the *length* of the sds string as returned
* by sdslen(), but only the free buffer space we have. */
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
)
{
struct
sdshdr
*
sh
,
*
newsh
;
size_t
free
=
sdsavail
(
s
);
void
*
sh
,
*
newsh
;
size_t
avail
=
sdsavail
(
s
);
size_t
len
,
newlen
;
char
type
,
oldtype
=
s
[
-
1
];
int
hdrlen
;
if
(
free
>=
addlen
)
return
s
;
if
(
avail
>=
addlen
)
return
s
;
len
=
sdslen
(
s
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
))
);
sh
=
(
char
*
)
s
-
sdsHdrSize
(
oldtype
);
newlen
=
(
len
+
addlen
);
if
(
newlen
<
SDS_MAX_PREALLOC
)
newlen
*=
2
;
else
newlen
+=
SDS_MAX_PREALLOC
;
newsh
=
zrealloc
(
sh
,
sizeof
(
struct
sdshdr
)
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
newsh
->
free
=
newlen
-
len
;
return
newsh
->
buf
;
assert
(
!
(
s
[
-
1
]
>>
SDS_TYPE_BITS
));
/* verify that the ref count is 0 (non ref count managed string) */
type
=
sdsReqType
(
newlen
);
hdrlen
=
sdsHdrSize
(
type
);
if
(
oldtype
==
type
)
{
newsh
=
zrealloc
(
sh
,
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
s
=
(
char
*
)
newsh
+
hdrlen
;
}
else
{
/* since the header size changes, need to move the string forward, and can't use realloc */
newsh
=
zmalloc
(
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
zfree
(
sh
);
s
=
(
char
*
)
newsh
+
hdrlen
;
s
[
-
1
]
=
type
;
sdssetlen
(
s
,
len
);
}
sdssetalloc
(
s
,
newlen
);
s
[
-
1
]
=
type
;
return
s
;
}
/* Reallocate the sds string so that it has no free space at the end. The
...
...
@@ -153,12 +236,31 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds
sdsRemoveFreeSpace
(
sds
s
)
{
struct
sdshdr
*
sh
;
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
sh
=
zrealloc
(
sh
,
sizeof
(
struct
sdshdr
)
+
sh
->
len
+
1
);
sh
->
free
=
0
;
return
sh
->
buf
;
void
*
sh
,
*
newsh
;
char
type
,
oldtype
=
s
[
-
1
];
int
hdrlen
;
size_t
len
=
sdslen
(
s
);
sh
=
(
char
*
)
s
-
sdsHdrSize
(
oldtype
);
type
=
sdsReqType
(
len
);
hdrlen
=
sdsHdrSize
(
type
);
if
(
oldtype
==
type
)
{
newsh
=
zrealloc
(
sh
,
hdrlen
+
len
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
s
=
(
char
*
)
newsh
+
hdrlen
;
}
else
{
newsh
=
zmalloc
(
hdrlen
+
len
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
zfree
(
sh
);
s
=
(
char
*
)
newsh
+
hdrlen
;
s
[
-
1
]
=
type
;
sdssetlen
(
s
,
len
);
}
sdssetalloc
(
s
,
len
);
assert
(
!
(
s
[
-
1
]
>>
SDS_TYPE_BITS
));
/* verify that the ref count is 0 (non ref count managed string) */
s
[
-
1
]
=
type
;
return
s
;
}
/* Return the total size of the allocation of the specifed sds string,
...
...
@@ -169,9 +271,15 @@ sds sdsRemoveFreeSpace(sds s) {
* 4) The implicit null term.
*/
size_t
sdsAllocSize
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
alloc
=
sdsalloc
(
s
);
return
sdsHdrSize
(
s
[
-
1
])
+
alloc
+
1
;
}
return
sizeof
(
*
sh
)
+
sh
->
len
+
sh
->
free
+
1
;
/* Return the size consumed from the allocator,
* including internal fragmentation */
size_t
sdsZmallocSize
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sdsHdrSize
(
s
[
-
1
]));
return
zmalloc_size
(
sh
);
}
/* Increment the sds length and decrements the left free space at the
...
...
@@ -198,15 +306,35 @@ size_t sdsAllocSize(sds s) {
* sdsIncrLen(s, nread);
*/
void
sdsIncrLen
(
sds
s
,
int
incr
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
if
(
incr
>=
0
)
assert
(
sh
->
free
>=
(
unsigned
int
)
incr
);
else
assert
(
sh
->
len
>=
(
unsigned
int
)(
-
incr
));
sh
->
len
+=
incr
;
sh
->
free
-=
incr
;
s
[
sh
->
len
]
=
'\0'
;
char
flags
=
s
[
-
1
];
size_t
len
;
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
{
SDS_HDR_VAR
(
8
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
case
SDS_TYPE_16
:
{
SDS_HDR_VAR
(
16
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
case
SDS_TYPE_32
:
{
SDS_HDR_VAR
(
32
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
unsigned
int
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
case
SDS_TYPE_64
:
{
SDS_HDR_VAR
(
64
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
uint64_t
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
uint64_t
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
}
s
[
len
]
=
'\0'
;
}
/* Grow the sds to have the specified length. Bytes that were not part of
...
...
@@ -215,19 +343,15 @@ void sdsIncrLen(sds s, int incr) {
* if the specified length is smaller than the current length, no operation
* is performed. */
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
struct
sdshdr
*
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
totlen
,
curlen
=
sh
->
len
;
size_t
curlen
=
sdslen
(
s
);
if
(
len
<=
curlen
)
return
s
;
s
=
sdsMakeRoomFor
(
s
,
len
-
curlen
);
if
(
s
==
NULL
)
return
NULL
;
/* Make sure added region doesn't contain garbage */
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
memset
(
s
+
curlen
,
0
,(
len
-
curlen
+
1
));
/* also set trailing \0 byte */
totlen
=
sh
->
len
+
sh
->
free
;
sh
->
len
=
len
;
sh
->
free
=
totlen
-
sh
->
len
;
sdssetlen
(
s
,
len
);
return
s
;
}
...
...
@@ -237,15 +361,12 @@ sds sdsgrowzero(sds s, size_t len) {
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
)
{
struct
sdshdr
*
sh
;
size_t
curlen
=
sdslen
(
s
);
s
=
sdsMakeRoomFor
(
s
,
len
);
if
(
s
==
NULL
)
return
NULL
;
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
memcpy
(
s
+
curlen
,
t
,
len
);
sh
->
len
=
curlen
+
len
;
sh
->
free
=
sh
->
free
-
len
;
sdssetlen
(
s
,
curlen
+
len
);
s
[
curlen
+
len
]
=
'\0'
;
return
s
;
}
...
...
@@ -269,19 +390,13 @@ sds sdscatsds(sds s, const sds t) {
/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
sds
sdscpylen
(
sds
s
,
const
char
*
t
,
size_t
len
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
totlen
=
sh
->
free
+
sh
->
len
;
if
(
totlen
<
len
)
{
s
=
sdsMakeRoomFor
(
s
,
len
-
sh
->
len
);
if
(
sdsalloc
(
s
)
<
len
)
{
s
=
sdsMakeRoomFor
(
s
,
len
-
sdslen
(
s
));
if
(
s
==
NULL
)
return
NULL
;
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
totlen
=
sh
->
free
+
sh
->
len
;
}
memcpy
(
s
,
t
,
len
);
s
[
len
]
=
'\0'
;
sh
->
len
=
len
;
sh
->
free
=
totlen
-
len
;
sdssetlen
(
s
,
len
);
return
s
;
}
...
...
@@ -449,7 +564,6 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
* %% - Verbatim "%" character.
*/
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
initlen
=
sdslen
(
s
);
const
char
*
f
=
fmt
;
int
i
;
...
...
@@ -460,14 +574,13 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
i
=
initlen
;
/* Position of the next byte to write to dest str. */
while
(
*
f
)
{
char
next
,
*
str
;
unsigned
in
t
l
;
size_
t
l
;
long
long
num
;
unsigned
long
long
unum
;
/* Make sure there is always space for at least 1 char. */
if
(
s
h
->
free
==
0
)
{
if
(
s
dsavail
(
s
)
==
0
)
{
s
=
sdsMakeRoomFor
(
s
,
1
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
switch
(
*
f
)
{
...
...
@@ -479,13 +592,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
case
'S'
:
str
=
va_arg
(
ap
,
char
*
);
l
=
(
next
==
's'
)
?
strlen
(
str
)
:
sdslen
(
str
);
if
(
s
h
->
free
<
l
)
{
if
(
s
dsavail
(
s
)
<
l
)
{
s
=
sdsMakeRoomFor
(
s
,
l
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
memcpy
(
s
+
i
,
str
,
l
);
sh
->
len
+=
l
;
sh
->
free
-=
l
;
sdsinclen
(
s
,
l
);
i
+=
l
;
break
;
case
'i'
:
...
...
@@ -497,13 +608,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
{
char
buf
[
SDS_LLSTR_SIZE
];
l
=
sdsll2str
(
buf
,
num
);
if
(
s
h
->
free
<
l
)
{
if
(
s
dsavail
(
s
)
<
l
)
{
s
=
sdsMakeRoomFor
(
s
,
l
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
memcpy
(
s
+
i
,
buf
,
l
);
sh
->
len
+=
l
;
sh
->
free
-=
l
;
sdsinclen
(
s
,
l
);
i
+=
l
;
}
break
;
...
...
@@ -516,27 +625,23 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
{
char
buf
[
SDS_LLSTR_SIZE
];
l
=
sdsull2str
(
buf
,
unum
);
if
(
s
h
->
free
<
l
)
{
if
(
s
dsavail
(
s
)
<
l
)
{
s
=
sdsMakeRoomFor
(
s
,
l
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
memcpy
(
s
+
i
,
buf
,
l
);
sh
->
len
+=
l
;
sh
->
free
-=
l
;
sdsinclen
(
s
,
l
);
i
+=
l
;
}
break
;
default:
/* Handle %% and generally %<unknown>. */
s
[
i
++
]
=
next
;
sh
->
len
+=
1
;
sh
->
free
-=
1
;
sdsinclen
(
s
,
1
);
break
;
}
break
;
default:
s
[
i
++
]
=
*
f
;
sh
->
len
+=
1
;
sh
->
free
-=
1
;
sdsinclen
(
s
,
1
);
break
;
}
f
++
;
...
...
@@ -563,7 +668,6 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
* Output will be just "Hello World".
*/
sds
sdstrim
(
sds
s
,
const
char
*
cset
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
char
*
start
,
*
end
,
*
sp
,
*
ep
;
size_t
len
;
...
...
@@ -572,10 +676,9 @@ sds sdstrim(sds s, const char *cset) {
while
(
sp
<=
end
&&
strchr
(
cset
,
*
sp
))
sp
++
;
while
(
ep
>
sp
&&
strchr
(
cset
,
*
ep
))
ep
--
;
len
=
(
sp
>
ep
)
?
0
:
((
ep
-
sp
)
+
1
);
if
(
sh
->
buf
!=
sp
)
memmove
(
sh
->
buf
,
sp
,
len
);
sh
->
buf
[
len
]
=
'\0'
;
sh
->
free
=
sh
->
free
+
(
sh
->
len
-
len
);
sh
->
len
=
len
;
if
(
s
!=
sp
)
memmove
(
s
,
sp
,
len
);
s
[
len
]
=
'\0'
;
sdssetlen
(
s
,
len
);
return
s
;
}
...
...
@@ -596,7 +699,6 @@ sds sdstrim(sds s, const char *cset) {
* sdsrange(s,1,-1); => "ello World"
*/
void
sdsrange
(
sds
s
,
int
start
,
int
end
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
newlen
,
len
=
sdslen
(
s
);
if
(
len
==
0
)
return
;
...
...
@@ -619,10 +721,9 @@ void sdsrange(sds s, int start, int end) {
}
else
{
start
=
0
;
}
if
(
start
&&
newlen
)
memmove
(
sh
->
buf
,
sh
->
buf
+
start
,
newlen
);
sh
->
buf
[
newlen
]
=
0
;
sh
->
free
=
sh
->
free
+
(
sh
->
len
-
newlen
);
sh
->
len
=
newlen
;
if
(
start
&&
newlen
)
memmove
(
s
,
s
+
start
,
newlen
);
s
[
newlen
]
=
0
;
sdssetlen
(
s
,
newlen
);
}
/* Apply tolower() to every character of the sds string 's'. */
...
...
src/sds.h
浏览文件 @
f15df8ba
...
...
@@ -35,32 +35,157 @@
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>
typedef
char
*
sds
;
struct
sdshdr
{
unsigned
int
len
;
unsigned
int
free
;
struct
__attribute__
((
__packed__
))
sdshdr8
{
uint8_t
len
;
/* used */
uint8_t
alloc
;
/* excluding the header and null terminator */
char
flags
;
/* 2 lsb of type, and 6 msb of refcount */
char
buf
[];
};
struct
__attribute__
((
__packed__
))
sdshdr16
{
uint16_t
len
;
/* used */
uint16_t
alloc
;
/* excluding the header and null terminator */
char
flags
;
/* 2 lsb of type, and 6 msb of refcount */
char
buf
[];
};
struct
__attribute__
((
__packed__
))
sdshdr32
{
uint32_t
len
;
/* used */
uint32_t
alloc
;
/* excluding the header and null terminator */
char
flags
;
/* 2 lsb of type, and 6 msb of refcount */
char
buf
[];
};
struct
__attribute__
((
__packed__
))
sdshdr64
{
uint64_t
len
;
/* used */
uint64_t
alloc
;
/* excluding the header and null terminator */
char
flags
;
/* 2 lsb of type, and 6 msb of refcount */
char
buf
[];
};
#define SDS_TYPE_8 0
#define SDS_TYPE_16 1
#define SDS_TYPE_32 2
#define SDS_TYPE_64 3
#define SDS_TYPE_MASK 3
#define SDS_TYPE_BITS 2
#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))))
static
inline
size_t
sdslen
(
const
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
return
sh
->
len
;
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
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
)
{
struct
sdshdr
*
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
return
sh
->
free
;
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
{
SDS_HDR_VAR
(
8
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
case
SDS_TYPE_16
:
{
SDS_HDR_VAR
(
16
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
case
SDS_TYPE_32
:
{
SDS_HDR_VAR
(
32
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
case
SDS_TYPE_64
:
{
SDS_HDR_VAR
(
64
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
}
return
0
;
}
static
inline
void
sdssetlen
(
sds
s
,
size_t
newlen
)
{
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
SDS_HDR
(
8
,
s
)
->
len
=
newlen
;
break
;
case
SDS_TYPE_16
:
SDS_HDR
(
16
,
s
)
->
len
=
newlen
;
break
;
case
SDS_TYPE_32
:
SDS_HDR
(
32
,
s
)
->
len
=
newlen
;
break
;
case
SDS_TYPE_64
:
SDS_HDR
(
64
,
s
)
->
len
=
newlen
;
break
;
}
}
static
inline
void
sdsinclen
(
sds
s
,
size_t
inc
)
{
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
SDS_HDR
(
8
,
s
)
->
len
+=
inc
;
break
;
case
SDS_TYPE_16
:
SDS_HDR
(
16
,
s
)
->
len
+=
inc
;
break
;
case
SDS_TYPE_32
:
SDS_HDR
(
32
,
s
)
->
len
+=
inc
;
break
;
case
SDS_TYPE_64
:
SDS_HDR
(
64
,
s
)
->
len
+=
inc
;
break
;
}
}
/* sdsalloc() = sdsavail() + sdslen() */
static
inline
size_t
sdsalloc
(
const
sds
s
)
{
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
return
SDS_HDR
(
8
,
s
)
->
alloc
;
case
SDS_TYPE_16
:
return
SDS_HDR
(
16
,
s
)
->
alloc
;
case
SDS_TYPE_32
:
return
SDS_HDR
(
32
,
s
)
->
alloc
;
case
SDS_TYPE_64
:
return
SDS_HDR
(
64
,
s
)
->
alloc
;
}
return
0
;
}
static
inline
void
sdssetalloc
(
sds
s
,
size_t
newlen
)
{
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_8
:
SDS_HDR
(
8
,
s
)
->
alloc
=
newlen
;
break
;
case
SDS_TYPE_16
:
SDS_HDR
(
16
,
s
)
->
alloc
=
newlen
;
break
;
case
SDS_TYPE_32
:
SDS_HDR
(
32
,
s
)
->
alloc
=
newlen
;
break
;
case
SDS_TYPE_64
:
SDS_HDR
(
64
,
s
)
->
alloc
=
newlen
;
break
;
}
}
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
);
sds
sdsnew
(
const
char
*
init
);
sds
sdsempty
(
void
);
size_t
sdslen
(
const
sds
s
);
sds
sdsdup
(
const
sds
s
);
void
sdsfree
(
sds
s
);
size_t
sdsavail
(
const
sds
s
);
sds
sdsgrowzero
(
sds
s
,
size_t
len
);
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
);
sds
sdscat
(
sds
s
,
const
char
*
t
);
...
...
@@ -68,6 +193,11 @@ sds sdscatsds(sds s, const sds t);
sds
sdscpylen
(
sds
s
,
const
char
*
t
,
size_t
len
);
sds
sdscpy
(
sds
s
,
const
char
*
t
);
/* we can add a reference count on top of any
* existing sds. (max up to 63 references) */
void
sdsIncRefcount
(
sds
s
);
void
sdsDecRefcount
(
sds
s
);
sds
sdscatvprintf
(
sds
s
,
const
char
*
fmt
,
va_list
ap
);
#ifdef __GNUC__
sds
sdscatprintf
(
sds
s
,
const
char
*
fmt
,
...)
...
...
@@ -97,6 +227,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen);
void
sdsIncrLen
(
sds
s
,
int
incr
);
sds
sdsRemoveFreeSpace
(
sds
s
);
size_t
sdsAllocSize
(
sds
s
);
size_t
sdsZmallocSize
(
sds
s
);
#ifdef REDIS_TEST
int
sdsTest
(
int
argc
,
char
*
argv
[]);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录