Changeset: 1a3171304e2f for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=1a3171304e2f
Modified Files:
        monetdb5/mal/mal_runtime.c
        monetdb5/mal/mal_runtime.h
        monetdb5/modules/mal/sysmon.c
        monetdb5/modules/mal/sysmon.h
        monetdb5/modules/mal/sysmon.mal
        sql/ChangeLog
        sql/backends/monet5/sql.mal
        sql/backends/monet5/sql_upgrades.c
        sql/scripts/26_sysmon.sql
Branch: userstats
Log Message:

Adding a new monitoring function user_statistics

A table-returning function in which we keep some statistics for each SQL user.
Initial implementation was done by Martin (K.)


diffs (truncated from 317 to 300 lines):

diff --git a/monetdb5/mal/mal_runtime.c b/monetdb5/mal/mal_runtime.c
--- a/monetdb5/mal/mal_runtime.c
+++ b/monetdb5/mal/mal_runtime.c
@@ -27,9 +27,43 @@
 
 
 QueryQueue QRYqueue = NULL;
+UserStats  USRstats;
+lng        usize = 0;
+
 size_t qsize = 0, qhead = 0, qtail = 0;
 static oid qtag= 1;            // A unique query identifier
 
+static
+str
+updateUserStats(Client cntxt, lng ticks, time_t started, time_t finished, str 
query)
+{
+       int idx = (int) cntxt->idx;
+
+       if(idx > MAL_MAXCLIENTS){
+       }
+
+       if(usize == 0){
+               USRstats = (UserStats) GDKzalloc( sizeof (struct USERSTAT) * 
(size_t) (usize= MAL_MAXCLIENTS));
+       }
+       if(idx > usize){
+               USRstats = (UserStats) GDKrealloc( USRstats, sizeof (struct 
USERSTAT) * (size_t) (usize += MAL_MAXCLIENTS));
+       }
+       if( USRstats == NULL){
+       }
+       USRstats[idx].username= strdup(cntxt->username);
+       USRstats[idx].querycount++;
+       USRstats[idx].totalticks += ticks;
+       if( ticks > USRstats[idx].maxticks && query){
+               USRstats[idx].started = started;
+               USRstats[idx].finished = finished;
+               USRstats[idx].maxticks = ticks;
+               if( USRstats[idx].maxquery)
+                       GDKfree(USRstats[idx].maxquery);
+               USRstats[idx].maxquery= strdup(query);
+       }
+       return MAL_SUCCEED;
+}
+
 void
 mal_runtime_reset(void)
 {
@@ -155,7 +189,7 @@ runtimeProfileInit(Client cntxt, MalBlkP
                        paused += (QRYqueue[i].status[0] == 'p' || 
QRYqueue[i].status[0] == 'r'); /* running, prepared or paused */
        }
        assert(qhead < qsize);
-       if( (int) (qsize - paused) < MAL_MAXCLIENTS){
+       if( qsize - paused < (size_t) MAL_MAXCLIENTS){
                qsize += MAL_MAXCLIENTS;
                QRYqueue = (QueryQueue) GDKrealloc( QRYqueue, sizeof (struct 
QRYQUEUE) * qsize);
                if ( QRYqueue == NULL){
@@ -184,6 +218,7 @@ runtimeProfileInit(Client cntxt, MalBlkP
        QRYqueue[qhead].workers = (int) stk->workers;
        QRYqueue[qhead].status = "running";
        QRYqueue[qhead].cntxt = cntxt;
+       QRYqueue[qhead].ticks = GDKusec();
        stk->tag = mb->tag = QRYqueue[qhead].tag;
        advanceQRYqueue();
        MT_lock_unset(&mal_delayLock);
@@ -213,6 +248,7 @@ runtimeProfileFinish(Client cntxt, MalBl
                                mb->tag = stk->tag;
                                break;
                        }
+                       updateUserStats(cntxt, QRYqueue[i].ticks, 
QRYqueue[i].start, QRYqueue[i].finished, QRYqueue[i].query);
                        QRYqueue[i].status = "finished";
                        QRYqueue[i].finished = time(0);
                        QRYqueue[i].cntxt = 0;
diff --git a/monetdb5/mal/mal_runtime.h b/monetdb5/mal/mal_runtime.h
--- a/monetdb5/mal/mal_runtime.h
+++ b/monetdb5/mal/mal_runtime.h
@@ -35,11 +35,23 @@ typedef struct QRYQUEUE{
        int idx;
        int workers;
        int memory;
+       lng ticks;
        time_t start;
        time_t finished;
 } *QueryQueue;
 mal_export size_t qhead, qtail, qsize;
 
+/* We keep a few statistics per user to identify unexpected behavior */
+typedef struct USERSTAT{
+       str username;
+       int querycount;
+       lng totalticks;
+       time_t started;
+       time_t finished;
+       lng maxticks;
+       str maxquery;
+} *UserStats;
+
 typedef struct WORKINGSET{
        Client          cntxt;
     MalBlkPtr   mb;
@@ -58,4 +70,5 @@ mal_export lng getVolume(MalStkPtr stk, 
 mal_export lng getBatSpace(BAT *b);
 
 mal_export QueryQueue QRYqueue;
+mal_export UserStats USRstats;
 #endif
diff --git a/monetdb5/modules/mal/sysmon.c b/monetdb5/modules/mal/sysmon.c
--- a/monetdb5/modules/mal/sysmon.c
+++ b/monetdb5/modules/mal/sysmon.c
@@ -18,6 +18,116 @@
 */
 
 str
+SYSMONstatistics(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
+{
+       BAT *user, *querycount, *totalticks, *started, *finished, *query, 
*maxticks;
+       bat *u = getArgReference_bat(stk,pci,0);
+       bat *c = getArgReference_bat(stk,pci,1);
+       bat *t = getArgReference_bat(stk,pci,2);
+       bat *s = getArgReference_bat(stk,pci,3);
+       bat *f = getArgReference_bat(stk,pci,4);
+       bat *q = getArgReference_bat(stk,pci,5);
+       bat *m = getArgReference_bat(stk,pci,6);
+       lng i;
+       int sz;
+       timestamp tsn;
+       str msg = MAL_SUCCEED;
+
+       (void) cntxt;
+       (void) mb;
+       sz = MAL_MAXCLIENTS; // reserve space for all possible clients.
+       user = COLnew(0, TYPE_str, sz, TRANSIENT);
+       querycount = COLnew(0, TYPE_lng, sz, TRANSIENT);
+       totalticks = COLnew(0, TYPE_lng, sz, TRANSIENT);
+       started = COLnew(0, TYPE_timestamp, sz, TRANSIENT);
+       finished = COLnew(0, TYPE_timestamp, sz, TRANSIENT);
+       query = COLnew(0, TYPE_str, sz, TRANSIENT);
+       maxticks = COLnew(0, TYPE_lng, sz, TRANSIENT);
+       if ( user == NULL || querycount == NULL || totalticks == NULL || 
started == NULL || finished == NULL || query == NULL || maxticks == NULL){
+               BBPreclaim(user);
+               BBPreclaim(started);
+               BBPreclaim(querycount);
+               BBPreclaim(totalticks);
+               BBPreclaim(finished);
+               BBPreclaim(query);
+               BBPreclaim(maxticks);
+               throw(MAL, "SYSMONqueue", SQLSTATE(HY013) MAL_MALLOC_FAIL);
+       }
+
+       MT_lock_set(&mal_delayLock);
+       for ( i = 0; i < MAL_MAXCLIENTS; i++)
+               if( USRstats[i].querycount && cntxt->user == MAL_ADMIN ){
+
+                       if (BUNappend(user, USRstats[i].username, false) != 
GDK_SUCCEED) {
+                               msg = createException(MAL, "SYSMONqueue", 
"Username issue");
+                               goto bailout;
+                       }
+
+                       if( USRstats[i].maxquery == 0){
+                               if (BUNappend(query, "none", false) != 
GDK_SUCCEED ){
+                                       msg = createException(MAL, 
"SYSMONqueue", "Maxquery issue 1");
+                                       goto bailout;
+                               }
+                       }else {
+                               if (BUNappend(query, USRstats[i].maxquery, 
false) != GDK_SUCCEED ){
+                                       msg = createException(MAL, 
"SYSMONqueue", "Maxquery issue 2");
+                                       goto bailout;
+                               }
+                       }
+
+                       /* convert number of seconds into a timestamp */
+                       tsn = timestamp_fromtime(USRstats[i].started);
+                       if (is_timestamp_nil(tsn)) {
+                               msg = createException(MAL, "SYSMONqueue", 
SQLSTATE(22003) "cannot convert time");
+                               goto bailout;
+                       }
+                       if (BUNappend(started, &tsn, false) != GDK_SUCCEED){
+                               msg = createException(MAL, "SYSMONqueue", 
"Started");
+                               goto bailout;
+                       }
+
+                       tsn = timestamp_fromtime(USRstats[i].finished);
+                       if (is_timestamp_nil(tsn)) {
+                               msg = createException(MAL, "SYSMONqueue", 
SQLSTATE(22003) "cannot convert time");
+                               goto bailout;
+                       }
+                       if (BUNappend(finished, &tsn, false) != GDK_SUCCEED){
+                               msg = createException(MAL, "SYSMONqueue", 
"Finished");
+                               goto bailout;
+                       }
+                       if (BUNappend(querycount, &USRstats[i].querycount, 
false) != GDK_SUCCEED){
+                               msg = createException(MAL, "SYSMONqueue", 
"querycount");
+                               goto bailout;
+                       }
+                       if (BUNappend(totalticks, &USRstats[i].totalticks, 
false) != GDK_SUCCEED){
+                               msg = createException(MAL, "SYSMONqueue", 
"totalticks");
+                               goto bailout;
+                       }
+
+               }
+       MT_lock_unset(&mal_delayLock);
+       BBPkeepref( *u =user->batCacheid);
+       BBPkeepref( *c =querycount->batCacheid);
+       BBPkeepref( *t =totalticks->batCacheid);
+       BBPkeepref( *q =query->batCacheid);
+       BBPkeepref( *s =started->batCacheid);
+       BBPkeepref( *f =finished->batCacheid);
+       BBPkeepref( *m =maxticks->batCacheid);
+       return MAL_SUCCEED;
+
+bailout:
+       MT_lock_unset(&mal_delayLock);
+       BBPunfix(user->batCacheid);
+       BBPunfix(started->batCacheid);
+       BBPunfix(querycount->batCacheid);
+       BBPunfix(totalticks->batCacheid);
+       BBPunfix(finished->batCacheid);
+       BBPunfix(query->batCacheid);
+       BBPunfix(maxticks->batCacheid);
+       return msg;
+}
+
+str
 SYSMONqueue(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
 {
        BAT *tag, *sessionid, *user, *started, *status, *query, *finished, 
*workers, *memory;
diff --git a/monetdb5/modules/mal/sysmon.h b/monetdb5/modules/mal/sysmon.h
--- a/monetdb5/modules/mal/sysmon.h
+++ b/monetdb5/modules/mal/sysmon.h
@@ -15,5 +15,6 @@ mal_export str SYSMONpause(Client cntxt,
 mal_export str SYSMONresume(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 mal_export str SYSMONstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr 
pci);
 mal_export str SYSMONqueue(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr 
pci);
+mal_export str SYSMONstatistics(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 
 #endif /* _SYSMON_H */
diff --git a/monetdb5/modules/mal/sysmon.mal b/monetdb5/modules/mal/sysmon.mal
--- a/monetdb5/modules/mal/sysmon.mal
+++ b/monetdb5/modules/mal/sysmon.mal
@@ -39,3 +39,7 @@ comment "Stop a single query a.s.a.p.";
 pattern queue()(tag:bat[:lng], sessionid:bat[:int], user:bat[:str], 
started:bat[:timestamp],
 status:bat[:str], query:bat[:str], finished:bat[:timestamp], 
workers:bat[:int], memory:bat[:int])
 address SYSMONqueue;
+
+pattern statistics()(usr:bat[:str], qrycnt:bat[:lng], totalticks:bat[:lng], 
started:bat[:timestamp],
+finished:bat[:timestamp], maxqry:bat[:str], maxticks:bat[:lng])
+address SYSMONstatistics;
diff --git a/sql/ChangeLog b/sql/ChangeLog
--- a/sql/ChangeLog
+++ b/sql/ChangeLog
@@ -1,3 +1,8 @@
 # ChangeLog file for sql
 # This file is updated with Maddlog
 
+* Thu Apr  2 2020 Martin Kersten <[email protected]>
+- Extended the system monitor with a table-returning function
+  user_statistics() which keeps some statistics for each SQL user, e.g. the
+  user's query count, total time spent, and maximal query seen.
+
diff --git a/sql/backends/monet5/sql.mal b/sql/backends/monet5/sql.mal
--- a/sql/backends/monet5/sql.mal
+++ b/sql/backends/monet5/sql.mal
@@ -577,6 +577,10 @@ pattern sysmon_queue()(tag:bat[:lng], se
 status:bat[:str], query:bat[:str], finished:bat[:timestamp], 
workers:bat[:int], memory:bat[:int])
 address SYSMONqueue;
 
+pattern user_statistics()(usr:bat[:str], qrycnt:bat[:lng], 
totalticks:bat[:lng], started:bat[:timestamp],
+finished:bat[:timestamp], maxqry:bat[:str], maxticks:bat[:lng])
+address SYSMONstatistics;
+
 unsafe pattern sysmon_pause(tag:bte)
 address SYSMONpause;
 unsafe pattern sysmon_pause(tag:sht)
diff --git a/sql/backends/monet5/sql_upgrades.c 
b/sql/backends/monet5/sql_upgrades.c
--- a/sql/backends/monet5/sql_upgrades.c
+++ b/sql/backends/monet5/sql_upgrades.c
@@ -2311,7 +2311,19 @@ sql_update_jun2020(Client c, mvc *sql, c
 
                        "grant execute on procedure sys.pause(bigint) to 
public;\n"
                        "grant execute on procedure sys.resume(bigint) to 
public;\n"
-                       "grant execute on procedure sys.stop(bigint) to 
public;\n");
+                       "grant execute on procedure sys.stop(bigint) to 
public;\n"
+
+                       "create function sys.user_statistics() returns table(\n"
+                               "username string,\n"
+                               "querycount bigint,\n"
+                               "totalticks bigint,\n"
+                               "started timestamp,\n"
+                               "finished timestamp,\n"
+                               "maxquery string,\n"
+                               "maxticks bigint\n"
+                       ")\n"
+                       "external name sql.sysmon_statistics;\n"
+       );
 
        pos += snprintf(buf + pos, bufsize - pos,
                        "update sys.functions set system = true where system <> 
true and schema_id = (select id from sys.schemas where name = 'sys')"
diff --git a/sql/scripts/26_sysmon.sql b/sql/scripts/26_sysmon.sql
--- a/sql/scripts/26_sysmon.sql
+++ b/sql/scripts/26_sysmon.sql
@@ -35,3 +35,17 @@ grant execute on procedure sys.resume(bi
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to