diff options
Diffstat (limited to 'src/pmlogrewrite/result.c')
-rw-r--r-- | src/pmlogrewrite/result.c | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/src/pmlogrewrite/result.c b/src/pmlogrewrite/result.c new file mode 100644 index 0000000..715b9d5 --- /dev/null +++ b/src/pmlogrewrite/result.c @@ -0,0 +1,730 @@ +/* + * pmResult rewrite methods for pmlogrewrite + * + * Copyright (c) 2011 Ken McDonell. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * pmResult rewriting is complicated because ... + * + * - deleting a metric involves moving all of the following rp->vset[] + * entries "up" one position and decrementing rp->numpmid + * - deleting an instance involves moving all of the following + * rp->vset[i]->vlist[] enties "up" one position and then decrementing + * rp->vset[i]->numval + * - rescaling values involves calling __pmStuffValue which modifies + * rp->vset[i]->vlist[j].value, and in the case of all types other than + * U32 or 32 this will involve an allocation for a new pmValueBlock + * ... we need to keep track of the previous pmValueBlock (if any) to + * avoid memory leaks + * - changing type has the same implications as rescaling + * - a single metric within a pmResult may have both rescaling and type + * change + * - the initial pmResult contains pointers into a PDU buffer so the fast + * track case in pmFreeresult() may not release any of the pmValueSet + * or pmValue or pmValueBlock allocations if pmFreeResult is given a + * rewritten pmResult, so we modify the pmResult in place but use save[] + * to remember the original pmValueSet when retyping or rescaling, use + * orig_numval[] to remember how many pmValue instances we had had for + * each pmValueSet, and use orig_numpmid to remember the original numpmid + * value + */ + +#include "pmapi.h" +#include "impl.h" +#include "logger.h" +#include <assert.h> + +/* + * Keep track of pmValueSets that have been moved aside to allow for + * new values from __pmStuffValue() during rewriting. + */ +static pmValueSet **save = NULL; +static int len_save = 0; + +/* + * Save rp->vset[idx] in save[idx], and build a new rp->vset[idx] + * for the number of values expected for this metric + */ +static int +save_vset(pmResult *rp, int idx) +{ + pmValueSet *vsp; + int need; + int j; + + if (save[idx] != NULL) + /* already done */ + return 1; + + vsp = save[idx] = rp->vset[idx]; + + if (vsp->numval > 0) + need = sizeof(pmValueSet) + (vsp->numval-1)*sizeof(pmValue); + else + need = sizeof(pmValueSet); + rp->vset[idx] = (pmValueSet *)malloc(need); + if (rp->vset[idx] == NULL) { + fprintf(stderr, "save_vset: malloc(%d) failed: %s\n", need, strerror(errno)); + abandon(); + /*NOTREACHED*/ + } + rp->vset[idx]->pmid = vsp->pmid; + rp->vset[idx]->numval = vsp->numval; + rp->vset[idx]->valfmt = vsp->valfmt; + for (j = 0; j < vsp->numval; j++) + rp->vset[idx]->vlist[j].inst = vsp->vlist[j].inst; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "save_vset: vset[%d] -> " PRINTF_P_PFX "%p (was " PRINTF_P_PFX "%p) pmid=%s numval=%d\n", + idx, rp->vset[idx], save[idx], pmIDStr(rp->vset[idx]->pmid), rp->vset[idx]->numval); + } +#endif + return 0; +} + +/* + * free the pval for the jth instance of the ith metric + */ +static void +free_pval(pmResult *rp, int i, int j) +{ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "free_pval: free(" PRINTF_P_PFX "%p) pmid=%s inst=%d\n", + rp->vset[i]->vlist[j].value.pval, pmIDStr(rp->vset[i]->pmid), rp->vset[i]->vlist[j].inst); + } +#endif + free(rp->vset[i]->vlist[j].value.pval); +} + +/* + * if a pmValueSet was saved via save_vset(), then free the newly build + * pmValueSet and put the old one back in place + */ +static void +clean_vset(pmResult *rp) +{ + int i; + int j; + + for (i = 0; i < rp->numpmid; i++) { + if (save[i] != NULL) { + if (rp->vset[i]->valfmt == PM_VAL_DPTR) { + /* values hanging off the pval */ + for (j = 0; j < rp->vset[i]->numval; j++) + free_pval(rp, i, j); + } + /* + * we did the vset[i] allocation in save_vset(), so malloc() + */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "clean_vset: free(" PRINTF_P_PFX "%p) pmValueSet pmid=%s\n", + rp->vset[i], pmIDStr(rp->vset[i]->pmid)); + } +#endif + free(rp->vset[i]); + rp->vset[i] = save[i]; + save[i] = NULL; + } + } +} + +/* + * pick/calculate one value from multiple values for the ith vset[] ... + * + * Note: pval->vbuf may not have correct alignment for all data types, + * so memcpy() rather than assign. + */ +static int +pick_val(int i, metricspec_t *mp) +{ + int j; + int pick = -1; + pmAtomValue jval; + pmAtomValue pickval; + + assert(inarch.rp->vset[i]->numval > 0); + + for (j = 0; j < inarch.rp->vset[i]->numval; j++) { + if (mp->output == OUTPUT_ONE) { + if (inarch.rp->vset[i]->vlist[j].inst == mp->one_inst) { + pick = j; + break; + } + continue; + } + if (j == 0) { + pick = 0; + switch (mp->old_desc.type) { + case PM_TYPE_64: + memcpy(&pickval.ll, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(__int64_t)); + break; + case PM_TYPE_U64: + memcpy(&pickval.ull, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(__uint64_t)); + break; + case PM_TYPE_FLOAT: + memcpy(&pickval.f, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(float)); + break; + case PM_TYPE_DOUBLE: + memcpy(&pickval.d, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(double)); + break; + } + if (mp->output == OUTPUT_MIN || mp->output == OUTPUT_MAX || + mp->output == OUTPUT_SUM || mp->output == OUTPUT_AVG) + continue; + } + switch (mp->old_desc.type) { + case PM_TYPE_32: + switch (mp->output) { + case OUTPUT_MIN: + if (inarch.rp->vset[i]->vlist[j].value.lval < inarch.rp->vset[i]->vlist[pick].value.lval) + pick = j; + break; + case OUTPUT_MAX: + if (inarch.rp->vset[i]->vlist[j].value.lval > inarch.rp->vset[i]->vlist[pick].value.lval) + pick = j; + break; + case OUTPUT_SUM: + case OUTPUT_AVG: + inarch.rp->vset[i]->vlist[0].value.lval += inarch.rp->vset[i]->vlist[j].value.lval; + break; + } + break; + case PM_TYPE_U32: + switch (mp->output) { + case OUTPUT_MIN: + if ((__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval < (__uint32_t)inarch.rp->vset[i]->vlist[pick].value.lval) + pick = j; + break; + case OUTPUT_MAX: + if ((__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval > (__uint32_t)inarch.rp->vset[i]->vlist[pick].value.lval) + pick = j; + break; + case OUTPUT_SUM: + case OUTPUT_AVG: + *(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval += (__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval; + break; + } + break; + case PM_TYPE_64: + memcpy(&jval.ll, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(__int64_t)); + switch (mp->output) { + case OUTPUT_MIN: + if (jval.ll < pickval.ll) { + pickval.ll = jval.ll; + pick = j; + } + break; + case OUTPUT_MAX: + if (jval.ll > pickval.ll) { + pickval.ll = jval.ll; + pick = j; + } + break; + case OUTPUT_SUM: + case OUTPUT_AVG: + pickval.ll += jval.ll; + break; + } + break; + case PM_TYPE_U64: + memcpy(&jval.ull, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(__int64_t)); + switch (mp->output) { + case OUTPUT_MIN: + if (jval.ull < pickval.ull) { + pickval.ull = jval.ull; + pick = j; + } + break; + case OUTPUT_MAX: + if (jval.ull > pickval.ull) { + pickval.ull = jval.ull; + pick = j; + } + break; + case OUTPUT_SUM: + case OUTPUT_AVG: + pickval.ull += jval.ull; + break; + } + break; + case PM_TYPE_FLOAT: + memcpy(&jval.f, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(float)); + switch (mp->output) { + case OUTPUT_MIN: + if (jval.f < pickval.f) { + pickval.f = jval.f; + pick = j; + } + break; + case OUTPUT_MAX: + if (jval.f > pickval.f) { + pickval.f = jval.f; + pick = j; + } + break; + case OUTPUT_SUM: + case OUTPUT_AVG: + pickval.f += jval.f; + break; + } + break; + case PM_TYPE_DOUBLE: + memcpy(&jval.d, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(double)); + switch (mp->output) { + case OUTPUT_MIN: + if (jval.d < pickval.d) { + pickval.d = jval.d; + pick = j; + } + break; + case OUTPUT_MAX: + if (jval.d > pickval.d) { + pickval.d = jval.d; + pick = j; + } + break; + case OUTPUT_SUM: + case OUTPUT_AVG: + pickval.d += jval.d; + break; + } + break; + } + } + + if (mp->output == OUTPUT_AVG) { + switch (mp->old_desc.type) { + case PM_TYPE_32: + inarch.rp->vset[i]->vlist[0].value.lval = (int)(0.5 + inarch.rp->vset[i]->vlist[0].value.lval / (double)inarch.rp->vset[i]->numval); + break; + case PM_TYPE_U32: + *(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval = (__uint32_t)(0.5 + *(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval / (double)inarch.rp->vset[i]->numval); + break; + case PM_TYPE_64: + pickval.ll = 0.5 + pickval.ll / (double)inarch.rp->vset[i]->numval; + break; + case PM_TYPE_U64: + pickval.ull = 0.5 + pickval.ull / (double)inarch.rp->vset[i]->numval; + break; + case PM_TYPE_FLOAT: + pickval.f = pickval.f / (float)inarch.rp->vset[i]->numval; + break; + case PM_TYPE_DOUBLE: + pickval.d = pickval.d / (double)inarch.rp->vset[i]->numval; + break; + } + } + if (mp->output == OUTPUT_AVG || mp->output == OUTPUT_SUM) { + switch (mp->old_desc.type) { + case PM_TYPE_64: + memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.ll, sizeof(__int64_t)); + break; + case PM_TYPE_U64: + memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.ull, sizeof(__uint64_t)); + break; + case PM_TYPE_FLOAT: + memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.f, sizeof(float)); + break; + case PM_TYPE_DOUBLE: + memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.d, sizeof(double)); + break; + } + } + + return pick; +} + +/* + * rescale values for the ith vset[] + */ +static void +rescale(int i, metricspec_t *mp) +{ + int sts; + int j; + pmAtomValue ival; + pmAtomValue oval; + int old_valfmt = inarch.rp->vset[i]->valfmt; + int already_saved; + pmValueSet *vsp; + + sts = old_valfmt; + already_saved = save_vset(inarch.rp, i); + if (already_saved) + vsp = inarch.rp->vset[i]; + else + vsp = save[i]; + for (j = 0; j < inarch.rp->vset[i]->numval; j++) { + sts = pmExtractValue(old_valfmt, &vsp->vlist[j], mp->old_desc.type, &ival, mp->old_desc.type); + if (sts < 0) { + /* + * No type conversion here, so error not expected + */ + fprintf(stderr, "%s: Botch: %s (%s): extracting value: %s\n", + pmProgname, mp->old_name, pmIDStr(mp->old_desc.pmid), pmErrStr(sts)); + inarch.rp->vset[i]->numval = j; + __pmDumpResult(stderr, inarch.rp); + abandon(); + /*NOTREACHED*/ + } + sts = pmConvScale(mp->old_desc.type, &ival, &mp->old_desc.units, &oval, &mp->new_desc.units); + if (sts < 0) { + /* + * unless the "units" are bad (and the parser is supposed to + * make sure this does not happen) we do not expect errors + * from pmConvScale() + */ + fprintf(stderr, "%s: Botch: %s (%s): scale conversion from %s", + pmProgname, mp->old_name, pmIDStr(mp->old_desc.pmid), pmUnitsStr(&mp->old_desc.units)); + fprintf(stderr, " to %s failed: %s\n", pmUnitsStr(&mp->new_desc.units), pmErrStr(sts)); + inarch.rp->vset[i]->numval = j; + __pmDumpResult(stderr, inarch.rp); + abandon(); + /*NOTREACHED*/ + } + if (already_saved && old_valfmt == PM_VAL_DPTR) { + /* + * current value uses pval that is from a previous call to + * __pmStuffValue() during rewriting, not a pointer into a + * PDU buffer + */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "rescale free(" PRINTF_P_PFX "%p) pval pmid=%s inst=%d\n", + inarch.rp->vset[i]->vlist[j].value.pval, + pmIDStr(inarch.rp->vset[i]->pmid), + inarch.rp->vset[i]->vlist[j].inst); + } +#endif + free(inarch.rp->vset[i]->vlist[j].value.pval); + } + sts = __pmStuffValue(&oval, &inarch.rp->vset[i]->vlist[j], mp->old_desc.type); + if (sts < 0) { + /* + * unless "type" is bad (which the parser is supposed to + * prevent) or malloc() failed, we do not expect errors from + * __pmStuffValue() + */ + fprintf(stderr, "%s: Botch: %s (%s): stuffing value %s (type=%s) into rewritten pmResult: %s\n", + pmProgname, mp->old_name, pmIDStr(mp->old_desc.pmid), pmAtomStr(&oval, mp->old_desc.type), pmTypeStr(mp->old_desc.type), pmErrStr(sts)); + inarch.rp->vset[i]->numval = j; + __pmDumpResult(stderr, inarch.rp); + abandon(); + /*NOTREACHED*/ + } + } + inarch.rp->vset[i]->valfmt = sts; +} + +/* + * change type of values for the ith vset[] ... real chance that this will + * fail, as some failure modes depend on the sign or size of the data + * values found in the pmResult + */ +static void +retype(int i, metricspec_t *mp) +{ + int sts; + int j; + pmAtomValue val; + int old_valfmt = inarch.rp->vset[i]->valfmt; + int already_saved; + pmValueSet *vsp; + + sts = old_valfmt; + already_saved = save_vset(inarch.rp, i); + if (already_saved) + vsp = inarch.rp->vset[i]; + else + vsp = save[i]; + for (j = 0; j < inarch.rp->vset[i]->numval; j++) { + sts = pmExtractValue(old_valfmt, &vsp->vlist[j], mp->old_desc.type, &val, mp->new_desc.type); + if (sts < 0) { + fprintf(stderr, "%s: Error: %s (%s): extracting value from type %s", + pmProgname, mp->old_name, pmIDStr(mp->old_desc.pmid), pmTypeStr(mp->old_desc.type)); + fprintf(stderr, " to %s: %s\n", pmTypeStr(mp->new_desc.type), pmErrStr(sts)); + inarch.rp->vset[i]->numval = j; + __pmDumpResult(stderr, inarch.rp); + abandon(); + /*NOTREACHED*/ + } + if (already_saved && old_valfmt == PM_VAL_DPTR) { + /* + * current value uses pval that is from a previous call to + * __pmStuffValue() during rewriting, not a pointer into a + * PDU buffer + */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "retype free(" PRINTF_P_PFX "%p) pval pmid=%s inst=%d\n", + inarch.rp->vset[i]->vlist[j].value.pval, + pmIDStr(inarch.rp->vset[i]->pmid), + inarch.rp->vset[i]->vlist[j].inst); + } +#endif + free(inarch.rp->vset[i]->vlist[j].value.pval); + } + sts = __pmStuffValue(&val, &inarch.rp->vset[i]->vlist[j], mp->new_desc.type); + if (sts < 0) { + /* + * unless "type" is bad (which the parser is supposed to + * prevent) or malloc() failed, we do not expect errors from + * __pmStuffValue() + */ + fprintf(stderr, "%s: Botch: %s (%s): stuffing value %s (type=%s) into rewritten pmResult: %s\n", + pmProgname, mp->old_name, pmIDStr(mp->old_desc.pmid), pmAtomStr(&val, mp->new_desc.type), pmTypeStr(mp->new_desc.type), pmErrStr(sts)); + inarch.rp->vset[i]->numval = j; + __pmDumpResult(stderr, inarch.rp); + abandon(); + /*NOTREACHED*/ + } + } + inarch.rp->vset[i]->valfmt = sts; +} + +void +do_result(void) +{ + metricspec_t *mp; + int i; + int j; + int sts; + int orig_numpmid; + int *orig_numval = NULL; + + orig_numpmid = inarch.rp->numpmid; + + if (inarch.rp->numpmid > len_save) { + /* expand save[] */ + save = (pmValueSet **)realloc(save, inarch.rp->numpmid * sizeof(save[0])); + if (save == NULL) { + fprintf(stderr, "save_vset: save realloc(...,%d) failed: %s\n", (int)(inarch.rp->numpmid * sizeof(save[0])), strerror(errno)); + abandon(); + /*NOTREACHED*/ + } + for (i = len_save; i < inarch.rp->numpmid; i++) + save[i] = NULL; + len_save = inarch.rp->numpmid; + } + orig_numval = (int *)malloc(orig_numpmid * sizeof(int)); + if (orig_numval == NULL) { + fprintf(stderr, "orig_numval malloc(%d) failed: %s\n", (int)(orig_numpmid * sizeof(int)), strerror(errno)); + abandon(); + /*NOTREACHED*/ + } + for (i = 0; i < orig_numpmid; i++) + orig_numval[i] = inarch.rp->vset[i]->numval; + + for (i = 0; i < inarch.rp->numpmid; i++) { + for (mp = metric_root; mp != NULL; mp = mp->m_next) { + if (inarch.rp->vset[i]->pmid != mp->old_desc.pmid) + continue; + if (mp->flags == 0 && mp->ip == NULL) + break; + if (mp->flags & METRIC_DELETE) { + /* move vset[i] to end of list, shuffle lower ones up */ + pmValueSet *vsp = inarch.rp->vset[i]; + pmValueSet *save_vsp = save[i]; + int save_numval; + save_numval = orig_numval[i]; +#if PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) + fprintf(stderr, "Delete: vset[%d] for %s\n", i, pmIDStr(inarch.rp->vset[i]->pmid)); +#endif + for (j = i+1; j < inarch.rp->numpmid; j++) { + inarch.rp->vset[j-1] = inarch.rp->vset[j]; + save[j-1] = save[j]; + orig_numval[j-1] = orig_numval[j]; + } + inarch.rp->vset[j-1] = vsp; + save[j-1] = save_vsp; + orig_numval[j-1] = save_numval; + /* one less metric to write out, process vset[i] again */ + inarch.rp->numpmid--; + i--; + break; + } +#if PCP_DEBUG + /* + * mflags that will not force any pmResult rewrite ... + * METRIC_CHANGE_NAME + * METRIC_CHANGE_SEM + */ + if (pmDebug & DBG_TRACE_APPL1) + fprintf(stderr, "Rewrite: vset[%d] for %s\n", i, pmIDStr(inarch.rp->vset[i]->pmid)); + +#endif + if (mp->flags & METRIC_CHANGE_PMID) + inarch.rp->vset[i]->pmid = mp->new_desc.pmid; + if ((mp->flags & METRIC_CHANGE_INDOM) && inarch.rp->vset[i]->numval > 0) { + if (mp->output != OUTPUT_ALL) { + /* + * Output only one value ... + * Some instance selection to be done for the following + * indom cases: + * non-NULL -> NULL + * pick one input value, singular output + * NULL -> non-NULL + * only one input value, magic-up instance id for + * output value from mp->one_inst + * non-NULL -> non-NULL + * pick one input value base in mp->one_inst, + * copy to output + */ + int pick = 0; + switch (mp->output) { + case OUTPUT_FIRST: + break; + case OUTPUT_LAST: + pick = inarch.rp->vset[i]->numval-1; + break; + case OUTPUT_ONE: + case OUTPUT_MIN: + case OUTPUT_MAX: + case OUTPUT_SUM: + case OUTPUT_AVG: + pick = pick_val(i, mp); + break; + } + if (pick >= 0) { + if (pick > 0) { + /* swap vlist[0] and vlist[pick] */ + pmValue save; + save = inarch.rp->vset[i]->vlist[0]; + inarch.rp->vset[i]->vlist[0] = inarch.rp->vset[i]->vlist[pick]; + inarch.rp->vset[i]->vlist[0].inst = inarch.rp->vset[i]->vlist[pick].inst; + inarch.rp->vset[i]->vlist[pick] = save; + } + if (mp->new_desc.indom == PM_INDOM_NULL) + inarch.rp->vset[i]->vlist[0].inst = PM_IN_NULL; + else if (mp->old_desc.indom == PM_INDOM_NULL) + inarch.rp->vset[i]->vlist[0].inst = mp->one_inst; + inarch.rp->vset[i]->numval = 1; + } + else + inarch.rp->vset[i]->numval = 0; + } + } + /* + * order below is deliberate ... + * - cull/renumber instances if needed + * - rescale if needed + * - fix type if needed + */ + if (mp->ip != NULL) { + /* rewrite/delete instance ids from the indom map */ + int k; + for (k = 0; k < mp->ip->numinst; k++) { + if (mp->ip->inst_flags[k] & INST_CHANGE_INST) { + for (j = 0; j < inarch.rp->vset[i]->numval; j++) { + if (inarch.rp->vset[i]->vlist[j].inst == mp->ip->old_inst[k]) { + inarch.rp->vset[i]->vlist[j].inst = mp->ip->new_inst[k]; + } + } + } + if (mp->ip->inst_flags[k] & INST_DELETE) { + for (j = 0; j < inarch.rp->vset[i]->numval; j++) { + if (inarch.rp->vset[i]->vlist[j].inst == mp->ip->old_inst[k]) { + j++; + while (j < inarch.rp->vset[i]->numval) { + inarch.rp->vset[i]->vlist[j-1] = inarch.rp->vset[i]->vlist[j]; + j++; + } + if (save[i] != NULL && + inarch.rp->vset[i]->valfmt == PM_VAL_DPTR) { + /* + * messy case ... last instance pval is + * from calling __pmStuffValue() in + * rewriting not a pointer into the PDU + * buffer, so free here because + * clean_vset() won't find it + */ + free_pval(inarch.rp, i, j-1); + } + inarch.rp->vset[i]->numval--; + } + } + } + } + } + if (mp->flags & METRIC_RESCALE) { + /* + * parser already checked that dimension is unchanged, + * scale is different and -s on command line or RESCALE + * in UNITS clause of metricspec => rescale values + */ + rescale(i, mp); + } + if (mp->flags & METRIC_CHANGE_TYPE) + retype(i, mp); + break; + } + } + + /* + * only output numpmid == 0 case if input was a mark record + */ + if (orig_numpmid == 0 || inarch.rp->numpmid > 0) { + unsigned long out_offset; + unsigned long peek_offset; + peek_offset = ftell(outarch.logctl.l_mfp); + sts = __pmEncodeResult(PDU_OVERRIDE2, inarch.rp, &inarch.logrec); + if (sts < 0) { + fprintf(stderr, "%s: Error: __pmEncodeResult: %s\n", + pmProgname, pmErrStr(sts)); + abandon(); + /*NOTREACHED*/ + } + peek_offset += ((__pmPDUHdr *)inarch.logrec)->len - sizeof(__pmPDUHdr) + 2*sizeof(int); + if (peek_offset > 0x7fffffff) { + /* + * data file size will exceed 2^31-1 bytes, so force + * volume switch + */ + newvolume(outarch.logctl.l_curvol+1); + } + out_offset = ftell(outarch.logctl.l_mfp); + if ((sts = __pmLogPutResult2(&outarch.logctl, inarch.logrec)) < 0) { + fprintf(stderr, "%s: Error: __pmLogPutResult2: log data: %s\n", + pmProgname, pmErrStr(sts)); + abandon(); + /*NOTREACHED*/ + } + /* do not free inarch.logrec ... this is a libpcp PDU buffer */ +#if PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + struct timeval stamp; + fprintf(stderr, "Log: write "); + stamp.tv_sec = inarch.rp->timestamp.tv_sec; + stamp.tv_usec = inarch.rp->timestamp.tv_usec; + __pmPrintStamp(stderr, &stamp); + fprintf(stderr, " numpmid=%d @ offset=%ld\n", inarch.rp->numpmid, out_offset); + } +#endif + } + + /* restore numpmid up so all vset[]s are freed */ + inarch.rp->numpmid = orig_numpmid; + /* + * put pmResult back the way it was (so pmFreeResult works correctly) + * and release any allocated memory used in the rewriting + */ + clean_vset(inarch.rp); + /* restore numval up so all vlist[]s are freed */ + for (i = 0; i < orig_numpmid; i++) + inarch.rp->vset[i]->numval = orig_numval[i]; + free(orig_numval); + + pmFreeResult(inarch.rp); +} |