pgbouncer.git / summary / log / commit / refs
commit e94aeecaeebd277606f4e71ebfff55f68cdabca0
Author: Marko Kreen <markokr@gmail.com>
Date: Fri Jan 02 10:54:47 2009 +0000
Reserve pool implementation.
Allow to increased pool size in case main pool size
cannot serve clients anymore.
This allows to continue use of small pool_size, which
smooths small peaks, while also handling large peaks.
(Eg, one bouncer server down, others need to handle load.)
doc/config.txt | 16 ++++++++++++++++
etc/pgbouncer.ini | 8 ++++++++
include/bouncer.h | 3 +++
src/admin.c | 7 ++++---
src/janitor.c | 10 +++++++---
src/loader.c | 4 ++++
src/main.c | 4 ++++
src/objects.c | 14 ++++++++++++++
8 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/doc/config.txt b/doc/config.txt
index aa8f81e..85d666c 100644
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -139,6 +139,22 @@ per-database config.
Default: 20
+==== reserve_pool_size ====
+
+How many additional connections to allow to a pool.
+
+How many server connection to allow per user/database pair. Can be overrided in
+per-database config. 0 disables.
+
+Default: 0 (disabled)
+
+==== reserve_pool_timeout ====
+
+If a client has not been services in this many seconds, pgbouncer enables
+use of additional connections from reserve pool. 0 disables.
+
+Default: 5
+
==== server_round_robin ====
By default, pgbouncer reuses server connections in LIFO manner, so that few
diff --git a/etc/pgbouncer.ini b/etc/pgbouncer.ini
index 7c38f34..87bae3a 100644
--- a/etc/pgbouncer.ini
+++ b/etc/pgbouncer.ini
@@ -10,6 +10,8 @@ bardb = host=127.0.0.1 dbname=bazdb
; acceess to dest database will go with single user
forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1'
+nondefaultdb = pool_size=50 reserve_pool=10
+
;; Configuation section
[pgbouncer]
@@ -93,6 +95,12 @@ server_check_delay = 10
max_client_conn = 100
default_pool_size = 20
+; how many additional connection to allow in case of trouble
+;reserve_pool_size = 5
+
+; if a clients needs to wait more than this many seconds, use reserve pool
+;reserve_pool_timeout = 3
+
log_connections = 1
log_disconnections = 1
diff --git a/include/bouncer.h b/include/bouncer.h
index b4239ac..87a5a6c 100644
--- a/include/bouncer.h
+++ b/include/bouncer.h
@@ -232,6 +232,7 @@ struct PgDatabase {
char unix_socket_dir[UNIX_PATH_MAX]; /* custom unix socket dir */
int pool_size; /* max server connections in one pool */
+ int res_pool_size; /* additional server connections in case of trouble */
const char *dbname; /* server-side name, pointer to inside startup_msg */
@@ -309,6 +310,8 @@ extern int cf_listen_port;
extern int cf_pool_mode;
extern int cf_max_client_conn;
extern int cf_default_pool_size;
+extern int cf_res_pool_size;
+extern usec_t cf_res_pool_timeout;
extern char * cf_autodb_connstr;
extern usec_t cf_autodb_idle_timeout;
diff --git a/src/admin.c b/src/admin.c
index 55f559b..e757474 100644
--- a/src/admin.c
+++ b/src/admin.c
@@ -415,9 +415,9 @@ static bool admin_show_databases(PgSocket *admin, const char *arg)
return true;
}
- pktbuf_write_RowDescription(buf, "ssissi",
+ pktbuf_write_RowDescription(buf, "ssissii",
"name", "host", "port",
- "database", "force_user", "pool_size");
+ "database", "force_user", "pool_size", "reserve_pool");
statlist_for_each(item, &database_list) {
db = container_of(item, PgDatabase, head);
@@ -430,7 +430,8 @@ static bool admin_show_databases(PgSocket *admin, const char *arg)
pktbuf_write_DataRow(buf, "ssissi",
db->name, host, db->addr.port,
db->dbname, f_user,
- db->pool_size);
+ db->pool_size,
+ db->res_pool_size);
}
admin_flush(admin, buf, "SHOW");
return true;
diff --git a/src/janitor.c b/src/janitor.c
index c8e1217..8ec9b47 100644
--- a/src/janitor.c
+++ b/src/janitor.c
@@ -403,7 +403,7 @@ static void check_pool_size(PgPool *pool)
* statlist_count(&pool->new_server_list)
*/
- int many = cur - pool->db->pool_size;
+ int many = cur - (pool->db->pool_size + pool->db->res_pool_size);
Assert(pool->db->pool_size >= 0);
@@ -591,10 +591,14 @@ void config_postprocess(void)
statlist_for_each_safe(item, &database_list, tmp) {
db = container_of(item, PgDatabase, head);
- if (db->db_dead)
+ if (db->db_dead) {
kill_database(db);
- else if (db->pool_size < 0)
+ continue;
+ }
+ if (db->pool_size < 0)
db->pool_size = cf_default_pool_size;
+ if (db->res_pool_size < 0)
+ db->res_pool_size = cf_res_pool_size;
}
}
diff --git a/src/loader.c b/src/loader.c
index 5c64f0f..5a8a262 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -173,6 +173,7 @@ void parse_database(char *name, char *connstr)
PktBuf buf;
PgDatabase *db;
int pool_size = -1;
+ int res_pool_size = -1;
char *dbname = name;
char *host = NULL;
@@ -220,6 +221,8 @@ void parse_database(char *name, char *connstr)
timezone = val;
else if (strcmp("pool_size", key) == 0)
pool_size = atoi(val);
+ else if (strcmp("reserve_pool", key) == 0)
+ res_pool_size = atoi(val);
else if (strcmp("connect_query", key) == 0)
connect_query = val;
else {
@@ -319,6 +322,7 @@ void parse_database(char *name, char *connstr)
/* if pool_size < 0 it will be set later */
db->pool_size = pool_size;
+ db->res_pool_size = res_pool_size;
db->addr.port = v_port;
db->addr.ip_addr.s_addr = v_addr;
db->addr.is_unix = host ? 0 : 1;
diff --git a/src/main.c b/src/main.c
index 2209cfc..9472176 100644
--- a/src/main.c
+++ b/src/main.c
@@ -91,6 +91,8 @@ char *cf_auth_file = "unconfigured_file";
int cf_max_client_conn = 100;
int cf_default_pool_size = 20;
+int cf_res_pool_size = 0;
+usec_t cf_res_pool_timeout = 5;
char *cf_server_reset_query = "";
char *cf_server_check_query = "select 1";
@@ -143,6 +145,8 @@ ConfElem bouncer_params[] = {
{"pool_mode", true, {get_mode, set_mode}},
{"max_client_conn", true, CF_INT, &cf_max_client_conn},
{"default_pool_size", true, CF_INT, &cf_default_pool_size},
+{"reserve_pool_size", true, CF_INT, &cf_res_pool_size},
+{"reserve_pool_timeout",true, CF_INT, &cf_res_pool_timeout},
{"syslog", true, CF_INT, &cf_syslog},
{"syslog_facility", true, CF_STR, &cf_syslog_facility},
#ifndef WIN32
diff --git a/src/objects.c b/src/objects.c
index 8799ddd..18f9930 100644
--- a/src/objects.c
+++ b/src/objects.c
@@ -331,6 +331,8 @@ PgDatabase *register_auto_database(const char *name)
/* do not forget to check pool_size like in config_postprocess */
if (db->pool_size < 0)
db->pool_size = cf_default_pool_size;
+ if (db->res_pool_size < 0)
+ db->res_pool_size = cf_res_pool_size;
}
return db;
@@ -772,11 +774,23 @@ void launch_new_connection(PgPool *pool)
/* is it allowed to add servers? */
total = pool_server_count(pool);
if (total >= pool->db->pool_size && pool->welcome_msg_ready) {
+ /* should we use reserve pool? */
+ if (cf_res_pool_timeout && pool->db->res_pool_size) {
+ usec_t now = get_cached_time();
+ PgSocket *c = first_socket(&pool->waiting_client_list);
+ if (c && (now - c->request_time) >= cf_res_pool_timeout) {
+ if (total < pool->db->pool_size + pool->db->res_pool_size) {
+ log_debug("reserve_pool activated");
+ goto allow_new;
+ }
+ }
+ }
log_debug("launch_new_connection: pool full (%d >= %d)",
total, pool->db->pool_size);
return;
}
+allow_new:
/* get free conn object */
server = obj_alloc(server_cache);
if (!server) {
[parent: 2fa646f51a52]