Changeset: 19c920ee76ea for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/19c920ee76ea Modified Files: ChangeLog.Mar2025 monetdb5/mal/mal_client.c monetdb5/mal/mal_client.h monetdb5/mal/mal_session.c sql/backends/monet5/sql_scenario.c tools/mserver/mserver5.1.in Branch: Mar2025 Log Message:
Implemented an idle timeout. See mserver5 manual. (grafted from 233ef8b71026e64b3d7d6b3d925af9fb84e63537) diffs (142 lines): diff --git a/ChangeLog.Mar2025 b/ChangeLog.Mar2025 --- a/ChangeLog.Mar2025 +++ b/ChangeLog.Mar2025 @@ -1,3 +1,9 @@ # ChangeLog file for devel # This file is updated with Maddlog +* Thu May 8 2025 Sjoerd Mullender <[email protected]> +- It is now possible to specify an idle timeout using --set + idle_timeout=<seconds> (see mserver5 manual page) which gets triggered + if a connection to the server is idle (i.e. does not send any queries + to the server) while there is a SQL transaction active. + diff --git a/monetdb5/mal/mal_client.c b/monetdb5/mal/mal_client.c --- a/monetdb5/mal/mal_client.c +++ b/monetdb5/mal/mal_client.c @@ -265,6 +265,7 @@ MCinitClientRecord(Client c, oid user, b c->querytimeout = 0; c->sessiontimeout = 0; c->logical_sessiontimeout = 0; + c->idletimeout = 0; c->qryctx.starttime = 0; c->qryctx.endtime = 0; ATOMIC_SET(&c->qryctx.datasize, 0); @@ -399,6 +400,7 @@ MCcloseClient(Client c) c->qryctx.endtime = 0; c->sessiontimeout = 0; c->logical_sessiontimeout = 0; + c->idletimeout = 0; c->user = oid_nil; if (c->username) { GDKfree(c->username); diff --git a/monetdb5/mal/mal_client.h b/monetdb5/mal/mal_client.h --- a/monetdb5/mal/mal_client.h +++ b/monetdb5/mal/mal_client.h @@ -79,6 +79,7 @@ typedef struct CLIENT { lng maxmem; /* max_memory from db_user_info table */ lng sessiontimeout; /* session abort after x usec, 0 = no limit */ lng logical_sessiontimeout; /* logical session timeout, client defined */ + lng idletimeout; /* idle in active transaction timeout */ lng querytimeout; /* timeout per query in usec, 0 = no limit */ QryCtx qryctx; /* per query limitations */ diff --git a/monetdb5/mal/mal_session.c b/monetdb5/mal/mal_session.c --- a/monetdb5/mal/mal_session.c +++ b/monetdb5/mal/mal_session.c @@ -361,6 +361,7 @@ MSscheduleClient(str command, str peer, c->protocol = protocol; c->blocksize = blocksize; + mnstr_settimeout(c->fdin->s, 50, is_exiting, NULL); if (c->initClient) { if ((msg = c->initClient(c, passwd, challenge, algo)) != MAL_SUCCEED) { mnstr_printf(fout, "!%s\n", msg); @@ -373,7 +374,6 @@ MSscheduleClient(str command, str peer, } GDKfree(command); - mnstr_settimeout(c->fdin->s, 50, is_exiting, NULL); msg = MSserveClient(c); if (msg != MAL_SUCCEED) { freeException(msg); diff --git a/sql/backends/monet5/sql_scenario.c b/sql/backends/monet5/sql_scenario.c --- a/sql/backends/monet5/sql_scenario.c +++ b/sql/backends/monet5/sql_scenario.c @@ -936,11 +936,37 @@ SQLtrans(mvc *m) return MAL_SUCCEED; } +static bool +shouldStop(void *data) +{ + if (GDKexiting()) + return true; + Client c = data; + if (c) { + if (c->idletimeout && + c->idle && + c->sqlcontext && + ((backend *) c->sqlcontext)->mvc && + ((backend *) c->sqlcontext)->mvc->session && + ((backend *) c->sqlcontext)->mvc->session->tr && + ((backend *) c->sqlcontext)->mvc->session->tr->active && + time(NULL)- c->idle > c->idletimeout) + return true; + if (c->sessiontimeout && + c->session && + (GDKusec() - c->session) > c->sessiontimeout) + return true; + } + return false; +} + str SQLinitClient(Client c, const char *passwd, const char *challenge, const char *algo) { str msg = MAL_SUCCEED; + mnstr_settimeout(c->fdin->s, 50, shouldStop, c); + c->idletimeout = GDKgetenv_int("idle_timeout", 0); MT_lock_set(&sql_contextLock); if (!SQLstore) { MT_lock_unset(&sql_contextLock); @@ -1192,6 +1218,21 @@ SQLreader(Client c, backend *be) MT_lock_unset(&mal_contextLock); return msg; } + if (msg == MAL_SUCCEED && + c->idletimeout && + c->idle && + c->sqlcontext && + ((backend *) c->sqlcontext)->mvc && + ((backend *) c->sqlcontext)->mvc->session && + ((backend *) c->sqlcontext)->mvc->session->tr && + ((backend *) c->sqlcontext)->mvc->session->tr->active && + GDKusec() - c->idle > c->idletimeout) { + in->pos = in->len; /* skip rest of the input */ + MT_lock_set(&mal_contextLock); + c->mode = FINISHCLIENT; + MT_lock_unset(&mal_contextLock); + throw(SQL, "SQLreader", "Session aborted due to idle timeout"); + } MT_lock_set(&mal_contextLock); c->idle = 0; MT_lock_unset(&mal_contextLock); diff --git a/tools/mserver/mserver5.1.in b/tools/mserver/mserver5.1.in --- a/tools/mserver/mserver5.1.in +++ b/tools/mserver/mserver5.1.in @@ -510,6 +510,13 @@ therefore able to read and modify all da access to. In addition, if the C code causes a crash, all bets are off. .TP +\fBidle_timeout=\fP\fIseconds\fP +Set the idle timeout. +If there is an active transaction, and the client has not provided any +input to the server for the specified amount of time, the server will +close the connection and abort (rollback) the transaction. +The default is \fB0\fP which means no timeout. +.TP .B raw_strings=true The boolean option raw_strings controls how the sql scanner interprets string literals. If the value is _______________________________________________ checkin-list mailing list -- [email protected] To unsubscribe send an email to [email protected]
