
net.grinder.statistics.StatisticsIndexMap Maven / Gradle / Ivy
// Copyright (C) 2000 - 2012 Philip Aston
// Copyright (C) 2004 John Stanford White
// Copyright (C) 2004 Calum Fitzgerald
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
package net.grinder.statistics;
import static java.util.Arrays.asList;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A registry of statistic index objects.
*
*
* Each statistic has a unique index object and a name. The index objects are
* used with {@link net.grinder.script.Statistics} and the names can be used in
* expressions (see {@link ExpressionView}). Statistics can either be
* long integer values (see {@link #getLongIndex}) or
* double floating-point values ({@link #getDoubleIndex}).
*
*
See {@link net.grinder.script.Statistics} for details of the statistics
* provided by The Grinder.
*
*
Sample Statistics
*
*
* There is a special type of index object for sample statistics, see
* {@link #getLongSampleIndex} and {@link #getDoubleSampleIndex}. Sample
* statistics are the result of a series of sample values. The values can be
* either longs or doubles. Sample statistics have three
* attribute values that can be read: the count (number of samples),
* sum (total of all sample values), and sample variance.
* These attributes can be queried using the appropriate expression function
* (e.g. count()), see {@link ExpressionView}.
*
*
* @author Philip Aston
*/
public final class StatisticsIndexMap implements Serializable {
private static final long serialVersionUID = 1;
private final Map m_doubleMap =
new HashMap();
private final Map m_longMap =
new HashMap();
private final Map m_transientLongMap =
new HashMap();
private final Map m_doubleSampleMap =
new HashMap();
private final Map m_longSampleMap =
new HashMap();
// These are bigger than m_doubleMap.size() and m_longMap.size()
// as the sample indicies also use slots.
private final int m_numberOfDoubles;
private final int m_numberOfLongs;
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indicies. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_RESPONSE_STATUS_KEY =
"httpplugin.responseStatus";
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indicies. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_RESPONSE_LENGTH_KEY =
"httpplugin.responseLength";
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indices. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_RESPONSE_ERRORS_KEY =
"httpplugin.responseErrors";
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indices. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_DNS_TIME_KEY =
"httpplugin.dnsTime";
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indices. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_CONNECT_TIME_KEY =
"httpplugin.connectTime";
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indices. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_FIRST_BYTE_TIME_KEY =
"httpplugin.firstByteTime";
/**
* Special slot for the HTTP plugin so it doesn't steal "user"
* indices. Use with {@link #getLongIndex(String)}.
*/
public static final String HTTP_PLUGIN_CONNECTIONS_ESTABLISHED =
"httpplugin.connectionsEstablished";
/**
* Constructor.
*/
StatisticsIndexMap() {
// Set up standard statistic index values. When adding new values
// or changing the order, you should also change the serialVersionUID
// of TestStatisticsMap.
this(asList("errors",
"untimedTests",
HTTP_PLUGIN_RESPONSE_STATUS_KEY,
HTTP_PLUGIN_RESPONSE_LENGTH_KEY,
HTTP_PLUGIN_RESPONSE_ERRORS_KEY,
HTTP_PLUGIN_DNS_TIME_KEY,
HTTP_PLUGIN_CONNECT_TIME_KEY,
HTTP_PLUGIN_FIRST_BYTE_TIME_KEY,
HTTP_PLUGIN_CONNECTIONS_ESTABLISHED,
"userLong0",
"userLong1",
"userLong2",
"userLong3",
"userLong4"),
asList("peakTPS",
"userDouble0",
"userDouble1",
"userDouble2",
"userDouble3",
"userDouble4"),
asList("period"),
asList("timedTests"));
}
/**
* Open constructor for use by unit tests.
*
* @param longNames
* Names of long statistics.
* @param doubleNames
* Names of double statistics.
* @param transientLongNames
* Names of transient long statistics.
* @param longSampleNames
* Names of long sample statistics.
*/
StatisticsIndexMap(List longNames,
List doubleNames,
List transientLongNames,
List longSampleNames) {
int nextLongIndex = 0;
int nextTransientLongIndex = 0;
for (String longName : longNames) {
m_longMap.put(longName, new LongIndex(nextLongIndex++));
}
int nextDoubleIndex = 0;
for (String doubleName : doubleNames) {
m_doubleMap.put(doubleName, new DoubleIndex(nextDoubleIndex++));
}
for (String longSampleName : longSampleNames) {
createLongSampleIndex(longSampleName,
new LongIndex(nextLongIndex++),
new LongIndex(nextLongIndex++),
new DoubleIndex(nextDoubleIndex++));
}
for (String transientLongName : transientLongNames) {
m_transientLongMap.put(transientLongName,
new LongIndex(nextTransientLongIndex++, true));
}
m_numberOfDoubles = nextDoubleIndex;
m_numberOfLongs = nextLongIndex;
}
int getNumberOfDoubles() {
return m_numberOfDoubles;
}
int getNumberOfLongs() {
return m_numberOfLongs;
}
int getNumberOfTransientLongs() {
return m_transientLongMap.size();
}
Collection getDoubleSampleIndicies() {
return m_doubleSampleMap.values();
}
Collection getLongSampleIndicies() {
return m_longSampleMap.values();
}
/**
* Obtain the index object for the named double statistic.
*
* @param statisticName The statistic name.
* @return The index object, or null
if there is no such
* double statistic.
*/
public DoubleIndex getDoubleIndex(String statisticName) {
return m_doubleMap.get(statisticName);
}
/**
* Obtain the index object for the named long statistic.
*
* @param statisticName The statistic name.
* @return The index object, or null
if there is no such
* long statistic.
*/
public LongIndex getLongIndex(String statisticName) {
final LongIndex nonTransient = m_longMap.get(statisticName);
if (nonTransient != null) {
return nonTransient;
}
else {
return m_transientLongMap.get(statisticName);
}
}
/**
* Obtain the index object for the named double sample statistic.
*
* @param statisticName The statistic name.
* @return The index object, or null
if there is no such
* double sample statistic.
*/
public DoubleSampleIndex getDoubleSampleIndex(String statisticName) {
return m_doubleSampleMap.get(statisticName);
}
/**
* Obtain the index object for the named long statistic.
*
* @param statisticName The statistic name.
* @return The index object, or null
if there is no such
* long sample statistic.
*/
public LongSampleIndex getLongSampleIndex(String statisticName) {
return m_longSampleMap.get(statisticName);
}
/**
* Factory for {@link LongSampleIndex}s.
*
* If this is made public and called from somewhere other than our
* constructor, we need to address synchronisation.
*
* @param statisticName Name to register index under.
* @param sumIndex Index to hold sum.
* @param countIndex Index to hold count.
* @param varianceIndex Index to hold variance.
* @return The new index.
*/
private LongSampleIndex createLongSampleIndex(String statisticName,
LongIndex sumIndex,
LongIndex countIndex,
DoubleIndex varianceIndex) {
final LongSampleIndex result =
new LongSampleIndex(sumIndex, countIndex, varianceIndex);
m_longSampleMap.put(statisticName, result);
return result;
}
/**
* Factory for {@link DoubleSampleIndex}s.
*
* Package scope for unit tests.
*
* If this is made public and called from somewhere other than our
* constructor, we need to address synchronisation.
*
* @param statisticName Name to register index under.
* @param sumIndex Index to hold sum.
* @param countIndex Index to hold count.
* @param varianceIndex Index to hold variance.
* @return The new index.
*/
DoubleSampleIndex createDoubleSampleIndex(String statisticName,
DoubleIndex sumIndex,
LongIndex countIndex,
DoubleIndex varianceIndex) {
final DoubleSampleIndex result =
new DoubleSampleIndex(sumIndex, countIndex, varianceIndex);
m_doubleSampleMap.put(statisticName, result);
return result;
}
/**
* For unit tests to remove {@link DoubleSampleIndex}s they've created.
*
* @param statisticName Name of the DoubleSampleIndex.
*/
void removeDoubleSampleIndex(String statisticName) {
m_doubleSampleMap.remove(statisticName);
}
/**
* Base for index classes.
*
*
* Refactor me: move the index implementations to nested classes of
* StatisticsSetImplementation and expose a single, opaque StatsiticsSet.Index
* interface.
*
*/
abstract static class AbstractSimpleIndex {
private final int m_value;
private final boolean m_transient;
protected AbstractSimpleIndex(int i, boolean isTransient) {
m_value = i;
m_transient = isTransient;
}
public final int getValue() {
return m_value;
}
public boolean isTransient() {
return m_transient;
}
}
/**
* Class of opaque objects that represent double
statistics.
*/
public static final class DoubleIndex extends AbstractSimpleIndex {
private DoubleIndex(int i) {
super(i, false);
}
}
/**
* Class of opaque objects that represent long
statistics.
*/
public static final class LongIndex extends AbstractSimpleIndex {
private LongIndex(int i) {
this(i, false);
}
private LongIndex(int i, boolean isTransient) {
super(i, isTransient);
}
}
/**
* Base class for sample statistic indices.
*/
static class SampleIndex {
private final LongIndex m_countIndex;
private final DoubleIndex m_varianceIndex;
protected SampleIndex(LongIndex countIndex, DoubleIndex varianceIndex) {
m_countIndex = countIndex;
m_varianceIndex = varianceIndex;
}
/**
* Get the index object for our count (the number of samples).
*
* Package scope to prevent direct write access. External clients should
* use the {@link StatisticsSet} or {@link StatisticExpression} interfaces.
*
*
* @return The index object.
*/
final LongIndex getCountIndex() {
return m_countIndex;
}
/**
* Get the index object for our variance.
*
* Package scope to prevent direct write access. External clients should
* use the {@link StatisticsSet} or {@link StatisticExpression} interfaces.
*
*
* @return The index object.
*/
final DoubleIndex getVarianceIndex() {
return m_varianceIndex;
}
}
/**
* Class of objects that represent sample statistics with double
* sample values.
*/
public static final class DoubleSampleIndex extends SampleIndex {
private final DoubleIndex m_sumIndex;
private DoubleSampleIndex(DoubleIndex sumIndex,
LongIndex countIndex,
DoubleIndex varianceIndex) {
super(countIndex, varianceIndex);
m_sumIndex = sumIndex;
}
/**
* Get the index object for our sum.
*
* Package scope to prevent direct write access. External clients should
* use the {@link StatisticsSet} or {@link StatisticExpression} interfaces.
*
*
* @return The index object.
*/
DoubleIndex getSumIndex() {
return m_sumIndex;
}
}
/**
* Class of objects that represent sample statistics with long
* sample values.
*/
public static final class LongSampleIndex extends SampleIndex {
private final LongIndex m_sumIndex;
private LongSampleIndex(LongIndex sumIndex,
LongIndex countIndex,
DoubleIndex varianceIndex) {
super(countIndex, varianceIndex);
m_sumIndex = sumIndex;
}
/**
* Get the index object for our sum.
*
* Package scope to prevent direct write access. External clients should
* use the {@link StatisticsSet} or {@link StatisticExpression} interfaces.
*
*
* @return The index object.
*/
LongIndex getSumIndex() {
return m_sumIndex;
}
}
}