@@ -52,13 +52,33 @@ robj *createRawStringObject(char *ptr, size_t len) {
5252
5353/* Create a string object with encoding REDIS_ENCODING_EMBSTR, that is
5454 * an object where the sds string is actually an unmodifiable string
55- * allocated in the same chunk as the object itself. */
55+ * allocated in the same chunk as the object itself.
56+ *
57+ * We try to cache and reuse EMBSTR allocated objects according to
58+ * size classes modeled after the jemalloc size classes. */
59+ #define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
60+ #define EMB_OBJ_CACHE_CLASSES 3 /* 32, 48, 64 */
61+ #define EMB_OBJ_CACHE_SIZE 1024
62+ robj * emb_obj_cache [EMB_OBJ_CACHE_CLASSES ][EMB_OBJ_CACHE_SIZE ];
63+ unsigned long emb_obj_cache_len [EMB_OBJ_CACHE_CLASSES ];
64+
5665robj * createEmbeddedStringObject (char * ptr , size_t len ) {
57- robj * o = zmalloc (sizeof (robj )+ sizeof (struct sdshdr )+ len + 1 );
58- struct sdshdr * sh = (void * )(o + 1 );
66+ robj * o ;
67+ struct sdshdr * sh ;
68+ int alloc_size = sizeof (robj )+ sizeof (struct sdshdr )+ len + 1 ;
69+ int cache_class = (((alloc_size + 15 )- ((alloc_size + 15 )& 15 ))- 32 )/16 ;
70+
71+ /* Try to reuse a cached object. */
72+ if (cache_class < EMB_OBJ_CACHE_CLASSES && emb_obj_cache_len [cache_class ]) {
73+ emb_obj_cache_len [cache_class ]-- ;
74+ o = emb_obj_cache [cache_class ][emb_obj_cache_len [cache_class ]];
75+ } else {
76+ o = zmalloc (alloc_size );
77+ o -> type = REDIS_STRING ;
78+ o -> encoding = REDIS_ENCODING_EMBSTR ;
79+ }
5980
60- o -> type = REDIS_STRING ;
61- o -> encoding = REDIS_ENCODING_EMBSTR ;
81+ sh = (void * )(o + 1 );
6282 o -> ptr = sh + 1 ;
6383 o -> refcount = 1 ;
6484 o -> lru = LRU_CLOCK ();
@@ -80,7 +100,6 @@ robj *createEmbeddedStringObject(char *ptr, size_t len) {
80100 *
81101 * The current limit of 39 is chosen so that the biggest string object
82102 * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
83- #define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
84103robj * createStringObject (char * ptr , size_t len ) {
85104 if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT )
86105 return createEmbeddedStringObject (ptr ,len );
@@ -215,7 +234,21 @@ robj *createZsetZiplistObject(void) {
215234void freeStringObject (robj * o ) {
216235 if (o -> encoding == REDIS_ENCODING_RAW ) {
217236 sdsfree (o -> ptr );
237+ } else if (o -> encoding == REDIS_ENCODING_EMBSTR ) {
238+ struct sdshdr * sh = (void * )(o + 1 );
239+ int alloc_size = sizeof (robj )+ sizeof (struct sdshdr )+ sh -> len + 1 ;
240+ int cache_class = (((alloc_size + 15 )- ((alloc_size + 15 )& 15 ))- 32 )/16 ;
241+
242+ /* Try to cache the object instead of freeing it. */
243+ if (cache_class < EMB_OBJ_CACHE_CLASSES &&
244+ emb_obj_cache_len [cache_class ] != EMB_OBJ_CACHE_SIZE )
245+ {
246+ emb_obj_cache [cache_class ][emb_obj_cache_len [cache_class ]] = o ;
247+ emb_obj_cache_len [cache_class ]++ ;
248+ return ; /* Don't free the object. */
249+ }
218250 }
251+ zfree (o );
219252}
220253
221254void freeListObject (robj * o ) {
@@ -229,6 +262,7 @@ void freeListObject(robj *o) {
229262 default :
230263 redisPanic ("Unknown list encoding type" );
231264 }
265+ zfree (o );
232266}
233267
234268void freeSetObject (robj * o ) {
@@ -242,6 +276,7 @@ void freeSetObject(robj *o) {
242276 default :
243277 redisPanic ("Unknown set encoding type" );
244278 }
279+ zfree (o );
245280}
246281
247282void freeZsetObject (robj * o ) {
@@ -259,6 +294,7 @@ void freeZsetObject(robj *o) {
259294 default :
260295 redisPanic ("Unknown sorted set encoding" );
261296 }
297+ zfree (o );
262298}
263299
264300void freeHashObject (robj * o ) {
@@ -273,6 +309,7 @@ void freeHashObject(robj *o) {
273309 redisPanic ("Unknown hash encoding type" );
274310 break ;
275311 }
312+ zfree (o );
276313}
277314
278315void incrRefCount (robj * o ) {
@@ -290,7 +327,6 @@ void decrRefCount(robj *o) {
290327 case REDIS_HASH : freeHashObject (o ); break ;
291328 default : redisPanic ("Unknown object type" ); break ;
292329 }
293- zfree (o );
294330 } else {
295331 o -> refcount -- ;
296332 }
0 commit comments