summaryrefslogtreecommitdiff
path: root/src/sds.c
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2017-11-03 10:19:27 +0100
committerantirez <antirez@gmail.com>2017-11-03 10:19:27 +0100
commit34d5804d4c85d077b6af6265ebd86f35ecca89de (patch)
treec43bf869387867ea4e58c44a15396338e4a8b7d1 /src/sds.c
parentffcf7d5ab1e98d84c28af9bea7be76c6737820ad (diff)
downloadredis-34d5804d4c85d077b6af6265ebd86f35ecca89de.tar.gz
SDS: improve sdsRemoveFreeSpace() to avoid useless data copy.
Since SDS v2, we no longer have a single header, so the function to rewrite the SDS in terms of the minimum space required, instead of just using realloc() and let the underlying allocator decide what to do, was doing an allocation + copy every time the minimum possible header needed to represent the string was different than the current one. This could be often a bit wasteful, because if we go, for instance, from the 32 bit fields header to the 16 bit fields header, the overhead of the header is normally very small. With this commit we call realloc instead, unless the change in header size is very significant in relation to the string length.
Diffstat (limited to 'src/sds.c')
-rw-r--r--src/sds.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/src/sds.c b/src/sds.c
index eafa13c29..ff633c8bc 100644
--- a/src/sds.c
+++ b/src/sds.c
@@ -248,16 +248,23 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
sds sdsRemoveFreeSpace(sds s) {
void *sh, *newsh;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
- int hdrlen;
+ int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
size_t len = sdslen(s);
- sh = (char*)s-sdsHdrSize(oldtype);
+ sh = (char*)s-oldhdrlen;
+ /* Check what would be the minimum SDS header that is just good enough to
+ * fit this string. */
type = sdsReqType(len);
hdrlen = sdsHdrSize(type);
- if (oldtype==type) {
- newsh = s_realloc(sh, hdrlen+len+1);
+
+ /* If the type is the same, or at least a large enough type is still
+ * required, we just realloc(), letting the allocator to do the copy
+ * only if really needed. Otherwise if the change is huge, we manually
+ * reallocate the string to use the different header type. */
+ if (oldtype==type || type > SDS_TYPE_8) {
+ newsh = s_realloc(sh, oldhdrlen+len+1);
if (newsh == NULL) return NULL;
- s = (char*)newsh+hdrlen;
+ s = (char*)newsh+oldhdrlen;
} else {
newsh = s_malloc(hdrlen+len+1);
if (newsh == NULL) return NULL;