/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB Inc.
*
* VoltDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VoltDB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.voltdb;
import org.voltdb.VoltTable.ColumnInfo;
import edu.brown.hstore.HStore;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Abstract superclass of all sources of statistical information inside the Java frontend.
*/
public abstract class StatsSource {
/**
* Name of this source of statistical information
*/
private final String name;
private Integer m_hostId;
private String m_hostname;
/**
* Statistics from ee are already formatted in VoltTable
*/
private final boolean m_isEEStats;
private VoltTable m_table = null;
/**
* Column schema for statistical result rows
*/
protected final ArrayList<ColumnInfo> columns = new ArrayList<ColumnInfo>();
/**
* Map from the name of a column to its index in the a result row. In order to decouple the contributions of each class
* in the inheritance hierarchy from the integer index in the result row this map is used for lookups instead of hard coding an index.
*/
protected final Map<String, Integer> columnNameToIndex = new LinkedHashMap<String, Integer>();
/**
* Initialize this source of statistical information with the specified name. Populate the column schema by calling populateColumnSchema
* on the derived class and use it to populate the columnNameToIndex map.
* @param name
* @param isEE If this source represents statistics from EE
*/
public StatsSource(String name, boolean isEE) {
populateColumnSchema(columns);
for (int ii = 0; ii < columns.size(); ii++) {
columnNameToIndex.put(columns.get(ii).name, ii);
}
String hostname = null;
int hostId = 0;
if (HStore.instance() != null) {
hostname = HStore.instance().getSiteName();
hostId = HStore.instance().getSiteId();
}
m_hostname = hostname;
m_hostId = hostId;
this.name = name;
m_isEEStats = isEE;
}
/**
* Called from the constructor to generate the column schema at run time. Derived classes need to override this method in order
* to specify the columns they will be adding. The first line must always be a call the superclasses version of populateColumnSchema
* in order to ensure the columns are add to the list in the right order.
* @param columns Output list for the column schema.
*/
protected void populateColumnSchema(ArrayList<ColumnInfo> columns) {
columns.add(new ColumnInfo("TIMESTAMP", VoltType.BIGINT));
columns.add(new ColumnInfo(VoltSystemProcedure.CNAME_HOST_ID,
VoltSystemProcedure.CTYPE_ID));
columns.add(new ColumnInfo("HOSTNAME", VoltType.STRING));
}
/**
* Retrieve the already constructed column schema
* @return List of column names and types
*/
public ArrayList<ColumnInfo> getColumnSchema() {
return columns;
}
/**
* Get the name of this source of statistical information
* @return Name of this source
*/
public String getName() {
return name;
}
/**
* Get the latest stat values as an array of arrays of objects suitable for insertion into an VoltTable
* @param interval Whether to get stats since the beginning or since the last time stats were retrieved
* @return Array of Arrays of objects containing the latest values
*/
public Object[][] getStatsRows(boolean interval, final Long now) {
this.now = now;
/*
* Synchronizing on this allows derived classes to maintain thread safety
*/
synchronized (this) {
Iterator<Object> i = getStatsRowKeyIterator(interval);
ArrayList<Object[]> rows = new ArrayList<Object[]>();
while (i.hasNext()) {
Object rowKey = i.next();
Object rowValues[] = new Object[columns.size()];
updateStatsRow(rowKey, rowValues);
rows.add(rowValues);
}
return rows.toArray(new Object[0][]);
}
}
/**
* If this source contains statistics from EE. EE statistics are already
* formatted in VoltTable, so use getStatsTable() to get the result.
*/
public boolean isEEStats() {
return m_isEEStats;
}
/**
* For some sources like TableStats, they use VoltTable to keep track of
* statistics. This method will return it directly.
*
* @return If the return value is null, you should fall back to using
* getStatsRows()
*/
public VoltTable getStatsTable() {
return m_table;
}
/**
* Sets the VoltTable which contains the statistics. Only sources which use
* VoltTable to keep track of statistics need to use this.
*
* @param statsTable
* The VoltTable which contains the statistics.
*/
public void setStatsTable(VoltTable statsTable) {
m_table = statsTable;
}
private Long now = System.currentTimeMillis();
/**
* Update the parameter array with the latest values. This is similar
* to populateColumnSchema in that it must be overriden by
* derived classes and the derived class implementation must call the super classes implementation.
* @param rowKey Key identifying the specific row to be populated
* @param rowValues Output parameter. Array of values to be updated.
*/
protected void updateStatsRow(Object rowKey, Object rowValues[]) {
if (m_hostname == null && HStore.instance() != null) {
m_hostname = HStore.instance().getSiteName();
m_hostId = HStore.instance().getSiteId();
}
rowValues[0] = now;
rowValues[1] = m_hostId;
rowValues[2] = m_hostname;
}
/**
* Retrieve an iterator that iterates over the keys identifying all unique stats rows
* available for retrieval from the stats source
* @param interval Whether return stats that are recorded from the beginning or since
* the last time they were iterated
* @return Iterator of Objects representing keys that identify unique stats rows
*/
abstract protected Iterator<Object> getStatsRowKeyIterator(boolean interval);
}