Changeset: f293b967a5f7 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=f293b967a5f7
Modified Files:
monetdb5/mal/mal.c
monetdb5/mal/mal_runtime.c
monetdb5/mal/mal_runtime.h
monetdb5/modules/mal/sysmon.c
monetdb5/modules/mal/sysmon.mal
sql/backends/monet5/sql_upgrades.c
sql/scripts/26_sysmon.sql
Branch: userstats
Log Message:
A basic working version of the sys.user_statistics() function.
Manually tested with two users.
diffs (truncated from 477 to 300 lines):
diff --git a/monetdb5/mal/mal.c b/monetdb5/mal/mal.c
--- a/monetdb5/mal/mal.c
+++ b/monetdb5/mal/mal.c
@@ -103,6 +103,7 @@ void mal_reset(void)
GDKprepareExit();
MCstopClients(0);
dropQRYqueue();
+ dropUSRstats();
setHeartbeat(-1);
stopProfiler(0);
AUTHreset();
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,30 +27,71 @@
QueryQueue QRYqueue = NULL;
-UserStats USRstats;
-lng usize = 0;
-
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
-str
-updateUserStats(Client cntxt, lng ticks, time_t started, time_t finished, str
query)
+size_t
+getUSRstatsIdx(MalBlkPtr mb, oid user)
{
- int idx = (int) cntxt->idx;
+ 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;
- if(idx > MAL_MAXCLIENTS){
+ /* 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(usize == 0){
- USRstats = (UserStats) GDKzalloc( sizeof (struct USERSTAT) *
(size_t) (usize= MAL_MAXCLIENTS));
+ if (USRstats[idx].username == NULL) {
+ USRstats[idx].user = cntxt->user;
+ USRstats[idx].username = GDKstrdup(cntxt->username);
}
- 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){
@@ -59,9 +100,26 @@ updateUserStats(Client cntxt, lng ticks,
USRstats[idx].maxticks = ticks;
if( USRstats[idx].maxquery)
GDKfree(USRstats[idx].maxquery);
- USRstats[idx].maxquery= strdup(query);
+ USRstats[idx].maxquery= GDKstrdup(query);
}
- return MAL_SUCCEED;
+}
+
+void
+dropUSRstats(void)
+{
+ size_t i;
+ MT_lock_set(&mal_delayLock);
+ for(i = 0; i < usrstatscnt; i++){
+ if(USRstats[i].username)
+ GDKfree(USRstats[i].username);
+ if( USRstats[i].maxquery)
+ GDKfree(USRstats[i].maxquery);
+ clearUSRstats(i); // FIXME: not needed since it's freed below
+ }
+ GDKfree(USRstats);
+ USRstats = NULL;
+ // FIXME: shouldn't reset usrstatscnt?
+ MT_lock_unset(&mal_delayLock);
}
void
@@ -73,6 +131,10 @@ mal_runtime_reset(void)
qtag= 1;
qhead = 0;
qtail = 0;
+
+ GDKfree(USRstats); // FIXME: where should we free the contents of
USRstats?
+ USRstats = NULL;
+ usrstatscnt = 0;
}
static str
@@ -148,7 +210,7 @@ dropQRYqueue(void)
GDKfree(QRYqueue[i].query);
if(QRYqueue[i].username)
GDKfree(QRYqueue[i].username);
- clearQRYqueue(i);
+ clearQRYqueue(i); // FIXME: not needed since it's freed below?
}
GDKfree(QRYqueue);
QRYqueue = NULL;
@@ -163,6 +225,18 @@ runtimeProfileInit(Client cntxt, MalBlkP
QueryQueue tmp;
MT_lock_set(&mal_delayLock);
+
+ // FIXME: is this the correct init function to initiate this?
+ if(USRstats == NULL){ // FIXME: isn't USRstats always NULL here?
+ 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= 8)); /* for testing */
@@ -194,7 +268,7 @@ runtimeProfileInit(Client cntxt, MalBlkP
QRYqueue = (QueryQueue) GDKrealloc( QRYqueue, sizeof (struct
QRYQUEUE) * qsize);
if ( QRYqueue == NULL){
addMalException(mb,"runtimeProfileInit"
MAL_MALLOC_FAIL);
- GDKfree(tmp);
+ GDKfree(tmp); // FIXME: shouldn't we free the contents
of 'tmp'?
MT_lock_unset(&mal_delayLock);
return;
}
@@ -235,9 +309,6 @@ runtimeProfileFinish(Client cntxt, MalBl
{
size_t i;
- (void) cntxt;
- (void) mb;
-
MT_lock_set(&mal_delayLock);
i=qtail;
while (i != qhead){
@@ -248,12 +319,12 @@ 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;
QRYqueue[i].stk = 0;
QRYqueue[i].mb = 0;
+ 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;
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
@@ -43,20 +43,22 @@ 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;
- int querycount;
+ 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];
@@ -66,6 +68,7 @@ mal_export void runtimeProfileFinish(Cli
mal_export void runtimeProfileBegin(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
InstrPtr pci, RuntimeProfile prof);
mal_export void runtimeProfileExit(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
InstrPtr pci, RuntimeProfile prof);
mal_export void dropQRYqueue(void);
+mal_export void dropUSRstats(void);
mal_export lng getVolume(MalStkPtr stk, InstrPtr pci, int rd);
mal_export lng getBatSpace(BAT *b);
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
@@ -20,110 +20,110 @@
str
SYSMONstatistics(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
- BAT *user, *querycount, *totalticks, *started, *finished, *query,
*maxticks;
+ 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 *q = getArgReference_bat(stk,pci,5);
- bat *m = getArgReference_bat(stk,pci,6);
- lng i;
- int sz;
+ bat *m = getArgReference_bat(stk,pci,5);
+ bat *q = getArgReference_bat(stk,pci,6);
+ size_t i;
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){
+ user = COLnew(0, TYPE_str, usrstatscnt, TRANSIENT);
+ querycount = COLnew(0, TYPE_lng, usrstatscnt, TRANSIENT);
+ totalticks = COLnew(0, TYPE_lng, usrstatscnt, TRANSIENT);
+ started = COLnew(0, TYPE_timestamp, usrstatscnt, TRANSIENT);
+ finished = COLnew(0, TYPE_timestamp, usrstatscnt, TRANSIENT);
+ maxticks = COLnew(0, TYPE_lng, usrstatscnt, TRANSIENT);
+ maxquery = COLnew(0, TYPE_str, usrstatscnt, TRANSIENT);
+ if (user == NULL || querycount == NULL || totalticks == NULL || started
== NULL || finished == NULL || maxquery == 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);
+ BBPreclaim(maxquery);
+ throw(MAL, "SYSMONstatistics", 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) {
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list