com.persistit.StatisticsTask Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of akiban-persistit Show documentation
Show all versions of akiban-persistit Show documentation
Java B+Tree Key-Value Store Library
/**
* Copyright © 2011-2012 Akiban Technologies, Inc. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This program may also be available under different license terms.
* For more information, see www.akiban.com or contact [email protected].
*
* Contributors:
* Akiban Technologies, Inc.
*/
package com.persistit;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.persistit.CLI.Arg;
import com.persistit.CLI.Cmd;
import com.persistit.Management.BufferPoolInfo;
import com.persistit.Management.JournalInfo;
import com.persistit.Management.TransactionInfo;
import com.persistit.mxbeans.IOMeterMXBean;
import com.persistit.util.Util;
/**
* Task that reports, either once or periodically, various runtime statistics.
*
* @author peter
*/
public class StatisticsTask extends Task {
static final long NANOS_PER_MILLI = 1000000;
static final long NANOS_PER_SECOND = 1000000000;
final static String COUNT_FORMAT = "%s=%d";
final static String RATE_FORMAT = "%s=%.3f";
final static String PHEADER_FORMAT = " %10s";
final static String PCOUNT_FORMAT = " %,10d";
final static String PRATE_FORMAT = " %,10.3f";
final static String TIME_HEADER_FORMAT = "%12s ";
final static String TIME_FORMAT = "%,12d ";
long _delay;
long _count;
boolean _bpool;
boolean _journal;
boolean _io;
boolean _transactions;
boolean _showRate;
boolean _showValue;
String _fileName;
PrintWriter _pw;
String _lastUpdate = "none";
private final Map _statsMap = new HashMap();
private final List _statsList = new ArrayList();
enum Display {
TOTAL, CHANGE, RATE
};
static class Stat {
final String _name;
long _time;
long _value;
long _interval;
long _change;
Stat(final String name) {
this._name = name;
}
final void update(final long time, final long value) {
_interval = time - _time;
_change = value - _value;
_time = time;
_value = value;
}
@Override
public String toString() {
return toString(Display.TOTAL);
}
public String toString(final Display display) {
switch (display) {
case TOTAL:
return String.format(COUNT_FORMAT, _name, _value);
case CHANGE:
return String.format(COUNT_FORMAT, _name, _change);
case RATE:
return String.format(RATE_FORMAT, _name, rate());
default:
throw new IllegalStateException();
}
}
public void printHeader(final PrintWriter pw) throws IOException {
pw.print(String.format(PHEADER_FORMAT, _name));
}
public void printValue(final PrintWriter pw, final Display display) throws IOException {
switch (display) {
case TOTAL:
pw.print(String.format(PCOUNT_FORMAT, _value));
break;
case CHANGE:
pw.print(String.format(PCOUNT_FORMAT, _change));
break;
case RATE:
pw.print(String.format(PRATE_FORMAT, rate()));
break;
default:
throw new IllegalStateException();
}
}
public double rate() {
if (_interval > 0) {
return ((double) _change * NANOS_PER_SECOND) / _interval;
}
return -1.0d;
}
}
@Cmd("stat")
static Task createStatisticsTask(
@Arg("delay|long:10:0:10000000|Interval in seconds between updates") final long delay,
@Arg("count|long:1:0:|Number of updates") final long count,
@Arg("file|string|Output file name") final String toFile, @Arg("_flag|a|All") final boolean all,
@Arg("_flag|b|Buffer pool statistics") final boolean bstats,
@Arg("_flag|j|Journal statistics") final boolean jstats,
@Arg("_flag|i|I/O Statistics") final boolean istats,
@Arg("_flag|t|Transaction statistics") final boolean tstats,
@Arg("_flag|r|Show rates") final boolean showRates, @Arg("_flag|v|Show values") final boolean showValues)
throws Exception {
final StatisticsTask task = new StatisticsTask();
task._delay = delay;
task._count = count;
task._fileName = toFile;
task._bpool = bstats || all;
task._journal = jstats || all;
task._io = istats || all;
task._transactions = tstats || all;
task._showRate = showRates;
task._showValue = showValues;
return task;
}
@Override
protected void runTask() throws Exception {
if (_fileName != null && !_fileName.isEmpty()) {
_pw = new PrintWriter(new FileOutputStream(_fileName, true));
}
if (!_bpool && !_journal && !_transactions && !_io) {
postMessage("No statistics selected", 0);
return;
}
final StringBuilder sb = new StringBuilder();
long now = System.nanoTime();
long next = now;
boolean first = true;
for (long count = 0; count < _count || count == 0; count++) {
if (count != 0) {
next += (_delay * NANOS_PER_SECOND);
while (true) {
poll();
now = System.nanoTime();
final long sleep = Math.min(1000, (next - now) / NANOS_PER_MILLI);
if (sleep <= 0) {
break;
}
Util.sleep(sleep);
}
}
updateStatistics(now);
sb.setLength(0);
final Display d = _showRate ? Display.RATE : count == 0 ? Display.TOTAL : Display.CHANGE;
if (count > 0 || !_showRate) {
for (final Stat stat : _statsList) {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(stat.toString(d));
}
sb.append(' ');
sb.append(d);
final String line = sb.toString();
_lastUpdate = line;
if (_pw != null) {
if (first) {
_pw.printf(TIME_HEADER_FORMAT, "elapsed ms");
for (final Stat stat : _statsList) {
stat.printHeader(_pw);
}
_pw.println();
first = false;
}
_pw.printf(TIME_FORMAT, _persistit.elapsedTime());
for (final Stat stat : _statsList) {
stat.printValue(_pw, d);
}
_pw.print(' ');
_pw.println(d.toString());
_pw.flush();
} else {
postMessage(line, 1);
}
}
if (_delay < 1) {
break;
}
}
}
private Stat stat(final String name) {
Stat stat = _statsMap.get(name);
if (stat == null) {
stat = new Stat(name);
_statsMap.put(name, stat);
_statsList.add(stat);
}
return stat;
}
private void updateStatistics(final long time) throws Exception {
final Management management = _persistit.getManagement();
if (_bpool) {
updateBPoolStatistics(management, time);
}
if (_journal) {
updateJournalStatistics(management, time);
}
if (_transactions) {
updateTransactionStatistics(management, time);
}
if (_io) {
updateIOStatistics(management, time);
}
}
private void updateBPoolStatistics(final Management management, final long time) throws Exception {
final BufferPoolInfo[] array = management.getBufferPoolInfoArray();
long hits = 0;
long misses = 0;
long newPages = 0;
long evictions = 0;
for (final BufferPoolInfo info : array) {
hits += info.getHitCount();
misses += info.getMissCount();
newPages += info.getNewCount();
evictions += info.getEvictCount();
}
stat("hit").update(time, hits);
stat("miss").update(time, misses);
stat("new").update(time, newPages);
stat("evict").update(time, evictions);
}
private void updateJournalStatistics(final Management management, final long time) throws Exception {
final JournalInfo info = management.getJournalInfo();
stat("jwrite").update(time, info.getJournaledPageCount());
stat("jread").update(time, info.getReadPageCount());
stat("jcopy").update(time, info.getCopiedPageCount());
}
private void updateTransactionStatistics(final Management management, final long time) throws Exception {
final TransactionInfo info = management.getTransactionInfo();
stat("tcommit").update(time, info.getCommitCount());
stat("troll").update(time, info.getRollbackCount());
}
private void updateIOStatistics(final Management management, final long time) throws Exception {
final IOMeterMXBean ioMeter = _persistit.getIOMeter();
final String[] items = IOMeterMXBean.SUMMARY_ITEMS;
long size = 0;
for (final String item : items) {
stat(item).update(time, ioMeter.totalOperations(item));
size += ioMeter.totalBytes(item);
}
stat("IOkbytes").update(time, (size + 600) / 1000);
}
@Override
public String getStatus() {
return _lastUpdate;
}
}