Changeset: 1e0de7ef57df for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=1e0de7ef57df Modified Files: clients/Tests/MAL-signatures.stable.out clients/Tests/MAL-signatures.stable.out.int128 Branch: default Log Message:
Merged branch 'userstats' into 'default' diffs (truncated from 679 to 300 lines): diff --git a/ChangeLog.userstats b/ChangeLog.userstats new file mode 100644 --- /dev/null +++ b/ChangeLog.userstats @@ -0,0 +1,19 @@ +# ChangeLog file for userstats +# This file is updated with Maddlog + +* Mon Aug 10 2020 Ying Zhang <y.zh...@cwi.nl> +- Finished a first version of the new monitoring function + user_statistics(), which is only intended for the DBAs. + For each database user who has logged in during the current mserver5 + session, it returns + "username": login name of the database user, + "querycount": the number of queries this user has executed since his/her + first login, + "totalticks": the total execution time (in microsecond) of the queries ran + by this user, + "maxquery": the query with the longest execution time (if two queries have + the same execution time, the newer overwrites the older), + "maxticks": the execution time of the 'maxquery' (in microsecond), + "started": the start timestamp of the 'maxquery', + "finished": the finish timestamp of the 'maxquery'. + diff --git a/clients/Tests/MAL-signatures.stable.out b/clients/Tests/MAL-signatures.stable.out --- a/clients/Tests/MAL-signatures.stable.out +++ b/clients/Tests/MAL-signatures.stable.out @@ -8766,6 +8766,7 @@ stdout of test 'MAL-signatures` in direc [ "sysmon", "stop", "pattern sysmon.stop(X_1:int):void ", "SYSMONstop;", "" ] [ "sysmon", "stop", "pattern sysmon.stop(X_1:lng):void ", "SYSMONstop;", "" ] [ "sysmon", "stop", "pattern sysmon.stop(X_1:sht):void ", "SYSMONstop;", "" ] +[ "sysmon", "user_statistics", "pattern sysmon.user_statistics() (X_0:bat[:str], X_1:bat[:lng], X_2:bat[:lng], X_3:bat[:timestamp], X_4:bat[:timestamp], X_5:bat[:lng], X_6:bat[:str]) ", "SYSMONstatistics;", "" ] [ "tokenizer", "append", "command tokenizer.append(X_1:str):oid ", "TKNZRappend;", "" ] [ "tokenizer", "close", "command tokenizer.close():void ", "TKNZRclose;", "" ] [ "tokenizer", "depositFile", "command tokenizer.depositFile(X_1:str):void ", "TKNZRdepositFile;", "" ] diff --git a/clients/Tests/MAL-signatures.stable.out.int128 b/clients/Tests/MAL-signatures.stable.out.int128 --- a/clients/Tests/MAL-signatures.stable.out.int128 +++ b/clients/Tests/MAL-signatures.stable.out.int128 @@ -11730,6 +11730,7 @@ stdout of test 'MAL-signatures` in direc [ "sysmon", "stop", "pattern sysmon.stop(X_1:int):void ", "SYSMONstop;", "" ] [ "sysmon", "stop", "pattern sysmon.stop(X_1:lng):void ", "SYSMONstop;", "" ] [ "sysmon", "stop", "pattern sysmon.stop(X_1:sht):void ", "SYSMONstop;", "" ] +[ "sysmon", "user_statistics", "pattern sysmon.user_statistics() (X_0:bat[:str], X_1:bat[:lng], X_2:bat[:lng], X_3:bat[:timestamp], X_4:bat[:timestamp], X_5:bat[:lng], X_6:bat[:str]) ", "SYSMONstatistics;", "" ] [ "tokenizer", "append", "command tokenizer.append(X_1:str):oid ", "TKNZRappend;", "" ] [ "tokenizer", "close", "command tokenizer.close():void ", "TKNZRclose;", "" ] [ "tokenizer", "depositFile", "command tokenizer.depositFile(X_1:str):void ", "TKNZRdepositFile;", "" ] diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -1126,6 +1126,7 @@ str STRtostr(str *res, const str *src); str SYSMONpause(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str SYSMONqueue(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str SYSMONresume(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); +str SYSMONstatistics(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str SYSMONstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str SYScpuStatistics(bat *ret, bat *ret2); str SYSgdkEnv(bat *ret, bat *ret2); @@ -1176,6 +1177,7 @@ str TRNtrans_commit(Client cntxt, MalBlk int TYPE_blob; int TYPE_uuid; int TYPE_xml; +UserStats USRstats; str WLCaction(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str WLCappend(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str WLCcatalog(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); @@ -1837,6 +1839,7 @@ str updateRef; void updateScenario(str scen, str nme, MALfcn fcn); Module userModule(void); str userRef; +size_t usrstatscnt; str vectorRef; str window_boundRef; str wlcRef; 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 @@ -30,6 +30,97 @@ QueryQueue QRYqueue = NULL; size_t qsize = 0, qhead = 0, qtail = 0; static oid qtag= 1; // A unique query identifier +UserStats USRstats = NULL; +size_t usrstatscnt = 0; + +static void +clearUSRstats(size_t idx) +{ + USRstats[idx].user= 0; + USRstats[idx].username = 0; + USRstats[idx].querycount = 0; + USRstats[idx].totalticks = 0; + USRstats[idx].started = 0; + USRstats[idx].finished = 0; + USRstats[idx].maxticks = 0; + USRstats[idx].maxquery = 0; +} + +/* + * Find the index of the given 'user' in USRstats. + * For a new 'user' return a new free slot. + * If USRstats is full, extend it. + */ +static +size_t +getUSRstatsIdx(MalBlkPtr mb, oid user) +{ + size_t i = 0; + UserStats tmp = NULL; + + for (i = 0; i < usrstatscnt; i++) + /* The array is dense, so we either find the user or an empty slot. */ + if (USRstats[i].user == user || USRstats[i].username == NULL) + return i; + + /* expand USRstats */ + tmp = (UserStats) GDKrealloc(USRstats, sizeof (struct USERSTAT) * (size_t) (usrstatscnt += MAL_MAXCLIENTS)); + if (tmp == NULL) { + /* It's not a fatal error if we can't extend USRstats. + * We don't want to affect existing USRstats. */ + addMalException(mb,"getUSRstatsIdx" MAL_MALLOC_FAIL); + return (size_t) -1; + } + USRstats = tmp; + for ( ; i < usrstatscnt; i++) + clearUSRstats(i); + return usrstatscnt - MAL_MAXCLIENTS; +} + +static +void +updateUserStats(Client cntxt, MalBlkPtr mb, lng ticks, time_t started, time_t finished, str query) +{ + size_t idx = getUSRstatsIdx(mb, cntxt->user); + + if (idx == (size_t) -1) { + addMalException(mb, "updateUserStats" "Failed to get an entry in user statistics"); + return; + } + + if (USRstats[idx].username == NULL) { + USRstats[idx].user = cntxt->user; + USRstats[idx].username = GDKstrdup(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; + GDKfree(USRstats[idx].maxquery); + USRstats[idx].maxquery= GDKstrdup(query); + } +} + +/* + * Free up the whole USRstats before mserver5 exits. + */ +static void +dropUSRstats(void) +{ + size_t i; + MT_lock_set(&mal_delayLock); + for(i = 0; i < usrstatscnt; i++){ + GDKfree(USRstats[i].username); + GDKfree(USRstats[i].maxquery); + clearUSRstats(i); + } + GDKfree(USRstats); + USRstats = NULL; + MT_lock_unset(&mal_delayLock); +} + static str isaSQLquery(MalBlkPtr mb){ int i; @@ -116,6 +207,18 @@ runtimeProfileInit(Client cntxt, MalBlkP QueryQueue tmp = NULL; MT_lock_set(&mal_delayLock); + + if(USRstats == NULL){ + usrstatscnt = MAL_MAXCLIENTS; + USRstats = (UserStats) GDKzalloc( sizeof (struct USERSTAT) * usrstatscnt); + if(USRstats == NULL) { + addMalException(mb,"runtimeProfileInit" MAL_MALLOC_FAIL); + MT_lock_unset(&mal_delayLock); + return; + } + } + + tmp = QRYqueue; if ( QRYqueue == NULL) { QRYqueue = (QueryQueue) GDKzalloc( sizeof (struct QRYQUEUE) * (qsize= MAL_MAXCLIENTS)); @@ -141,7 +244,7 @@ runtimeProfileInit(Client cntxt, MalBlkP i = 0; } assert(qhead < qsize); - if( (int) (qsize - paused) < MAL_MAXCLIENTS){ + if( qsize - paused < (size_t) MAL_MAXCLIENTS){ qsize += MAL_MAXCLIENTS; tmp = (QueryQueue) GDKrealloc( QRYqueue, sizeof (struct QRYQUEUE) * qsize); if ( tmp == NULL){ @@ -171,6 +274,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); @@ -186,8 +290,6 @@ runtimeProfileFinish(Client cntxt, MalBl { size_t i; - (void) cntxt; - MT_lock_set(&mal_delayLock); i=qtail; while (i != qhead){ @@ -203,6 +305,8 @@ runtimeProfileFinish(Client cntxt, MalBl QRYqueue[i].cntxt = 0; QRYqueue[i].stk = 0; QRYqueue[i].mb = 0; + QRYqueue[i].ticks = GDKusec() - QRYqueue[i].ticks; + updateUserStats(cntxt, mb, QRYqueue[i].ticks, QRYqueue[i].start, QRYqueue[i].finished, QRYqueue[i].query); // assume that the user is now idle cntxt->idle = time(0); break; @@ -223,6 +327,9 @@ mal_runtime_reset(void) qtag= 1; qhead = 0; qtail = 0; + + dropUSRstats(); + usrstatscnt = 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,16 +35,30 @@ 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{ + oid user; /* user id in the auth administration */ + str username; + lng querycount; + lng totalticks; + time_t started; + time_t finished; + lng maxticks; + str maxquery; +} *UserStats; +mal_export size_t usrstatscnt; + typedef struct WORKINGSET{ Client cntxt; - MalBlkPtr mb; - MalStkPtr stk; - InstrPtr pci; + MalBlkPtr mb; + MalStkPtr stk; + InstrPtr pci; } Workingset; mal_export Workingset workingset[THREADS]; @@ -57,4 +71,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,129 @@ */ str +SYSMONstatistics(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) +{ + BAT *user, *querycount, *totalticks, *started, *finished, *maxquery, *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 *m = getArgReference_bat(stk,pci,5); + bat *q = getArgReference_bat(stk,pci,6); + size_t i; + timestamp tsn = timestamp_nil; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list