/* * INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa * Copyright 2013 INESC-ID and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3.0 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.reconfigurableprotocol.manager; import java.util.HashMap; import java.util.Map; /** * Statistics collection about the switch, namely duration between phases * * @author Pedro Ruivo * @since 5.2 */ public class StatisticManager { private static final long NO_STAT = -1; private final Map<String, Map<String, StatEntry>> switchStats; public StatisticManager() { switchStats = new HashMap<String, Map<String, StatEntry>>(); } public final void add(Stats stats) { synchronized (switchStats) { if (!switchStats.containsKey(stats.from)) { createNonExistingNewEntry(stats); } else if (!switchStats.get(stats.from).containsKey(stats.to)) { createNewEntry(stats); } else { updateEntry(stats); } } } public final double getSafeToSafe(String from, String to) { synchronized (switchStats) { StatEntry entry = getEntry(from, to); return entry == null ? NO_STAT : convertNanosToMilli(entry.getSafeToSafe()); } } public final double getSafeToUnsafe(String from, String to) { synchronized (switchStats) { StatEntry entry = getEntry(from, to); return entry == null ? NO_STAT : convertNanosToMilli(entry.getSafeToUnsafe()); } } public final double getUnsafeToSafe(String from, String to) { synchronized (switchStats) { StatEntry entry = getEntry(from, to); return entry == null ? NO_STAT : convertNanosToMilli(entry.getUnsafeToSafe()); } } public final int getSwitchCounter(String from, String to) { synchronized (switchStats) { StatEntry entry = getEntry(from, to); return entry == null ? (int)NO_STAT : entry.switchCount; } } public final int getNumberOfAbortedTransactions(String from, String to) { synchronized (switchStats) { StatEntry entry = getEntry(from, to); return entry == null ? (int)NO_STAT : entry.numberOfTransactionAborted; } } public final String printAllStats() { StringBuilder sb = new StringBuilder(); synchronized (switchStats) { for (Map.Entry<String, Map<String, StatEntry>> outside : switchStats.entrySet()) { String from = outside.getKey(); for (Map.Entry<String, StatEntry> inside : outside.getValue().entrySet()) { String to = inside.getKey(); StatEntry entry = inside.getValue(); sb.append(from).append("=>").append(to).append(": "); sb.append("SafeToSafe=").append(convertNanosToMilli(entry.getSafeToSafe())); sb.append(",SafeToUnsafe=").append(convertNanosToMilli(entry.getSafeToUnsafe())); sb.append(",UnsafeToSafe=").append(convertNanosToMilli(entry.getUnsafeToSafe())); sb.append(",Counter=").append(entry.switchCount); sb.append(",NumberOfTransactionAborted=").append(entry.numberOfTransactionAborted); sb.append("\n"); } } } return sb.toString(); } public final void reset() { synchronized (switchStats) { switchStats.clear(); } } public final Stats createNewStats(String from) { return new Stats(from, this); } private void createNonExistingNewEntry(Stats stats) { Map<String, StatEntry> newEntry = new HashMap<String, StatEntry>(); StatEntry statEntry = new StatEntry(); statEntry.add(stats.start, stats.unsafe, stats.safe, stats.numberOfTransactionAborted); newEntry.put(stats.to, statEntry); switchStats.put(stats.from, newEntry); } private void createNewEntry(Stats stats) { StatEntry statEntry = new StatEntry(); statEntry.add(stats.start, stats.unsafe, stats.safe, stats.numberOfTransactionAborted); switchStats.get(stats.from).put(stats.to, statEntry); } private void updateEntry(Stats stats) { StatEntry entry = switchStats.get(stats.from).get(stats.to); entry.add(stats.start, stats.unsafe, stats.safe, stats.numberOfTransactionAborted); } private StatEntry getEntry(String from, String to) { Map<String, StatEntry> line = switchStats.get(from); return line == null ? null : line.get(to); } private double convertNanosToMilli(double nanos) { if (nanos == NO_STAT) { return nanos; } return nanos / 1000000.0; } private class StatEntry { private long safeToSafe; private long safeToUnsafe; private long unsafeToSafe; private int safeToSafeCounter; private int safeToUnsafeCounter; private int unsafeToSafeCounter; private int switchCount; private int numberOfTransactionAborted; public void add(long start, long unsafe, long safe, int numberOfTransactionAborted) { if (unsafe != NO_STAT) { safeToSafe += (safe - start); safeToUnsafe += (unsafe - start); unsafeToSafe += (safe - unsafe); safeToSafeCounter++; safeToUnsafeCounter++; unsafeToSafeCounter++; } else { safeToSafe += (safe - start); safeToSafeCounter++; } switchCount++; this.numberOfTransactionAborted += numberOfTransactionAborted; } public double getSafeToSafe() { if (safeToSafeCounter == 0) { return NO_STAT; } return safeToSafe * 1.0 / safeToSafeCounter; } public double getSafeToUnsafe() { if (safeToUnsafeCounter == 0) { return NO_STAT; } return safeToUnsafe * 1.0 / safeToUnsafeCounter; } public double getUnsafeToSafe() { if (unsafeToSafeCounter == 0) { return NO_STAT; } return unsafeToSafe * 1.0 / unsafeToSafeCounter; } public int getNumberOfTransactionAborted() { return numberOfTransactionAborted; } } public static class Stats { private final long start; private final String from; private final StatisticManager manager; private long unsafe = NO_STAT; private long safe = NO_STAT; private String to; private int numberOfTransactionAborted; private Stats(String from, StatisticManager manager) { this.start = System.nanoTime(); this.from = from; this.manager = manager; } public final void unsafe(String to) { if (to != null) { this.to = to; } unsafe = System.nanoTime(); } public final void safe(String to) { if (to != null) { this.to = to; } safe = System.nanoTime(); manager.add(this); } public final void addNumberOfTransactionAborted(int val) { numberOfTransactionAborted += val; } } }