From 5050658ae4d134f2fc808d9a47433f85aef0900a Mon Sep 17 00:00:00 2001 From: "Stephen R. van den Berg" <srb@cuci.nl> Date: Sun, 16 Dec 2018 11:14:34 +0100 Subject: [PATCH] pgsql: Autoterminate dangling database connections at program exit. --- lib/modules/Sql.pmod/pgsql_util.pmod | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/modules/Sql.pmod/pgsql_util.pmod b/lib/modules/Sql.pmod/pgsql_util.pmod index 6799aa42c2..645b494dae 100644 --- a/lib/modules/Sql.pmod/pgsql_util.pmod +++ b/lib/modules/Sql.pmod/pgsql_util.pmod @@ -84,7 +84,7 @@ final Pike.Backend local_backend; private Pike.Backend cb_backend; private sql_result qalreadyprinted; private Thread.Mutex backendmux = Thread.Mutex(); -private Thread.ResourceCount clientsregistered = Thread.ResourceCount(); +final multiset(proxy) clients = set_weak_flag((<>), Pike.WEAK); constant emptyarray = ({}); constant describenodata @@ -147,11 +147,17 @@ private void default_backend_runs() { // Runs as soon as the } private void create() { + atexit(destroy); // Run callbacks from our local_backend until DefaultBackend has started cb_backend = local_backend = Pike.SmallBackend(); call_out(default_backend_runs, 0); } +private void destroy() { + foreach (clients; proxy client; ) + destruct(client); +} + private Regexp iregexp(string expr) { Stdio.Buffer ret = Stdio.Buffer(); foreach (expr; ; int c) @@ -178,7 +184,7 @@ private void run_local_backend() { looponce = 0; if (lock = backendmux->trylock()) { PD("Starting local backend\n"); - while (!clientsregistered->drained() // Autoterminate when not needed + while (sizeof(clients) // Autoterminate when not needed || sizeof(local_backend->call_out_info())) { mixed err; if (err = catch(local_backend(4096.0))) @@ -186,19 +192,18 @@ private void run_local_backend() { } PD("Terminating local backend\n"); lock = 0; - looponce = !clientsregistered->drained(); + looponce = sizeof(clients); } } while (looponce); } //! Registers yourself as a user of this backend. If the backend //! has not been started yet, it will be spawned automatically. -final Thread.ResourceCountKey register_backend() { - int startbackend = clientsregistered->drained(); - Thread.ResourceCountKey key = clientsregistered->acquire(); +final void register_backend(proxy client) { + int startbackend = !sizeof(clients); + clients[client] = 1; if (startbackend) Thread.Thread(run_local_backend); - return key; } final void throwdelayederror(sql_result|proxy parent) { @@ -1718,7 +1723,6 @@ class proxy { final MUTEX unnamedportalmux; final MUTEX unnamedstatement; private Thread.MutexKey termlock; - private Thread.ResourceCountKey backendreg; final Thread.ResourceCount portalsinflight, statementsinflight; final int(0..1) wasparallelisable; final int(0..1) intransaction; @@ -1783,7 +1787,7 @@ class proxy { if (!port) port = PGSQL_DEFAULT_PORT; - backendreg = register_backend(); + register_backend(this); shortmux = MUTEX(); PD("Connect\n"); waitforauthready = Thread.Condition(); @@ -2544,7 +2548,7 @@ class proxy { if (err == MAGICTERMINATE) { // Announce connection termination to server catch { void|bufcon|conxsess cs = ci->start(); - CHAIN(cs)->add("X\0\0\0\4"); + CHAIN(cs)->add(PGSYNC)->add("X\0\0\0\4"); cs->sendcmd(SENDOUT); }; terminating = 1; @@ -2612,7 +2616,7 @@ class proxy { private void destroy() { string errstring; mixed err = catch(close()); - backendreg = 0; + clients[this] = 0; if (untolderror) { /* * Flush out any asynchronously reported errors to stderr; because we are -- GitLab