+++ /dev/null
-/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "array.h"
-#include "hash.h"
-#include "sql-api-private.h"
-#include "sql-db-cache-legacy.h"
-
-#define SQL_DB_CACHE_CONTEXT(obj) \
- MODULE_CONTEXT_REQUIRE(obj, sql_db_cache_module_legacy)
-
-struct sql_db_cache_context {
- union sql_db_module_context module_ctx;
- struct sql_db *prev, *next; /* These are set while refcount=0 */
-
- struct sql_db_cache *cache;
- int refcount;
- char *key;
- void (*orig_deinit)(struct sql_db *db);
-};
-
-struct sql_db_cache {
- HASH_TABLE(char *, struct sql_db *) dbs;
- unsigned int unused_count, max_unused_connections;
- struct sql_db *unused_tail, *unused_head;
-};
-
-static MODULE_CONTEXT_DEFINE_INIT(sql_db_cache_module_legacy,
- &sql_db_module_register);
-
-static void sql_db_cache_db_unref(struct sql_db *db)
-{
- struct sql_db_cache_context *ctx = SQL_DB_CACHE_CONTEXT(db);
- struct sql_db_cache_context *head_ctx;
-
- if (--ctx->refcount > 0)
- return;
-
- i_assert(db->refcount == 2);
-
- ctx->cache->unused_count++;
- if (ctx->cache->unused_tail == NULL)
- ctx->cache->unused_tail = db;
- else {
- head_ctx = SQL_DB_CACHE_CONTEXT(ctx->cache->unused_head);
- head_ctx->next = db;
- }
- ctx->prev = ctx->cache->unused_head;
- ctx->cache->unused_head = db;
-}
-
-static void sql_db_cache_unlink(struct sql_db_cache_context *ctx)
-{
- struct sql_db_cache_context *prev_ctx, *next_ctx;
-
- i_assert(ctx->refcount == 0);
-
- if (ctx->prev == NULL)
- ctx->cache->unused_tail = ctx->next;
- else {
- prev_ctx = SQL_DB_CACHE_CONTEXT(ctx->prev);
- prev_ctx->next = ctx->next;
- }
- if (ctx->next == NULL)
- ctx->cache->unused_head = ctx->prev;
- else {
- next_ctx = SQL_DB_CACHE_CONTEXT(ctx->next);
- next_ctx->prev = ctx->prev;
- }
- ctx->cache->unused_count--;
-}
-
-static void sql_db_cache_free_tail(struct sql_db_cache *cache)
-{
- struct sql_db *db;
- struct sql_db_cache_context *ctx;
-
- db = cache->unused_tail;
- i_assert(db->refcount == 1);
-
- ctx = SQL_DB_CACHE_CONTEXT(db);
- sql_db_cache_unlink(ctx);
- hash_table_remove(cache->dbs, ctx->key);
-
- i_free(ctx->key);
- i_free(ctx);
-
- db->v.unref = NULL;
- sql_unref(&db);
-}
-
-static void sql_db_cache_drop_oldest(struct sql_db_cache *cache)
-{
- while (cache->unused_count >= cache->max_unused_connections)
- sql_db_cache_free_tail(cache);
-}
-
-int sql_db_cache_new_legacy(struct sql_db_cache *cache,
- const struct sql_legacy_settings *set,
- struct sql_db **db_r, const char **error_r)
-{
- struct sql_db_cache_context *ctx;
- struct sql_db *db;
- char *key;
-
- key = i_strdup_printf("%s\t%s", set->driver, set->connect_string);
- db = hash_table_lookup(cache->dbs, key);
- if (db != NULL) {
- ctx = SQL_DB_CACHE_CONTEXT(db);
- if (ctx->refcount == 0) {
- sql_db_cache_unlink(ctx);
- ctx->prev = ctx->next = NULL;
- }
- i_free(key);
- } else {
- sql_db_cache_drop_oldest(cache);
-
- if (sql_init_legacy_full(set, &db, error_r) < 0) {
- i_free(key);
- return -1;
- }
-
- ctx = i_new(struct sql_db_cache_context, 1);
- ctx->cache = cache;
- ctx->key = key;
- ctx->orig_deinit = db->v.deinit;
- db->v.unref = sql_db_cache_db_unref;
-
- MODULE_CONTEXT_SET(db, sql_db_cache_module_legacy, ctx);
- hash_table_insert(cache->dbs, ctx->key, db);
- }
-
- ctx->refcount++;
- sql_ref(db);
- *db_r = db;
- return 0;
-}
-
-struct sql_db_cache *
-sql_db_cache_init_legacy(unsigned int max_unused_connections)
-{
- struct sql_db_cache *cache;
-
- cache = i_new(struct sql_db_cache, 1);
- hash_table_create(&cache->dbs, default_pool, 0, str_hash, strcmp);
- cache->max_unused_connections = max_unused_connections;
- return cache;
-}
-
-void sql_db_cache_deinit_legacy(struct sql_db_cache **_cache)
-{
- struct sql_db_cache *cache = *_cache;
-
- *_cache = NULL;
- while (cache->unused_tail != NULL)
- sql_db_cache_free_tail(cache);
- hash_table_destroy(&cache->dbs);
- i_free(cache);
-}