]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-dict: Add refcounting
authorAki Tuomi <aki.tuomi@open-xchange.com>
Tue, 24 Mar 2020 09:49:07 +0000 (11:49 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Tue, 31 Mar 2020 20:39:08 +0000 (20:39 +0000)
This way we do not crash if lookup callback happens after caller
has already called dict_deinit. This is now done because
dict-sql does not support aborting SQL queries. This is hopefully
fixed in future.

src/lib-dict/dict-private.h
src/lib-dict/dict.c

index 0738ea1210a5c47e0604f824a47f5cbb3599f013..01bdb7946f77e4b2bfd8133d745a4e28b26efcab 100644 (file)
@@ -54,6 +54,7 @@ struct dict {
        unsigned int iter_count;
        unsigned int transaction_count;
        struct dict_transaction_context *transactions;
+       int refcount;
        struct ioloop *ioloop, *prev_ioloop;
 };
 
index 5a6763b2318df1f48ba59e32d832a667bd3b5bd6..df2c7f7653f6a718490aba5169d42d63b9a6f2cf 100644 (file)
@@ -98,10 +98,29 @@ int dict_init(const char *uri, const struct dict_settings *set,
                return -1;
        }
        i_assert(*dict_r != NULL);
+       (*dict_r)->refcount++;
 
        return 0;
 }
 
+static void dict_ref(struct dict *dict)
+{
+       i_assert(dict->refcount > 0);
+
+       dict->refcount++;
+}
+
+static void dict_unref(struct dict **_dict)
+{
+       struct dict *dict = *_dict;
+       *_dict = NULL;
+       if (dict == NULL)
+               return;
+       i_assert(dict->refcount > 0);
+       if (--dict->refcount == 0)
+               dict->v.deinit(dict);
+}
+
 void dict_deinit(struct dict **_dict)
 {
        struct dict *dict = *_dict;
@@ -111,8 +130,7 @@ void dict_deinit(struct dict **_dict)
        i_assert(dict->iter_count == 0);
        i_assert(dict->transaction_count == 0);
        i_assert(dict->transactions == NULL);
-
-       dict->v.deinit(dict);
+       dict_unref(&dict);
 }
 
 void dict_wait(struct dict *dict)
@@ -163,6 +181,7 @@ dict_lookup_callback(const struct dict_lookup_result *result,
        ctx->callback(result, ctx->context);
        dict_post_api_callback(ctx->dict);
 
+       dict_unref(&ctx->dict);
        i_free(ctx);
 }
 
@@ -179,6 +198,8 @@ static void dict_commit_callback(const struct dict_commit_result *result,
                i_error("dict(%s): Commit failed: %s",
                        ctx->dict->name, result->error);
        dict_post_api_callback(ctx->dict);
+
+       dict_unref(&ctx->dict);
        i_free(ctx);
 }
 
@@ -206,6 +227,7 @@ void dict_lookup_async(struct dict *dict, const char *key,
        struct dict_lookup_callback_ctx *lctx =
                i_new(struct dict_lookup_callback_ctx, 1);
        lctx->dict = dict;
+       dict_ref(lctx->dict);
        lctx->callback = callback;
        lctx->context = context;
        dict->v.lookup_async(dict, key, dict_lookup_callback, lctx);
@@ -357,6 +379,7 @@ int dict_transaction_commit(struct dict_transaction_context **_ctx,
        ctx->dict->transaction_count--;
        DLLIST_REMOVE(&ctx->dict->transactions, ctx);
        cctx->dict = ctx->dict;
+       dict_ref(cctx->dict);
        cctx->callback = dict_transaction_commit_sync_callback;
        cctx->context = &result;
 
@@ -381,8 +404,10 @@ void dict_transaction_commit_async(struct dict_transaction_context **_ctx,
        if (callback == NULL)
                callback = dict_transaction_commit_async_noop_callback;
        cctx->dict = ctx->dict;
+       dict_ref(cctx->dict);
        cctx->callback = callback;
        cctx->context = context;
+
        ctx->dict->v.transaction_commit(ctx, TRUE, dict_commit_callback, cctx);
 }