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

com.sleepycat.je.utilint.LongAvgRate 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 static java.util.concurrent.TimeUnit.MILLISECONDS;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.concurrent.TimeUnit;

import com.sleepycat.utilint.FormatUtil;

/**
 * A long JE stat component generated from an exponential moving average over a
 * specified time period of the rate of change in a long value over time.
 */
public class LongAvgRate extends MapStatComponent {
    private static final long serialVersionUID = 1L;

    /**
     * The minimum number of milliseconds for computing rate changes, to avoid
     * quantizing errors.
     */
    public static final long MIN_PERIOD = 200;

    /** The time unit for reporting the result. */
    private final TimeUnit reportTimeUnit;

    /** The average of the rate values. */
    private final DoubleExpMovingAvg avg;

    /**
     * The previous value, or 0.  Synchronize on this instance when accessing
     * this field.
     */
    private long prevValue;

    /**
     * The time in milliseconds of the previous value, or 0.  Synchronize on
     * this instance when accessing this field.
     */
    private long prevTime;

    /**
     * Creates an instance of this class.
     *
     * @param name the name of this stat
     * @param periodMillis the averaging period in milliseconds
     * @param reportTimeUnit the time unit for reporting the result
     */
    public LongAvgRate(String name,
                       long periodMillis,
                       TimeUnit reportTimeUnit) {
        avg = new DoubleExpMovingAvg(name, periodMillis);
        assert reportTimeUnit != null;
        this.reportTimeUnit = reportTimeUnit;
    }

    /**
     * Creates an instance of this class as a copy of another instance.
     *
     * @param other the other instance to copy
     */
    private LongAvgRate(LongAvgRate other) {
        avg = new DoubleExpMovingAvg(other.avg.copy());
        reportTimeUnit = other.reportTimeUnit;
        synchronized (this) {
            synchronized (other) {
                prevValue = other.prevValue;
                prevTime = other.prevTime;
            }
        }
    }

    /**
     * Returns the name of this stat.
     *
     * @return the name of this stat
     */
    public String getName() {
        return avg.getName();
    }

    /**
     * Adds a new value to the average, ignoring values that are less than
     * {@link #MIN_PERIOD} milliseconds older than the last entry.
     *
     * @param value the new value
     * @param time the current time in milliseconds
     */
    public synchronized void add(long value, long time) {
        assert time > 0;
        if (prevTime != 0) {
            final long deltaTime = time - prevTime;
            if (deltaTime < MIN_PERIOD) {
                return;
            }
            avg.add(((double) (value - prevValue)) / ((double) deltaTime),
                    time);
        }
        prevValue = value;
        prevTime = time;
    }

    /**
     * Update with more recent values from another stat.
     *
     * @param other the other stat
     */
    public void add(LongAvgRate other) {
        final LongAvgRate copyOther = other.copy();
        synchronized (this) {
            synchronized (copyOther) {
                addInternal(copyOther);
            }
        }
    }

    /**
     * Do an  add, letting the caller  arrange to synchronize on  this instance
     * and the argument safely.
     */
    private void addInternal(LongAvgRate other) {
        assert(Thread.holdsLock(this));
        assert(Thread.holdsLock(other));

        /*
         * Only use the other values if they are newer by more than the
         * minimum
         */
        if ((other.prevTime - prevTime) > MIN_PERIOD) {
            avg.add(other.avg);
            prevValue = other.prevValue;
            prevTime = other.prevTime;
        }
    }

    /**
     * Create and return a new stat that includes the most recent values from
     * this stat and another stat.
     *
     * @param other the other stat
     * @return a copy containing all new values
     */
    public LongAvgRate copyLatest(LongAvgRate other) {
        final LongAvgRate otherCopy = other.copy();
        synchronized (this) {
            synchronized (otherCopy) {
                if (prevTime > otherCopy.prevTime) {
                    otherCopy.addInternal(this);
                    return otherCopy;
                }
                final LongAvgRate result = copy();
                synchronized (result) {
                    result.addInternal(otherCopy);
                    return result;
                }
            }
        }
    }

    /**
     * Returns the time the last new value was added, or 0 if no values have
     * been added.
     *
     * @return the time or 0
     */
    synchronized long getPrevTime() {
        return prevTime;
    }

    /**
     * Returns the current average rate, or 0 if no rate has been computed.
     */
    @Override
    public Long get() {
        return getPrimitive();
    }

    /** Returns the current average rate as a primitive value. */
    private long getPrimitive() {
        final double inMillis = avg.getPrimitive();
        if (reportTimeUnit == MILLISECONDS) {
            return Math.round(inMillis);
        } else if (reportTimeUnit.compareTo(MILLISECONDS) < 0) {
            return Math.round(
                inMillis / reportTimeUnit.convert(1, MILLISECONDS));
        } else {
            return Math.round(inMillis * reportTimeUnit.toMillis(1));
        }
    }

    @Override
    public synchronized void clear() {
        avg.clear();
        prevValue = 0;
        prevTime = 0;
    }

    @Override
    public LongAvgRate copy() {
        return new LongAvgRate(this);
    }

    @Override
    protected String getFormattedValue(boolean useCommas) {
        if (isNotSet()) {
            return "unknown";
        }
        final long val = getPrimitive();
        if (useCommas) {
            return FormatUtil.decimalScale0().format(val);
        } else {
            return Long.toString(val);
        }
    }

    @Override
    public boolean isNotSet() {
        return avg.isNotSet();
    }

    @Override
    public synchronized String toString() {
        return "LongAvgRate[" + avg + ", prevValue=" + prevValue +
            ", prevTime=" + prevTime + "]";
    }

    /** Synchronize access to fields. */
    private synchronized void readObject(ObjectInputStream in)
        throws IOException, ClassNotFoundException {

        in.defaultReadObject();
    }

    /** Synchronize access to fields. */
    private synchronized void writeObject(ObjectOutputStream out)
        throws IOException {

        out.defaultWriteObject();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy