static void foo(FILE *f, char *fn, int i) { pmDesc desc; char strbuf[60]; int sts; sts = pmLookupDesc(pmidlist[i], &desc); if (sts < 0) { fprintf(f, "%s: pmLookupDesc[%s] -> %s\n", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)), pmErrStr(sts)); pthread_exit("botch"); } else if (pmidlist[i] != desc.pmid) { fprintf(f, "%s: pmLookupDesc: Expecting PMID: %s", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); fprintf(f, " got: %s\n", pmIDStr_r(desc.pmid, strbuf, sizeof(strbuf))); pthread_exit("botch"); } else { fprintf(f, "%s: %s (%s) ->", fn, namelist[i], pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); fprintf(f, " %s", pmTypeStr_r(desc.type, strbuf, sizeof(strbuf))); fprintf(f, " %s", pmInDomStr_r(desc.indom, strbuf, sizeof(strbuf))); if (desc.sem == PM_SEM_COUNTER) fprintf(f, " counter"); else if (desc.sem == PM_SEM_INSTANT) fprintf(f, " instant"); else if (desc.sem == PM_SEM_DISCRETE) fprintf(f, " discrete"); else fprintf(f, " sem-%d", desc.sem); fprintf(f, " %s\n", pmUnitsStr_r(&desc.units, strbuf, sizeof(strbuf))); } }
int pmdaFetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; /* over pmidlist[] */ int j; /* over metatab and vset->vlist[] */ int sts; int need; int inst; int numval; pmValueSet *vset; pmDesc *dp; pmdaMetric metaBuf; pmdaMetric *metap; pmAtomValue atom; int type; e_ext_t *extp = (e_ext_t *)pmda->e_ext; if (extp->dispatch->version.any.ext != pmda) fprintf(stderr, "Botch: pmdaFetch: PMDA domain=%d pmda=%p extp=%p backpointer=%p pmda-via-backpointer %p NOT EQUAL to pmda\n", pmda->e_domain, pmda, extp, extp->dispatch, extp->dispatch->version.any.ext); if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5) __pmdaSetContext(pmda->e_context); if (numpmid > extp->maxnpmids) { if (extp->res != NULL) free(extp->res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((extp->res = (pmResult *) malloc(need)) == NULL) return -oserror(); extp->maxnpmids = numpmid; } extp->res->timestamp.tv_sec = 0; extp->res->timestamp.tv_usec = 0; extp->res->numpmid = numpmid; /* Look up the pmDesc for the incoming pmids in our pmdaMetrics tables, if present. Fall back to .desc callback if not found (for highly dynamic pmdas). */ for (i = 0; i < numpmid; i++) { dp = NULL; if (pmda->e_flags & PMDA_EXT_FLAG_HASHED) metap = __pmdaHashedSearch(pmidlist[i], &extp->hashpmids); else if (pmda->e_direct) metap = __pmdaDirectSearch(pmidlist[i], pmda); else metap = __pmdaLinearSearch(pmidlist[i], pmda); if (metap != NULL) dp = &(metap->m_desc); else { /* possibly a highly dynamic metric with null metrictab[] */ if (extp->dispatch->version.any.desc != NULL) { /* may need a temporary pmdaMetric for passing to e_fetchCallBack */ sts = (*(extp->dispatch->version.any.desc))(pmidlist[i], &metaBuf.m_desc, pmda); if (sts >= 0) { metaBuf.m_user = NULL; metap = &metaBuf; dp = &metaBuf.m_desc; } } } if (dp != NULL) { if (dp->indom != PM_INDOM_NULL) { /* count instances in the profile */ numval = 0; /* count instances in indom */ __pmdaStartInst(dp->indom, pmda); while (__pmdaNextInst(&inst, pmda)) { numval++; } } else { /* singular instance domains */ numval = 1; } } else { /* dynamic name metrics may often vanish, avoid log spam */ if (extp->dispatch->comm.pmda_interface < PMDA_INTERFACE_4) { char strbuf[20]; __pmNotifyErr(LOG_ERR, "pmdaFetch: Requested metric %s is not defined", pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); } numval = PM_ERR_PMID; } /* Must use individual malloc()s because of pmFreeResult() */ if (numval >= 1) extp->res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); else extp->res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) - sizeof(pmValue)); if (vset == NULL) { sts = -oserror(); goto error; } vset->pmid = pmidlist[i]; vset->numval = numval; vset->valfmt = PM_VAL_INSITU; if (vset->numval <= 0) continue; if (dp->indom == PM_INDOM_NULL) inst = PM_IN_NULL; else { __pmdaStartInst(dp->indom, pmda); __pmdaNextInst(&inst, pmda); } type = dp->type; j = 0; do { if (j == numval) { /* more instances than expected! */ numval++; extp->res->vset[i] = vset = (pmValueSet *)realloc(vset, sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); if (vset == NULL) { sts = -oserror(); goto error; } } vset->vlist[j].inst = inst; if ((sts = (*(pmda->e_fetchCallBack))(metap, inst, &atom)) < 0) { char strbuf[20]; pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)); if (sts == PM_ERR_PMID) { __pmNotifyErr(LOG_ERR, "pmdaFetch: PMID %s not handled by fetch callback\n", strbuf); } else if (sts == PM_ERR_INST) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { __pmNotifyErr(LOG_ERR, "pmdaFetch: Instance %d of PMID %s not handled by fetch callback\n", inst, strbuf); } #endif } else if (sts == PM_ERR_APPVERSION || sts == PM_ERR_PERMISSION || sts == PM_ERR_AGAIN || sts == PM_ERR_NYI) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { __pmNotifyErr(LOG_ERR, "pmdaFetch: Unavailable metric PMID %s[%d]\n", strbuf, inst); } #endif } else { __pmNotifyErr(LOG_ERR, "pmdaFetch: Fetch callback error from metric PMID %s[%d]: %s\n", strbuf, inst, pmErrStr(sts)); } } else { /* * PMDA_INTERFACE_2 * >= 0 => OK * PMDA_INTERFACE_3 or PMDA_INTERFACE_4 * == 0 => no values * > 0 => OK * PMDA_INTERFACE_5 or later * == 0 (PMDA_FETCH_NOVALUES) => no values * == 1 (PMDA_FETCH_STATIC) or > 2 => OK * == 2 (PMDA_FETCH_DYNAMIC) => OK and free(atom.vp) * after __pmStuffValue() called */ if (extp->dispatch->comm.pmda_interface == PMDA_INTERFACE_2 || (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_3 && sts > 0)) { int lsts; if ((lsts = __pmStuffValue(&atom, &vset->vlist[j], type)) == PM_ERR_TYPE) { char strbuf[20]; char st2buf[20]; __pmNotifyErr(LOG_ERR, "pmdaFetch: Descriptor type (%s) for metric %s is bad", pmTypeStr_r(type, strbuf, sizeof(strbuf)), pmIDStr_r(dp->pmid, st2buf, sizeof(st2buf))); } else if (lsts >= 0) { vset->valfmt = lsts; j++; } if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5 && sts == PMDA_FETCH_DYNAMIC) { if (type == PM_TYPE_STRING) free(atom.cp); else if (type == PM_TYPE_AGGREGATE) free(atom.vbp); else { char strbuf[20]; char st2buf[20]; __pmNotifyErr(LOG_WARNING, "pmdaFetch: Attempt to free value for metric %s of wrong type %s\n", pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)), pmTypeStr_r(type, st2buf, sizeof(st2buf))); } } if (lsts < 0) sts = lsts; } } } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, pmda)); if (j == 0) vset->numval = sts; else vset->numval = j; } *resp = extp->res; return 0; error: if (i) { extp->res->numpmid = i; __pmFreeResultValues(extp->res); } return sts; }
/* * Called when an error PDU containing PMCD_ADD_AGENT is received. * This function checks all of the configured metrics to make sure that * they have not changed. For example due to a PMDA being replaced by an * updated version */ void validate_metrics(void) { const task_t *tp; pmID *new_pmids; const pmDesc *old_desc; pmDesc new_desc; int index; int error; int sts; time_t now; char buf1[20], buf2[20]; time(&now); fprintf(stderr, "%s: Validating metrics after PMCD state changed at %s", pmProgname, ctime(&now)); /* * Check each metric in each element of the task list, whether it is * active or not. */ error = 0; for (tp = tasklist; tp != NULL; tp = tp->t_next) { /* We need at least one metric to look up. */ if (tp->t_numpmid < 1) continue; /* * Perform a bulk lookup and then check for consistency. * Lookup the metrics by name, since that's the way they are * specified in the pmlogger config file. * We need a temporary array for the new pmIDs */ new_pmids = malloc(tp->t_numpmid * sizeof(*tp->t_pmidlist)); if (new_pmids == NULL) { __pmNoMem("allocating pmID array for validating metrice", tp->t_numpmid * sizeof(*tp->t_pmidlist), PM_FATAL_ERR); } if ((sts = pmLookupName(tp->t_numpmid, tp->t_namelist, new_pmids)) < 0) { fprintf(stderr, "Error looking up metrics: Reason: %s\n", pmErrStr(sts)); exit(1); } /* Now check the individual metrics for problems. */ for (index = 0; index < tp->t_numpmid; ++index) { /* If there was an error looking up this metric, try again in order * to obtain the reason. If there is no error the second time * (possible), then the needed pmID will be fetched. */ if (new_pmids[index] == PM_ID_NULL) { if ((sts = pmLookupName(1, &tp->t_namelist[index], &new_pmids[index])) < 0) { /* The lookup of the metric is still in error. */ fprintf(stderr, "Error looking up %s: Reason: %s\n", tp->t_namelist[index], pmErrStr(sts)); ++error; continue; } /* No error the second time. Fall through */ } /* * Check that the pmid, type, semantics, instance domain and units * of the metric have not changed. */ if (new_pmids[index] != tp->t_pmidlist[index]) { fprintf(stderr, "PMID of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmIDStr_r(tp->t_pmidlist[index], buf1, sizeof(buf1)), pmIDStr_r(new_pmids[index], buf2, sizeof(buf2))); ++error; } if ((sts = pmLookupDesc(new_pmids[index], &new_desc)) < 0) { fprintf(stderr, "Description unavailable for metric \"%s\": %s\n", tp->t_namelist[index], pmErrStr(sts)); ++error; continue; } old_desc = &tp->t_desclist[index]; if (new_desc.type != old_desc->type) { fprintf(stderr, "Type of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmTypeStr_r(old_desc->type, buf1, sizeof(buf1)), pmTypeStr_r(new_desc.type, buf2, sizeof(buf2))); ++error; } if (new_desc.sem != old_desc->sem) { fprintf(stderr, "Semantics of metric \"%s\" have changed from %s to %s\n", tp->t_namelist[index], pmSemStr_r(old_desc->sem, buf1, sizeof(buf1)), pmSemStr_r(new_desc.sem, buf2, sizeof(buf2))); ++error; } if (new_desc.indom != old_desc->indom) { fprintf(stderr, "Instance domain of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmInDomStr_r(old_desc->indom, buf1, sizeof(buf1)), pmInDomStr_r(new_desc.indom, buf2, sizeof(buf2))); ++error; } if (new_desc.units.dimSpace != old_desc->units.dimSpace || new_desc.units.dimTime != old_desc->units.dimTime || new_desc.units.dimCount != old_desc->units.dimCount || new_desc.units.scaleSpace != old_desc->units.scaleSpace || new_desc.units.scaleTime != old_desc->units.scaleTime || new_desc.units.scaleCount != old_desc->units.scaleCount) { ++error; fprintf(stderr, "Units of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmUnitsStr_r(&old_desc->units, buf1, sizeof(buf1)), pmUnitsStr_r(&new_desc.units, buf2, sizeof(buf2))); } } /* loop over metrics */ free(new_pmids); } /* Loop over task list */ /* We cannot continue, if any of the metrics have changed. */ if (error) { fprintf(stderr, "One or more configured metrics have changed after pmcd state change. Exiting\n"); exit(1); } }