/* 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); }