/* * 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.stats; import org.infinispan.configuration.cache.Configuration; import org.infinispan.stats.translations.ExposedStatistics.IspnStats; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import java.util.HashMap; import java.util.Map; /** * @author Diego Didona <didona@gsd.inesc-id.pt> * @author Pedro Ruivo * @since 5.2 */ public abstract class TransactionStatistics implements InfinispanStat { private final Log log = LogFactory.getLog(getClass()); //Here the elements which are common for local and remote transactions protected long initTime; private boolean isReadOnly; private boolean isCommit; private String transactionalClass; private Map<Object, Long> takenLocks = new HashMap<Object, Long>(); private long lastOpTimestamp; private final StatisticsContainer statisticsContainer; protected Configuration configuration; public TransactionStatistics(int size, Configuration configuration) { this.initTime = System.nanoTime(); this.isReadOnly = true; //as far as it does not tries to perform a put operation this.takenLocks = new HashMap<Object, Long>(); this.transactionalClass = TransactionsStatisticsRegistry.DEFAULT_ISPN_CLASS; this.statisticsContainer = new StatisticsContainerImpl(size); this.configuration = configuration; if (log.isTraceEnabled()) { log.tracef("Created transaction statistics. Class is %s. Start time is %s", transactionalClass, initTime); } } public final String getTransactionalClass(){ return this.transactionalClass; } public final void setTransactionalClass(String className){ this.transactionalClass = className; } public final boolean isCommit(){ return this.isCommit; } public final void setCommit(boolean commit) { isCommit = commit; } public final boolean isReadOnly(){ return this.isReadOnly; } public final void setUpdateTransaction(){ this.isReadOnly = false; } public final void addTakenLock(Object lock){ if(!this.takenLocks.containsKey(lock)) this.takenLocks.put(lock, System.nanoTime()); } public final void addValue(IspnStats param, double value){ try{ int index = this.getIndex(param); this.statisticsContainer.addValue(index,value); if (log.isTraceEnabled()) { log.tracef("Add %s to %s", value, param); } } catch(NoIspnStatException e){ log.warnf(e, "Exception caught when trying to add the value %s to %s.", value, param); } } public final long getValue(IspnStats param){ int index = this.getIndex(param); long value = this.statisticsContainer.getValue(index); if (log.isTraceEnabled()) { log.tracef("Value of %s is %s", param, value); } return value; } public final void incrementValue(IspnStats param){ this.addValue(param,1); } public final void terminateTransaction() { if (log.isTraceEnabled()) { log.tracef("Terminating transaction. Is read only? %s. Is commit? %s", isReadOnly, isCommit); } long now = System.nanoTime(); double execTime = now - this.initTime; if(this.isReadOnly){ if(isCommit){ this.incrementValue(IspnStats.NUM_COMMITTED_RO_TX); this.addValue(IspnStats.RO_TX_SUCCESSFUL_EXECUTION_TIME,execTime); this.addValue(IspnStats.NUM_SUCCESSFUL_GETS_RO_TX, this.getValue(IspnStats.NUM_GET)); this.addValue(IspnStats.NUM_SUCCESSFUL_REMOTE_GETS_RO_TX, this.getValue(IspnStats.NUM_REMOTE_GET)); } else{ this.incrementValue(IspnStats.NUM_ABORTED_RO_TX); this.addValue(IspnStats.RO_TX_ABORTED_EXECUTION_TIME,execTime); } } else{ if(isCommit){ this.incrementValue(IspnStats.NUM_COMMITTED_WR_TX); this.addValue(IspnStats.WR_TX_SUCCESSFUL_EXECUTION_TIME,execTime); this.addValue(IspnStats.NUM_SUCCESSFUL_GETS_WR_TX, this.getValue(IspnStats.NUM_GET)); this.addValue(IspnStats.NUM_SUCCESSFUL_REMOTE_GETS_WR_TX, this.getValue(IspnStats.NUM_REMOTE_GET)); this.addValue(IspnStats.NUM_SUCCESSFUL_PUTS_WR_TX, this.getValue(IspnStats.NUM_PUT)); this.addValue(IspnStats.NUM_SUCCESSFUL_REMOTE_PUTS_WR_TX, this.getValue(IspnStats.NUM_REMOTE_PUT)); } else{ this.incrementValue(IspnStats.NUM_ABORTED_WR_TX); this.addValue(IspnStats.WR_TX_ABORTED_EXECUTION_TIME,execTime); } } int heldLocks = this.takenLocks.size(); double cumulativeLockHoldTime = this.computeCumulativeLockHoldTime(heldLocks,now); this.addValue(IspnStats.NUM_HELD_LOCKS,heldLocks); this.addValue(IspnStats.LOCK_HOLD_TIME,cumulativeLockHoldTime); terminate(); } public final void flush(TransactionStatistics ts){ if (log.isTraceEnabled()) { log.tracef("Flush this [%s] to %s", this, ts); } this.statisticsContainer.mergeTo(ts.statisticsContainer); } public final void dump(){ this.statisticsContainer.dump(); } @Override public String toString() { return "initTime=" + initTime + ", isReadOnly=" + isReadOnly + ", isCommit=" + isCommit + ", transactionalClass=" + transactionalClass + '}'; } protected abstract int getIndex(IspnStats param); protected abstract void onPrepareCommand(); protected abstract void terminate(); private long computeCumulativeLockHoldTime(int numLocks,long currentTime){ long ret = numLocks * currentTime; for(Object o:this.takenLocks.keySet()) ret-=this.takenLocks.get(o); return ret; } public void setLastOpTimestamp(long lastOpTimestamp) { this.lastOpTimestamp = lastOpTimestamp; } public long getLastOpTimestamp() { return lastOpTimestamp; } }