]> granicus.if.org Git - pgbouncer/commitdiff
add per-user pool_mode
authorCody Cutrer <cody@cutrer.us>
Thu, 19 Jan 2012 23:01:30 +0000 (16:01 -0700)
committerCody Cutrer <cody@instructure.com>
Fri, 27 Sep 2013 19:39:47 +0000 (13:39 -0600)
doc/config.txt
doc/todo.txt
doc/usage.txt
include/bouncer.h
include/loader.h
include/server.h
src/admin.c
src/loader.c
src/main.c
src/objects.c
src/server.c

index 8ca116f200f24f41d340e656d3af3a0c9e56b8cc..3dcf789bb10c5920d7bb2429662aa3dac897c09d 100644 (file)
@@ -558,6 +558,19 @@ Ask specific +datestyle+ from server.
 
 Ask specific +timezone+ from server.
 
+== SECTION [users] ==
+
+This contains key=value pairs where key will be taken as a user name and
+value as a libpq connect-string style list of key=value pairs. As actual libpq is not
+used, so not all features from libpq can be used.
+
+=== Pool configuration ===
+
+==== pool_mode ====
+
+Set the pool mode to be used for all connections from this user. If not set, the
+database or default pool_mode is used.
+
 == AUTHENTICATION FILE FORMAT ==
 
 PgBouncer needs its own user database. The users are loaded from a text
index 1425e33935c5063bfa0171b7c0d1acb607c9a871..5724092704a48ee9ecae02ef89b3535d6f8a66b8 100644 (file)
@@ -22,9 +22,7 @@ Waiting for contributors...
 
  * hba-style access control
 
- * per-db pool_mode
-
- * per-user pool_mode, other settings ([users], user=connstr?)
+ * other per-user settings
 
  * identd authentication
 
index 3033e5d6905d2123ad80188865f7fcb5aff4dbba..f554b1488b64df0d377b17b80e972b8da1874e1d 100644 (file)
@@ -321,6 +321,8 @@ maxwait::
   not handle requests quick enough.  Reason may be either overloaded
   server or just too small of a +pool_size+ setting.
 
+pool_mode::
+  The pooling mode in use.
 
 ==== SHOW LISTS; ====
 
@@ -352,7 +354,11 @@ used_servers::
 
 ==== SHOW USERS; ====
 
-Shows one line per user, under the +name+ column name.
+name::
+  The user name
+
+pool_mode::
+  The user's override pool_mode, or NULL if the default will be used instead.
 
 ==== SHOW DATABASES; ====
 
@@ -377,7 +383,7 @@ pool_size::
   Maximum number of server connections.
 
 pool_mode::
-  The pooling mode in user for this database.
+  The database's override pool_mode, or NULL if the default will be used instead.
 
 ==== SHOW FDS; ====
 
index 3398e94b7d4e6b77452eda127aebf21717371985..e2e963f94efbaea82a8c9714460924700f1af3bd 100644 (file)
@@ -251,6 +251,7 @@ struct PgUser {
        struct AANode tree_node;        /* used to attach user to tree */
        char name[MAX_USERNAME];
        char passwd[MAX_PASSWORD];
+       int pool_mode;
 };
 
 /*
index 1400b61a7f938d70b8420d16981072ccf50e13fb..b9f02772b063d90a976ae14aab59f78d924a9bdb 100644 (file)
@@ -19,6 +19,8 @@
 /* connstring parsing */
 bool parse_database(void *base, const char *name, const char *connstr);
 
+bool parse_user(void *base, const char *name, const char *params);
+
 /* user file parsing */
 bool load_auth_file(const char *fn)  /* _MUSTCHECK */;
 bool loader_users_check(void)  /* _MUSTCHECK */;
index 870a590bc82f4b6e040cc085ad7e17b0c2570a1a..9e3490c67ab58148e85ede7a654980ab5858d3a9 100644 (file)
@@ -17,4 +17,4 @@
  */
 
 bool server_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *pkt)  _MUSTCHECK;
-
+int pool_pool_mode(PgPool *pool) _MUSTCHECK;
index a30eff1ca57956c5ca09548dc13532358ff8135c..5ae76979fbce9b57a3977ab3b16fe4446008a063 100644 (file)
@@ -441,8 +441,9 @@ static bool admin_show_databases(PgSocket *admin, const char *arg)
        const char *f_user;
        PktBuf *buf;
        struct CfValue cv;
-       int pool_mode;
+       const char *pool_mode_str;
 
+       cv.extra = pool_mode_map;
        buf = pktbuf_dynamic(256);
        if (!buf) {
                admin_error(admin, "no mem");
@@ -457,17 +458,16 @@ static bool admin_show_databases(PgSocket *admin, const char *arg)
                db = container_of(item, PgDatabase, head);
 
                f_user = db->forced_user ? db->forced_user->name : NULL;
-               pool_mode = db->pool_mode;
-               if (pool_mode == POOL_INHERIT)
-                       pool_mode = cf_pool_mode;
-               cv.value_p = &pool_mode;
-               cv.extra = pool_mode_map;
+               pool_mode_str = NULL;
+               cv.value_p = &db->pool_mode;
+               if (db->pool_mode != POOL_INHERIT)
+                       pool_mode_str = cf_get_lookup(&cv);
                pktbuf_write_DataRow(buf, "ssissiis",
                                     db->name, db->host, db->port,
                                     db->dbname, f_user,
                                     db->pool_size,
                                     db->res_pool_size,
-                                    cf_get_lookup(&cv));
+                                    pool_mode_str);
        }
        admin_flush(admin, buf, "SHOW");
        return true;
@@ -510,14 +510,24 @@ static bool admin_show_users(PgSocket *admin, const char *arg)
        PgUser *user;
        struct List *item;
        PktBuf *buf = pktbuf_dynamic(256);
+       struct CfValue cv;
+       const char *pool_mode_str;
+
        if (!buf) {
                admin_error(admin, "no mem");
                return true;
        }
-       pktbuf_write_RowDescription(buf, "s", "name");
+       cv.extra = pool_mode_map;
+
+       pktbuf_write_RowDescription(buf, "ss", "name", "pool_mode");
        statlist_for_each(item, &user_list) {
                user = container_of(item, PgUser, head);
-               pktbuf_write_DataRow(buf, "s", user->name);
+               pool_mode_str = NULL;
+               cv.value_p = &user->pool_mode;
+               if (user->pool_mode != POOL_INHERIT)
+                       pool_mode_str = cf_get_lookup(&cv);
+
+               pktbuf_write_DataRow(buf, "ss", user->name, pool_mode_str);
        }
        admin_flush(admin, buf, "SHOW");
        return true;
@@ -731,22 +741,28 @@ static bool admin_show_pools(PgSocket *admin, const char *arg)
        PktBuf *buf;
        PgSocket *waiter;
        usec_t now = get_cached_time();
+       struct CfValue cv;
+       int pool_mode;
 
+       cv.extra = pool_mode_map;
+       cv.value_p = &pool_mode;
        buf = pktbuf_dynamic(256);
        if (!buf) {
                admin_error(admin, "no mem");
                return true;
        }
-       pktbuf_write_RowDescription(buf, "ssiiiiiiii",
+       pktbuf_write_RowDescription(buf, "ssiiiiiiiis",
                                    "database", "user",
                                    "cl_active", "cl_waiting",
                                    "sv_active", "sv_idle",
                                    "sv_used", "sv_tested",
-                                   "sv_login", "maxwait");
+                                   "sv_login", "maxwait",
+                                   "pool_mode");
        statlist_for_each(item, &pool_list) {
                pool = container_of(item, PgPool, head);
                waiter = first_socket(&pool->waiting_client_list);
-               pktbuf_write_DataRow(buf, "ssiiiiiiii",
+               pool_mode = pool_pool_mode(pool);
+               pktbuf_write_DataRow(buf, "ssiiiiiiiis",
                                     pool->db->name, pool->user->name,
                                     statlist_count(&pool->active_client_list),
                                     statlist_count(&pool->waiting_client_list),
@@ -757,7 +773,8 @@ static bool admin_show_pools(PgSocket *admin, const char *arg)
                                     statlist_count(&pool->new_server_list),
                                     /* how long is the oldest client waited */
                                     (waiter && waiter->query_start)
-                                    ?  (int)((now - waiter->query_start) / USEC) : 0);
+                                    ?  (int)((now - waiter->query_start) / USEC) : 0,
+                                    cf_get_lookup(&cv));
        }
        admin_flush(admin, buf, "SHOW");
        return true;
index e7db4fd0559c40ef36a4b1d50a2763b4c90abc04..62b20560fb82e44bc26d62e7ace1863fa65ddeb6 100644 (file)
@@ -374,6 +374,58 @@ fail:
        return true;
 }
 
+bool parse_user(void *base, const char *name, const char *connstr)
+{
+       char *p, *key, *val, *tmp_connstr;
+       PgUser *user;
+       struct CfValue cv;
+       int pool_mode = POOL_INHERIT;
+
+       cv.value_p = &pool_mode;
+       cv.extra = (const void *)pool_mode_map;
+
+       tmp_connstr = strdup(connstr);
+       if (!tmp_connstr)
+               return false;
+
+       p = tmp_connstr;
+       while (*p) {
+               p = cstr_get_pair(p, &key, &val);
+               if (p == NULL) {
+                       log_error("%s: syntax error in user settings", name);
+                       goto fail;
+               } else if (!key[0])
+                       break;
+
+               if (strcmp("pool_mode", key) == 0) {
+                       if (!cf_set_lookup(&cv, val)) {
+                               log_error("skipping user %s because"
+                                         " of invalid pool mode: %s", name, val);
+                               goto fail;
+                       }
+               } else {
+                       log_error("skipping user %s because"
+                                 " of unknown parameter in settings: %s", name, key);
+                       goto fail;
+               }
+       }
+
+       user = find_user(name);
+       if (!user) {
+               user = add_user(name, "");
+               if (!user) {
+                       log_error("cannot create user, no memory?");
+                       goto fail;
+               }
+       }
+
+       user->pool_mode = pool_mode;
+
+fail:
+       free(tmp_connstr);
+       return true;
+}
+
 /*
  * User file parsing
  */
index 923b5302ab02a6896d5ba3238e2fb303f2430223..f74bd7bc470676522470e1a2d76ec737ad744c46 100644 (file)
@@ -235,6 +235,9 @@ static const struct CfSect config_sects [] = {
        }, {
                .sect_name = "databases",
                .set_key = parse_database,
+       }, {
+               .sect_name = "users",
+               .set_key = parse_user,
        }, {
                .sect_name = NULL,
        }
index d56dcd82ca2da67470d30387a02c1bb760572d53..b48f7740040981d2e58468550db8740a14a21f82 100644 (file)
@@ -361,6 +361,7 @@ PgUser *add_user(const char *name, const char *passwd)
                put_in_order(&user->head, &user_list, cmp_user);
 
                aatree_insert(&user_tree, (uintptr_t)user->name, &user->tree_node);
+               user->pool_mode = POOL_INHERIT;
        }
        safe_strcpy(user->passwd, passwd, sizeof(user->passwd));
        return user;
@@ -376,6 +377,7 @@ PgUser *force_user(PgDatabase *db, const char *name, const char *passwd)
                        return NULL;
                list_init(&user->head);
                list_init(&user->pool_list);
+               user->pool_mode = POOL_INHERIT;
        }
        safe_strcpy(user->name, name, sizeof(user->name));
        safe_strcpy(user->passwd, passwd, sizeof(user->passwd));
index ffa2515b6cd50ed8ec3c58d8c1f8e30fe079fe86..f21ba7af393f51f1c22aec0b3cb7e95a694059c4 100644 (file)
@@ -185,6 +185,16 @@ static bool handle_server_startup(PgSocket *server, PktHdr *pkt)
        return res;
 }
 
+int pool_pool_mode(PgPool *pool)
+{
+       int pool_mode = pool->user->pool_mode;
+       if (pool_mode == POOL_INHERIT)
+               pool_mode = pool->db->pool_mode;
+       if (pool_mode == POOL_INHERIT)
+               pool_mode = cf_pool_mode;
+       return pool_mode;
+}
+
 /* process packets on logged in connection */
 static bool handle_server_work(PgSocket *server, PktHdr *pkt)
 {
@@ -210,10 +220,9 @@ static bool handle_server_work(PgSocket *server, PktHdr *pkt)
                        return false;
 
                /* set ready only if no tx */
-               if (state == 'I') {
+               if (state == 'I')
                        ready = true;
-               } else if (server->pool->db->pool_mode == POOL_STMT ||
-                       (server->pool->db->pool_mode == POOL_INHERIT && cf_pool_mode == POOL_STMT)) {
+               else if (pool_pool_mode(server->pool) == POOL_STMT) {
                        disconnect_server(server, true, "Long transactions not allowed");
                        return false;
                } else if (state == 'T' || state == 'E') {
@@ -352,7 +361,6 @@ bool server_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *data)
        PgSocket *server = container_of(sbuf, PgSocket, sbuf);
        PgPool *pool = server->pool;
        PktHdr pkt;
-       int pool_mode;
 
        Assert(is_server_socket(server));
        Assert(server->state != SV_FREE);
@@ -420,10 +428,7 @@ bool server_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *data)
                        break;
                }
 
-               pool_mode = server->pool->db->pool_mode;
-               if (pool_mode == POOL_INHERIT)
-                       pool_mode = cf_pool_mode;               
-               if (pool_mode  != POOL_SESSION || server->state == SV_TESTED) {
+               if (pool_pool_mode(pool)  != POOL_SESSION || server->state == SV_TESTED) {
                        switch (server->state) {
                        case SV_ACTIVE:
                        case SV_TESTED: