Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
f15df8ba
Commit
f15df8ba
authored
Apr 09, 2015
by
Oran Agra
Committed by
antirez
Jul 14, 2015
Browse files
sds size classes - memory optimization
parent
0f64080d
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/Makefile
View file @
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
View file @
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
View file @
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
z
malloc
_s
ize
_sds
(
o
->
ptr
);
case
REDIS_ENCODING_EMBSTR
:
return
sdslen
(
o
->
ptr
);
case
REDIS_ENCODING_RAW
:
return
sdsZ
malloc
S
ize
(
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
-=
z
malloc
_s
ize
_sds
(
tail
->
ptr
);
c
->
reply_bytes
-=
sdsZ
malloc
S
ize
(
tail
->
ptr
);
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
o
->
ptr
,
sdslen
(
o
->
ptr
));
c
->
reply_bytes
+=
z
malloc
_s
ize
_sds
(
tail
->
ptr
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
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
+=
z
malloc
_s
ize
_sds
(
s
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
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
-=
z
malloc
_s
ize
_sds
(
tail
->
ptr
);
c
->
reply_bytes
-=
sdsZ
malloc
S
ize
(
tail
->
ptr
);
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
s
,
sdslen
(
s
));
c
->
reply_bytes
+=
z
malloc
_s
ize
_sds
(
tail
->
ptr
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
tail
->
ptr
);
sdsfree
(
s
);
}
else
{
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
c
->
reply_bytes
+=
z
malloc
_s
ize
_sds
(
s
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
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
-=
z
malloc
_s
ize
_sds
(
tail
->
ptr
);
c
->
reply_bytes
-=
sdsZ
malloc
S
ize
(
tail
->
ptr
);
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
s
,
len
);
c
->
reply_bytes
+=
z
malloc
_s
ize
_sds
(
tail
->
ptr
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
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
+=
z
malloc
_s
ize
_sds
(
len
->
ptr
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
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
-=
z
malloc
_s
ize
_sds
(
len
->
ptr
);
c
->
reply_bytes
-=
sdsZ
malloc
S
ize
(
len
->
ptr
);
c
->
reply_bytes
-=
getStringObjectSdsUsedMemory
(
next
);
len
->
ptr
=
sdscatlen
(
len
->
ptr
,
next
->
ptr
,
sdslen
(
next
->
ptr
));
c
->
reply_bytes
+=
z
malloc
_s
ize
_sds
(
len
->
ptr
);
c
->
reply_bytes
+=
sdsZ
malloc
S
ize
(
len
->
ptr
);
listDelNode
(
c
->
reply
,
ln
->
next
);
}
}
...
...
src/object.c
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
[]);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment