blob: 3b6a4e92173decaf990b24d677b6dbe56af2f957 [file] [log] [blame]
/*-
* 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.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import com.sleepycat.utilint.FormatUtil;
/**
* A long JE stat component that computes the difference between another stat
* and a specified value. Reports 0 if the value is greater than the stat
* value. The computed difference remains valid for a specified amount of
* time, which should represent the maximum amount of time expected to elapse
* between when new values are provided. If no value is specified within the
* validity interval, then the difference is recomputed using the current base
* stat value and the last specified value. The idea is to treat the specified
* value as up-to-date for a certain period of time, and then represent that
* the lack of updates means it is falling behind.
*/
public class LongDiffStat extends MapStatComponent<Long, LongDiffStat> {
private static final long serialVersionUID = 1L;
/** The stat that supplies the base value for computing differences. */
private final Stat<Long> base;
/**
* The maximum time, in milliseconds, that a computed difference is
* valid.
*/
private final long validityMillis;
/**
* 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;
/**
* The last computed difference, or 0. Synchronize on this instance when
* accessing this field.
*/
private long diff;
/**
* Creates an instance of this class.
*
* @param base the base stat used for computing differences
* @param validityMillis the amount of time, in milliseconds, which a
* computed difference remains valid
*/
public LongDiffStat(Stat<Long> base, long validityMillis) {
assert base != null;
assert validityMillis > 0;
this.base = base;
this.validityMillis = validityMillis;
}
private LongDiffStat(LongDiffStat other) {
base = other.base.copy();
validityMillis = other.validityMillis;
synchronized (this) {
synchronized (other) {
prevValue = other.prevValue;
prevTime = other.prevTime;
diff = other.diff;
}
}
}
/**
* Returns the value of the stat for the specified time.
*
* @param time the time
* @return the value of the stat
*/
public long get(long time) {
assert time > 0;
synchronized (this) {
if (prevTime == 0) {
return 0;
}
if (time < (prevTime + validityMillis)) {
return diff;
}
}
final long baseValue = base.get();
synchronized (this) {
return Math.max(baseValue - prevValue, 0);
}
}
/**
* Specifies a new value for the current time.
*
* @param newValue the new value
*/
public void set(long newValue) {
set(newValue, System.currentTimeMillis());
}
/**
* Specifies a new value for the specified time.
*
* @param newValue the new value
* @param time the time
*/
public void set(long newValue, long time) {
assert time > 0;
final long baseValue = base.get();
synchronized (this) {
prevValue = newValue;
prevTime = time;
diff = Math.max(baseValue - newValue, 0);
}
}
/**
* Returns the value of the stat for the current time.
*/
@Override
public Long get() {
return get(System.currentTimeMillis());
}
@Override
public synchronized void clear() {
prevValue = 0;
prevTime = 0;
diff = 0;
}
@Override
public LongDiffStat copy() {
return new LongDiffStat(this);
}
@Override
protected synchronized String getFormattedValue(boolean useCommas) {
if (isNotSet()) {
return "Unknown";
} else if (useCommas) {
return FormatUtil.decimalScale0().format(
get(System.currentTimeMillis()));
} else {
return String.valueOf(get(System.currentTimeMillis()));
}
}
@Override
public synchronized boolean isNotSet() {
return prevTime == 0;
}
@Override
public synchronized String toString() {
return "LongDiffStat[prevValue=" + prevValue +
", prevTime=" + prevTime + ", diff=" + diff + "]";
}
/** 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();
}
}