diff --git a/src/object.c b/src/object.c index 853e36e5f41..e0fa767c910 100644 --- a/src/object.c +++ b/src/object.c @@ -281,6 +281,12 @@ robj *createModuleObject(moduleType *mt, void *value) { return createObject(OBJ_MODULE,mv); } +void freeStringObjectOptim(robj *o) { + if (o->encoding == OBJ_ENCODING_RAW) { + sdsfreeOptim(o->ptr); + } +} + void freeStringObject(robj *o) { if (o->encoding == OBJ_ENCODING_RAW) { sdsfree(o->ptr); @@ -356,7 +362,7 @@ void incrRefCount(robj *o) { static void _decrRefCount(robj *o, int on_dram) { if (o->refcount == 1) { switch(o->type) { - case OBJ_STRING: freeStringObject(o); break; + case OBJ_STRING: freeStringObjectOptim(o); break; case OBJ_LIST: freeListObject(o); break; case OBJ_SET: freeSetObject(o); break; case OBJ_ZSET: freeZsetObject(o); break; diff --git a/src/sds.c b/src/sds.c index d7c657268f1..1a3ec4a21ed 100644 --- a/src/sds.c +++ b/src/sds.c @@ -60,6 +60,24 @@ static inline int sdsHdrSize(char type) { return 0; } +/* Returns size of sdsHdr by checking pointer alignment (expects 8 byte + * alignment). Optimizes retriving sdsHdr size by not refering to sds data */ +static inline int sdsHdrSizeOptim(char* s) { + switch((uintptr_t)s&7) { + case SDS_MOD8(5): + return sizeof(struct sdshdr5); + case SDS_MOD8(8): + return sizeof(struct sdshdr8); + case SDS_MOD8(16): + return sizeof(struct sdshdr16); + case SDS_MOD8(32): + return sizeof(struct sdshdr32); + case SDS_MOD8(64): + return sizeof(struct sdshdr64); + } + return 0; +} + static inline char sdsReqType(size_t string_size) { if (string_size < 1<<5) return SDS_TYPE_5; @@ -185,6 +203,11 @@ void sdsfree(sds s) { s_free((char*)s-sdsHdrSize(s[-1])); } +void sdsfreeOptim(sds s) { + if (s == NULL) return; + s_free((char*)s-sdsHdrSizeOptim(s)); +} + /* Set the sds string length to the length as obtained with strlen(), so * considering as content only up to the first null term character. * diff --git a/src/sds.h b/src/sds.h index 5bdeedad78c..9cd9ebb335f 100644 --- a/src/sds.h +++ b/src/sds.h @@ -64,12 +64,14 @@ struct __attribute__ ((__packed__)) sdshdr32 { uint32_t len; /* used */ uint32_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ + char padding; /* Added to have unique value for %8 operation*/ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr64 { uint64_t len; /* used */ uint64_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ + char padding[3]; /* Added to have unique value for %8 operation */ char buf[]; }; @@ -83,6 +85,7 @@ struct __attribute__ ((__packed__)) sdshdr64 { #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) +#define SDS_MOD8(T) (sizeof(struct sdshdr##T)&7) static inline size_t sdslen(const sds s) { unsigned char flags = s[-1]; @@ -221,6 +224,7 @@ sds sdsempty(void); sds sdsdramempty(void); sds sdsdup(const sds s); void sdsfree(sds s); +void sdsfreeOptim(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); diff --git a/src/server.h b/src/server.h index f54cdc630a0..20fe9e14b11 100644 --- a/src/server.h +++ b/src/server.h @@ -1724,6 +1724,7 @@ void incrRefCount(robj *o); robj *makeObjectShared(robj *o); robj *resetRefCount(robj *obj); void freeStringObject(robj *o); +void freeStringObjectOptim(robj *o); void freeListObject(robj *o); void freeSetObject(robj *o); void freeZsetObject(robj *o);