diff options
Diffstat (limited to 'qa/pmlogconv/pmlogconv.c')
-rw-r--r-- | qa/pmlogconv/pmlogconv.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/qa/pmlogconv/pmlogconv.c b/qa/pmlogconv/pmlogconv.c new file mode 100644 index 0000000..0387ec0 --- /dev/null +++ b/qa/pmlogconv/pmlogconv.c @@ -0,0 +1,354 @@ +/* + * pmlogconv - convert PCP archive logs from V1 to V2 format + */ + +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include "pcp/pmapi.h" +#include "pcp/impl.h" + +#define LOG 0 +#define META 1 + +typedef struct { /* input archive control */ + int ctx; + char *name; + pmLogLabel label; + __pmPDU *pb[2]; + int pick[2]; + int eof[2]; +} inarch_t; + +static __pmLogCtl logctl; /* output archive control */ + +static inarch_t inarch; +static __pmTimeval current; /* most recently output timestamp */ + +static __pmHashCtl pmid_done; + +static int exit_status = 0; + +extern int _pmLogGet(__pmLogCtl *, int, __pmPDU **); +extern int _pmLogPut(FILE *, __pmPDU *); +extern void _pmUnpackDesc(__pmPDU *, pmDesc *); +extern void rewrite_pdu(__pmPDU *); + +/* + * + */ +void +writelabel_metati(int do_rewind) +{ + if (do_rewind) rewind(logctl.l_tifp); + logctl.l_label.ill_vol = PM_LOG_VOL_TI; + __pmLogWriteLabel(logctl.l_tifp, &logctl.l_label); + + + if (do_rewind) rewind(logctl.l_mdfp); + logctl.l_label.ill_vol = PM_LOG_VOL_META; + __pmLogWriteLabel(logctl.l_mdfp, &logctl.l_label); +} + +void +writelabel_data(void) +{ + logctl.l_label.ill_vol = 0; + __pmLogWriteLabel(logctl.l_mfp, &logctl.l_label); +} + +static void +_report(FILE *fp) +{ + off_t here; + struct stat sbuf; + + here = lseek(fileno(fp), 0L, SEEK_CUR); + fprintf(stderr, "Error occurred at byte offset %ld into a file of", here); + if (fstat(fileno(fp), &sbuf) < 0) + fprintf(stderr, ": stat: %s\n", strerror(errno)); + else + fprintf(stderr, " %ld bytes.\n", sbuf.st_size); + fprintf(stderr, "The last record, and the remainder of this file will not be merged.\n"); + exit_status = 1; +} + +/* + * pick next archive record + * - if next metadata is pmDesc, output this + * - else choose youngest data or pmInDom metadata + * - if data and pmIndom have same timestamp, choose pmInDom + */ +static int +nextrec(void) +{ + int sts; + int pick = PM_ERR_EOL; + __pmTimeval *this; + __pmLogCtl *lcp; + __pmContext *ctxp; + + if (!inarch.eof[META]) { + if (inarch.pb[META] == (__pmPDU *)0) { + /* refill metadata buffer */ + ctxp = __pmHandleToPtr(inarch.ctx); + lcp = ctxp->c_archctl->ac_log; + if ((sts = _pmLogGet(lcp, PM_LOG_VOL_META, &inarch.pb[META])) < 0) { + inarch.eof[META] = 1; + if (sts != PM_ERR_EOL) { + fprintf(stderr, "%s: Error: __pmLogRead[meta %s]: %s\n", + pmProgname, inarch.name, pmErrStr(sts)); + _report(lcp->l_mdfp); + exit(1); + } + } + } + } + + if (!inarch.eof[LOG]) { + if (inarch.pb[LOG] == (__pmPDU *)0) { + ctxp = __pmHandleToPtr(inarch.ctx); + lcp = ctxp->c_archctl->ac_log; + if ((sts = _pmLogGet(lcp, 0, &inarch.pb[LOG])) < 0) { + inarch.eof[LOG] = 1; + if (sts != PM_ERR_EOL) { + fprintf(stderr, "%s: Error: __pmLogRead[log %s]: %s\n", + pmProgname, inarch.name, pmErrStr(sts)); + _report(lcp->l_mfp); + exit(1); + } + } + } + } + + if (!inarch.eof[META] && ntohl(inarch.pb[META][1]) == TYPE_DESC) { + /* pmDesc entry, output this immediately */ + pmDesc desc; + _pmUnpackDesc(inarch.pb[META], &desc); + if (__pmHashSearch((int)desc.pmid, &pmid_done) != (__pmHashNode *)0) { + /* already been processed from another log, skip this one */ + fprintf(stderr, "Botch: pmDesc for pmid %s seen twice in input archive\n", pmIDStr(desc.pmid)); + exit(1); + } + __pmHashAdd((int)desc.pmid, (void *)0, &pmid_done); + inarch.pick[META] = TYPE_DESC; + return 0; + } + + if (!inarch.eof[LOG]) { + this = (__pmTimeval *)&inarch.pb[LOG][1]; + inarch.pick[LOG] = 1; + pick = 0; + current.tv_sec = ntohl(this->tv_sec); + current.tv_usec = ntohl(this->tv_usec); + } + + if (!inarch.eof[META]) { + this = (__pmTimeval *)&inarch.pb[META][2]; + if (ntohl(this->tv_sec) < current.tv_sec || + (ntohl(this->tv_sec) == current.tv_sec && ntohl(this->tv_usec) <= current.tv_usec)) { + inarch.pick[LOG] = 0; + inarch.pick[META] = TYPE_INDOM; + pick = 0; + current.tv_sec = ntohl(this->tv_sec); + current.tv_usec = ntohl(this->tv_usec); + } + } + + return pick; +} + +int +main(int argc, char **argv) +{ + int c; + int sts; + char *p; + int errflag = 0; + char *output; + char *pmnsfile = NULL; + int needti = 0; + off_t old_log_offset; + off_t new_log_offset; + off_t old_meta_offset; + off_t new_meta_offset; + extern char *optarg; + extern int optind; + extern int pmDebug; + + /* trim cmd name of leading directory components */ + pmProgname = argv[0]; + for (p = pmProgname; *p; p++) { + if (*p == '/') + pmProgname = p+1; + } + + while ((c = getopt(argc, argv, "D:n:?")) != EOF) { + switch (c) { + + case 'D': /* debug flag */ + sts = __pmParseDebug(optarg); + if (sts < 0) { + fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", + pmProgname, optarg); + errflag++; + } + else + pmDebug |= sts; + break; + + case 'n': + pmnsfile = optarg; + break; + + case '?': + default: + errflag++; + break; + } + } + + if (errflag != 0 || pmnsfile == NULL || optind != argc-2) { + fprintf(stderr, +"Usage: %s [options] input-archive output-archive\n\ +\n\ +Options\n\ + -D debug standard PCP debug flag\n\ + -n pmnsfile PMNS to use (not optional)\n", + pmProgname); + exit(1); + } + + if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { + fprintf(stderr, "%s: Error loading namespace: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + + inarch.name = argv[optind]; + if ((inarch.ctx = pmNewContext(PM_CONTEXT_ARCHIVE, inarch.name)) < 0) { + fprintf(stderr, "%s: Error: cannot open archive \"%s\": %s\n", + pmProgname, inarch.name, pmErrStr(inarch.ctx)); + exit(1); + } + if ((sts = pmGetArchiveLabel(&inarch.label)) < 0) { + fprintf(stderr, "%s: Error: cannot get archive label record (%s): %s\n", + pmProgname, inarch.name, pmErrStr(sts)); + exit(1); + } + + inarch.pb[LOG] = inarch.pb[META] = (__pmPDU *)0; + inarch.eof[LOG] = inarch.eof[META] = 0; + inarch.pick[LOG] = inarch.pick[META] = 0; + + output = argv[argc-1]; + if ((sts = __pmLogCreate("", output, PM_LOG_VERS02, &logctl)) < 0) { + fprintf(stderr, "%s: Error: __pmLogCreate: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + + logctl.l_label.ill_magic = PM_LOG_MAGIC | PM_LOG_VERS02; + logctl.l_label.ill_pid = inarch.label.ll_pid; + logctl.l_label.ill_start.tv_sec = inarch.label.ll_start.tv_sec; + logctl.l_label.ill_start.tv_usec = inarch.label.ll_start.tv_usec; + strcpy(logctl.l_label.ill_hostname, inarch.label.ll_hostname); + strcpy(logctl.l_label.ill_tz, inarch.label.ll_tz); + writelabel_metati(0); + + /* + * do meta and log records at the same time ... in the case of an + * equal match, the log record is processed before the corresponding + * meta data + */ + for ( ; ; ) { + if (nextrec() < 0) + break; + + if (inarch.pick[LOG]) { + old_log_offset = ftell(logctl.l_mfp); + old_meta_offset = ftell(logctl.l_mdfp); + if (old_log_offset == 0) { + /* write label record for data file */ + logctl.l_label.ill_start.tv_sec = current.tv_sec; + logctl.l_label.ill_start.tv_usec = current.tv_usec; + writelabel_data(); + old_log_offset = ftell(logctl.l_mfp); + needti = 1; + } + + /* + * ignore 2^31 check for vol switch on output archive ... + * if input archive is one volume, would have been unreadable + * if too large + * if input archive is multivolume, we create a single + * volume output, so there is a potential problem here ... + * TODO - revisit this issue only if a need arises + */ + + /* translate data record from V1 to V2 */ + rewrite_pdu(inarch.pb[LOG]); + + /* write data record out */ + if ((sts = _pmLogPut(logctl.l_mfp, inarch.pb[LOG])) < 0) { + fprintf(stderr, "%s: Error: _pmLogPut: log data: %s\n", + pmProgname, pmErrStr(sts)); + exit(1); + } + /* free data record buffer */ + free(inarch.pb[LOG]); + inarch.pb[LOG] = (__pmPDU *)0; + inarch.pick[LOG] = 0; + + if (needti) { + fflush(logctl.l_mfp); + fflush(logctl.l_mdfp); + new_log_offset = ftell(logctl.l_mfp); + new_meta_offset = ftell(logctl.l_mdfp); + fseek(logctl.l_mfp, old_log_offset, SEEK_SET); + fseek(logctl.l_mdfp, old_meta_offset, SEEK_SET); + __pmLogPutIndex(&logctl, ¤t); + fseek(logctl.l_mfp, new_log_offset, SEEK_SET); + fseek(logctl.l_mdfp, new_log_offset, SEEK_SET); + needti = 0; + } + } + + if (inarch.pick[META]) { + /* write metadata out and force temporal index update if indom */ + if (inarch.pick[META] == TYPE_DESC) { + pmDesc desc; + char **names = NULL; + int numnames; + char *myname; + + _pmUnpackDesc(inarch.pb[META], &desc); + if ((numnames = pmNameAll(desc.pmid, &names)) < 0) { + myname = strdup(pmIDStr(desc.pmid)); + } + else { + myname = strdup(names[0]); + free(names); + } + __pmLogPutDesc(&logctl, &desc, 1, &myname); + free(myname); + } + else { + if ((sts = _pmLogPut(logctl.l_mdfp, inarch.pb[META])) < 0) { + fprintf(stderr, "%s: Error: _pmLogPut: meta data: %s\n", + pmProgname, pmErrStr(sts)); + exit(1); + } + needti = 1; + } + /* free metadata buffer */ + free(inarch.pb[META]); + inarch.pb[META] = (__pmPDU *)0; + inarch.pick[META] = 0; + } + } + + writelabel_metati(1); + + exit(exit_status); +} |