diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java new file mode 100644 index 0000000..7fbd081 --- /dev/null +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java @@ -0,0 +1,49 @@ +package org.apache.jackrabbit.oak.api.jmx; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import aQute.bnd.annotation.ProviderType; + +import javax.management.openmbean.CompositeData; + +@ProviderType +public interface PersistentCacheStatsMBean extends CacheStatsMBean { + String TYPE = "PersistentCacheStats"; + + CompositeData getRequestRateHistory(); + + CompositeData getHitRateHistory(); + + CompositeData getLoadRateHistory(); + + CompositeData getLoadExceptionRateHistory(); + + CompositeData getHitPercentageHistory(); + + CompositeData getPutRateHistory(); + + CompositeData getInvalidateOneRateHistory(); + + CompositeData getInvalidateAllRateHistory(); + + CompositeData getBroadcastRecvRateHistory(); + + String cacheInfoAsString(); + +} + + diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java index b0f2b7b..2c85c00 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java @@ -15,7 +15,7 @@ * limitations under the License. */ -@Version("3.0.0") +@Version("3.1.0") @Export(optional = "provide:=true") package org.apache.jackrabbit.oak.api.jmx; diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/ConsolidatedCacheStats.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/ConsolidatedCacheStats.java index b8d5dd7..7f13405 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/ConsolidatedCacheStats.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/ConsolidatedCacheStats.java @@ -37,6 +37,7 @@ import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean; import org.apache.jackrabbit.oak.api.jmx.ConsolidatedCacheStatsMBean; +import org.apache.jackrabbit.oak.api.jmx.PersistentCacheStatsMBean; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; import org.apache.jackrabbit.oak.spi.whiteboard.Registration; import org.apache.jackrabbit.oak.spi.whiteboard.Tracker; @@ -51,6 +52,7 @@ import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerM public class ConsolidatedCacheStats implements ConsolidatedCacheStatsMBean { private Tracker cacheStats; + private Tracker persistentCacheStats; private Registration mbeanReg; @@ -64,6 +66,9 @@ public class ConsolidatedCacheStats implements ConsolidatedCacheStatsMBean { for(CacheStatsMBean stats : cacheStats.getServices()){ tds.put(new CacheStatsData(stats).toCompositeData()); } + for(CacheStatsMBean stats : persistentCacheStats.getServices()){ + tds.put(new CacheStatsData(stats).toCompositeData()); + } } catch (OpenDataException e) { throw new IllegalStateException(e); } @@ -74,6 +79,7 @@ public class ConsolidatedCacheStats implements ConsolidatedCacheStatsMBean { private void activate(BundleContext context){ Whiteboard wb = new OsgiWhiteboard(context); cacheStats = wb.track(CacheStatsMBean.class); + persistentCacheStats = wb.track(PersistentCacheStatsMBean.class); mbeanReg = registerMBean(wb, ConsolidatedCacheStatsMBean.class, this, @@ -90,6 +96,10 @@ public class ConsolidatedCacheStats implements ConsolidatedCacheStatsMBean { if(cacheStats != null){ cacheStats.stop(); } + + if(persistentCacheStats != null) { + persistentCacheStats.stop(); + } } private static class CacheStatsData { diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java index 8643bf7..6a36b55 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java @@ -20,7 +20,9 @@ import static com.google.common.base.Preconditions.checkArgument; import java.io.InputStream; import java.net.UnknownHostException; +import java.util.EnumMap; import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -60,6 +62,7 @@ import org.apache.jackrabbit.oak.plugins.document.mongo.MongoMissingLastRevSeeke import org.apache.jackrabbit.oak.plugins.document.mongo.MongoVersionGCSupport; import org.apache.jackrabbit.oak.plugins.document.persistentCache.CacheType; import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCache; +import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCacheStats; import org.apache.jackrabbit.oak.plugins.document.rdb.RDBBlobStore; import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore; import org.apache.jackrabbit.oak.plugins.document.rdb.RDBOptions; @@ -521,6 +524,8 @@ public class DocumentMK { private BlobStoreStats blobStoreStats; private CacheStats blobStoreCacheStats; private DocumentStoreStatsCollector documentStoreStatsCollector; + private Map persistentCacheStats = + new EnumMap(CacheType.class); public Builder() { } @@ -875,6 +880,9 @@ public class DocumentMK { return this; } + public StatisticsProvider getStatisticsProvider() { + return this.statisticsProvider; + } public DocumentStoreStatsCollector getDocumentStoreStatsCollector() { if (documentStoreStatsCollector == null) { documentStoreStatsCollector = new DocumentStoreStats(statisticsProvider); @@ -887,6 +895,11 @@ public class DocumentMK { return this; } + @Nonnull + public Map getPersistenceCacheStats() { + return persistentCacheStats; + } + @CheckForNull public BlobStoreStats getBlobStoreStats() { return blobStoreStats; @@ -1003,7 +1016,12 @@ public class DocumentMK { if (docNodeStore != null) { docNodeStore.setPersistentCache(p); } - cache = p.wrap(docNodeStore, docStore, cache, cacheType); + cache = p.wrap(docNodeStore, docStore, cache, cacheType, statisticsProvider); + + PersistentCacheStats stats = PersistentCache.getPersistentCacheStats(cache); + if (stats != null) { + persistentCacheStats.put(cacheType, stats); + } } return cache; } diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java index d3a4c11..e7eb262 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java @@ -56,6 +56,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.ReferencePolicy; import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean; import org.apache.jackrabbit.oak.api.jmx.CheckpointMBean; +import org.apache.jackrabbit.oak.api.jmx.PersistentCacheStatsMBean; import org.apache.jackrabbit.oak.cache.CacheStats; import org.apache.jackrabbit.oak.commons.PropertiesUtil; import org.apache.jackrabbit.oak.osgi.ObserverTracker; @@ -66,6 +67,8 @@ import org.apache.jackrabbit.oak.plugins.blob.BlobGarbageCollector; import org.apache.jackrabbit.oak.plugins.blob.BlobStoreStats; import org.apache.jackrabbit.oak.plugins.blob.SharedDataStore; import org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils; +import org.apache.jackrabbit.oak.plugins.document.persistentCache.CacheType; +import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCacheStats; import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection; import org.apache.jackrabbit.oak.plugins.identifier.ClusterRepositoryInfo; import org.apache.jackrabbit.oak.spi.blob.BlobStore; @@ -651,6 +654,19 @@ public class DocumentNodeStoreService { ); } + // register persistent cache stats + Map persistenceCacheStats = mkBuilder.getPersistenceCacheStats(); + for (PersistentCacheStats pcs: persistenceCacheStats.values()) { + registrations.add( + registerMBean(whiteboard, + PersistentCacheStatsMBean.class, + pcs, + PersistentCacheStatsMBean.TYPE, + pcs.getName()) + ); + } + + final long versionGcMaxAgeInSecs = toLong(prop(PROP_VER_GC_MAX_AGE), DEFAULT_VER_GC_MAX_AGE); final long blobGcMaxAgeInSecs = toLong(prop(PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE); diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java index 8903471..f7c983c 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java @@ -27,6 +27,8 @@ import javax.annotation.Nullable; import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; import org.apache.jackrabbit.oak.plugins.document.DocumentStore; import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCache.GenerationCache; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; +import org.apache.jackrabbit.oak.stats.TimerStats; import org.h2.mvstore.MVMap; import org.h2.mvstore.WriteBuffer; import org.h2.mvstore.type.DataType; @@ -39,6 +41,7 @@ import com.google.common.collect.ImmutableMap; class NodeCache implements Cache, GenerationCache { private final PersistentCache cache; + private final PersistentCacheStats stats; private final Cache memCache; private final MultiGenerationMap map; private final CacheType type; @@ -49,7 +52,8 @@ class NodeCache implements Cache, GenerationCache { PersistentCache cache, Cache memCache, DocumentNodeStore docNodeStore, - DocumentStore docStore, CacheType type) { + DocumentStore docStore, CacheType type, + StatisticsProvider statisticsProvider) { this.cache = cache; this.memCache = memCache; this.type = type; @@ -57,6 +61,7 @@ class NodeCache implements Cache, GenerationCache { map = new MultiGenerationMap(); keyType = new KeyDataType(type); valueType = new ValueDataType(docNodeStore, docStore, type); + stats = new PersistentCacheStats(type, statisticsProvider); } @Override @@ -131,9 +136,13 @@ class NodeCache implements Cache, GenerationCache { if (value != null) { return value; } + stats.markRequest(); + value = readIfPresent((K) key); + if (value != null) { memCache.put((K) key, value); + stats.markHit(); } return value; } @@ -142,12 +151,25 @@ class NodeCache implements Cache, GenerationCache { public V get(K key, Callable valueLoader) throws ExecutionException { + + // hit/request stats covered by getIfPresent V value = getIfPresent(key); if (value != null) { return value; } + + // Track entry load time + TimerStats.Context ctx = stats.startLoaderTimer(); + try { value = memCache.get(key, valueLoader); + ctx.stop(); + } + catch (ExecutionException e) { + this.stats.markException(); + throw e; + } write(key, value); + return value; } @@ -161,6 +183,7 @@ class NodeCache implements Cache, GenerationCache { public void put(K key, V value) { memCache.put(key, value); write(key, value); + stats.markPut(); } @SuppressWarnings("unchecked") @@ -168,6 +191,7 @@ class NodeCache implements Cache, GenerationCache { public void invalidate(Object key) { memCache.invalidate(key); write((K) key, (V) null); + stats.markInvalidateOne(); } @Override @@ -184,6 +208,7 @@ class NodeCache implements Cache, GenerationCache { public void invalidateAll() { memCache.invalidateAll(); map.clear(); + stats.markInvalidateAll(); } @Override @@ -219,6 +244,11 @@ class NodeCache implements Cache, GenerationCache { memCache.put(key, value); } writeWithoutBroadcast(key, value); + stats.markRecvBroadcast(); + } + + public PersistentCacheStats getPersistentCacheStats() { + return stats; } } \ No newline at end of file diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java index cfe480d..9b13906 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java @@ -33,6 +33,7 @@ import org.apache.jackrabbit.oak.plugins.document.persistentCache.broadcast.InMe import org.apache.jackrabbit.oak.plugins.document.persistentCache.broadcast.TCPBroadcaster; import org.apache.jackrabbit.oak.plugins.document.persistentCache.broadcast.UDPBroadcaster; import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.h2.mvstore.FileStore; import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap.Builder; @@ -363,6 +364,14 @@ public class PersistentCache implements Broadcaster.Listener { DocumentNodeStore docNodeStore, DocumentStore docStore, Cache base, CacheType type) { + return wrap(docNodeStore, docStore, base, type, StatisticsProvider.NOOP); + } + + public synchronized Cache wrap( + DocumentNodeStore docNodeStore, + DocumentStore docStore, + Cache base, CacheType type, + StatisticsProvider statisticsProvider) { boolean wrap; switch (type) { case NODE: @@ -389,7 +398,7 @@ public class PersistentCache implements Broadcaster.Listener { } if (wrap) { NodeCache c = new NodeCache(this, - base, docNodeStore, docStore, type); + base, docNodeStore, docStore, type, statisticsProvider); initGenerationCache(c); return c; } @@ -509,6 +518,15 @@ public class PersistentCache implements Broadcaster.Listener { buff.position(end); } + public static PersistentCacheStats getPersistentCacheStats(Cache cache) { + if (cache instanceof NodeCache) { + return ((NodeCache) cache).getPersistentCacheStats(); + } + else { + return null; + } + } + private void receiveMessage(ByteBuffer buff) { CacheType type = CacheType.VALUES[buff.get()]; GenerationCache cache = caches.get(type); @@ -538,7 +556,5 @@ public class PersistentCache implements Broadcaster.Listener { void receive(ByteBuffer buff); void removeGeneration(int oldReadGeneration); - } - } diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java new file mode 100644 index 0000000..a562c48 --- /dev/null +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java @@ -0,0 +1,374 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.persistentCache; + +import com.google.common.base.Objects; +import org.apache.jackrabbit.api.stats.TimeSeries; +import org.apache.jackrabbit.oak.api.jmx.PersistentCacheStatsMBean; +import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean; +import org.apache.jackrabbit.oak.stats.MeterStats; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; +import org.apache.jackrabbit.oak.stats.StatsOptions; +import org.apache.jackrabbit.oak.stats.TimerStats; +import org.apache.jackrabbit.stats.TimeSeriesStatsUtil; + +import javax.management.openmbean.CompositeData; + +/** + * Persistence Cache Statistics. + */ +public class PersistentCacheStats extends AnnotatedStandardMBean implements PersistentCacheStatsMBean { + + private static final String HITS = "HITS"; + private static final String REQUESTS = "REQUESTS"; + private static final String LOAD_TIME = "LOAD_TIME"; + private static final String LOAD_EXCEPTIONS = "LOAD_EXCEPTIONS"; + private static final String PUT_ONE = "CACHE_PUT"; + private static final String BROADCAST_RECV = "BROADCAST_RECV"; + private static final String INVALIDATE_ONE = "INVALIDATE_ONE"; + private static final String INVALIDATE_ALL = "INVALIDATE_ALL"; + + private final StatisticsProvider statisticsProvider; + private final String cacheName; + + private final MeterStats hitMeter; + private final TimeSeries hitRateHistory; + + private final MeterStats requestMeter; + private final TimeSeries requestRateHistory; + + private final MeterStats loadExceptionMeter; + private final TimeSeries loadExceptionRateHistory; + + private final TimerStats loadTimer; + private final TimeSeries loadRateHistory; + + private final MeterStats putMeter; + private final TimeSeries putRateHistory; + + private final MeterStats broadcastRecvMeter; + private final TimeSeries broadcastRecvRateHistory; + + private final MeterStats invalidateOneMeter; + private final TimeSeries invalidateOneRateHistory; + + private final MeterStats invalidateAllMeter; + private final TimeSeries invalidateAllRateHistory; + + private final TimeSeries hitPercentageHistory; + + public PersistentCacheStats(CacheType cacheType, StatisticsProvider statisticsProvider) { + super(PersistentCacheStatsMBean.class); + + if (statisticsProvider == null) { + this.statisticsProvider = StatisticsProvider.NOOP; + } else { + this.statisticsProvider = statisticsProvider; + } + + // Configure cache name + cacheName = "PersistentCache.NodeCache." + cacheType.name().toLowerCase(); + + // Fetch stats and time series + String statName; + + statName = getStatName(HITS, cacheName); + hitMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + hitRateHistory = getTimeSeries(statName); + + statName = getStatName(REQUESTS, cacheName); + requestMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + requestRateHistory = getTimeSeries(statName); + hitPercentageHistory = new PercentageTimeSeries(hitRateHistory, requestRateHistory); + + statName = getStatName(LOAD_TIME, cacheName); + loadTimer = statisticsProvider.getTimer(statName, StatsOptions.DEFAULT); + loadRateHistory = getTimeSeries(statName); + + statName = getStatName(LOAD_EXCEPTIONS, cacheName); + loadExceptionMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + loadExceptionRateHistory = getTimeSeries(statName); + + statName = getStatName(PUT_ONE, cacheName); + putMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + putRateHistory = getTimeSeries(statName); + + statName = getStatName(BROADCAST_RECV, cacheName); + broadcastRecvMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + broadcastRecvRateHistory = getTimeSeries(statName); + + statName = getStatName(INVALIDATE_ONE, cacheName); + invalidateOneMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + invalidateOneRateHistory = getTimeSeries(statName); + + statName = getStatName(INVALIDATE_ALL, cacheName); + invalidateAllMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT); + invalidateAllRateHistory = getTimeSeries(statName); + } + + //~--------------------------------------< stats update methods + + public void markHit() { + hitMeter.mark(); + } + + public void markRequest() { + requestMeter.mark(); + } + + public void markException() { + loadExceptionMeter.mark(); + } + + public void markPut() { + putMeter.mark(); + } + + public void markRecvBroadcast() { + broadcastRecvMeter.mark(); + } + + public void markInvalidateOne() { + invalidateOneMeter.mark(); + } + + public void markInvalidateAll() { + invalidateAllMeter.mark(); + } + + public TimerStats.Context startLoaderTimer() { + return this.loadTimer.time(); + } + + //~--------------------------------------< CacheStatsMbean + + @Override + public String getName() { + return cacheName; + } + + @Override + public long getRequestCount() { + return requestMeter.getCount(); + } + + @Override + public long getHitCount() { + return hitMeter.getCount(); + } + + @Override + public double getHitRate() { + if (requestMeter.getCount() == 0) { + return 0; + } + return (double)hitMeter.getCount() / requestMeter.getCount(); + } + + @Override + public long getMissCount() { + return requestMeter.getCount() - hitMeter.getCount(); + } + + @Override + public double getMissRate() { + if (requestMeter.getCount() == 0) { + return 0; + } + return (double)getMissCount() / requestMeter.getCount(); + } + + @Override + public long getLoadCount() { + return loadTimer.getCount(); + } + + @Override + public long getLoadSuccessCount() { + return loadTimer.getCount() - loadExceptionMeter.getCount(); + } + + @Override + public long getLoadExceptionCount() { + return loadExceptionMeter.getCount(); + } + + @Override + public double getLoadExceptionRate() { + if (requestMeter.getCount() == 0) { + return 0; + } + return (double)loadExceptionMeter.getCount() / loadTimer.getCount(); + } + + @Override + public CompositeData getRequestRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(requestRateHistory, "Persistent cache requests"); + } + + @Override + public CompositeData getHitRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(hitRateHistory, "Persistent cache hits"); + } + + @Override + public CompositeData getLoadRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(loadRateHistory, "Persistent cache loads/misses"); + } + + @Override + public CompositeData getLoadExceptionRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(loadExceptionRateHistory, "Persistent cache load exceptions"); + } + + @Override + public CompositeData getHitPercentageHistory() { + return TimeSeriesStatsUtil.asCompositeData(hitPercentageHistory, "Persistent cache hit percentage"); + } + + @Override + public CompositeData getPutRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(putRateHistory, "Persistent cache manual put entry"); + } + + @Override + public CompositeData getInvalidateOneRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(invalidateOneRateHistory, "Persistent cache invalidate one entry"); + } + + @Override + public CompositeData getInvalidateAllRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(invalidateAllRateHistory, "Persistent cache invalidate all entries"); + } + + @Override + public CompositeData getBroadcastRecvRateHistory() { + return TimeSeriesStatsUtil.asCompositeData(broadcastRecvRateHistory, "Persistent cache entries received from broadcast"); + } + + @Override + public String cacheInfoAsString() { + return Objects.toStringHelper("PersistentCacheStats") + .add("requestCount", getRequestCount()) + .add("hitCount", getHitCount()) + .add("hitRate", String.format("%1.2f", getHitRate())) + .add("missCount", getMissCount()) + .add("missRate", String.format("%1.2f", getMissRate())) + .add("loadCount", getLoadCount()) + .add("loadSuccessCount", getLoadSuccessCount()) + .add("loadExceptionCount", getLoadExceptionCount()) + .toString(); + } + + //~--------------------------------------< CacheStatsMbean - stats that are not (yet) available + @Override + public long getTotalLoadTime() { + return 0; + } + + @Override + public double getAverageLoadPenalty() { + return 0; + } + + @Override + public long getEvictionCount() { + return 0; + } + + @Override + public long getElementCount() { + return 0; + } + + @Override + public long getMaxTotalWeight() { + return 0; + } + + @Override + public long estimateCurrentWeight() { + return 0; + } + + @Override + public void resetStats() { + } + + + //~--------------------------------------< private helpers + + private static String getStatName(String meter, String cacheName) { + return cacheName + "." + meter; + } + + private TimeSeries getTimeSeries(String name) { + return statisticsProvider.getStats().getTimeSeries(name, true); + } + + /** + * TimeSeries that computes the hit ratio in percentages. ( hit/total * 100 ) + */ + private static class PercentageTimeSeries implements TimeSeries { + + private TimeSeries hit, total; + + PercentageTimeSeries(TimeSeries hit, TimeSeries total) { + this.hit = hit; + this.total = total; + } + + @Override + public long[] getValuePerSecond() { + return percentage(hit.getValuePerSecond(), total.getValuePerSecond()); + } + + @Override + public long[] getValuePerMinute() { + return percentage(hit.getValuePerMinute(), total.getValuePerMinute()); + } + + @Override + public long[] getValuePerHour() { + return percentage(hit.getValuePerHour(), total.getValuePerHour()); + } + + @Override + public long[] getValuePerWeek() { + return percentage(hit.getValuePerWeek(), total.getValuePerWeek()); + } + + @Override + public long getMissingValue() { + return 0; + } + + private long[] percentage(long[] a, long[] b) { + long[] result = new long[a.length]; + for (int i=0; i