diff options
Diffstat (limited to 'src/lazyfree.c')
-rw-r--r-- | src/lazyfree.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/src/lazyfree.c b/src/lazyfree.c index b0fc26fcf..5a78d5a55 100644 --- a/src/lazyfree.c +++ b/src/lazyfree.c @@ -4,6 +4,7 @@ #include "cluster.h" static redisAtomic size_t lazyfree_objects = 0; +static redisAtomic size_t lazyfreed_objects = 0; /* Return the number of currently pending objects to free. */ size_t lazyfreeGetPendingObjectsCount(void) { @@ -12,6 +13,13 @@ size_t lazyfreeGetPendingObjectsCount(void) { return aux; } +/* Return the number of objects that have been freed. */ +size_t lazyfreeGetFreedObjectsCount(void) { + size_t aux; + atomicGet(lazyfreed_objects,aux); + return aux; +} + /* Return the amount of work needed in order to free an object. * The return value is not always the actual number of allocations the * object is composed of, but a number proportional to it. @@ -27,7 +35,7 @@ size_t lazyfreeGetPendingObjectsCount(void) { * * For lists the function returns the number of elements in the quicklist * representing the list. */ -size_t lazyfreeGetFreeEffort(robj *obj) { +size_t lazyfreeGetFreeEffort(robj *key, robj *obj) { if (obj->type == OBJ_LIST) { quicklist *ql = obj->ptr; return ql->len; @@ -64,6 +72,17 @@ size_t lazyfreeGetFreeEffort(robj *obj) { raxStop(&ri); } return effort; + } else if (obj->type == OBJ_MODULE) { + moduleValue *mv = obj->ptr; + moduleType *mt = mv->type; + if (mt->free_effort != NULL) { + size_t effort = mt->free_effort(key,mv->value); + /* If the module's free_effort returns 0, it will use asynchronous free + memory by default */ + return effort == 0 ? ULONG_MAX : effort; + } else { + return 1; + } } else { return 1; /* Everything else is a single allocation. */ } @@ -85,7 +104,11 @@ int dbAsyncDelete(redisDb *db, robj *key) { dictEntry *de = dictUnlink(db->dict,key->ptr); if (de) { robj *val = dictGetVal(de); - size_t free_effort = lazyfreeGetFreeEffort(val); + + /* Tells the module that the key has been unlinked from the database. */ + moduleNotifyKeyUnlink(key,val); + + size_t free_effort = lazyfreeGetFreeEffort(key,val); /* If releasing the object is too much work, do it in the background * by adding the object to the lazy free list. @@ -114,13 +137,13 @@ int dbAsyncDelete(redisDb *db, robj *key) { } /* Free an object, if the object is huge enough, free it in async way. */ -void freeObjAsync(robj *o) { - size_t free_effort = lazyfreeGetFreeEffort(o); - if (free_effort > LAZYFREE_THRESHOLD && o->refcount == 1) { +void freeObjAsync(robj *key, robj *obj) { + size_t free_effort = lazyfreeGetFreeEffort(key,obj); + if (free_effort > LAZYFREE_THRESHOLD && obj->refcount == 1) { atomicIncr(lazyfree_objects,1); - bioCreateBackgroundJob(BIO_LAZY_FREE,o,NULL,NULL); + bioCreateBackgroundJob(BIO_LAZY_FREE,obj,NULL,NULL); } else { - decrRefCount(o); + decrRefCount(obj); } } @@ -152,6 +175,7 @@ void slotToKeyFlushAsync(void) { void lazyfreeFreeObjectFromBioThread(robj *o) { decrRefCount(o); atomicDecr(lazyfree_objects,1); + atomicIncr(lazyfreed_objects,1); } /* Release a database from the lazyfree thread. The 'db' pointer is the @@ -164,6 +188,7 @@ void lazyfreeFreeDatabaseFromBioThread(dict *ht1, dict *ht2) { dictRelease(ht1); dictRelease(ht2); atomicDecr(lazyfree_objects,numkeys); + atomicIncr(lazyfreed_objects,numkeys); } /* Release the skiplist mapping Redis Cluster keys to slots in the @@ -172,4 +197,5 @@ void lazyfreeFreeSlotsMapFromBioThread(rax *rt) { size_t len = rt->numele; raxFree(rt); atomicDecr(lazyfree_objects,len); + atomicIncr(lazyfreed_objects,len); } |