diff --git a/src/pmlogger/src/dopdu.c b/src/pmlogger/src/dopdu.c index 258a1ab..8bab8bc 100644 --- a/src/pmlogger/src/dopdu.c +++ b/src/pmlogger/src/dopdu.c @@ -80,11 +80,8 @@ reality_check(void) } } } - - } -/* Call this in dbx to dump the task list (dbx doesn't know about stdout) */ void dumpit(void) { @@ -180,7 +177,7 @@ findoptreq(pmID pmid, int inst) * structures lying about, i.e. MAYBE (mandatory) is the default, * and does not have to be explicitly stored, while OFF (advisory) * reverts to MAYBE (mandatory). - * There is one execption to the above assumption, namely for + * There is one exception to the above assumption, namely for * cases where the initial specification includes "all" instances, * then some later concurrent specification may refer to specific * instances ... in this case, the specific optreq_t structure is @@ -746,31 +743,6 @@ update_metric(pmValueSet *vsp, int reqstate, int mflags, task_t **result) return 0; } -/* Given a state and a delta, return in result the first matching task. - * Return true if a matching task was found - */ -static int -find_task(int state, int delta, task_t **result) -{ - task_t *tp; - int tdelta; - - /* Never return a "once only" task, it may have gone off already and just - * be hanging around - * TODO: cleanup once only tasks after callback invoked - */ - if (delta == 0) - return 0; - - for (tp = tasklist; tp != NULL; tp = tp->t_next) { - tdelta = tp->t_delta.tv_sec * 1000 + (tp->t_delta.tv_usec / 1000); - if (state == (tp->t_state & 0x3) && delta == tdelta) - break; - } - *result = tp; - return tp != NULL; -} - /* Return a mask containing the history flags for a given metric/instance. * the history flags indicate whether the metric/instance is in the log at all * and whether the last fetch of the metric/instance was successful. @@ -1051,7 +1023,8 @@ do_control(__pmPDU *pb) /* update the logging status of metrics */ task_t *newtp = NULL; /* task for metrics/insts in request */ - int newtask; + struct timeval tdelta = { 0 }; + int newtask = 0; int mflags; /* convert state and control to the bitmask used in pmlogger and values @@ -1069,8 +1042,16 @@ do_control(__pmPDU *pb) PMLC_SET_MAND(reqstate, 1); } - /* try to find an existing task for the request */ - newtask = !find_task(reqstate, delta, &newtp); + /* try to find an existing task for the request + * Never return a "once only" task, it may have gone off already and just + * be hanging around + * TODO: cleanup once only tasks after callback invoked + */ + if (delta != 0) { + tdelta.tv_sec = delta / 1000; + tdelta.tv_usec = (delta % 1000) * 1000; + newtask = !find_task(reqstate, &tdelta, &newtp); + } for (i = 0; i < request->numpmid; i++) { vsp = request->vset[i]; @@ -1110,16 +1091,15 @@ do_control(__pmPDU *pb) tasklist = newtp; /* use only the MAND/ADV and ON/OFF bits of reqstate */ - newtp->t_state = reqstate & 0x3; + newtp->t_state = newtp->t_firststate = reqstate & 0x3; if (PMLC_GET_ON(reqstate)) { - newtp->t_delta.tv_sec = delta / 1000; - newtp->t_delta.tv_usec = (delta % 1000) * 1000; - newtp->t_afid = __pmAFregister(&newtp->t_delta, (void *)newtp, + newtp->t_delta = tdelta; + newtp->t_afid = __pmAFregister(&tdelta, (void *)newtp, log_callback); } else newtp->t_delta.tv_sec = newtp->t_delta.tv_usec = 0; - linkback(newtp); /* TODO: really needed? (no) */ + linkback(newtp); } } } diff --git a/src/pmlogger/src/gram.y b/src/pmlogger/src/gram.y index 36b36fd..4ccfda2 100644 --- a/src/pmlogger/src/gram.y +++ b/src/pmlogger/src/gram.y @@ -54,15 +54,20 @@ typedef struct _hl { int hl_line; } hostlist_t; -static hostlist_t *hl_root = NULL; -static hostlist_t *hl_last = NULL; +static hostlist_t *hl_root; +static hostlist_t *hl_last; static hostlist_t *hlp; static hostlist_t *prevhlp; -static int opmask = 0; -static int specmask = 0; +static int opmask; +static int specmask; static int allow; -static int state = 0; -static char * metricName; +static int state; +static char *metricName; + +static int lookup_metric(const char *, task_t *, task_t **); +static void activate_metric(const char *); +static void activate_cached_metric(const char *, task_t *, int); + %} %union { long lval; @@ -117,7 +122,7 @@ stmt : dowhat somemetrics /* link fetchctl back to task */ fp->f_aux = (void *)tp; - if (PMLC_GET_ON(state)) + if (PMLC_GET_ON(tp->t_firststate)) tp->t_afid = __pmAFregister(&tp->t_delta, (void *)tp, log_callback); @@ -139,7 +144,7 @@ dowhat : logopt action } tp->t_delta.tv_sec = $2 / 1000; tp->t_delta.tv_usec = 1000 * ($2 % 1000); - tp->t_state = state; + tp->t_state = tp->t_firststate = state; } ; @@ -218,35 +223,32 @@ metricspec : NAME } optinst { + task_t *itp, *saved_tp = tp; + int sts; + /* - * search cache for previously seen metrics for this task + * search cache for previously seen metrics for this task; + * if found in cache we skip namespace PDU exchanges. */ - int j; - for (j = 0; j < tp->t_numpmid; j++) { - if (tp->t_namelist[j] != NULL && - strcmp(tp->t_namelist[j], metricName) == 0) { - break; - } - } - if (j < tp->t_numpmid) { - /* found in cache */ - dometric(metricName); + sts = lookup_metric(metricName, tp, &itp); + if (sts >= 0) { + activate_cached_metric(metricName, itp, sts); } else { /* - * either a new metric, and so it may be a - * non-terminal in the PMNS + * either a new metric or a non-terminal in the PMNS */ - if ((sts = pmTraversePMNS(metricName, dometric)) < 0 ) { + if ((sts = pmTraversePMNS(metricName, activate_metric)) < 0 ) { char emess[256]; sprintf(emess, "Problem with lookup for metric \"%s\" " - "... logging not activated",metricName); + "... logging not activated", metricName); yywarn(emess); fprintf(stderr, "Reason: %s\n", pmErrStr(sts)); } } freeinst(&numinst, intlist, extlist); - free (metricName); + free(metricName); + tp = saved_tp; } ; @@ -364,39 +366,49 @@ op : ADVISORY { opmask |= PM_OP_LOG_ADV; } %% /* + * Search the cache for previously seen metrics for given task. + * Optionally, attempt metric de-duplication by scanning other + * tasks with a matching delta/state combo as well. + * + * Returns -1 if not found, else index into t_namelist for the + * task returned via tpp. + */ +static int +lookup_metric(const char *name, task_t *itp, task_t **tpp) +{ + int j; + task_t *ltp = itp; + + if (!find_task(ltp->t_firststate, <p->t_delta, <p)) + ltp = itp; /* no match, reset to the default task (itp) */ + + for (j = 0; j < tp->t_numpmid; j++) { + if (ltp->t_namelist[j] && strcmp(ltp->t_namelist[j], name) == 0) + break; + } + *tpp = ltp; + return (j < tp->t_numpmid) ? j : -1; +} + +/* * Assumed calling context ... - * tp the correct task for the requested metric * numinst number of instances associated with this request * extlist[] external instance names if numinst > 0 * intlist[] internal instance identifier if numinst > 0 and * corresponding extlist[] entry is NULL */ - -void -dometric(const char *name) +static void +activate_cached_metric(const char *name, task_t *ltp, int dup) { - int sts = 0; /* initialize to pander to gcc */ + int sts = 0; int inst; int i; int j; - int dup = -1; int skip; pmID pmid; pmDesc *dp; optreq_t *rqp; - extern char *chk_emess[]; - char emess[1024]; - - /* - * search cache for previously seen metrics for this task - */ - for (j = 0; j < tp->t_numpmid; j++) { - if (tp->t_namelist[j] != NULL && - strcmp(tp->t_namelist[j], name) == 0) { - dup = j; - break; - } - } + char emess[1024]; /* * need new malloc'd pmDesc, even if metric found in cache @@ -409,7 +421,7 @@ dometric(const char *name) /* Cast away const, pmLookupName should never modify name */ if ((sts = pmLookupName(1, (char **)&name, &pmid)) < 0 || pmid == PM_ID_NULL) { - sprintf(emess, "Metric \"%s\" is unknown ... not logged", name); + sprintf(emess, "Metric \"%s\" is unknown ... not logged", name); goto defer; } @@ -420,24 +432,24 @@ dometric(const char *name) } } else { - *dp = tp->t_desclist[dup]; - pmid = tp->t_pmidlist[dup]; + *dp = ltp->t_desclist[dup]; + pmid = ltp->t_pmidlist[dup]; } - tp->t_numpmid++; - tp->t_pmidlist = (pmID *)realloc(tp->t_pmidlist, tp->t_numpmid * sizeof(pmID)); - if (tp->t_pmidlist == NULL) + ltp->t_numpmid++; + ltp->t_pmidlist = (pmID *)realloc(ltp->t_pmidlist, ltp->t_numpmid * sizeof(pmID)); + if (ltp->t_pmidlist == NULL) goto nomem; - tp->t_namelist = (char **)realloc(tp->t_namelist, tp->t_numpmid * sizeof(char *)); - if (tp->t_namelist == NULL) + ltp->t_namelist = (char **)realloc(ltp->t_namelist, ltp->t_numpmid * sizeof(char *)); + if (ltp->t_namelist == NULL) goto nomem; - tp->t_desclist = (pmDesc *)realloc(tp->t_desclist, tp->t_numpmid * sizeof(pmDesc)); - if (tp->t_desclist == NULL) + ltp->t_desclist = (pmDesc *)realloc(ltp->t_desclist, ltp->t_numpmid * sizeof(pmDesc)); + if (ltp->t_desclist == NULL) goto nomem; - if ((tp->t_namelist[tp->t_numpmid-1] = strdup(name)) == NULL) + if ((ltp->t_namelist[ltp->t_numpmid-1] = strdup(name)) == NULL) goto nomem; - tp->t_pmidlist[tp->t_numpmid-1] = pmid; - tp->t_desclist[tp->t_numpmid-1] = *dp; /* struct assignment */ + ltp->t_pmidlist[ltp->t_numpmid-1] = pmid; + ltp->t_desclist[ltp->t_numpmid-1] = *dp; /* struct assignment */ rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) @@ -477,7 +489,7 @@ dometric(const char *name) free(p); inst = intlist[i]; } - if ((sts = chk_one(tp, pmid, inst)) < 0) { + if ((sts = chk_one(ltp, pmid, inst)) < 0) { sprintf(emess, "Incompatible request for metric \"%s\" and instance \"%s\"", name, extlist[i]); yywarn(emess); @@ -491,7 +503,7 @@ dometric(const char *name) skip = 1; } else { - if ((sts = chk_all(tp, pmid)) < 0) { + if ((sts = chk_all(ltp, pmid)) < 0) { sprintf(emess, "Incompatible request for metric \"%s\"", name); yywarn(emess); @@ -540,3 +552,17 @@ snarf: free(dp); return; } + +/* + * Assumed calling context ... + * tp default (current) task for the requested metric + */ +static void +activate_metric(const char *name) +{ + int dup; + task_t *ltp = NULL; + + dup = lookup_metric(name, tp, <p); + activate_cached_metric(name, ltp, dup); +} diff --git a/src/pmlogger/src/logger.h b/src/pmlogger/src/logger.h index 7c136b9..c9551bc 100644 --- a/src/pmlogger/src/logger.h +++ b/src/pmlogger/src/logger.h @@ -30,6 +30,7 @@ typedef struct _task { struct _task *t_next; struct timeval t_delta; int t_state; /* logging state */ + int t_firststate; /* original logging state */ int t_numpmid; pmID *t_pmidlist; char **t_namelist; @@ -118,9 +119,9 @@ extern void yyerror(char *); extern void yywarn(char *); extern int yylex(void); extern int yyparse(void); -extern void dometric(const char *); extern void buildinst(int *, int **, char ***, int, char *); extern void freeinst(int *, int *, char **); +extern int find_task(int, struct timeval *, task_t **); extern void log_callback(int, void *); extern int chk_one(task_t *, pmID, int); extern int chk_all(task_t *, pmID); @@ -135,6 +136,7 @@ extern void run_done(int,char *); extern __pmPDU *rewrite_pdu(__pmPDU *, int); extern int putmark(void); extern int do_flush(void); +extern void dumpit(void); #include extern char pmlc_host[]; diff --git a/src/pmlogger/src/pmlogger.c b/src/pmlogger/src/pmlogger.c index e1d6455..526161d 100644 --- a/src/pmlogger/src/pmlogger.c +++ b/src/pmlogger/src/pmlogger.c @@ -751,10 +751,14 @@ Options:\n\ if (yyparse() != 0) exit(1); - - if ( configfile != NULL ) { + if (configfile != NULL) fclose(yyin); - } + + /* Walk tasklist post-config-parsing, tie off loose fetchgroup + * ends and register AFids now that we know what the tasks all + * are. + */ + /* prime_tasks(); */ #ifdef PCP_DEBUG fprintf(stderr, "Config parsed\n"); @@ -762,7 +766,6 @@ Options:\n\ fprintf(stderr, "Starting %slogger for host \"%s\" via \"%s\"\n", primary ? "primary " : "", pmcd_host, pmcd_host_conn); - #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "optFetch Cost Parameters: pmid=%d indom=%d fetch=%d scope=%d\n", diff --git a/src/pmlogger/src/util.c b/src/pmlogger/src/util.c index 0dfc47d..ba06556 100644 --- a/src/pmlogger/src/util.c +++ b/src/pmlogger/src/util.c @@ -70,3 +70,22 @@ freeinst(int *numinst, int *intlist, char **extlist) *numinst = 0; } } + +/* + * Given a state and a delta, return in result the first matching task. + * Return true if a matching task was found + */ +int +find_task(int state, struct timeval *delta, task_t **result) +{ + task_t *tp; + + for (tp = tasklist; tp != NULL; tp = tp->t_next) { + if (state == (tp->t_state & 0x3) && + delta->tv_sec == tp->t_delta.tv_sec && + delta->tv_usec == tp->t_delta.tv_usec) + break; + } + *result = tp; + return tp != NULL; +}