package org.infinispan.stats.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.infinispan.AdvancedCache;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.jmx.JmxStatisticsExposer;
import org.infinispan.jmx.annotations.DataType;
import org.infinispan.jmx.annotations.DisplayType;
import org.infinispan.jmx.annotations.MBean;
import org.infinispan.jmx.annotations.ManagedAttribute;
import org.infinispan.jmx.annotations.MeasurementType;
import org.infinispan.jmx.annotations.Units;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.stats.CacheContainerStats;
import org.infinispan.stats.Stats;
import org.infinispan.util.TimeService;
/**
* Cache container statistics needed for admin console
*
* @author Vladimir Blagojevic
* @since 7.1
*
*/
@MBean(objectName = CacheContainerStats.OBJECT_NAME, description = "General cache container statistics such as timings, hit/miss ratio, etc.")
public class CacheContainerStatsImpl implements CacheContainerStats, JmxStatisticsExposer {
private EmbeddedCacheManager cm;
private final AtomicLong resetNanoseconds = new AtomicLong(0);
private boolean statisticsEnabled = false;
private TimeService timeService;
public CacheContainerStatsImpl(EmbeddedCacheManager cm) {
this.cm = cm;
cm.getGlobalComponentRegistry().registerComponent(this, CacheContainerStats.class);
boolean globalJmxStatsEnabled = cm.getCacheManagerConfiguration().globalJmxStatistics().enabled();
setStatisticsEnabled(globalJmxStatsEnabled);
}
@Inject
public void setDependencies(TimeService timeService) {
this.timeService = timeService;
}
@Override
public void setStatisticsEnabled(boolean enabled) {
this.statisticsEnabled = enabled;
if (enabled) {
//yes technically we do not reset stats but we initialize them
resetNanoseconds.set(timeService.time());
}
}
@Override
public boolean getStatisticsEnabled() {
return statisticsEnabled;
}
@Override
public void resetStatistics() {
if (getStatisticsEnabled()) {
getEnabledStats().forEach( stats -> stats.reset());
resetNanoseconds.set(timeService.time());
}
}
@ManagedAttribute(description = "Enables or disables the gathering of statistics by this component",
displayName = "Statistics enabled",
dataType = DataType.TRAIT,
writable = true)
public boolean isStatisticsEnabled() {
return getStatisticsEnabled();
}
@ManagedAttribute(description = "Cache container total average number of milliseconds for all read operation in this cache container",
displayName = "Cache container total average read time",
units = Units.MILLISECONDS,
displayType = DisplayType.SUMMARY)
@Override
public long getAverageReadTime() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateAverageReadTime();
}
return result;
}
protected long calculateAverageReadTime() {
long totalAverageReadTime = 0;
int includedCacheCounter = 0;
for (Stats stats : getEnabledStats()) {
long averageReadTime = stats.getAverageReadTime();
if (averageReadTime > 0) {
includedCacheCounter++;
totalAverageReadTime += averageReadTime;
}
}
if (includedCacheCounter > 0) {
totalAverageReadTime = totalAverageReadTime / includedCacheCounter;
}
return totalAverageReadTime;
}
@ManagedAttribute(description = "Cache container total average number of milliseconds for all remove operation in this cache container",
displayName = "Cache container total average remove time",
units = Units.MILLISECONDS,
displayType = DisplayType.SUMMARY)
@Override
public long getAverageRemoveTime() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateAverageRemoveTime();
}
return result;
}
protected long calculateAverageRemoveTime() {
long totalAverageRemoveTime = 0;
int includedCacheCounter = 0;
for (Stats stats : getEnabledStats()) {
long averageRemoveTime = stats.getAverageRemoveTime();
if (averageRemoveTime > 0) {
includedCacheCounter++;
totalAverageRemoveTime += averageRemoveTime;
}
}
if (includedCacheCounter > 0) {
totalAverageRemoveTime = totalAverageRemoveTime / includedCacheCounter;
}
return totalAverageRemoveTime;
}
@ManagedAttribute(description = "Cache container average number of milliseconds for all write operation in this cache container",
displayName = "Cache container average write time",
units = Units.MILLISECONDS,
displayType = DisplayType.SUMMARY)
@Override
public long getAverageWriteTime() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateAverageWriteTime();
}
return result;
}
protected long calculateAverageWriteTime() {
long totalAverageWriteTime = 0;
int includedCacheCounter = 0;
for (Stats stats : getEnabledStats()) {
long averageWriteTime = stats.getAverageWriteTime();
if (averageWriteTime > 0) {
includedCacheCounter++;
totalAverageWriteTime += averageWriteTime;
}
}
if (includedCacheCounter > 0) {
totalAverageWriteTime = totalAverageWriteTime / includedCacheCounter;
}
return totalAverageWriteTime;
}
@ManagedAttribute(
description = "Cache container total number of cache eviction operations",
displayName = "Cache container total number of cache evictions",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
@Override
public long getEvictions() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateEvictions();
}
return result;
}
protected long calculateEvictions() {
long totalEvictions = 0;
for (Stats stats : getEnabledStats()) {
long evictions = stats.getEvictions();
if (evictions > 0) {
totalEvictions += evictions;
}
}
return totalEvictions;
}
@ManagedAttribute(
description = "Cache container total number of cache attribute hits",
displayName = "Cache container total number of cache hits",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY)
@Override
public long getHits() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateHits();
}
return result;
}
protected long calculateHits() {
long totalHits = 0;
for (Stats stats : getEnabledStats()) {
long hits = stats.getHits();
if (hits > 0) {
totalHits += hits;
}
}
return totalHits;
}
@ManagedAttribute(
description = "Cache container total percentage hit/(hit+miss) ratio for this cache",
displayName = "Cache container total hit ratio",
units = Units.PERCENTAGE,
displayType = DisplayType.SUMMARY
)
@Override
public double getHitRatio() {
double result = -1d;
if (getStatisticsEnabled()) {
result = calculateHitRatio();
}
return result;
}
protected double calculateHitRatio() {
long totalHits = 0;
double totalRequests = 0;
double rwRatio = 0;
for (Stats stats : getEnabledStats()) {
long requests = stats.getRetrievals();
if (requests > 0) {
totalHits += stats.getHits();
totalRequests += requests;
}
}
if (totalRequests > 0) {
rwRatio = totalHits / totalRequests;
}
return rwRatio;
}
@ManagedAttribute(
description = "Cache container total number of cache attribute misses",
displayName = "Cache container total number of cache misses",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
@Override
public long getMisses() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateMisses();
}
return result;
}
protected long calculateMisses() {
long totalMisess = 0;
for (Stats stats : getEnabledStats()) {
long misses = stats.getMisses();
if (misses > 0) {
totalMisess += misses;
}
}
return totalMisess;
}
@ManagedAttribute(
description = "Cache container total number of entries currently in all caches from this cache container",
displayName = "Cache container total number of all cache entries",
displayType = DisplayType.SUMMARY
)
public int getNumberOfEntries() {
int result = statisticsEnabled ? 0 : -1;
if (statisticsEnabled) {
for (Stats stats : getEnabledStats()) {
int numOfEntries = stats.getCurrentNumberOfEntries();
if (numOfEntries > 0) {
result += numOfEntries;
}
}
}
return result;
}
@ManagedAttribute(
description = "Cache container total number of entries currently in-memory for all caches in this cache container",
displayName = "Cache container total number of in-memory cache entries",
displayType = DisplayType.SUMMARY
)
public int getCurrentNumberOfEntriesInMemory() {
int result = statisticsEnabled ? 0 : -1;
if (statisticsEnabled) {
for (Stats stats : getEnabledStats()) {
int numOfEntries = stats.getCurrentNumberOfEntriesInMemory();
if (numOfEntries > 0) {
result += numOfEntries;
}
}
}
return result;
}
@ManagedAttribute(
description = "Cache container read/writes ratio in all caches from this cache container",
displayName = "Cache container read/write ratio",
units = Units.PERCENTAGE,
displayType = DisplayType.SUMMARY
)
@Override
public double getReadWriteRatio() {
double result = -1d;
if (getStatisticsEnabled()) {
result = calculateReadWriteRatio();
}
return result;
}
protected double calculateReadWriteRatio() {
long sumOfAllReads = 0;
long sumOfAllWrites = 0;
double rwRatio = 0;
for (Stats stats : getEnabledStats()) {
long stores = stats.getStores();
if (stores > 0) {
sumOfAllReads += stats.getRetrievals();
sumOfAllWrites += stores;
}
}
if (sumOfAllWrites > 0) {
rwRatio = (double) sumOfAllReads / sumOfAllWrites;
}
return rwRatio;
}
@ManagedAttribute(
description = "Cache container total number of cache removal hits",
displayName = "Cache container total number of cache removal hits",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
@Override
public long getRemoveHits() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateRemoveHits();
}
return result;
}
protected long calculateRemoveHits() {
long totalRemoveHits = 0;
for (Stats stats : getEnabledStats()) {
long removeHits = stats.getRemoveHits();
if (removeHits > 0) {
totalRemoveHits += removeHits;
}
}
return totalRemoveHits;
}
@ManagedAttribute(
description = "Cache container total number of cache removals where keys were not found",
displayName = "Cache container total number of cache removal misses",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
@Override
public long getRemoveMisses() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateRemoveMisses();
}
return result;
}
protected long calculateRemoveMisses() {
long totalRemoveMisses = 0;
for (Stats stats : getEnabledStats()) {
long removeMisses = stats.getRemoveMisses();
if (removeMisses > 0) {
totalRemoveMisses += removeMisses;
}
}
return totalRemoveMisses;
}
@ManagedAttribute(
description = "Cache container total number of cache attribute put operations",
displayName = "Cache container total number of cache puts" ,
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
@Override
public long getStores() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateStores();
}
return result;
}
@Override
@ManagedAttribute(
description = "Number of seconds since the cache container statistics were last reset",
displayName = "Seconds since cache container statistics were reset",
units = Units.SECONDS,
displayType = DisplayType.SUMMARY
)
public long getTimeSinceReset() {
long result = -1;
if (getStatisticsEnabled()) {
result = timeService.timeDuration(resetNanoseconds.get(), TimeUnit.SECONDS);
}
return result;
}
protected long calculateStores() {
long totalStores = 0;
for (Stats stats : getEnabledStats()) {
long stores = stats.getStores();
if (stores > 0) {
totalStores+= stores;
}
}
return totalStores;
}
@Override
public long getTimeSinceStart() {
long result = -1;
if (getStatisticsEnabled()) {
result = calculateTimeSinceStart();
}
return result;
}
protected long calculateTimeSinceStart() {
long longestRunning = 0;
for (Stats stats : getEnabledStats()) {
long runningTime = stats.getTimeSinceStart();
if (runningTime > longestRunning) {
longestRunning = runningTime;
}
}
return longestRunning;
}
@Override
public int getCurrentNumberOfEntries() {
return getNumberOfEntries();
}
@Override
public long getTotalNumberOfEntries() {
return getStores();
}
@Override
@ManagedAttribute(
description = "Amount in bytes of off-heap memory used by this cache container",
displayName = "Off-Heap memory used",
displayType = DisplayType.SUMMARY
)
public long getOffHeapMemoryUsed() {
return calculateOffHeapUsed();
}
protected long calculateOffHeapUsed() {
long totalOffHeapUsed = 0;
for (Stats stats : getEnabledStats()) {
long offHeapUsed = stats.getOffHeapMemoryUsed();
if (offHeapUsed > 0) {
totalOffHeapUsed += offHeapUsed;
}
}
return totalOffHeapUsed;
}
@Override
public long getRetrievals() {
return getHits() + getMisses();
}
@Override
public void reset() {
resetStatistics();
}
private Set<Stats> getEnabledStats() {
Set<Stats> stats = new HashSet<Stats>();
for (String cn : cm.getCacheNames()) {
if (cm.cacheExists(cn)) {
AdvancedCache cache = cm.getCache(cn).getAdvancedCache();
Configuration cfg = SecurityActions.getCacheConfiguration(cache);
if (cfg.jmxStatistics().enabled()) {
stats.add(cache.getStats());
}
}
}
return stats;
}
}