~ubuntu-branches/ubuntu/wily/dovecot/wily-proposed

« back to all changes in this revision

Viewing changes to src/lib-sql/sql-pool.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2008-08-02 14:00:15 UTC
  • mto: (1.11.1 upstream) (4.2.1 sid)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: james.westby@ubuntu.com-20080802140015-zbmjsgoodeyc9z4s
Tags: upstream-1.1.2
ImportĀ upstreamĀ versionĀ 1.1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "array.h"
 
5
#include "hash.h"
 
6
#include "sql-api-private.h"
 
7
#include "sql-pool.h"
 
8
 
 
9
#define SQL_POOL_CONTEXT(obj) \
 
10
        MODULE_CONTEXT(obj, sql_pool_module)
 
11
 
 
12
struct sql_pool_context {
 
13
        union sql_db_module_context module_ctx;
 
14
        struct sql_db *prev, *next; /* These are set while refcount=0 */
 
15
 
 
16
        struct sql_pool *pool;
 
17
        int refcount;
 
18
        char *key;
 
19
        void (*orig_deinit)(struct sql_db *db);
 
20
};
 
21
 
 
22
struct sql_pool {
 
23
        struct hash_table *dbs;
 
24
        unsigned int unused_count, max_unused_connections;
 
25
        struct sql_db *unused_tail, *unused_head;
 
26
};
 
27
 
 
28
static MODULE_CONTEXT_DEFINE_INIT(sql_pool_module, &sql_db_module_register);
 
29
 
 
30
static void sql_pool_db_deinit(struct sql_db *db)
 
31
{
 
32
        struct sql_pool_context *ctx = SQL_POOL_CONTEXT(db);
 
33
        struct sql_pool_context *head_ctx;
 
34
 
 
35
        if (--ctx->refcount > 0)
 
36
                return;
 
37
 
 
38
        ctx->pool->unused_count++;
 
39
        if (ctx->pool->unused_tail == NULL)
 
40
                ctx->pool->unused_tail = db;
 
41
        else {
 
42
                head_ctx = SQL_POOL_CONTEXT(ctx->pool->unused_head);
 
43
                head_ctx->next = db;
 
44
        }
 
45
        ctx->prev = ctx->pool->unused_head;
 
46
        ctx->pool->unused_head = db;
 
47
}
 
48
 
 
49
static void sql_pool_unlink(struct sql_pool_context *ctx)
 
50
{
 
51
        struct sql_pool_context *prev_ctx, *next_ctx;
 
52
 
 
53
        i_assert(ctx->refcount == 0);
 
54
 
 
55
        if (ctx->prev == NULL)
 
56
                ctx->pool->unused_tail = ctx->next;
 
57
        else {
 
58
                prev_ctx = SQL_POOL_CONTEXT(ctx->prev);
 
59
                prev_ctx->next = ctx->next;
 
60
        }
 
61
        if (ctx->next == NULL)
 
62
                ctx->pool->unused_head = ctx->prev;
 
63
        else {
 
64
                next_ctx = SQL_POOL_CONTEXT(ctx->prev);
 
65
                next_ctx->prev = ctx->prev;
 
66
        }
 
67
        ctx->pool->unused_count--;
 
68
}
 
69
 
 
70
static void sql_pool_drop_oldest(struct sql_pool *pool)
 
71
{
 
72
        struct sql_db *db;
 
73
        struct sql_pool_context *ctx;
 
74
 
 
75
        while (pool->unused_count >= pool->max_unused_connections) {
 
76
                db = pool->unused_tail;
 
77
                ctx = SQL_POOL_CONTEXT(db);
 
78
                sql_pool_unlink(ctx);
 
79
 
 
80
                i_free(ctx->key);
 
81
                ctx->orig_deinit(db);
 
82
        }
 
83
}
 
84
 
 
85
struct sql_db *sql_pool_new(struct sql_pool *pool,
 
86
                            const char *db_driver, const char *connect_string)
 
87
{
 
88
        struct sql_pool_context *ctx;
 
89
        struct sql_db *db;
 
90
        char *key;
 
91
 
 
92
        key = i_strdup_printf("%s\t%s", db_driver, connect_string);
 
93
        db = hash_lookup(pool->dbs, key);
 
94
        if (db != NULL) {
 
95
                ctx = SQL_POOL_CONTEXT(db);
 
96
                if (ctx->refcount == 0) {
 
97
                        sql_pool_unlink(ctx);
 
98
                        ctx->prev = ctx->next = NULL;
 
99
                }
 
100
                i_free(key);
 
101
        } else {
 
102
                sql_pool_drop_oldest(pool);
 
103
 
 
104
                ctx = i_new(struct sql_pool_context, 1);
 
105
                ctx->pool = pool;
 
106
                ctx->key = key;
 
107
 
 
108
                db = sql_init(db_driver, connect_string);
 
109
                ctx->orig_deinit = db->v.deinit;
 
110
                db->v.deinit = sql_pool_db_deinit;
 
111
 
 
112
                MODULE_CONTEXT_SET(db, sql_pool_module, ctx);
 
113
                hash_insert(pool->dbs, ctx->key, db);
 
114
        }
 
115
 
 
116
        ctx->refcount++;
 
117
        return db;
 
118
}
 
119
 
 
120
struct sql_pool *sql_pool_init(unsigned int max_unused_connections)
 
121
{
 
122
        struct sql_pool *pool;
 
123
 
 
124
        pool = i_new(struct sql_pool, 1);
 
125
        pool->dbs = hash_create(default_pool, default_pool, 0, str_hash,
 
126
                                (hash_cmp_callback_t *)strcmp);
 
127
        pool->max_unused_connections = max_unused_connections;
 
128
        return pool;
 
129
}
 
130
 
 
131
void sql_pool_deinit(struct sql_pool **_pool)
 
132
{
 
133
        struct sql_pool *pool = *_pool;
 
134
 
 
135
        *_pool = NULL;
 
136
        hash_destroy(&pool->dbs);
 
137
        i_free(pool);
 
138
}