diff options
Diffstat (limited to 'src/libpcp_import')
-rw-r--r-- | src/libpcp_import/GNUmakefile | 38 | ||||
-rw-r--r-- | src/libpcp_import/src/GNUmakefile | 81 | ||||
-rw-r--r-- | src/libpcp_import/src/archive.c | 144 | ||||
-rw-r--r-- | src/libpcp_import/src/exports | 28 | ||||
-rw-r--r-- | src/libpcp_import/src/import.c | 726 | ||||
-rw-r--r-- | src/libpcp_import/src/private.h | 71 | ||||
-rw-r--r-- | src/libpcp_import/src/stuff.c | 178 |
7 files changed, 1266 insertions, 0 deletions
diff --git a/src/libpcp_import/GNUmakefile b/src/libpcp_import/GNUmakefile new file mode 100644 index 0000000..0cb0f4a --- /dev/null +++ b/src/libpcp_import/GNUmakefile @@ -0,0 +1,38 @@ +# +# Copyright (C) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This library 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 Lesser General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +# libpcp_import.so - import performance data and create PCP archives +# + +TOPDIR = ../.. + +include $(TOPDIR)/src/include/builddefs + +BASE = libpcp_import.a + +SUBDIRS = src + +default install: $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) + +default_pcp: default + +install_pcp: install + diff --git a/src/libpcp_import/src/GNUmakefile b/src/libpcp_import/src/GNUmakefile new file mode 100644 index 0000000..6c3c2aa --- /dev/null +++ b/src/libpcp_import/src/GNUmakefile @@ -0,0 +1,81 @@ +# +# Copyright (c) 2013 Red Hat. +# Copyright (c) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This library 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 Lesser General Public +# License for more details. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs +-include ./GNUlocaldefs + +CFILES = import.c stuff.c archive.c +HFILES = private.h +VERSION_SCRIPT = exports + +STATICLIBTARGET = libpcp_import.a +DSOVERSION = 1 +LIBTARGET = libpcp_import.$(DSOSUFFIX).$(DSOVERSION) +SYMTARGET = libpcp_import.$(DSOSUFFIX) +ifeq "$(TARGET_OS)" "darwin" +LIBTARGET = libpcp_import.$(DSOVERSION).$(DSOSUFFIX) +endif +ifeq "$(TARGET_OS)" "mingw" +LIBTARGET = libpcp_import.$(DSOSUFFIX) +SYMTARGET = +STATICLIBTARGET = +endif +ifeq "$(ENABLE_SHARED)" "no" +LIBTARGET = +SYMTARGET = +endif + +LCFLAGS = +LLDLIBS = -lpcp +LSRCFILES = $(VERSION_SCRIPT) +LDIRT = $(SYMTARGET) domain.h + +DOMAIN = PMI_DOMAIN + +default: domain.h $(LIBTARGET) $(SYMTARGET) $(STATICLIBTARGET) + +$(OBJECTS): $(HFILES) + +include $(BUILDRULES) + +install: default +ifneq ($(LIBTARGET),) + $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET) +endif +ifneq ($(SYMTARGET),) + for tt in $(SYMTARGET); do \ + $(INSTALL) -S $(LIBTARGET) $(PCP_LIB_DIR)/$$tt || exit 1; \ + done +endif +ifneq ($(STATICLIBTARGET),) + $(INSTALL) -m 755 $(STATICLIBTARGET) $(PCP_LIB_DIR)/$(STATICLIBTARGET) +endif + +default_pcp: default + +install_pcp: install + +ifneq ($(SYMTARGET),) +$(SYMTARGET): + $(LN_S) -f $(LIBTARGET) $@ +endif + +ifneq ($(LIBTARGET),) +$(LIBTARGET): $(VERSION_SCRIPT) +endif + +domain.h: $(TOPDIR)/src/pmns/stdpmid + $(DOMAIN_MAKERULE) diff --git a/src/libpcp_import/src/archive.c b/src/libpcp_import/src/archive.c new file mode 100644 index 0000000..4c1a0e3 --- /dev/null +++ b/src/libpcp_import/src/archive.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2010 Ken McDonell. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "import.h" +#include "private.h" + +static __pmTimeval stamp; + +int +_pmi_put_result(pmi_context *current, pmResult *result) +{ + int sts; + char *host; + char myname[MAXHOSTNAMELEN]; + __pmPDU *pb; + __pmLogCtl *lcp = ¤t->logctl; + int k; + int i; + int m; + int needti; + + /* + * some front-end tools use lazy discovery of instances and/or process + * data in non-deterministic order ... it is simpler for everyone if + * we sort the values into ascending instance order. + */ + pmSortInstances(result); + + stamp.tv_sec = result->timestamp.tv_sec; + stamp.tv_usec = result->timestamp.tv_usec; + + if (current->state == CONTEXT_START) { + if (current->hostname == NULL) { + (void)gethostname(myname, MAXHOSTNAMELEN); + myname[MAXHOSTNAMELEN-1] = '\0'; + host = myname; + } + else + host = current->hostname; + + sts = __pmLogCreate(host, current->archive, PM_LOG_VERS02, lcp); + if (sts < 0) + return sts; + + if (current->timezone == NULL) { + char tzbuf[PM_TZ_MAXLEN]; + strcpy(lcp->l_label.ill_tz, __pmTimezone_r(tzbuf, sizeof(tzbuf))); + } + else + strcpy(lcp->l_label.ill_tz, current->timezone); + pmNewZone(lcp->l_label.ill_tz); + current->state = CONTEXT_ACTIVE; + + /* + * do the label records (it is too late when __pmLogPutResult + * or __pmLogPutResult2 is called as we've already output some + * metadata) ... this code is stolen from logputresult() in + * libpcp + */ + lcp->l_label.ill_start.tv_sec = stamp.tv_sec; + lcp->l_label.ill_start.tv_usec = stamp.tv_usec; + lcp->l_label.ill_vol = PM_LOG_VOL_TI; + __pmLogWriteLabel(lcp->l_tifp, &lcp->l_label); + lcp->l_label.ill_vol = PM_LOG_VOL_META; + __pmLogWriteLabel(lcp->l_mdfp, &lcp->l_label); + lcp->l_label.ill_vol = 0; + __pmLogWriteLabel(lcp->l_mfp, &lcp->l_label); + lcp->l_state = PM_LOG_STATE_INIT; + __pmLogPutIndex(¤t->logctl, &stamp); + } + + __pmOverrideLastFd(fileno(lcp->l_mfp)); + if ((sts = __pmEncodeResult(fileno(lcp->l_mfp), result, &pb)) < 0) + return sts; + + needti = 0; + for (k = 0; k < result->numpmid; k++) { + for (m = 0; m < current->nmetric; m++) { + if (result->vset[k]->pmid != current->metric[m].pmid) + continue; + if (current->metric[m].meta_done == 0) { + char **namelist = ¤t->metric[m].name; + + if ((sts = __pmLogPutDesc(lcp, ¤t->metric[m].desc, 1, namelist)) < 0) { + __pmUnpinPDUBuf(pb); + return sts; + } + current->metric[m].meta_done = 1; + needti = 1; + } + if (current->metric[m].desc.indom != PM_INDOM_NULL) { + for (i = 0; i < current->nindom; i++) { + if (current->metric[m].desc.indom == current->indom[i].indom) { + if (current->indom[i].meta_done == 0) { + if ((sts = __pmLogPutInDom(lcp, current->indom[i].indom, &stamp, current->indom[i].ninstance, current->indom[i].inst, current->indom[i].name)) < 0) { + __pmUnpinPDUBuf(pb); + return sts; + } + current->indom[i].meta_done = 1; + needti = 1; + } + } + } + } + break; + } + } + if (needti) { + __pmLogPutIndex(lcp, &stamp); + } + + if ((sts = __pmLogPutResult2(lcp, pb)) < 0) { + __pmUnpinPDUBuf(pb); + return sts; + } + + __pmUnpinPDUBuf(pb); + return 0; +} + +int +_pmi_end(pmi_context *current) +{ + /* Final temporal index update to finish the archive + * ... same logic here as in run_done() for pmlogger + */ + __pmLogPutIndex(¤t->logctl, &stamp); + + current->state = CONTEXT_END; + return 0; +} diff --git a/src/libpcp_import/src/exports b/src/libpcp_import/src/exports new file mode 100644 index 0000000..a544262 --- /dev/null +++ b/src/libpcp_import/src/exports @@ -0,0 +1,28 @@ +PCP_IMPORT_1.0 { + global: + pmiStart; + pmiSetHostname; + pmiSetTimezone; + pmiUseContext; + pmiGetHandle; + pmiDump; + pmiEnd; + + pmiAddInstance; + pmiAddMetric; + + pmiErrStr; + pmiErrStr_r; + + pmiID; + pmiInDom; + pmiUnits; + + pmiPutResult; + pmiPutValue; + pmiPutValueHandle; + + pmiWrite; + + local: *; +}; diff --git a/src/libpcp_import/src/import.c b/src/libpcp_import/src/import.c new file mode 100644 index 0000000..71b8c7f --- /dev/null +++ b/src/libpcp_import/src/import.c @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 2010 Ken McDonell. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "import.h" +#include "domain.h" +#include "private.h" +#include <ctype.h> + +static pmi_context *context_tab; +static int ncontext; +static pmi_context *current; + +static void +printstamp(FILE *f, const struct timeval *tp) +{ + struct tm tmp; + time_t now; + + now = (time_t)tp->tv_sec; + pmLocaltime(&now, &tmp); + fprintf(f, "%4d-%02d-%02d %02d:%02d:%02d.%06d", 1900+tmp.tm_year, tmp.tm_mon, tmp.tm_mday, tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(tp->tv_usec)); +} + + +void +pmiDump(void) +{ + FILE *f = stderr; + + fprintf(f, "pmiDump: context %ld of %d", + (long)(current - context_tab), ncontext); + if (current == NULL) { + fprintf(f, " Error: current context is not defined.\n"); + return; + } + else { + fprintf(f, " archive: %s\n", + current->archive == NULL ? "<undefined>" : current->archive); + } + fprintf(f, " state: %d ", current->state); + switch (current->state) { + case CONTEXT_START: + fprintf(f, "(start)"); + break; + case CONTEXT_ACTIVE: + fprintf(f, "(active)"); + break; + case CONTEXT_END: + fprintf(f, "(end)"); + break; + default: + fprintf(f, "(BAD)"); + break; + } + fprintf(f, " hostname: %s timezone: %s\n", + current->hostname == NULL ? "<undefined>" : current->hostname, + current->timezone == NULL ? "<undefined>" : current->timezone); + if (current->nmetric == 0) + fprintf(f, " No metrics.\n"); + else { + int m; + char strbuf[20]; + for (m = 0; m < current->nmetric; m++) { + fprintf(f, " metric[%d] name=%s pmid=%s\n", + m, current->metric[m].name, + pmIDStr_r(current->metric[m].pmid, strbuf, sizeof(strbuf))); + __pmPrintDesc(f, ¤t->metric[m].desc); + } + } + if (current->nindom == 0) + fprintf(f, " No indoms.\n"); + else { + int i; + char strbuf[20]; + for (i = 0; i < current->nindom; i++) { + fprintf(f, " indom[%d] indom=%s", + i, pmInDomStr_r(current->indom[i].indom, strbuf, sizeof(strbuf))); + if (current->indom[i].ninstance == 0) { + fprintf(f, " No instances.\n"); + } + else { + int j; + fputc('\n', f); + for (j = 0; j < current->indom[i].ninstance; j++) { + fprintf(f, " instance[%d] %s (%d)\n", + j, current->indom[i].name[j], + current->indom[i].inst[j]); + } + } + } + } + if (current->nhandle == 0) + fprintf(f, " No handles.\n"); + else { + int h; + char strbuf[20]; + for (h = 0; h < current->nhandle; h++) { + fprintf(f, " handle[%d] metric=%s (%s) instance=%d\n", + h, current->metric[current->handle[h].midx].name, + pmIDStr_r(current->metric[current->handle[h].midx].pmid, strbuf, sizeof(strbuf)), + current->handle[h].inst); + } + } + if (current->result == NULL) + fprintf(f, " No pmResult.\n"); + else + __pmDumpResult(f, current->result); +} + +pmUnits +pmiUnits(int dimSpace, int dimTime, int dimCount, int scaleSpace, int scaleTime, int scaleCount) +{ + static pmUnits units; + units.dimSpace = dimSpace; + units.dimTime = dimTime; + units.dimCount = dimCount; + units.scaleSpace = scaleSpace; + units.scaleTime = scaleTime; + units.scaleCount = scaleCount; + + return units; +} + +pmID +pmiID(int domain, int cluster, int item) +{ + return pmid_build(domain, cluster, item); +} + +pmInDom +pmiInDom(int domain, int serial) +{ + return pmInDom_build(domain, serial); +} + +const char * +pmiErrStr(int sts) +{ + static char errmsg[PMI_MAXERRMSGLEN]; + pmiErrStr_r(sts, errmsg, sizeof(errmsg)); + return errmsg; +} + +char * +pmiErrStr_r(int code, char *buf, int buflen) +{ + const char *msg; + + if (code == -1 && current != NULL) code = current->last_sts; + switch (code) { + case PMI_ERR_DUPMETRICNAME: + msg = "Metric name already defined"; + break; + case PMI_ERR_DUPMETRICID: + msg = "Metric pmID already defined"; + break; + case PMI_ERR_DUPINSTNAME: + msg = "External instance name already defined"; + break; + case PMI_ERR_DUPINSTID: + msg = "Internal instance identifer already defined"; + break; + case PMI_ERR_INSTNOTNULL: + msg = "Null instance expected for a singular metric"; + break; + case PMI_ERR_INSTNULL: + msg = "Null instance not allowed for a non-singular metric"; + break; + case PMI_ERR_BADHANDLE: + msg = "Illegal handle"; + break; + case PMI_ERR_DUPVALUE: + msg = "Value already assigned for this metric-instance"; + break; + case PMI_ERR_BADTYPE: + msg = "Illegal metric type"; + break; + case PMI_ERR_BADSEM: + msg = "Illegal metric semantics"; + break; + case PMI_ERR_NODATA: + msg = "No data to output"; + break; + case PMI_ERR_BADMETRICNAME: + msg = "Illegal metric name"; + break; + case PMI_ERR_BADTIMESTAMP: + msg = "Illegal result timestamp"; + break; + default: + return pmErrStr_r(code, buf, buflen); + } + strncpy(buf, msg, buflen); + buf[buflen-1] = '\0'; + return buf; +} + +int +pmiStart(const char *archive, int inherit) +{ + pmi_context *old_current; + char *np; + int c = current - context_tab; + + ncontext++; + context_tab = (pmi_context *)realloc(context_tab, ncontext*sizeof(context_tab[0])); + if (context_tab == NULL) { + __pmNoMem("pmiStart: context_tab", ncontext*sizeof(context_tab[0]), PM_FATAL_ERR); + } + old_current = &context_tab[c]; + current = &context_tab[ncontext-1]; + + current->state = CONTEXT_START; + current->archive = strdup(archive); + if (current->archive == NULL) { + __pmNoMem("pmiStart", strlen(archive)+1, PM_FATAL_ERR); + } + current->hostname = NULL; + current->timezone = NULL; + current->result = NULL; + memset((void *)¤t->logctl, 0, sizeof(current->logctl)); + if (inherit && old_current != NULL) { + current->nmetric = old_current->nmetric; + if (old_current->metric != NULL) { + int m; + current->metric = (pmi_metric *)malloc(current->nmetric*sizeof(pmi_metric)); + if (current->metric == NULL) { + __pmNoMem("pmiStart: pmi_metric", current->nmetric*sizeof(pmi_metric), PM_FATAL_ERR); + } + for (m = 0; m < current->nmetric; m++) { + current->metric[m].name = old_current->metric[m].name; + current->metric[m].pmid = old_current->metric[m].pmid; + current->metric[m].desc = old_current->metric[m].desc; + current->metric[m].meta_done = 0; + } + } + else + current->metric = NULL; + current->nindom = old_current->nindom; + if (old_current->indom != NULL) { + int i; + current->indom = (pmi_indom *)malloc(current->nindom*sizeof(pmi_indom)); + if (current->indom == NULL) { + __pmNoMem("pmiStart: pmi_indom", current->nindom*sizeof(pmi_indom), PM_FATAL_ERR); + } + for (i = 0; i < current->nindom; i++) { + int j; + current->indom[i].indom = old_current->indom[i].indom; + current->indom[i].ninstance = old_current->indom[i].ninstance; + current->indom[i].meta_done = 0; + if (old_current->indom[i].ninstance > 0) { + current->indom[i].name = (char **)malloc(current->indom[i].ninstance*sizeof(char *)); + if (current->indom[i].name == NULL) { + __pmNoMem("pmiStart: name", current->indom[i].ninstance*sizeof(char *), PM_FATAL_ERR); + } + current->indom[i].inst = (int *)malloc(current->indom[i].ninstance*sizeof(int)); + if (current->indom[i].inst == NULL) { + __pmNoMem("pmiStart: inst", current->indom[i].ninstance*sizeof(int), PM_FATAL_ERR); + } + current->indom[i].namebuflen = old_current->indom[i].namebuflen; + current->indom[i].namebuf = (char *)malloc(old_current->indom[i].namebuflen); + if (current->indom[i].namebuf == NULL) { + __pmNoMem("pmiStart: namebuf", old_current->indom[i].namebuflen, PM_FATAL_ERR); + } + np = current->indom[i].namebuf; + for (j = 0; j < current->indom[i].ninstance; j++) { + strcpy(np, old_current->indom[i].name[j]); + current->indom[i].name[j] = np; + np += strlen(np)+1; + current->indom[i].inst[j] = old_current->indom[i].inst[j]; + } + } + else { + current->indom[i].name = NULL; + current->indom[i].inst = NULL; + current->indom[i].namebuflen = 0; + current->indom[i].namebuf = NULL; + } + } + } + else + current->indom = NULL; + current->nhandle = old_current->nhandle; + if (old_current->handle != NULL) { + int h; + current->handle = (pmi_handle *)malloc(current->nhandle*sizeof(pmi_handle)); + if (current->handle == NULL) { + __pmNoMem("pmiStart: pmi_handle", current->nhandle*sizeof(pmi_handle), PM_FATAL_ERR); + } + for (h = 0; h < current->nhandle; h++) { + current->handle[h].midx = old_current->handle[h].midx; + current->handle[h].inst = old_current->handle[h].inst; + } + } + else + current->handle = NULL; + current->last_stamp = old_current->last_stamp; + } + else { + current->nmetric = 0; + current->metric = NULL; + current->nindom = 0; + current->indom = NULL; + current->nhandle = 0; + current->handle = NULL; + current->last_stamp.tv_sec = current->last_stamp.tv_usec = 0; + } + return ncontext; +} + +int +pmiUseContext(int context) +{ + if (context < 1 || context > ncontext) { + if (current != NULL) current->last_sts = PM_ERR_NOCONTEXT; + return PM_ERR_NOCONTEXT; + } + current = &context_tab[context-1]; + return current->last_sts = 0; +} + +int +pmiEnd(void) +{ + if (current == NULL) + return PM_ERR_NOCONTEXT; + + return current->last_sts = _pmi_end(current); +} + +int +pmiSetHostname(const char *value) +{ + if (current == NULL) + return PM_ERR_NOCONTEXT; + current->hostname = strdup(value); + if (current->hostname == NULL) { + __pmNoMem("pmiSetHostname", strlen(value)+1, PM_FATAL_ERR); + } + return current->last_sts = 0; +} + +int +pmiSetTimezone(const char *value) +{ + if (current == NULL) + return PM_ERR_NOCONTEXT; + current->timezone = strdup(value); + if (current->timezone == NULL) { + __pmNoMem("pmiSetTimezone", strlen(value)+1, PM_FATAL_ERR); + } + return current->last_sts = 0; +} + +static int +valid_pmns_name(const char *name) +{ + const char *previous; + + /* + * Ensure requested metric name conforms to the PMNS rules: + * Should start with an alphabetic, then any combination of + * alphanumerics or underscore. Dot separators are OK, but + * ensure only one (no repeats). + */ + if (name == NULL) + return 0; + if (!isalpha((int)*name)) + return 0; + for (previous = name++; *name != '\0'; name++) { + if (!isalnum((int)*name) && *name != '_' && *name != '.') + return 0; + if (*previous == '.') { + if (!isalpha((int)*name)) /* non-alphabetic first */ + return 0; + if (*name == *previous) /* repeated . separator */ + return 0; + } + previous = name; + } + if (*previous == '.') /* shouldn't end with separator */ + return 0; + return 1; +} + +int +pmiAddMetric(const char *name, pmID pmid, int type, pmInDom indom, int sem, pmUnits units) +{ + int m; + int item; + int cluster; + size_t size; + pmi_metric *mp; + + if (current == NULL) + return PM_ERR_NOCONTEXT; + + if (valid_pmns_name(name) == 0) + return current->last_sts = PMI_ERR_BADMETRICNAME; + + for (m = 0; m < current->nmetric; m++) { + if (strcmp(name, current->metric[m].name) == 0) { + /* duplicate metric name is not good */ + return current->last_sts = PMI_ERR_DUPMETRICNAME; + } + if (pmid == current->metric[m].pmid) { + /* duplicate metric pmID is not good */ + return current->last_sts = PMI_ERR_DUPMETRICID; + } + } + + /* + * basic sanity check of metadata ... we do not check later so this + * needs to be robust + */ + switch (type) { + case PM_TYPE_32: + case PM_TYPE_U32: + case PM_TYPE_64: + case PM_TYPE_U64: + case PM_TYPE_FLOAT: + case PM_TYPE_DOUBLE: + case PM_TYPE_STRING: + break; + default: + return current->last_sts = PMI_ERR_BADTYPE; + } + switch (sem) { + case PM_SEM_INSTANT: + case PM_SEM_COUNTER: + case PM_SEM_DISCRETE: + break; + default: + return current->last_sts = PMI_ERR_BADSEM; + } + + current->nmetric++; + size = current->nmetric * sizeof(pmi_metric); + current->metric = (pmi_metric *)realloc(current->metric, size); + if (current->metric == NULL) { + __pmNoMem("pmiAddMetric: pmi_metric", size, PM_FATAL_ERR); + } + mp = ¤t->metric[current->nmetric-1]; + if (pmid != PM_ID_NULL) { + mp->pmid = pmid; + } else { + /* choose a PMID on behalf of the caller - check boundaries first */ + item = cluster = current->nmetric; + if (item >= (1<<22)) { /* enough room for unique item:cluster? */ + current->nmetric--; + return current->last_sts = PMI_ERR_DUPMETRICID; /* wrap */ + } + item %= (1<<10); + cluster >>= 10; + mp->pmid = pmid_build(PMI_DOMAIN, cluster, item); + } + mp->name = strdup(name); + if (mp->name == NULL) { + __pmNoMem("pmiAddMetric: name", strlen(name)+1, PM_FATAL_ERR); + } + mp->desc.pmid = mp->pmid; + mp->desc.type = type; + mp->desc.indom = indom; + mp->desc.sem = sem; + mp->desc.units = units; + mp->meta_done = 0; + + return current->last_sts = 0; +} + +int +pmiAddInstance(pmInDom indom, const char *instance, int inst) +{ + pmi_indom *idp; + const char *p; + char *np; + int spaced; + int i; + int j; + + if (current == NULL) + return PM_ERR_NOCONTEXT; + + for (i = 0; i < current->nindom; i++) { + if (current->indom[i].indom == indom) + break; + } + if (i == current->nindom) { + /* extend indom table */ + current->nindom++; + current->indom = (pmi_indom *)realloc(current->indom, current->nindom*sizeof(pmi_indom)); + if (current->indom == NULL) { + __pmNoMem("pmiAddInstance: pmi_indom", current->nindom*sizeof(pmi_indom), PM_FATAL_ERR); + } + current->indom[i].indom = indom; + current->indom[i].ninstance = 0; + current->indom[i].name = NULL; + current->indom[i].inst = NULL; + current->indom[i].namebuflen = 0; + current->indom[i].namebuf = NULL; + } + idp = ¤t->indom[i]; + /* + * duplicate external instance identifier would be bad, but need + * to honour unique to first space rule ... + * duplicate instance internal identifier is also not allowed + */ + for (p = instance; *p && *p != ' '; p++) + ; + spaced = (*p == ' ') ? p - instance + 1: 0; /* +1 => *must* compare the space too */ + for (j = 0; j < idp->ninstance; j++) { + if (spaced) { + if (strncmp(instance, idp->name[j], spaced) == 0) + return current->last_sts = PMI_ERR_DUPINSTNAME; + } else { + if (strcmp(instance, idp->name[j]) == 0) + return current->last_sts = PMI_ERR_DUPINSTNAME; + } + if (inst == idp->inst[j]) { + return current->last_sts = PMI_ERR_DUPINSTID; + } + } + /* add instance marks whole indom as needing to be written */ + idp->meta_done = 0; + idp->ninstance++; + idp->name = (char **)realloc(idp->name, idp->ninstance*sizeof(char *)); + if (idp->name == NULL) { + __pmNoMem("pmiAddInstance: name", idp->ninstance*sizeof(char *), PM_FATAL_ERR); + } + idp->inst = (int *)realloc(idp->inst, idp->ninstance*sizeof(int)); + if (idp->inst == NULL) { + __pmNoMem("pmiAddInstance: inst", idp->ninstance*sizeof(int), PM_FATAL_ERR); + } + idp->namebuf = (char *)realloc(idp->namebuf, idp->namebuflen+strlen(instance)+1); + if (idp->namebuf == NULL) { + __pmNoMem("pmiAddInstance: namebuf", idp->namebuflen+strlen(instance)+1, PM_FATAL_ERR); + } + strcpy(&idp->namebuf[idp->namebuflen], instance); + idp->namebuflen += strlen(instance)+1; + idp->inst[idp->ninstance-1] = inst; + /* in case namebuf moves, need to redo name[] pointers */ + np = idp->namebuf; + for (j = 0; j < current->indom[i].ninstance; j++) { + idp->name[j] = np; + np += strlen(np)+1; + } + + return current->last_sts = 0; +} + +static int +make_handle(const char *name, const char *instance, pmi_handle *hp) +{ + int m; + int i; + int j; + int spaced; + const char *p; + pmi_indom *idp; + + if (instance != NULL && instance[0] == '\0') + /* map "" to NULL to help Perl callers */ + instance = NULL; + + for (m = 0; m < current->nmetric; m++) { + if (strcmp(name, current->metric[m].name) == 0) + break; + } + if (m == current->nmetric) + return current->last_sts = PM_ERR_NAME; + hp->midx = m; + + if (current->metric[hp->midx].desc.indom == PM_INDOM_NULL) { + if (instance != NULL) { + /* expect "instance" to be NULL */ + return current->last_sts = PMI_ERR_INSTNOTNULL; + } + hp->inst = PM_IN_NULL; + } + else { + if (instance == NULL) + /* don't expect "instance" to be NULL */ + return current->last_sts = PMI_ERR_INSTNULL; + for (i = 0; i < current->nindom; i++) { + if (current->metric[hp->midx].desc.indom == current->indom[i].indom) + break; + } + if (i == current->nindom) + return current->last_sts = PM_ERR_INDOM; + idp = ¤t->indom[i]; + + /* match to first space rule */ + + for (p = instance; *p && *p != ' '; p++) + ; + spaced = (*p == ' ') ? p - instance + 1: 0; /* +1 => *must* compare the space too */ + for (j = 0; j < idp->ninstance; j++) { + if (spaced) { + if (strncmp(instance, idp->name[j], spaced) == 0) + break; + } else { + if (strcmp(instance, idp->name[j]) == 0) + break; + } + } + if (j == idp->ninstance) + return current->last_sts = PM_ERR_INST; + hp->inst = idp->inst[j]; + } + + return current->last_sts = 0; +} + +int +pmiPutValue(const char *name, const char *instance, const char *value) +{ + pmi_handle tmp; + int sts; + + if (current == NULL) + return PM_ERR_NOCONTEXT; + + sts = make_handle(name, instance, &tmp); + if (sts != 0) + return current->last_sts = sts; + + return current->last_sts = _pmi_stuff_value(current, &tmp, value); +} + +int +pmiGetHandle(const char *name, const char *instance) +{ + int sts; + pmi_handle tmp; + pmi_handle *hp; + + if (current == NULL) + return PM_ERR_NOCONTEXT; + + sts = make_handle(name, instance, &tmp); + if (sts != 0) + return current->last_sts = sts; + + current->nhandle++; + current->handle = (pmi_handle *)realloc(current->handle, current->nhandle*sizeof(pmi_handle)); + if (current->handle == NULL) { + __pmNoMem("pmiGetHandle: pmi_handle", current->nhandle*sizeof(pmi_handle), PM_FATAL_ERR); + } + hp = ¤t->handle[current->nhandle-1]; + hp->midx = tmp.midx; + hp->inst = tmp.inst; + + return current->last_sts = current->nhandle; +} + +int +pmiPutValueHandle(int handle, const char *value) +{ + if (current == NULL) + return PM_ERR_NOCONTEXT; + if (handle <= 0 || handle > current->nhandle) + return current->last_sts = PMI_ERR_BADHANDLE; + + return current->last_sts = _pmi_stuff_value(current, ¤t->handle[handle-1], value); +} + +int +pmiWrite(int sec, int usec) +{ + int sts; + + if (current == NULL) + return PM_ERR_NOCONTEXT; + if (current->result == NULL) + return current->last_sts = PMI_ERR_NODATA; + + if (sec < 0) { + __pmtimevalNow(¤t->result->timestamp); + } + else { + current->result->timestamp.tv_sec = sec; + current->result->timestamp.tv_usec = usec; + } + if (current->result->timestamp.tv_sec < current->last_stamp.tv_sec || + (current->result->timestamp.tv_sec == current->last_stamp.tv_sec && + current->result->timestamp.tv_usec < current->last_stamp.tv_usec)) { + fprintf(stderr, "Fatal Error: timestamp "); + printstamp(stderr, ¤t->result->timestamp); + fprintf(stderr, " not greater than previous valid timestamp "); + printstamp(stderr, ¤t->last_stamp); + fputc('\n', stderr); + sts = PMI_ERR_BADTIMESTAMP; + } + else { + sts = _pmi_put_result(current, current->result); + current->last_stamp = current->result->timestamp; + } + + pmFreeResult(current->result); + current->result = NULL; + + return current->last_sts = sts; +} + +int +pmiPutResult(const pmResult *result) +{ + if (current == NULL) + return PM_ERR_NOCONTEXT; + + return current->last_sts = _pmi_put_result(current, current->result); +} diff --git a/src/libpcp_import/src/private.h b/src/libpcp_import/src/private.h new file mode 100644 index 0000000..735d35c --- /dev/null +++ b/src/libpcp_import/src/private.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 2010 Ken McDonell. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + */ +#ifndef _PRIVATE_H +#define _PRIVATE_H + +typedef struct { + char *name; + pmID pmid; + pmDesc desc; + int meta_done; +} pmi_metric; + +typedef struct { + pmInDom indom; + int ninstance; + char **name; // list of external instance names + int *inst; // list of internal instance identifiers + int namebuflen; // names are packed in namebuf[] as + char *namebuf; // required by __pmLogPutInDom() + int meta_done; +} pmi_indom; + +typedef struct { + int midx; // index into metric[] + int inst; // internal instance identifier +} pmi_handle; + +typedef struct { + int state; + char *archive; + char *hostname; + char *timezone; + __pmLogCtl logctl; + pmResult *result; + int nmetric; + pmi_metric *metric; + int nindom; + pmi_indom *indom; + int nhandle; + pmi_handle *handle; + int last_sts; + struct timeval last_stamp; +} pmi_context; + +#define CONTEXT_START 1 +#define CONTEXT_ACTIVE 2 +#define CONTEXT_END 3 + +#if defined(__GNUC__) && (__GNUC__ >= 4) +# define _PMI_HIDDEN __attribute__ ((visibility ("hidden"))) +#else +# define _PMI_HIDDEN +#endif + +extern int _pmi_stuff_value(pmi_context *, pmi_handle *, const char *) _PMI_HIDDEN; +extern int _pmi_put_result(pmi_context *, pmResult *) _PMI_HIDDEN; +extern int _pmi_end(pmi_context *) _PMI_HIDDEN; + +#endif /* _PRIVATE_H */ diff --git a/src/libpcp_import/src/stuff.c b/src/libpcp_import/src/stuff.c new file mode 100644 index 0000000..bfb4935 --- /dev/null +++ b/src/libpcp_import/src/stuff.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2010 Ken McDonell. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "import.h" +#include "private.h" + +int +_pmi_stuff_value(pmi_context *current, pmi_handle *hp, const char *value) +{ + pmResult *rp; + int i; + pmID pmid; + pmValueSet *vsp; + pmValue *vp; + pmi_metric *mp; + char *end; + int dsize; + void *data; + __int64_t ll; + __uint64_t ull; + float f; + double d; + + mp = ¤t->metric[hp->midx]; + + if (current->result == NULL) { + /* first time */ + current->result = (pmResult *)malloc(sizeof(pmResult)); + if (current->result == NULL) { + __pmNoMem("_pmi_stuff_value: result malloc:", sizeof(pmResult), PM_FATAL_ERR); + } + current->result->numpmid = 0; + current->result->timestamp.tv_sec = 0; + current->result->timestamp.tv_usec = 0; + } + rp = current->result; + + pmid = current->metric[hp->midx].pmid; + for (i = 0; i < rp->numpmid; i++) { + if (pmid == rp->vset[i]->pmid) { + if (mp->desc.indom == PM_INDOM_NULL) + /* singular metric, cannot have more than one value */ + return PMI_ERR_DUPVALUE; + break; + } + } + if (i == rp->numpmid) { + rp->numpmid++; + rp = current->result = (pmResult *)realloc(current->result, sizeof(pmResult) + (rp->numpmid - 1)*sizeof(pmValueSet *)); + if (current->result == NULL) { + __pmNoMem("_pmi_stuff_value: result realloc:", sizeof(pmResult) + (rp->numpmid - 1)*sizeof(pmValueSet *), PM_FATAL_ERR); + } + rp->vset[rp->numpmid-1] = (pmValueSet *)malloc(sizeof(pmValueSet)); + if (rp->vset[rp->numpmid-1] == NULL) { + __pmNoMem("_pmi_stuff_value: vset alloc:", sizeof(pmValueSet), PM_FATAL_ERR); + } + vsp = rp->vset[rp->numpmid-1]; + vsp->pmid = pmid; + vsp->numval = 1; + } + else { + int j; + for (j = 0; j < rp->vset[i]->numval; j++) { + if (rp->vset[i]->vlist[j].inst == hp->inst) + /* each metric-instance can appear at most once per pmResult */ + return PMI_ERR_DUPVALUE; + } + rp->vset[i]->numval++; + vsp = rp->vset[i] = (pmValueSet *)realloc(rp->vset[i], sizeof(pmValueSet) + (rp->vset[i]->numval-1)*sizeof(pmValue)); + if (rp->vset[i] == NULL) { + __pmNoMem("_pmi_stuff_value: vset realloc:", sizeof(pmValueSet) + (rp->vset[i]->numval-1)*sizeof(pmValue), PM_FATAL_ERR); + } + } + vp = &vsp->vlist[vsp->numval-1]; + vp->inst = hp->inst; + dsize = -1; + switch (mp->desc.type) { + case PM_TYPE_32: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_INSITU; + vp->value.lval = strtol(value, &end, 10); + if (*end != '\0') { + vsp->numval = PM_ERR_CONV; + return PM_ERR_CONV; + } + break; + + case PM_TYPE_U32: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_INSITU; + vp->value.lval = strtoul(value, &end, 10); + if (*end != '\0') { + vsp->numval = PM_ERR_CONV; + return PM_ERR_CONV; + } + break; + + case PM_TYPE_64: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; + ll = strtoll(value, &end, 10); + if (*end != '\0') { + vsp->numval = PM_ERR_CONV; + return PM_ERR_CONV; + } + dsize = sizeof(ll); + data = (void *)≪ + break; + + case PM_TYPE_U64: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; + ull = strtoull(value, &end, 10); + if (*end != '\0') { + vsp->numval = PM_ERR_CONV; + return PM_ERR_CONV; + } + dsize = sizeof(ull); + data = (void *)&ull; + break; + + case PM_TYPE_FLOAT: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; + f = strtof(value, &end); + if (*end != '\0') { + vsp->numval = PM_ERR_CONV; + return PM_ERR_CONV; + } + dsize = sizeof(f); + data = (void *)&f; + break; + + case PM_TYPE_DOUBLE: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; + d = strtod(value, &end); + if (*end != '\0') { + vsp->numval = PM_ERR_CONV; + return PM_ERR_CONV; + } + dsize = sizeof(d); + data = (void *)&d; + break; + + case PM_TYPE_STRING: + if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; + dsize = strlen(value)+1; + data = (void *)value; + break; + + default: + vsp->numval = PM_ERR_TYPE; + return PM_ERR_TYPE; + } + + if (dsize != -1) { + /* logic copied from stuffvalue.c in libpcp */ + int need = dsize + PM_VAL_HDR_SIZE; + + vp->value.pval = (pmValueBlock *)malloc(need < sizeof(pmValueBlock) ? sizeof(pmValueBlock) : need); + if (vp->value.pval == NULL) { + __pmNoMem("_pmi_stuff_value: pmValueBlock:", need < sizeof(pmValueBlock) ? sizeof(pmValueBlock) : need, PM_FATAL_ERR); + } + vp->value.pval->vlen = (int)need; + vp->value.pval->vtype = mp->desc.type; + memcpy((void *)vp->value.pval->vbuf, data, dsize); + } + + return 0; +} |