All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.utilint.StatGroup Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je.utilint;

import java.io.Serializable;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import com.sleepycat.je.TransactionStats.Active;

/**
 * The Stats infrastructure provides context for JE statistics. Each statistic
 * has these attributes:
 * - metadata - specifically, a name and description
 * - each statistic is associated with a parent stat group, which itself has
 *   a name and description.
 * - support for the StatsConfig.clear semantics
 * - a way to print statistics in a user friendly way.
 *
 * To create a statistic variable, instantiate one of the concrete subclasses
 * of Stat. Each concrete subclass should hold the methods that are needed to
 * best set and display the value. For example, instead of using LongStat to
 * hold a timestamp or LSN value, use TimestampStat or LSNStat. A Stat instance
 * needs to specify a StatDefinition. There may be multiple Stat variables in
 * different components that share a StatDefinition. They are differentiated
 * when displayed by their parent StatGroup.
 *
 * Each Stat instance is associated with a StatGroup, which holds the
 * collection of stats that belong to a given component. Each member of the
 * StatGroup has a unique StatDefinition. StatGroups can be combined, in order
 * to accumulate values. For example, the LockManager may have multiple lock
 * tables. Each lock table keeps its own latch statistics. When LockStats are
 * generated, the StatsGroup for each latch is collected and rolled up into a
 * single StatGroup, using the addAll(StatGroup) method.
 *
 * The Stats infrastructure is for internal use only. Public API classes like
 * EnvironmentStats, LockStats, etc, contain StatGroups. A call to retrieve
 * stats is implemented by getting a clone of the StatGroups held by the
 * components like the cleaner, the incompressor, the LockManager, etc.  The
 * public API classes provide getter methods that reach into the StatGroups to
 * return the specific stat value.
 *
 * To add a statistic, create the Stat variable in the component where it is
 * being used and associate it with a StatGroup. The Stat infrastructure does
 * the rest of the work for plumbing that statistic up to the public API
 * class. Each API class must provide a getter method to access the specific
 * statistic. Currently, this is done manually.
 */
public class StatGroup implements Serializable {
    private static final long serialVersionUID = 1L;

    /*
     * User understandable description of the grouping. The description may
     * indicate that these stats are meant for internal use.
     */
    private final String groupName;
    private final String groupDescription;
    private final Map> stats;

    public StatGroup(String groupName, String groupDescription) {
        this(groupName, groupDescription,
             new HashMap>());
    }

    private StatGroup(String groupName,
                      String groupDescription,
                      Map> values) {
        this.groupName = groupName;
        this.groupDescription = groupDescription;
        this.stats = Collections.synchronizedMap(values);
    }

    /**
     * Returns a synchronized, unmodifiable view of the stats in this group.
     * Note that the returned set can still be modified by other threads, so
     * the caller needs to take that into account.
     */
    public Map> getStats() {
        return Collections.unmodifiableMap(stats);
    }

    /**
     * Add a stat to the group.
     */
    void register(Stat oneStat) {
        Stat prev = stats.put(oneStat.getDefinition(), oneStat);
        assert (prev == null) : "prev = " + prev + " oneStat=" +
            oneStat.getDefinition();
    }

    /**
     * Add all the stats from the other group into this group. If both groups
     * have the same stat, add the values.  The caller must make sure that no
     * stats are added to or removed from the argument during this call.
     *
     * @throws ConcurrentModificationException if the addition or removal of
     * stats in the argument is detected
     */
    @SuppressWarnings("unchecked")
    public void addAll(StatGroup other) {

        for (Entry> entry :
             other.stats.entrySet()) {

            StatDefinition definition = entry.getKey();
            Stat localStat;
            synchronized (stats) {
                localStat = stats.get(definition);
                if (localStat == null) {
                    stats.put(definition, entry.getValue());
                    continue;
                }
            }

            /*
             * Cast to get around type problem. We know it's the same stat type
             * because the definition is the same, but the compiler doesn't
             * know that.
             */
            @SuppressWarnings("rawtypes")
            Stat additionalValue = entry.getValue();
            localStat.add(additionalValue);
        }
    }

    /**
     * The caller must make sure that no stats are added to or removed from
     * this stat group while this method is being called.
     *
     * @throws ConcurrentModificationException if the addition or removal of
     * stats in this group is detected
     */
    @SuppressWarnings("unchecked")
    public StatGroup computeInterval(StatGroup baseGroup) {
        Map> intervalValues =
                new HashMap>();

        for (Entry> entry :
             stats.entrySet()) {
            StatDefinition definition = entry.getKey();
            Stat statValue = entry.getValue();
            @SuppressWarnings("rawtypes")
            Stat baseStat = baseGroup.stats.get(definition);
            if (baseStat == null) {
                intervalValues.put(definition, statValue.copy());
            } else {
                intervalValues.put(definition,
                                   statValue.computeInterval(baseStat));
            }
        }
        return new StatGroup(groupName, groupDescription, intervalValues);
    }

    /**
     * Clear all stats in a StatGroup.
     */
    public void clear() {
        synchronized (stats) {
            for (Stat s : stats.values()) {
                s.clear();
            }
        }
    }

    /**
     * Negates all stats in a StatGroup.
     */
    public void negate() {
        synchronized (stats) {
            for (Stat s : stats.values()) {
                s.negate();
            }
        }
    }

    public String getName() {
        return groupName;
    }

    public String getDescription() {
        return groupDescription;
    }

    /**
     * @return a Stats class that copies the value of all stats in the group
     */
    public StatGroup cloneGroup(boolean clear) {

        Map> copyValues =
            new HashMap>();

        synchronized (stats) {
            for (Stat s : stats.values()) {
                if (clear) {
                    copyValues.put(s.getDefinition(), s.copyAndClear());
                } else {
                    copyValues.put(s.getDefinition(), s.copy());
                }
            }
        }
        return new StatGroup(groupName, groupDescription, copyValues);
    }

    /**
     * Return the stat associated with the specified definition, or null if not
     * found.
     *
     * @return the stat or null
     */
    public Stat getStat(StatDefinition definition) {
        return stats.get(definition);
    }

    public int getInt(StatDefinition definition) {
        Stat s = stats.get(definition);
        if (s == null) {
            return 0;
        }
        if (s instanceof StatWithValueType) {
            final Integer retval =
                ((StatWithValueType) s).getForType(Integer.class);
            if (retval != null) {
                return retval;
            }
        }
        assert false : "Internal error calling getInt with" +
            " unexpected stat type: " + s.getClass().getName();
        return 0;
    }

    public LongStat getLongStat(StatDefinition definition) {
        return (LongStat) stats.get(definition);
    }

    public long getLong(StatDefinition definition) {
        Stat s = stats.get(definition);
        if (s == null) {
            return 0;
        }
        if (s instanceof StatWithValueType) {
            final Long retval =
                ((StatWithValueType) s).getForType(Long.class);
            if (retval != null) {
                return retval;
            }
        } else if (s instanceof IntegralLongAvgStat) {
            return ((IntegralLongAvgStat)s).get().compute();
        }
        assert false : "Internal error calling getLong with" +
            " unexpected stat type: " + s.getClass().getName();
        return 0;
    }

    public IntegralLongAvgStat getIntegralLongAvgStat(
        StatDefinition definition) {
        return (IntegralLongAvgStat) stats.get(definition);
    }

    public LongMinStat getLongMinStat(StatDefinition definition) {
        return (LongMinStat) stats.get(definition);
    }

    public LongMaxStat getLongMaxStat(StatDefinition definition) {
        return (LongMaxStat) stats.get(definition);
    }

    public AtomicLongStat getAtomicLongStat(StatDefinition definition) {
        return (AtomicLongStat) stats.get(definition);
    }

    public Long getAtomicLong(StatDefinition definition) {
        AtomicLongStat s = (AtomicLongStat) stats.get(definition);
        if (s == null) {
            return 0L;
        } else {
            return s.get();
        }
    }

    public Active[] getActiveTxnArray(StatDefinition definition) {
        ActiveTxnArrayStat s = (ActiveTxnArrayStat) stats.get(definition);
        if (s == null) {
            return null;
        } else {
            return s.get();
        }
    }

    public long[] getLongArray(StatDefinition definition) {
        LongArrayStat s = (LongArrayStat) stats.get(definition);
        if (s == null) {
            return null;
        } else {
            return s.get();
        }
    }

    public float getFloat(StatDefinition definition) {
        FloatStat s = (FloatStat) stats.get(definition);
        if (s == null) {
            return 0;
        } else {
            return s.get();
        }
    }

    public boolean getBoolean(StatDefinition definition) {
        BooleanStat s = (BooleanStat) stats.get(definition);
        if (s == null) {
            return false;
        } else {
            return s.get();
        }
    }

    public String getString(StatDefinition definition) {
        StringStat s = (StringStat) stats.get(definition);
        if (s == null) {
            return null;
        } else {
            return s.get();
        }
    }

    @SuppressWarnings("unchecked")
    public  SortedMap getMap(StatDefinition definition) {
        MapStat s = (MapStat) stats.get(definition);
        if (s == null) {
            return null;
        } else {
            return s.getMap();
        }
    }

    /*
     * Add this group's information to the jconsole tip map.
     */
    public void addToTipMap(Map tips) {
        tips.put(getName(), getDescription());
        for (StatDefinition d: stats.keySet()) {
            tips.put(d.getName(), d.getDescription());
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(groupName).append(": ");
        sb.append(groupDescription).append("\n");

        /* Order the stats for consistent display. */
        Map> sortedStats;
        synchronized (stats) {
            sortedStats = new TreeMap>(stats);
        }
        for (Stat s : sortedStats.values()) {
            sb.append("\t").append(s).append("\n");
        }

        return sb.toString();
    }

    /**
     * Includes the per-stat description in the output string.
     */
    public String toStringVerbose() {
        StringBuilder sb = new StringBuilder();
        sb.append(groupName).append(": ");
        sb.append(groupDescription).append("\n");

        /* Order the stats for consistent display.*/
        Map> sortedStats;
        synchronized (stats) {
            sortedStats = new TreeMap>(stats);
        }
        for (Stat s : sortedStats.values()) {
            sb.append("\t").append(s.toStringVerbose()).append("\n");
        }
        return sb.toString();
    }

    /**
     * Only print values that are not null or zero.
     */
    public String toStringConcise() {

        boolean headerPrinted = false;
        StringBuilder sb = new StringBuilder();

        /* Order the stats for consistent display.*/
        Map> sortedStats;
        synchronized (stats) {
            sortedStats = new TreeMap>(stats);
        }

        for (Stat s : sortedStats.values()) {

            if (s.isNotSet()) {
                continue;
            }

            /*
             * Print the group name lazily, in case no fields in this group are
             * set at all. In that case, this method will not print anything.
             */
            if (!headerPrinted) {
                sb.append(groupName + "\n");
                headerPrinted = true;
            }
            sb.append("\t").append(s).append("\n");
        }
        return sb.toString();
    }

    /**
     * Return a string suitable for using as the header for a .csv file.
     */
    public String getCSVHeader() {
        StringBuilder sb = new StringBuilder();
        synchronized (stats) {
            for (StatDefinition def : stats.keySet()) {
                sb.append(groupName + "_" + def.getName() + ",");
            }
        }
        return sb.toString();
    }

    /**
     * Return a string suitable for using as the data for a .csv file.
     */
    public String getCSVData() {
        StringBuilder sb = new StringBuilder();
        synchronized (stats) {
            for (Stat s : stats.values()) {
                sb.append(s.getFormattedValue() + ",");
            }
        }
        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy