Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.infinispan.interceptors.impl.CacheMgmtInterceptor Maven / Gradle / Ivy
package org.infinispan.interceptors.impl;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import org.infinispan.AdvancedCache;
import org.infinispan.commands.FlagAffectedCommand;
import org.infinispan.commands.read.AbstractDataCommand;
import org.infinispan.commands.read.GetAllCommand;
import org.infinispan.commands.read.GetCacheEntryCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
import org.infinispan.commands.write.ComputeCommand;
import org.infinispan.commands.write.ComputeIfAbsentCommand;
import org.infinispan.commands.write.EvictCommand;
import org.infinispan.commands.write.PutKeyValueCommand;
import org.infinispan.commands.write.PutMapCommand;
import org.infinispan.commands.write.RemoveCommand;
import org.infinispan.commands.write.ReplaceCommand;
import org.infinispan.commands.write.WriteCommand;
import org.infinispan.container.DataContainer;
import org.infinispan.container.offheap.OffHeapMemoryAllocator;
import org.infinispan.context.Flag;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.FlagBitSets;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.jmx.annotations.DisplayType;
import org.infinispan.jmx.annotations.MBean;
import org.infinispan.jmx.annotations.ManagedAttribute;
import org.infinispan.jmx.annotations.ManagedOperation;
import org.infinispan.jmx.annotations.MeasurementType;
import org.infinispan.jmx.annotations.Units;
import org.infinispan.util.TimeService;
import org.infinispan.util.concurrent.StripedCounters;
/**
* Captures cache management statistics
*
* @author Jerry Gauthier
* @since 9.0
*/
@MBean(objectName = "Statistics", description = "General statistics such as timings, hit/miss ratio, etc.")
public class CacheMgmtInterceptor extends JmxStatsCommandInterceptor {
private AdvancedCache cache;
private DataContainer dataContainer;
private TimeService timeService;
private OffHeapMemoryAllocator allocator;
private final AtomicLong startNanoseconds = new AtomicLong(0);
private volatile AtomicLong resetNanoseconds = new AtomicLong(0);
private StripedCounters counters = new StripedCounters<>(StripeC::new);
@Inject
@SuppressWarnings("unused")
public void setDependencies(AdvancedCache cache, DataContainer dataContainer, TimeService timeService, OffHeapMemoryAllocator allocator) {
this.cache = cache;
this.dataContainer = dataContainer;
this.timeService = timeService;
this.allocator = allocator;
}
@Start
public void start() {
startNanoseconds.set(timeService.time());
resetNanoseconds.set(startNanoseconds.get());
}
@Override
public Object visitEvictCommand(InvocationContext ctx, EvictCommand command) throws Throwable {
if (!getStatisticsEnabled(command))
return invokeNext(ctx, command);
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
counters.increment(StripeB.evictionsFieldUpdater, counters.stripeForCurrentThread());
});
}
@Override
public final Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable {
return visitDataReadCommand(ctx, command);
}
@Override
public final Object visitGetCacheEntryCommand(InvocationContext ctx, GetCacheEntryCommand command) throws Throwable {
return visitDataReadCommand(ctx, command);
}
private Object visitDataReadCommand(InvocationContext ctx, AbstractDataCommand command) throws Throwable {
boolean statisticsEnabled = getStatisticsEnabled(command);
if (!statisticsEnabled || !ctx.isOriginLocal())
return invokeNext(ctx, command);
long start = timeService.time();
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
StripeB stripe = counters.stripeForCurrentThread();
long intervalNanoseconds = timeService.timeDuration(start, TimeUnit.NANOSECONDS);
if (rv == null) {
counters.add(StripeB.missTimesFieldUpdater, stripe, intervalNanoseconds);
counters.increment(StripeB.missesFieldUpdater, stripe);
} else {
counters.add(StripeB.hitTimesFieldUpdater, stripe, intervalNanoseconds);
counters.increment(StripeB.hitsFieldUpdater, stripe);
}
});
}
@SuppressWarnings("unchecked")
@Override
public Object visitGetAllCommand(InvocationContext ctx, GetAllCommand command) throws Throwable {
boolean statisticsEnabled = getStatisticsEnabled(command);
if (!statisticsEnabled || !ctx.isOriginLocal())
return invokeNext(ctx, command);
long start = timeService.time();
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
long intervalNanoseconds = timeService.timeDuration(start, TimeUnit.NANOSECONDS);
int requests = ((GetAllCommand) rCommand).getKeys().size();
int hitCount = 0;
for (Entry entry : ((Map) rv).entrySet()) {
if (entry.getValue() != null) {
hitCount++;
}
}
int missCount = requests - hitCount;
StripeB stripe = counters.stripeForCurrentThread();
if (hitCount > 0) {
counters.add(StripeB.hitsFieldUpdater, stripe, hitCount);
counters.add(StripeB.hitTimesFieldUpdater, stripe, intervalNanoseconds * hitCount / requests);
}
if (missCount > 0) {
counters.add(StripeB.missesFieldUpdater, stripe, missCount);
counters.add(StripeB.missTimesFieldUpdater, stripe, intervalNanoseconds * missCount / requests);
}
});
}
@Override
public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable {
boolean statisticsEnabled = getStatisticsEnabled(command);
if (!statisticsEnabled || !ctx.isOriginLocal())
return invokeNext(ctx, command);
long start = timeService.time();
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
final long intervalNanoseconds = timeService.timeDuration(start, TimeUnit.NANOSECONDS);
final Map data = ((PutMapCommand) rCommand).getMap();
if (data != null && !data.isEmpty()) {
StripeB stripe = counters.stripeForCurrentThread();
counters.add(StripeB.storeTimesFieldUpdater, stripe, intervalNanoseconds);
counters.add(StripeB.storesFieldUpdater, stripe, data.size());
}
});
}
@Override
//Map.put(key,value) :: oldValue
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
return updateStoreStatistics(ctx, command);
}
@Override
public Object visitReplaceCommand(InvocationContext ctx, ReplaceCommand command) throws Throwable {
return updateStoreStatistics(ctx, command);
}
@Override
public Object visitComputeCommand(InvocationContext ctx, ComputeCommand command) throws Throwable {
boolean statisticsEnabled = getStatisticsEnabled(command);
if (!statisticsEnabled || !ctx.isOriginLocal())
return invokeNext(ctx, command);
long start = timeService.time();
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
if (rv == null && command.isSuccessful()) {
increaseRemoveMisses();
} else if (command.isSuccessful()) {
long intervalMilliseconds = timeService.timeDuration(start, TimeUnit.MILLISECONDS);
StripeB stripe = counters.stripeForCurrentThread();
counters.add(StripeB.storeTimesFieldUpdater, stripe, intervalMilliseconds);
counters.increment(StripeB.storesFieldUpdater, stripe);
}
});
}
@Override
public Object visitComputeIfAbsentCommand(InvocationContext ctx, ComputeIfAbsentCommand command) throws Throwable {
return updateStoreStatistics(ctx, command);
}
private Object updateStoreStatistics(InvocationContext ctx, WriteCommand command) throws Throwable {
boolean statisticsEnabled = getStatisticsEnabled(command);
if (!statisticsEnabled || !ctx.isOriginLocal())
return invokeNext(ctx, command);
long start = timeService.time();
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
if (command.isSuccessful()) {
long intervalNanoseconds = timeService.timeDuration(start, TimeUnit.NANOSECONDS);
StripeB stripe = counters.stripeForCurrentThread();
counters.add(StripeB.storeTimesFieldUpdater, stripe, intervalNanoseconds);
counters.increment(StripeB.storesFieldUpdater, stripe);
}
});
}
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
boolean statisticsEnabled = getStatisticsEnabled(command);
if (!statisticsEnabled || !ctx.isOriginLocal())
return invokeNext(ctx, command);
long start = timeService.time();
return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> {
RemoveCommand removeCommand = (RemoveCommand) rCommand;
if (removeCommand.isConditional()) {
if (removeCommand.isSuccessful())
increaseRemoveHits(start);
else
increaseRemoveMisses();
} else {
if (rv == null)
increaseRemoveMisses();
else
increaseRemoveHits(start);
}
});
}
private void increaseRemoveHits(long start) {
long intervalNanoseconds = timeService.timeDuration(start, TimeUnit.NANOSECONDS);
StripeB stripe = counters.stripeForCurrentThread();
counters.add(StripeB.removeTimesFieldUpdater, stripe, intervalNanoseconds);
counters.increment(StripeB.removeHitsFieldUpdater, stripe);
}
private void increaseRemoveMisses() {
counters.increment(StripeB.removeMissesFieldUpdater, counters.stripeForCurrentThread());
}
@ManagedAttribute(
description = "Number of cache attribute hits",
displayName = "Number of cache hits",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY)
public long getHits() {
return counters.get(StripeB.hitsFieldUpdater);
}
@ManagedAttribute(
description = "Number of cache attribute misses",
displayName = "Number of cache misses",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
public long getMisses() {
return counters.get(StripeB.missesFieldUpdater);
}
@ManagedAttribute(
description = "Number of cache removal hits",
displayName = "Number of cache removal hits",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
public long getRemoveHits() {
return counters.get(StripeB.removeHitsFieldUpdater);
}
@ManagedAttribute(
description = "Number of cache removals where keys were not found",
displayName = "Number of cache removal misses",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
public long getRemoveMisses() {
return counters.get(StripeB.removeMissesFieldUpdater);
}
@ManagedAttribute(
description = "number of cache attribute put operations",
displayName = "Number of cache puts" ,
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
public long getStores() {
return counters.get(StripeB.storesFieldUpdater);
}
@ManagedAttribute(
description = "Number of cache eviction operations",
displayName = "Number of cache evictions",
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
public long getEvictions() {
return counters.get(StripeB.evictionsFieldUpdater);
}
@ManagedAttribute(
description = "Percentage hit/(hit+miss) ratio for the cache",
displayName = "Hit ratio",
units = Units.PERCENTAGE,
displayType = DisplayType.SUMMARY
)
@SuppressWarnings("unused")
public double getHitRatio() {
long hitsL = counters.get(StripeB.hitsFieldUpdater);
double total = hitsL + counters.get(StripeB.missesFieldUpdater);
// The reason for <= is that equality checks
// should be avoided for floating point numbers.
if (total <= 0)
return 0;
return (hitsL / total);
}
@ManagedAttribute(
description = "read/writes ratio for the cache",
displayName = "Read/write ratio",
units = Units.PERCENTAGE,
displayType = DisplayType.SUMMARY
)
@SuppressWarnings("unused")
public double getReadWriteRatio() {
long sum = counters.get(StripeB.storesFieldUpdater);
if (sum == 0)
return 0;
return (((double) (counters.get(StripeB.hitsFieldUpdater) + counters.get(StripeB.missesFieldUpdater)) / (double) sum));
}
@ManagedAttribute(
description = "Average number of nanoseconds for a read operation on the cache",
displayName = "Average read time",
units = Units.NANOSECONDS,
displayType = DisplayType.SUMMARY
)
@SuppressWarnings("unused")
public long getAverageReadTime() {
long total = counters.get(StripeB.hitsFieldUpdater) + counters.get(StripeB.missesFieldUpdater);
if (total == 0)
return 0;
return (counters.get(StripeB.hitTimesFieldUpdater) + counters.get(StripeB.missTimesFieldUpdater)) / total;
}
@ManagedAttribute(
description = "Average number of nanoseconds for a write operation in the cache",
displayName = "Average write time",
units = Units.NANOSECONDS,
displayType = DisplayType.SUMMARY
)
@SuppressWarnings("unused")
public long getAverageWriteTime() {
long sum = counters.get(StripeB.storesFieldUpdater);
if (sum == 0)
return 0;
return (counters.get(StripeB.storeTimesFieldUpdater)) / sum;
}
@ManagedAttribute(
description = "Average number of nanoseconds for a remove operation in the cache",
displayName = "Average remove time",
units = Units.NANOSECONDS,
displayType = DisplayType.SUMMARY
)
@SuppressWarnings("unused")
public long getAverageRemoveTime() {
long removes = getRemoveHits();
if (removes == 0)
return 0;
return (counters.get(StripeB.removeTimesFieldUpdater)) / removes;
}
@ManagedAttribute(
description = "Number of entries in the cache including passivated entries",
displayName = "Number of current cache entries",
displayType = DisplayType.SUMMARY
)
public int getNumberOfEntries() {
return cache.withFlags(Flag.CACHE_MODE_LOCAL).size();
}
@ManagedAttribute(
description = "Number of entries currently in-memory excluding expired entries",
displayName = "Number of in-memory cache entries",
displayType = DisplayType.SUMMARY
)
public int getNumberOfEntriesInMemory() {
return dataContainer.size();
}
@ManagedAttribute(
description = "Amount of memory in bytes allocated in off-heap",
displayName = "Off-Heap Memory Used",
displayType = DisplayType.SUMMARY
)
public long getOffHeapMemoryUsed() {
return allocator.getAllocatedAmount();
}
@ManagedAttribute(
description = "Number of seconds since cache started",
displayName = "Seconds since cache started",
units = Units.SECONDS,
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
public long getTimeSinceStart() {
return timeService.timeDuration(startNanoseconds.get(), TimeUnit.SECONDS);
}
/**
* Returns number of seconds since cache started
*
* @deprecated use {@link #getTimeSinceStart()} instead.
* @return number of seconds since cache started
*/
@ManagedAttribute(
description = "Number of seconds since cache started",
displayName = "Seconds since cache started",
units = Units.SECONDS,
measurementType = MeasurementType.TRENDSUP,
displayType = DisplayType.SUMMARY
)
@Deprecated
public long getElapsedTime() {
// backward compatibility as we renamed ElapsedTime to TimeSinceStart
return getTimeSinceStart();
}
@ManagedAttribute(
description = "Number of seconds since the cache statistics were last reset",
displayName = "Seconds since cache statistics were reset",
units = Units.SECONDS,
displayType = DisplayType.SUMMARY
)
@SuppressWarnings("unused")
public long getTimeSinceReset() {
return timeService.timeDuration(resetNanoseconds.get(), TimeUnit.SECONDS);
}
@Override
@ManagedOperation(
description = "Resets statistics gathered by this component",
displayName = "Reset Statistics (Statistics)"
)
public void resetStatistics() {
counters.reset(StripeB.hitsFieldUpdater);
counters.reset(StripeB.missesFieldUpdater);
counters.reset(StripeB.storesFieldUpdater);
counters.reset(StripeB.evictionsFieldUpdater);
counters.reset(StripeB.hitTimesFieldUpdater);
counters.reset(StripeB.missTimesFieldUpdater);
counters.reset(StripeB.storeTimesFieldUpdater);
counters.reset(StripeB.removeHitsFieldUpdater);
counters.reset(StripeB.removeTimesFieldUpdater);
counters.reset(StripeB.removeMissesFieldUpdater);
resetNanoseconds.set(timeService.time());
}
private boolean getStatisticsEnabled(FlagAffectedCommand cmd) {
return super.getStatisticsEnabled() && !cmd.hasAnyFlag(FlagBitSets.SKIP_STATISTICS);
}
public void addEvictions(long numEvictions) {
counters.add(StripeB.evictionsFieldUpdater, counters.stripeForCurrentThread(), numEvictions);
}
@SuppressWarnings("unused")
private static class StripeA {
private long slack1, slack2, slack3, slack4, slack5, slack6, slack7, slack8;
}
@SuppressWarnings({"unused", "VolatileLongOrDoubleField"})
private static class StripeB extends StripeA {
static final AtomicLongFieldUpdater hitTimesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "hitTimes");
static final AtomicLongFieldUpdater missTimesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "missTimes");
static final AtomicLongFieldUpdater storeTimesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "storeTimes");
static final AtomicLongFieldUpdater removeHitsFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "removeHits");
static final AtomicLongFieldUpdater removeMissesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "removeMisses");
static final AtomicLongFieldUpdater storesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "stores");
static final AtomicLongFieldUpdater evictionsFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "evictions");
static final AtomicLongFieldUpdater missesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "misses");
static final AtomicLongFieldUpdater hitsFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "hits");
static final AtomicLongFieldUpdater removeTimesFieldUpdater =
AtomicLongFieldUpdater.newUpdater(StripeB.class, "removeTimes");
private volatile long hits = 0;
private volatile long hitTimes = 0;
private volatile long misses = 0;
private volatile long missTimes = 0;
private volatile long stores = 0;
private volatile long storeTimes = 0;
private volatile long evictions = 0;
private volatile long removeHits = 0;
private volatile long removeMisses = 0;
private volatile long removeTimes = 0;
}
@SuppressWarnings("unused")
private static class StripeC extends StripeB {
private long slack1, slack2, slack3, slack4, slack5, slack6, slack7, slack8;
}
}