diff options
author | chenyangyang <chenyang8094@users.noreply.github.com> | 2020-11-16 16:34:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-16 10:34:04 +0200 |
commit | c1aaad06d85c89ab7abebd5cefab026bdcb086ab (patch) | |
tree | d0bf36d0b1452381818b63d63ad0bd9e581a6b57 /src/lazyfree.c | |
parent | d8fd48c4363dd5265bb944c6ec881368d67f4afd (diff) | |
download | redis-c1aaad06d85c89ab7abebd5cefab026bdcb086ab.tar.gz |
Modules callbacks for lazy free effort, and unlink (#7912)
Add two optional callbacks to the RedisModuleTypeMethods structure, which is `free_effort`
and `unlink`. the `free_effort` callback indicates the effort required to free a module memory.
Currently, if the effort exceeds LAZYFREE_THRESHOLD, the module memory may be released
asynchronously. the `unlink` callback indicates the key has been removed from the DB by redis, and
may soon be freed by a background thread.
Add `lazyfreed_objects` info field, which represents the number of objects that have been
lazyfreed since redis was started.
Add `RM_GetTypeMethodVersion` API, which return the current redis-server runtime value of
`REDISMODULE_TYPE_METHOD_VERSION`. You can use that when calling `RM_CreateDataType` to know
which fields of RedisModuleTypeMethods are gonna be supported and which will be ignored.
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); } |