summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2018-09-25 12:45:02 +0200
committerantirez <antirez@gmail.com>2018-09-25 12:45:08 +0200
commitb6c794acf62223b9b46a14541f3b749969b378bf (patch)
treebb4f62d68453ef9297af611be5aa0b2851344c18
parent448d696549dc156fc26f93208d4e2a52d655dcea (diff)
downloadredis-b6c794acf62223b9b46a14541f3b749969b378bf.tar.gz
Modules: dictionary API WIP #6: implement automatic memory management.
-rw-r--r--src/module.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/src/module.c b/src/module.c
index 642b847ef..332686ace 100644
--- a/src/module.c
+++ b/src/module.c
@@ -64,6 +64,7 @@ struct AutoMemEntry {
#define REDISMODULE_AM_STRING 1
#define REDISMODULE_AM_REPLY 2
#define REDISMODULE_AM_FREED 3 /* Explicitly freed by user already. */
+#define REDISMODULE_AM_DICT 4
/* The pool allocator block. Redis Modules can allocate memory via this special
* allocator that will automatically release it all once the callback returns.
@@ -270,6 +271,7 @@ robj **moduleCreateArgvFromUserFormat(const char *cmdname, const char *fmt, int
void moduleReplicateMultiIfNeeded(RedisModuleCtx *ctx);
void RM_ZsetRangeStop(RedisModuleKey *kp);
static void zsetKeyReset(RedisModuleKey *key);
+void RM_FreeDict(RedisModuleDict *d);
/* --------------------------------------------------------------------------
* Heap allocation raw functions
@@ -791,6 +793,7 @@ void autoMemoryCollect(RedisModuleCtx *ctx) {
case REDISMODULE_AM_STRING: decrRefCount(ptr); break;
case REDISMODULE_AM_REPLY: RM_FreeCallReply(ptr); break;
case REDISMODULE_AM_KEY: RM_CloseKey(ptr); break;
+ case REDISMODULE_AM_DICT: RM_FreeDict(ptr); break;
}
}
ctx->flags |= REDISMODULE_CTX_AUTO_MEMORY;
@@ -4350,19 +4353,30 @@ int RM_GetTimerInfo(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remain
* capable of going back and forth.
* -------------------------------------------------------------------------- */
-/* Create a new dictionary. The 'ctx' may be NULL if the dictionary is created
- * in a situation where a context is not available. However in such case
- * certain future features (yet not implemented) may not be available, so if
- * possible create the dictionary passing the context. */
+/* Create a new dictionary. The 'ctx' pointer can be the current module context
+ * or NULL, depending on what you want. Please follow the following rules:
+ *
+ * 1. Use a NULL context if you plan to retain a reference to this dictionary
+ * that will survive the time of the module callback where you created it.
+ * 2. Use a NULL context if no context is available at the time you are creating
+ * the dictionary (of course...).
+ * 3. However use the current callback context as 'ctx' argument if the
+ * dictionary time to live is just limited to the callback scope. In this
+ * case, if enabled, you can enjoy the automatic memory management that will
+ * reclaim the dictionary memory, as well as the strings returned by the
+ * Next / Prev dictionary iterator calls.
+ */
RedisModuleDict *RM_CreateDict(RedisModuleCtx *ctx) {
struct RedisModuleDict *d = zmalloc(sizeof(*d));
d->ctx = ctx;
d->rax = raxNew();
+ if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_DICT,d);
return d;
}
/* Free a dictionary created with RM_CreateDict(). */
void RM_FreeDict(RedisModuleDict *d) {
+ if (d->ctx != NULL) autoMemoryFreed(d->ctx,REDISMODULE_AM_DICT,d);
raxFree(d->rax);
zfree(d);
}
@@ -4489,11 +4503,11 @@ int RM_DictIteratorReseek(RedisModuleDictIter *di, const char *op, RedisModuleSt
return RM_DictIteratorReseekC(di,op,key->ptr,sdslen(key->ptr));
}
-/* TODO
+/* TODO
+ RM_DictNextC();
+ RM_DictPrevC();
RM_DictNext();
RM_DictPrev();
- RM_DictNextStr();
- RM_DictPrevStr();
*/
/* --------------------------------------------------------------------------