fix
[libpgclient.git] / src / pgpool.c
blob466722eb3adb12409314c90283c5dc5e06cd94a3
1 /*Copyright (c) Brian B.
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 3 of the License, or (at your option) any later version.
7 See the file LICENSE included with this distribution for more
8 information.
9 */
10 #include "libpgcli/pgpool.h"
12 pgpool_t *pgpool_create () {
13 pgpool_t *pool = malloc(sizeof(pgpool_t));
14 pool->livingtime = 0;
15 pool->pg_free = lst_alloc(NULL);
16 pool->pg_busy = lst_alloc(NULL);
17 pthread_mutex_init(&pool->locker, NULL);
18 pthread_condattr_init(&pool->cond_attr);
19 pthread_condattr_setclock(&pool->cond_attr, CLOCK_MONOTONIC);
20 pthread_cond_init(&pool->cond, &pool->cond_attr);
21 return pool;
24 void pgpool_setopt_pchar (pgpool_t *pool, pgpool_opt_t opt, char *arg) {
25 if (PGPOOL_CONNINFO == opt)
26 pool->conn_info = arg;
29 void pgpool_setopt_time (pgpool_t *pool, pgpool_opt_t opt, time_t arg) {
30 pool->livingtime = arg;
33 void pgpool_setopt_int (pgpool_t *pool, pgpool_opt_t opt, uintptr_t arg) {
34 if (PGPOOL_LIVINGTIME == opt)
35 pool->livingtime = arg;
38 static void *_on_pgpool (void *param) {
39 pgpool_t *pool = (pgpool_t*)param;
40 while (pool->is_alive) {
41 struct timespec to_time;
42 clock_gettime(CLOCK_MONOTONIC, &to_time);
43 to_time.tv_sec += pool->livingtime;
44 pthread_mutex_lock(&pool->locker);
45 if (ETIMEDOUT == pthread_cond_timedwait(&pool->cond, &pool->locker, &to_time)) {
46 time_t t0 = time(0);
47 list_item_t *li;
48 if ((li = pool->pg_free->head)) {
49 do {
50 list_item_t *li_n = li->next;
51 pgconn_t *conn = (pgconn_t*)li->ptr;
52 if (conn->tm_released + pool->livingtime < t0) {
53 lst_del(li);
54 pg_disconnect(conn);
56 li = li_n;
57 } while (li != pool->pg_free->head);
60 pthread_mutex_unlock(&pool->locker);
62 return NULL;
65 int pgpool_start (pgpool_t *pool) {
66 if (0 == pool->livingtime)
67 return 0;
68 pool->is_alive = 1;
69 return pthread_create(&pool->th, NULL, _on_pgpool, (void*)pool);
72 static int _on_disconnect (list_item_t *li, void *dummy) {
73 pgconn_t *conn = (pgconn_t*)li->ptr;
74 pg_disconnect(conn);
75 return ENUM_CONTINUE;
78 void pgpool_free (pgpool_t *pool) {
79 if (0 != pool->th) {
80 pthread_mutex_lock(&pool->locker);
81 pool->is_alive = 0;
82 pthread_cond_signal(&pool->cond);
83 pthread_mutex_unlock(&pool->locker);
84 pthread_join(pool->th, NULL);
86 lst_enum(pool->pg_free, _on_disconnect, NULL, 0);
87 lst_enum(pool->pg_busy, _on_disconnect, NULL, 0);
88 lst_free(pool->pg_free);
89 lst_free(pool->pg_busy);
90 free(pool->conn_info);
91 pthread_condattr_destroy(&pool->cond_attr);
92 pthread_cond_destroy(&pool->cond);
93 pthread_mutex_destroy(&pool->locker);
94 free(pool);
97 static pgconn_t *_connect (pgpool_t *pool) {
98 pgconn_t *conn = pg_connect(pool->conn_info);
99 if (conn->error || conn->intr_error) {
100 if (pool->on_error)
101 pool->on_error(conn);
102 pg_disconnect(conn);
103 return NULL;
105 conn->li = lst_adde(pool->pg_busy, conn);
106 conn->tm_released = 0;
107 conn->pool = pool;
108 pthread_mutex_unlock(&pool->locker);
109 return conn;
112 pgconn_t *pgpool_get (pgpool_t *pool) {
113 list_item_t *li = pool->pg_free->head;
114 pgconn_t *conn;
115 pthread_mutex_lock(&pool->locker);
116 if (!li)
117 return _connect(pool);
118 conn = (pgconn_t*)li->ptr;
119 lst_del(li);
120 conn->tm_released = 0;
121 conn->li = lst_add(pool->pg_busy, conn);
122 pthread_mutex_unlock(&pool->locker);
123 return conn;
126 void pgpool_release (pgconn_t *conn) {
127 pthread_mutex_lock(&conn->pool->locker);
128 lst_del(conn->li);
129 conn->tm_released = time(0);
130 conn->li = lst_adde(conn->pool->pg_free, conn);
131 pthread_mutex_unlock(&conn->pool->locker);
134 static void _check (pgpool_t *pool, list_item_t *x, time_t t0) {
135 pgconn_t *conn = (pgconn_t*)x->ptr;
136 if (conn->tm_released + pool->livingtime < t0) {
137 lst_del(x);
138 pg_disconnect(conn);
142 void pgpool_check (pgpool_t *pool) {
143 if (pool->livingtime <= 0)
144 return;
145 list_t *lst = pool->pg_free;
146 list_item_t *x = lst->head;
147 if (x) {
148 time_t t0 = time(0);
149 do {
150 list_item_t *y = x->next;
151 _check(pool, x, t0);
152 x = y;
153 } while (x != lst->head);
154 _check(pool, x, t0);