]> granicus.if.org Git - pgbouncer/commitdiff
pause/resume specific database
authorMarko Kreen <markokr@gmail.com>
Wed, 13 Jun 2007 21:08:29 +0000 (21:08 +0000)
committerMarko Kreen <markokr@gmail.com>
Wed, 13 Jun 2007 21:08:29 +0000 (21:08 +0000)
src/admin.c
src/bouncer.h
src/janitor.c

index b6822c4137599efc4617ea248a2049070e7a7fdd..f116192719aac2cd99d5b61d155076f746c812fb 100644 (file)
@@ -86,6 +86,34 @@ bool admin_error(PgSocket *admin, const char *fmt, ...)
        return res;
 }
 
+static int count_paused_databases(void)
+{
+       List *item;
+       PgDatabase *db;
+       int cnt = 0;
+
+       statlist_for_each(item, &database_list) {
+               db = container_of(item, PgDatabase, head);
+               cnt += db->db_paused;
+       }
+       return cnt;
+}
+
+static int count_db_active(PgDatabase *db)
+{
+       List *item;
+       PgPool *pool;
+       int cnt = 0;
+
+       statlist_for_each(item, &pool_list) {
+               pool = container_of(item, PgPool, head);
+               if (pool->db != db)
+                       continue;
+               cnt += pool_server_count(pool);
+       }
+       return cnt;
+}
+
 void admin_flush(PgSocket *admin, PktBuf *buf, const char *desc)
 {
        pktbuf_write_CommandComplete(buf, desc);
@@ -597,20 +625,31 @@ static bool admin_cmd_shutdown(PgSocket *admin, const char *arg)
 /* Command: RESUME */
 static bool admin_cmd_resume(PgSocket *admin, const char *arg)
 {
-       int tmp_mode = cf_pause_mode;
        if (!admin->admin_user)
                return admin_error(admin, "admin access needed");
 
-       log_info("RESUME command issued");
-       cf_pause_mode = P_NONE;
-       switch (tmp_mode) {
-       case P_SUSPEND:
-               resume_all();
-       case P_PAUSE:
-               return admin_ready(admin, "RESUME");
-       default:
-               return admin_error(admin, "Pooler is not paused/suspended");
+       if (!arg[0]) {
+               int tmp_mode = cf_pause_mode;
+               log_info("RESUME command issued");
+               cf_pause_mode = P_NONE;
+               switch (tmp_mode) {
+               case P_SUSPEND:
+                       resume_all();
+               case P_PAUSE:
+                       break;
+               default:
+                       return admin_error(admin, "Pooler is not paused/suspended");
+               }
+       } else {
+               PgDatabase *db = find_database(arg);
+               log_info("PAUSE '%s' command issued", arg);
+               if (db == NULL)
+                       return admin_error(admin, "no such database: %s", arg);
+               if (!db->db_paused)
+                       return admin_error(admin, "database %s is not paused", arg);
+               db->db_paused = 0;
        }
+       return admin_ready(admin, "RESUME");
 }
 
 /* Command: SUSPEND */
@@ -625,6 +664,10 @@ static bool admin_cmd_suspend(PgSocket *admin, const char *arg)
        if (cf_pause_mode)
                return admin_error(admin, "already suspended/paused");
 
+       /* suspend needs to be able to flush buffers */
+       if (count_paused_databases() > 0)
+               return admin_error(admin, "cannot suspend with paused databases");
+
        log_info("SUSPEND command issued");
        cf_pause_mode = P_SUSPEND;
        admin->wait_for_response = 1;
@@ -642,9 +685,24 @@ static bool admin_cmd_pause(PgSocket *admin, const char *arg)
        if (cf_pause_mode)
                return admin_error(admin, "already suspended/paused");
 
-       log_info("PAUSE command issued");
-       cf_pause_mode = P_PAUSE;
-       admin->wait_for_response = 1;
+       if (!arg[0]) {
+               log_info("PAUSE command issued");
+               cf_pause_mode = P_PAUSE;
+               admin->wait_for_response = 1;
+       } else {
+               PgDatabase *db;
+               log_info("PAUSE '%s' command issued", arg);
+               db = find_database(arg);
+               if (db == NULL)
+                       return admin_error(admin, "no such database: %s", arg);
+               if (db == admin->pool->db)
+                       return admin_error(admin, "cannot pause admin db: %s", arg);
+               db->db_paused = 1;
+               if (count_db_active(db) > 0)
+                       admin->wait_for_response = 1;
+               else
+                       return admin_ready(admin, "PAUSE");
+       }
 
        return true;
 }
@@ -937,7 +995,10 @@ void admin_pause_done(void)
                        admin_ready(admin, "SUSPEND");
                        break;
                default:
-                       fatal("admin_pause_done: bad state");
+                       if (count_paused_databases() > 0)
+                               admin_ready(admin, "PAUSE");
+                       else
+                               fatal("admin_pause_done: bad state");
                }
                admin->wait_for_response = 0;
        }
index f81598a755422aaa6e18b50e25df817f38795e42..c586eb077ad58471ec23ef78363759c52778d8ca 100644 (file)
@@ -182,6 +182,8 @@ struct PgDatabase {
        unsigned                welcome_msg_len;
        unsigned                welcome_msg_ready:1;
 
+       unsigned                db_paused:1;
+
        /* key/val pairs (without user) for startup msg to be sent to server */
        uint8                   startup_params[256];
        unsigned                startup_params_len;
index bda506df4def6c2cb72bf861b856427e3d7b74d2..a2b52863cd8436510f8b9497d8ab8f73182f47b6 100644 (file)
@@ -236,6 +236,7 @@ void per_loop_maint(void)
        List *item;
        PgPool *pool;
        int active = 0;
+       int partial_pause = 0;
 
        /* dont touch anything if takeover is in progress */
        if (cf_reboot)
@@ -247,7 +248,11 @@ void per_loop_maint(void)
                        continue;
                switch (cf_pause_mode) {
                case P_NONE:
-                       per_loop_activate(pool);
+                       if (pool->db->db_paused) {
+                               partial_pause = 1;
+                               active += per_loop_pause(pool);
+                       } else
+                               per_loop_activate(pool);
                        break;
                case P_PAUSE:
                        active += per_loop_pause(pool);
@@ -264,7 +269,10 @@ void per_loop_maint(void)
        case P_PAUSE:
                if (!active)
                        admin_pause_done();
-       default:
+               break;
+       case P_NONE:
+               if (partial_pause && !active)
+                       admin_pause_done();
                break;
        }
 }