<commit_before>/*
 * Copyright (c) 2013-2016 Red Hat.
 * Copyright (c) 1995-2002 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.
 */

#include "pmapi.h"
#include "impl.h"
#include "fault.h"
#include "internal.h"
#include <stddef.h>

/* bytes for a length field in a header/trailer, or a string length field */
#define LENSIZE	4

#ifdef PCP_DEBUG
static void
StrTimeval(__pmTimeval *tp)
{
    if (tp == NULL)
	fprintf(stderr, "<null timeval>");
    else
	__pmPrintTimeval(stderr, tp);
}
#endif

/* Return 1 if the indoms are the same, 0 otherwise */
static int
sameindom(const __pmLogInDom *idp1, const __pmLogInDom *idp2) {
    int i;

    /*
     * Duplicate indoms at different timestamps are still duplicate, so don't compare the
     * timestamps.
     */
    if (idp1->numinst != idp2->numinst)
	return 0; /* different */

    for (i = 0; i < idp1->numinst; ++i) {
	if (idp1->instlist[i] != idp2->instlist[i])
	    return 0; /* different */
	if (strcmp(idp1->namelist[i], idp2->namelist[i]) != 0)
	    return 0; /* different */
    }

    return 1; /* duplicate */
}

/* Free the given indom. See the comment for the allocation of__pmLogIndom in impl.h */
static void
freeindom(__pmLogInDom *idp) {
    if (idp->buf) {
	free(idp->buf);
	if (idp->allinbuf == 0)
	    free(idp->namelist);
    }
    else {
	free(idp->instlist);
	free(idp->namelist);
    }
    free(idp);
}

/*
 * Add the given instance domain to the hashed instance domain.
 * Filter out duplicates.
 */
static int
addindom(__pmLogCtl *lcp, pmInDom indom, const __pmTimeval *tp, int numinst, 
         int *instlist, char **namelist, int *indom_buf, int allinbuf)
{
    const __pmLogInDom	*idp_cached;
    __pmLogInDom	*idp;
    __pmHashNode	*hp;
    int		sts;

PM_FAULT_POINT("libpcp/" __FILE__ ":1", PM_FAULT_ALLOC);
    if ((idp = (__pmLogInDom *)malloc(sizeof(__pmLogInDom))) == NULL)
	return -oserror();
    idp->stamp = *tp;		/* struct assignment */
    idp->numinst = numinst;
    idp->instlist = instlist;
    idp->namelist = namelist;
    idp->buf = indom_buf;
    idp->allinbuf = allinbuf;

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_LOGMETA) {
	char	strbuf[20];
	fprintf(stderr, "addindom( ..., %s, ", pmInDomStr_r(indom, strbuf, sizeof(strbuf)));
	StrTimeval((__pmTimeval *)tp);
	fprintf(stderr, ", numinst=%d)\n", numinst);
    }
#endif

    if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) {
	idp->next = NULL;
	sts = __pmHashAdd((unsigned int)indom, (void *)idp, &lcp->l_hashindom);
	/* __pmHashAdd returns 1 for success, but we want zero. */
	if (sts > 0)
	    sts = 0;
    }
    else {
	/*
	 * Filter out identical indoms. This is very common in multi-archive
	 * contexts where the individual archives almost always use the same
	 * instance domains.
	 */
	sts = 0;
	for (idp_cached = hp->data; idp_cached; idp_cached = idp_cached->next) {
	    if (sameindom(idp_cached, idp)) {
		sts = 1; /* duplicate */
		break;
	    }
	}
	if (sts == 0) {
	    idp->next = (__pmLogInDom *)hp->data;
	    hp->data = (void *)idp;
	}
    }

    /* It's a duplicate or an error has occurred, free the duplicate data. */
    if (sts != 0) {
	freeindom(idp);
	if (sts == 1)
	    sts = 0; /* duplicate is ok */
    }

    return sts;
}

/*
 * Load _all_ of the hashed pmDesc and __pmLogInDom structures from the metadata
 * log file -- used at the initialization (NewContext) of an archive.
 * Also load all the metric names from the metadata log file and create l_pmns,
 * if it does not already exist.
 */
int
__pmLogLoadMeta(__pmLogCtl *lcp)<commit_msg>RHBZ 1359975: pmchart run-away mem leak replaying multi-archive when rewinding<commit_after>/*
 * Copyright (c) 2013-2016 Red Hat.
 * Copyright (c) 1995-2002 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.
 */

#include "pmapi.h"
#include "impl.h"
#include "fault.h"
#include "internal.h"
#include <stddef.h>
#include <assert.h>

/* bytes for a length field in a header/trailer, or a string length field */
#define LENSIZE	4

#ifdef PCP_DEBUG
static void
StrTimeval(const __pmTimeval *tp)
{
    if (tp == NULL)
	fprintf(stderr, "<null timeval>");
    else
	__pmPrintTimeval(stderr, tp);
}
#endif

/* Return 1 if the indoms are the same, 0 otherwise */
static int
sameindom(const __pmLogInDom *idp1, const __pmLogInDom *idp2) {
    int i;

    /* The time stamp does not count for this test. */
    if (idp1->numinst != idp2->numinst)
	return 0; /* different */

    for (i = 0; i < idp1->numinst; ++i) {
	if (idp1->instlist[i] != idp2->instlist[i])
	    return 0; /* different */
	if (strcmp(idp1->namelist[i], idp2->namelist[i]) != 0)
	    return 0; /* different */
    }

    return 1; /* duplicate */
}

/* Free the given indom. See the comment for the allocation of__pmLogIndom in impl.h */
static void
freeindom(__pmLogInDom *idp) {
    if (idp->buf) {
	free(idp->buf);
	if (idp->allinbuf == 0)
	    free(idp->namelist);
    }
    else {
	free(idp->instlist);
	free(idp->namelist);
    }
    free(idp);
}

/*
 * Add the given instance domain to the hashed instance domain.
 * Filter out duplicates.
 */
static int
addindom(__pmLogCtl *lcp, pmInDom indom, const __pmTimeval *tp, int numinst, 
         int *instlist, char **namelist, int *indom_buf, int allinbuf)
{
    __pmLogInDom	*idp, *idp_prev;
    __pmLogInDom	*idp_cached, *idp_time;
    __pmHashNode	*hp;
    double		timediff;
    int			sts;

PM_FAULT_POINT("libpcp/" __FILE__ ":1", PM_FAULT_ALLOC);
    if ((idp = (__pmLogInDom *)malloc(sizeof(__pmLogInDom))) == NULL)
	return -oserror();
    idp->stamp = *tp;		/* struct assignment */
    idp->numinst = numinst;
    idp->instlist = instlist;
    idp->namelist = namelist;
    idp->buf = indom_buf;
    idp->allinbuf = allinbuf;

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_LOGMETA) {
	char    strbuf[20];
	fprintf(stderr, "addindom( ..., %s, ", pmInDomStr_r(indom, strbuf, sizeof(strbuf)));
	StrTimeval((__pmTimeval *)tp);
	fprintf(stderr, ", numinst=%d)\n", numinst);
    }
#endif

    if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) {
	idp->next = NULL;
	sts = __pmHashAdd((unsigned int)indom, (void *)idp, &lcp->l_hashindom);
	if (sts >= 0) {
	    /* __pmHashAdd returns 1 for success, but we want zero. */
	    sts = 0;
	}
	else
	    freeindom(idp); /* error */
	return sts;
    }

    /*
     * Filter out identical indoms. This is very common in multi-archive
     * contexts where the individual archives almost always use the same
     * instance domains.
     *
     * The indoms need to be sorted by decreasing time stamp. Before
     * multi-archive contexts, this happened automatically. Now we
     * must do it explicitely. Duplicates must be moved to the head of their
     * time slot.
     */
    idp_prev = NULL;
    for (idp_cached = (__pmLogInDom *)hp->data; idp_cached; idp_cached = idp_cached->next) {
	timediff = __pmTimevalSub(&idp_cached->stamp, &idp->stamp);

	/*
	 * If the time of the current cached item is before our time,
	 * then insert here.
	 */
	if (timediff < 0)
	    break;

	/*
	 * If the time of the current cached item is the same as our time,
	 * search for a duplicate in this time slot. If found, move it
	 * to the head of this time slot. Otherwise insert this new item
	 * at the head of the time slot.
	 */
	if (timediff == 0) {
	    sts = 0;
	    idp_time = idp_prev; /* just before this time slot */
	    do {
		/* Have we found a duplicate? */
		if (sameindom(idp_cached, idp)) {
		    sts = 1; /* duplicate */
		    break;
		}
		/* Try the next one */
		idp_prev = idp_cached;
		idp_cached = idp_cached->next;
		if (idp_cached == NULL)
		    break;
		timediff = __pmTimevalSub(&idp_cached->stamp, &idp->stamp);
	    } while (timediff == 0);

	    if (sts == 1) {
		/*
		 * We found a duplicate.  Free the new one.
		 */
		freeindom(idp);
		if (idp_prev == idp_time) {
		    /* The duplicate is already in the right place. */
		    return 0; /* ok */
		}
		    
		/* Unlink the duplicate and set it up to be re-inserted. */
		assert(idp_cached != NULL);
		if (idp_prev)
		    idp_prev->next = idp_cached->next;
		else
		    hp->data = (void *)idp_cached->next;
		idp = idp_cached;
	    }

	    /*
	     * Regardless of whether or not a duplicate was found, we will be
	     * inserting the indom we have at the head of the time slot.
	     */
	    idp_prev = idp_time;
	    break;
	}

	/*
	 * The time of the current cached item is after our time.
	 * Just keep looking.
	 */
	idp_prev = idp_cached;
    }

    /* Insert at the identified insertion point. */
    if (idp_prev == NULL) {
	idp->next = (__pmLogInDom *)hp->data;
	hp->data = (void *)idp;
    }
    else {
	idp->next = idp_prev->next;
	idp_prev->next = idp;
    }

    return 0; /* ok */
}

/*
 * Load _all_ of the hashed pmDesc and __pmLogInDom structures from the metadata
 * log file -- used at the initialization (NewContext) of an archive.
 * Also load all the metric names from the metadata log file and create l_pmns,
 * if it does not already exist.
 */
int
__pmLogLoadMeta(__pmLogCtl *lcp)
{'fraction_non_alphanumeric': 0.12279653420974007, 'fraction_numerical': 0.010656309132556519, 'mean_word_length': 3.0313127258129264, 'pattern_counts': {'":': 2, '<': 11, '<?xml version=': 0, '>': 76, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1326393', 'n_tokens_mistral': 3704, 'n_tokens_neox': 3490, 'n_words': 1146}