mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1685 - Add support for MetaCounterMetrics and refactor DefaultServerCache to use them
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -79,4 +81,11 @@ public interface ServerCache {
|
||||
* @param reset if true the statistics are reset.
|
||||
*/
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
|
||||
/**
|
||||
* Visit the metrics for the cache.
|
||||
*/
|
||||
default void visit(MetricVisitor visitor) {
|
||||
// do nothing by default
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -9,13 +9,15 @@ public class ServerCacheConfig {
|
||||
|
||||
private final ServerCacheType type;
|
||||
private final String cacheKey;
|
||||
private final String shortName;
|
||||
private final ServerCacheOptions cacheOptions;
|
||||
private final CurrentTenantProvider tenantProvider;
|
||||
private final QueryCacheEntryValidate queryCacheEntryValidate;
|
||||
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
public ServerCacheConfig(ServerCacheType type, String cacheKey, String shortName, ServerCacheOptions cacheOptions, CurrentTenantProvider tenantProvider, QueryCacheEntryValidate queryCacheEntryValidate) {
|
||||
this.type = type;
|
||||
this.cacheKey = cacheKey;
|
||||
this.shortName = shortName;
|
||||
this.cacheOptions = cacheOptions;
|
||||
this.tenantProvider = tenantProvider;
|
||||
this.queryCacheEntryValidate = queryCacheEntryValidate;
|
||||
@@ -35,6 +37,13 @@ public class ServerCacheConfig {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the short name for the cache.
|
||||
*/
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tuning options.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.cache;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -7,6 +9,11 @@ import java.util.List;
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* Visit the metrics for all the server caches.
|
||||
*/
|
||||
void visitMetrics(MetricVisitor visitor);
|
||||
|
||||
/**
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
|
||||
+12
-96
@@ -21,23 +21,13 @@ public class ServerCacheStatistics {
|
||||
|
||||
protected long missCount;
|
||||
|
||||
protected long insertCount;
|
||||
|
||||
protected long updateCount;
|
||||
protected long putCount;
|
||||
|
||||
protected long removeCount;
|
||||
|
||||
protected long clearCount;
|
||||
|
||||
protected long evictionRunCount;
|
||||
|
||||
protected long evictionRunMicros;
|
||||
|
||||
protected long evictByIdle;
|
||||
|
||||
protected long evictByTTL;
|
||||
|
||||
protected long evictByLRU;
|
||||
protected long evictCount;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -49,15 +39,10 @@ public class ServerCacheStatistics {
|
||||
sb.append(" hitRatio:").append(getHitRatio());
|
||||
sb.append(" hit:").append(hitCount);
|
||||
sb.append(" miss:").append(missCount);
|
||||
sb.append(" insert:").append(insertCount);
|
||||
sb.append(" update:").append(updateCount);
|
||||
sb.append(" put:").append(putCount);
|
||||
sb.append(" remove:").append(removeCount);
|
||||
sb.append(" clear:").append(clearCount);
|
||||
sb.append(" evictByIdle:").append(evictByIdle);
|
||||
sb.append(" evictByTTL:").append(evictByTTL);
|
||||
sb.append(" evictByLRU:").append(evictByLRU);
|
||||
sb.append(" evictionRunCount:").append(evictionRunCount);
|
||||
sb.append(" evictionRunMicros:").append(evictionRunMicros);
|
||||
sb.append(" evict:").append(evictCount);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -153,29 +138,15 @@ public class ServerCacheStatistics {
|
||||
/**
|
||||
* Set the put insert count.
|
||||
*/
|
||||
public void setInsertCount(long insertCount) {
|
||||
this.insertCount = insertCount;
|
||||
public void setPutCount(long putCount) {
|
||||
this.putCount = putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put insert count.
|
||||
*/
|
||||
public long getInsertCount() {
|
||||
return insertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the put update count.
|
||||
*/
|
||||
public void setUpdateCount(long updateCount) {
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put update count.
|
||||
*/
|
||||
public long getUpdateCount() {
|
||||
return updateCount;
|
||||
public long getPutCount() {
|
||||
return putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,73 +177,18 @@ public class ServerCacheStatistics {
|
||||
return clearCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run count.
|
||||
*/
|
||||
public void setEvictionRunCount(long evictCount) {
|
||||
this.evictionRunCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run count.
|
||||
*/
|
||||
public long getEvictionRunCount() {
|
||||
return evictionRunCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run time in micros.
|
||||
*/
|
||||
public void setEvictionRunMicros(long evictionRunMicros) {
|
||||
this.evictionRunMicros = evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run time in micros.
|
||||
*/
|
||||
public long getEvictionRunMicros() {
|
||||
return evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to idle time.
|
||||
*/
|
||||
public void setEvictByIdle(long evictByIdle) {
|
||||
this.evictByIdle = evictByIdle;
|
||||
public void setEvictCount(long evictCount) {
|
||||
this.evictCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to idle time.
|
||||
*/
|
||||
public long getEvictByIdle() {
|
||||
return evictByIdle;
|
||||
public long getEvictCount() {
|
||||
return evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time to live.
|
||||
*/
|
||||
public void setEvictByTTL(long evictByTTL) {
|
||||
this.evictByTTL = evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time to live.
|
||||
*/
|
||||
public long getEvictByTTL() {
|
||||
return evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public void setEvictByLRU(long evictByLRU) {
|
||||
this.evictByLRU = evictByLRU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public long getEvictByLRU() {
|
||||
return evictByLRU;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ public abstract class AbstractMetricVisitor implements MetricVisitor {
|
||||
private final boolean reset;
|
||||
private final boolean collectTransactionMetrics;
|
||||
private final boolean collectQueryMetrics;
|
||||
private final boolean collectL2Metrics;
|
||||
|
||||
public AbstractMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics) {
|
||||
public AbstractMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
|
||||
this.reset = reset;
|
||||
this.collectTransactionMetrics = collectTransactionMetrics;
|
||||
this.collectQueryMetrics = collectQueryMetrics;
|
||||
this.collectL2Metrics = collectL2Metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -30,6 +32,11 @@ public abstract class AbstractMetricVisitor implements MetricVisitor {
|
||||
return collectQueryMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectL2Metrics() {
|
||||
return collectL2Metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStart() {
|
||||
// do nothing by default
|
||||
|
||||
@@ -11,19 +11,20 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
private final List<MetaTimedMetric> timed = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> dtoQuery = new ArrayList<>();
|
||||
private final List<MetaOrmQueryMetric> ormQuery = new ArrayList<>();
|
||||
private final List<MetaCountMetric> countMetrics = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Construct to reset and collect everything.
|
||||
*/
|
||||
public BasicMetricVisitor() {
|
||||
super(true, true, true);
|
||||
super(true, true, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct specifying reset and what to collect.
|
||||
*/
|
||||
public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics) {
|
||||
super(reset, collectTransactionMetrics, collectQueryMetrics);
|
||||
public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
|
||||
super(reset, collectTransactionMetrics, collectQueryMetrics, collectL2Metrics);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,6 +51,11 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
return ormQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaCountMetric> getCountMetrics() {
|
||||
return countMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTimed(MetaTimedMetric metric) {
|
||||
timed.add(metric);
|
||||
@@ -64,4 +70,9 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
ormQuery.add(metric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
countMetrics.add(metric);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
/**
|
||||
* Count metrics.
|
||||
*/
|
||||
public interface MetaCountMetric {
|
||||
|
||||
/**
|
||||
* Return the metric type.
|
||||
*/
|
||||
MetricType getMetricType();
|
||||
|
||||
/**
|
||||
* Return the metric name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the total count.
|
||||
*/
|
||||
long getCount();
|
||||
|
||||
}
|
||||
@@ -20,6 +20,11 @@ public interface MetricVisitor {
|
||||
*/
|
||||
boolean isCollectQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return true if we should visit the L2 cache metrics.
|
||||
*/
|
||||
boolean isCollectL2Metrics();
|
||||
|
||||
/**
|
||||
* Visit has started.
|
||||
*/
|
||||
@@ -40,6 +45,11 @@ public interface MetricVisitor {
|
||||
*/
|
||||
void visitOrmQuery(MetaOrmQueryMetric metric);
|
||||
|
||||
/**
|
||||
* Visit a Counter metric.
|
||||
*/
|
||||
void visitCount(MetaCountMetric metric);
|
||||
|
||||
/**
|
||||
* Visit has completed.
|
||||
*/
|
||||
|
||||
@@ -21,4 +21,10 @@ public interface ServerMetrics {
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
List<MetaOrmQueryMetric> getOrmQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the Counter metrics.
|
||||
*/
|
||||
List<MetaCountMetric> getCountMetrics();
|
||||
|
||||
}
|
||||
|
||||
@@ -7,12 +7,35 @@ import java.util.Comparator;
|
||||
*/
|
||||
public class SortMetric {
|
||||
|
||||
public static final Comparator<MetaCountMetric> COUNT_NAME = new CountName();
|
||||
|
||||
public static final Comparator<MetaTimedMetric> NAME = new Name();
|
||||
public static final Comparator<MetaTimedMetric> COUNT = new Count();
|
||||
public static final Comparator<MetaTimedMetric> TOTAL = new Total();
|
||||
public static final Comparator<MetaTimedMetric> MEAN = new Mean();
|
||||
public static final Comparator<MetaTimedMetric> MAX = new Max();
|
||||
|
||||
private static int stringCompare(String name, String name2) {
|
||||
if (name == null) {
|
||||
return name2 == null ? 0 : -1;
|
||||
}
|
||||
if (name2 == null) {
|
||||
return 1;
|
||||
}
|
||||
return name.compareTo(name2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort MetaCountMetric's by name.
|
||||
*/
|
||||
public static class CountName implements Comparator<MetaCountMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaCountMetric o1, MetaCountMetric o2) {
|
||||
return stringCompare(o1.getName(), o2.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by name.
|
||||
*/
|
||||
@@ -20,16 +43,7 @@ public class SortMetric {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
String name = o1.getName();
|
||||
String name2 = o2.getName();
|
||||
if (name == null) {
|
||||
return name2 == null ? 0 : -1;
|
||||
}
|
||||
if (name2 == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int i = name.compareTo(name2);
|
||||
int i = stringCompare(o1.getName(), o2.getName());
|
||||
return i != 0 ? i : Long.compare(o1.getCount(), o2.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
/**
|
||||
* Metric for timed events like transaction execution times.
|
||||
*/
|
||||
public interface CountMetric {
|
||||
|
||||
/**
|
||||
* Add to the counter.
|
||||
*/
|
||||
void add(long micros);
|
||||
|
||||
/**
|
||||
* Increment the counter by 1.
|
||||
*/
|
||||
void increment();
|
||||
|
||||
/**
|
||||
* Return the count value.
|
||||
*/
|
||||
long get(boolean reset);
|
||||
|
||||
/**
|
||||
* Return true if there are no metrics collected since the last collection.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Reset the statistics.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Visit non empty metrics.
|
||||
*/
|
||||
void visit(MetricVisitor visitor);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
|
||||
public interface CountMetricStats extends MetaCountMetric {
|
||||
}
|
||||
@@ -25,6 +25,11 @@ public interface MetricFactory {
|
||||
*/
|
||||
TimedMetric createTimedMetric(MetricType metricType, String name);
|
||||
|
||||
/**
|
||||
* Create a counter metric.
|
||||
*/
|
||||
CountMetric createCountMetric(MetricType metricType, String name);
|
||||
|
||||
/**
|
||||
* Create a Timed metric.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.cache;
|
||||
import io.ebean.cache.ServerCache;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.cache.ServerCacheRegion;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -20,6 +21,11 @@ public class DefaultCacheAdapter implements ServerCacheManager {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMetrics(MetricVisitor visitor) {
|
||||
cacheManager.visitMetrics(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocalL2Caching() {
|
||||
return cacheManager.isLocalL2Caching();
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.ebean.cache.ServerCacheFactory;
|
||||
import io.ebean.cache.ServerCacheOptions;
|
||||
import io.ebean.cache.ServerCacheType;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -46,32 +47,50 @@ class DefaultCacheHolder {
|
||||
this.queryCacheEntryValidate = builder.getQueryCacheEntryValidate();
|
||||
}
|
||||
|
||||
ServerCache getCache(Class<?> beanType, String cacheKey, ServerCacheType type) {
|
||||
|
||||
return getCacheInternal(beanType, cacheKey, type);
|
||||
void visitMetrics(MetricVisitor visitor) {
|
||||
for (ServerCache serverCache : allCaches.values()) {
|
||||
serverCache.visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
private String key(String cacheKey, ServerCacheType type) {
|
||||
return cacheKey + type.code();
|
||||
ServerCache getCache(Class<?> beanType, ServerCacheType type) {
|
||||
return getCacheInternal(beanType, type, null);
|
||||
}
|
||||
|
||||
ServerCache getCache(Class<?> beanType, String collectionProperty) {
|
||||
return getCacheInternal(beanType, ServerCacheType.COLLECTION_IDS, collectionProperty);
|
||||
}
|
||||
|
||||
private String key(String beanName, ServerCacheType type) {
|
||||
return beanName + type.code();
|
||||
}
|
||||
|
||||
private String key(String beanName, String collectionProperty, ServerCacheType type) {
|
||||
if (collectionProperty != null) {
|
||||
return beanName + "." + collectionProperty + type.code();
|
||||
} else {
|
||||
return beanName + type.code();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache for a given bean type.
|
||||
*/
|
||||
private ServerCache getCacheInternal(Class<?> beanType, String cacheKey, ServerCacheType type) {
|
||||
private ServerCache getCacheInternal(Class<?> beanType, ServerCacheType type, String collectionProperty) {
|
||||
|
||||
String fullKey = key(cacheKey, type);
|
||||
return allCaches.computeIfAbsent(fullKey, s -> createCache(beanType, type, fullKey));
|
||||
String shortName = key(beanType.getSimpleName(), collectionProperty, type);
|
||||
String fullKey = key(beanType.getName(), collectionProperty, type);
|
||||
return allCaches.computeIfAbsent(fullKey, s -> createCache(beanType, type, fullKey, shortName));
|
||||
}
|
||||
|
||||
private ServerCache createCache(Class<?> beanType, ServerCacheType type, String key) {
|
||||
private ServerCache createCache(Class<?> beanType, ServerCacheType type, String key, String shortName) {
|
||||
ServerCacheOptions options = getCacheOptions(beanType, type);
|
||||
if (type == ServerCacheType.COLLECTION_IDS) {
|
||||
synchronized (this) {
|
||||
collectIdCaches.computeIfAbsent(beanType.getName(), s -> new ConcurrentSkipListSet<>()).add(key);
|
||||
}
|
||||
}
|
||||
return cacheFactory.createCache(new ServerCacheConfig(type, key, options, tenantProvider, queryCacheEntryValidate));
|
||||
return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, tenantProvider, queryCacheEntryValidate));
|
||||
}
|
||||
|
||||
void clearAll() {
|
||||
@@ -107,12 +126,10 @@ class DefaultCacheHolder {
|
||||
* Return the cache options for a given bean type.
|
||||
*/
|
||||
ServerCacheOptions getCacheOptions(Class<?> beanType, ServerCacheType type) {
|
||||
switch (type) {
|
||||
case QUERY:
|
||||
return getQueryOptions(beanType);
|
||||
default:
|
||||
return getBeanOptions(beanType);
|
||||
if (type == ServerCacheType.QUERY) {
|
||||
return getQueryOptions(beanType);
|
||||
}
|
||||
return getBeanOptions(beanType);
|
||||
}
|
||||
|
||||
private ServerCacheOptions getQueryOptions(Class<?> cls) {
|
||||
|
||||
@@ -4,6 +4,9 @@ import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.cache.ServerCache;
|
||||
import io.ebean.cache.ServerCacheStatistics;
|
||||
import io.ebean.cache.TenantAwareKey;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.CountMetric;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -14,7 +17,8 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
import static io.ebean.meta.MetricType.L2;
|
||||
|
||||
/**
|
||||
* The default cache implementation.
|
||||
@@ -37,39 +41,45 @@ public class DefaultServerCache implements ServerCache {
|
||||
*/
|
||||
protected final Map<Object, CacheEntry> map;
|
||||
|
||||
protected final LongAdder missCount = new LongAdder();
|
||||
protected final LongAdder hitCount = new LongAdder();
|
||||
protected final LongAdder insertCount = new LongAdder();
|
||||
protected final LongAdder updateCount = new LongAdder();
|
||||
protected final LongAdder removeCount = new LongAdder();
|
||||
protected final LongAdder clearCount = new LongAdder();
|
||||
|
||||
protected final LongAdder evictByIdle = new LongAdder();
|
||||
protected final LongAdder evictByTTL = new LongAdder();
|
||||
protected final LongAdder evictByLRU = new LongAdder();
|
||||
protected final LongAdder evictCount = new LongAdder();
|
||||
protected final LongAdder evictMicros = new LongAdder();
|
||||
protected final CountMetric hitCount;
|
||||
protected final CountMetric missCount;
|
||||
protected final CountMetric putCount;
|
||||
protected final CountMetric removeCount;
|
||||
protected final CountMetric clearCount;
|
||||
protected final CountMetric evictCount;
|
||||
|
||||
protected final String name;
|
||||
protected final String shortName;
|
||||
|
||||
protected int maxSize;
|
||||
private int maxSize;
|
||||
|
||||
protected final int trimFrequency;
|
||||
private final int trimFrequency;
|
||||
|
||||
protected int maxIdleSecs;
|
||||
private int maxIdleSecs;
|
||||
|
||||
protected int maxSecsToLive;
|
||||
private int maxSecsToLive;
|
||||
|
||||
protected TenantAwareKey tenantAwareKey;
|
||||
private TenantAwareKey tenantAwareKey;
|
||||
|
||||
public DefaultServerCache(DefaultServerCacheConfig config) {
|
||||
this.name = config.getName();
|
||||
this.shortName = config.getShortName();
|
||||
this.map = config.getMap();
|
||||
this.maxSize = config.getMaxSize();
|
||||
this.tenantAwareKey = new TenantAwareKey(config.getTenantProvider());
|
||||
this.maxIdleSecs = config.getMaxIdleSecs();
|
||||
this.maxSecsToLive = config.getMaxSecsToLive();
|
||||
this.trimFrequency = config.determineTrimFrequency();
|
||||
|
||||
MetricFactory factory = MetricFactory.get();
|
||||
|
||||
String prefix = "l2n.";
|
||||
this.hitCount = factory.createCountMetric(L2, prefix + shortName + ".hit");
|
||||
this.missCount = factory.createCountMetric(L2, prefix + shortName + ".miss");
|
||||
this.putCount = factory.createCountMetric(L2, prefix + shortName + ".put");
|
||||
this.removeCount = factory.createCountMetric(L2, prefix + shortName + ".remove");
|
||||
this.clearCount = factory.createCountMetric(L2, prefix + shortName + ".clear");
|
||||
this.evictCount = factory.createCountMetric(L2, prefix + shortName + ".evict");
|
||||
}
|
||||
|
||||
public void periodicTrim(BackgroundExecutor executor) {
|
||||
@@ -81,6 +91,16 @@ public class DefaultServerCache implements ServerCache {
|
||||
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MetricVisitor visitor) {
|
||||
hitCount.visit(visitor);
|
||||
missCount.visit(visitor);
|
||||
putCount.visit(visitor);
|
||||
removeCount.visit(visitor);
|
||||
clearCount.visit(visitor);
|
||||
evictCount.visit(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerCacheStatistics getStatistics(boolean reset) {
|
||||
|
||||
@@ -88,38 +108,13 @@ public class DefaultServerCache implements ServerCache {
|
||||
cacheStats.setCacheName(name);
|
||||
cacheStats.setMaxSize(maxSize);
|
||||
|
||||
// these counters won't necessarily be consistent with
|
||||
// respect to each other as activity can occur while
|
||||
// they are being calculated here but they should be good enough
|
||||
// and we don't want to reduce concurrent use to make them consistent
|
||||
long clear = reset ? clearCount.sumThenReset() : clearCount.sum();
|
||||
long remove = reset ? removeCount.sumThenReset() : removeCount.sum();
|
||||
long update = reset ? updateCount.sumThenReset() : updateCount.sum();
|
||||
long insert = reset ? insertCount.sumThenReset() : insertCount.sum();
|
||||
long miss = reset ? missCount.sumThenReset() : missCount.sum();
|
||||
long hit = reset ? hitCount.sumThenReset() : hitCount.sum();
|
||||
|
||||
long evict = reset ? evictCount.sumThenReset() : evictCount.sum();
|
||||
long evictTime = reset ? evictMicros.sumThenReset() : evictMicros.sum();
|
||||
long evictIdle = reset ? evictByIdle.sumThenReset() : evictByIdle.sum();
|
||||
long evictTTL = reset ? evictByTTL.sumThenReset() : evictByTTL.sum();
|
||||
long evictLRU = reset ? evictByLRU.sumThenReset() : evictByLRU.sum();
|
||||
|
||||
int size = size();
|
||||
|
||||
cacheStats.setSize(size);
|
||||
cacheStats.setHitCount(hit);
|
||||
cacheStats.setMissCount(miss);
|
||||
cacheStats.setInsertCount(insert);
|
||||
cacheStats.setUpdateCount(update);
|
||||
cacheStats.setRemoveCount(remove);
|
||||
cacheStats.setClearCount(clear);
|
||||
|
||||
cacheStats.setEvictionRunCount(evict);
|
||||
cacheStats.setEvictionRunMicros(evictTime);
|
||||
cacheStats.setEvictByIdle(evictIdle);
|
||||
cacheStats.setEvictByTTL(evictTTL);
|
||||
cacheStats.setEvictByLRU(evictLRU);
|
||||
cacheStats.setSize(size());
|
||||
cacheStats.setHitCount(hitCount.get(reset));
|
||||
cacheStats.setMissCount(missCount.get(reset));
|
||||
cacheStats.setPutCount(putCount.get(reset));
|
||||
cacheStats.setRemoveCount(removeCount.get(reset));
|
||||
cacheStats.setClearCount(clearCount.get(reset));
|
||||
cacheStats.setEvictCount(evictCount.get(reset));
|
||||
|
||||
return cacheStats;
|
||||
}
|
||||
@@ -127,8 +122,8 @@ public class DefaultServerCache implements ServerCache {
|
||||
@Override
|
||||
public int getHitRatio() {
|
||||
|
||||
long mc = missCount.sum();
|
||||
long hc = hitCount.sum();
|
||||
long mc = missCount.get(false);
|
||||
long hc = hitCount.get(false);
|
||||
|
||||
long totalCount = hc + mc;
|
||||
if (totalCount == 0) {
|
||||
@@ -145,6 +140,10 @@ public class DefaultServerCache implements ServerCache {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
@@ -171,10 +170,7 @@ public class DefaultServerCache implements ServerCache {
|
||||
if (entry == null) {
|
||||
missCount.increment();
|
||||
return null;
|
||||
|
||||
} else {
|
||||
// Important that hitCount.increment() MUST be low latency under concurrent
|
||||
// use hence must use LongAdder or better here
|
||||
hitCount.increment();
|
||||
return unwrapEntry(entry);
|
||||
}
|
||||
@@ -204,14 +200,9 @@ public class DefaultServerCache implements ServerCache {
|
||||
*/
|
||||
@Override
|
||||
public void put(Object id, Object value) {
|
||||
|
||||
Object key = key(id);
|
||||
CacheEntry entry = map.put(key, new CacheEntry(key, value));
|
||||
if (entry == null) {
|
||||
insertCount.increment();
|
||||
} else {
|
||||
updateCount.increment();
|
||||
}
|
||||
map.put(key, new CacheEntry(key, value));
|
||||
putCount.increment();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,7 +210,6 @@ public class DefaultServerCache implements ServerCache {
|
||||
*/
|
||||
@Override
|
||||
public void remove(Object id) {
|
||||
|
||||
CacheEntry entry = map.remove(key(id));
|
||||
if (entry != null) {
|
||||
removeCount.increment();
|
||||
@@ -269,7 +259,7 @@ public class DefaultServerCache implements ServerCache {
|
||||
|
||||
List<CacheEntry> activeList = new ArrayList<>(map.size());
|
||||
|
||||
long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs);
|
||||
long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs);
|
||||
long ttlExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxSecsToLive);
|
||||
|
||||
Iterator<CacheEntry> it = map.values().iterator();
|
||||
@@ -301,17 +291,12 @@ public class DefaultServerCache implements ServerCache {
|
||||
}
|
||||
}
|
||||
|
||||
long exeNanos = System.nanoTime() - startNanos;
|
||||
long exeMicros = TimeUnit.MICROSECONDS.convert(exeNanos, TimeUnit.NANOSECONDS);
|
||||
|
||||
// increment the eviction statistics
|
||||
evictMicros.add(exeMicros);
|
||||
evictCount.increment();
|
||||
evictByIdle.add(trimmedByIdle);
|
||||
evictByTTL.add(trimmedByTTL);
|
||||
evictByLRU.add(trimmedByLRU);
|
||||
evictCount.add(trimmedByIdle);
|
||||
evictCount.add(trimmedByTTL);
|
||||
evictCount.add(trimmedByLRU);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
|
||||
logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}]"
|
||||
, name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ public class DefaultServerCacheConfig {
|
||||
return config.getCacheKey();
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
return config.getShortName();
|
||||
}
|
||||
|
||||
public Map<Object, DefaultServerCache.CacheEntry> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
+13
-11
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.cache;
|
||||
import io.ebean.cache.ServerCache;
|
||||
import io.ebean.cache.ServerCacheRegion;
|
||||
import io.ebean.cache.ServerCacheType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebeaninternal.api.SpiCacheRegion;
|
||||
import io.ebeaninternal.server.cluster.ClusterManager;
|
||||
import io.ebeaninternal.server.deploy.DCacheRegion;
|
||||
@@ -99,6 +100,11 @@ public class DefaultServerCacheManager implements SpiCacheManager {
|
||||
return regionMap.computeIfAbsent(region, DCacheRegion::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMetrics(MetricVisitor visitor) {
|
||||
cacheHolder.visitMetrics(visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all caches.
|
||||
*/
|
||||
@@ -117,7 +123,7 @@ public class DefaultServerCacheManager implements SpiCacheManager {
|
||||
|
||||
@Override
|
||||
public void clear(Class<?> beanType) {
|
||||
cacheHolder.clear(name(beanType));
|
||||
cacheHolder.clear(beanType.getName());
|
||||
if (clusterManager != null) {
|
||||
clusterManager.cacheClear(serverName, beanType);
|
||||
}
|
||||
@@ -125,17 +131,17 @@ public class DefaultServerCacheManager implements SpiCacheManager {
|
||||
|
||||
@Override
|
||||
public void clearLocal(Class<?> beanType) {
|
||||
cacheHolder.clear(name(beanType));
|
||||
cacheHolder.clear(beanType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName) {
|
||||
return cacheHolder.getCache(beanType, name(beanType) + "." + propertyName, ServerCacheType.COLLECTION_IDS);
|
||||
public ServerCache getCollectionIdsCache(Class<?> beanType, String collectionProperty) {
|
||||
return cacheHolder.getCache(beanType, collectionProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerCache getNaturalKeyCache(Class<?> beanType) {
|
||||
return cacheHolder.getCache(beanType, name(beanType), ServerCacheType.NATURAL_KEY);
|
||||
return cacheHolder.getCache(beanType, ServerCacheType.NATURAL_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +149,7 @@ public class DefaultServerCacheManager implements SpiCacheManager {
|
||||
*/
|
||||
@Override
|
||||
public ServerCache getQueryCache(Class<?> beanType) {
|
||||
return cacheHolder.getCache(beanType, name(beanType), ServerCacheType.QUERY);
|
||||
return cacheHolder.getCache(beanType, ServerCacheType.QUERY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,11 +157,7 @@ public class DefaultServerCacheManager implements SpiCacheManager {
|
||||
*/
|
||||
@Override
|
||||
public ServerCache getBeanCache(Class<?> beanType) {
|
||||
return cacheHolder.getCache(beanType, name(beanType), ServerCacheType.BEAN);
|
||||
}
|
||||
|
||||
private String name(Class<?> beanType) {
|
||||
return beanType.getName();
|
||||
return cacheHolder.getCache(beanType, ServerCacheType.BEAN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.cache;
|
||||
|
||||
import io.ebean.cache.ServerCache;
|
||||
import io.ebean.cache.ServerCacheRegion;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebeaninternal.api.SpiCacheRegion;
|
||||
|
||||
import java.util.List;
|
||||
@@ -11,6 +12,11 @@ import java.util.List;
|
||||
*/
|
||||
public interface SpiCacheManager {
|
||||
|
||||
/**
|
||||
* Visit and collect the metrics.
|
||||
*/
|
||||
void visitMetrics(MetricVisitor visitor);
|
||||
|
||||
/**
|
||||
* Return true if the L2 caching is local.
|
||||
* <p>
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.meta.AbstractMetricVisitor;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaOrmQueryNode;
|
||||
@@ -71,7 +72,7 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
private static class ResetVisitor extends AbstractMetricVisitor {
|
||||
|
||||
ResetVisitor() {
|
||||
super(true, true, true);
|
||||
super(true, true, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,6 +89,11 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2389,6 +2389,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
if (visitor.isCollectTransactionMetrics()) {
|
||||
transactionManager.visitMetrics(visitor);
|
||||
}
|
||||
if (visitor.isCollectL2Metrics()) {
|
||||
serverCacheManager.visitMetrics(visitor);
|
||||
}
|
||||
if (visitor.isCollectQueryMetrics()) {
|
||||
beanDescriptorManager.visitMetrics(visitor);
|
||||
dtoBeanManager.visitMetrics(visitor);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
@@ -83,6 +84,15 @@ class DumpMetrics {
|
||||
log(metric);
|
||||
}
|
||||
|
||||
List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
|
||||
if (!countMetrics.isEmpty()) {
|
||||
out("\n-- Counters --");
|
||||
countMetrics.sort(SortMetric.COUNT_NAME);
|
||||
for (MetaCountMetric metric : countMetrics) {
|
||||
logCount(metric);
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
|
||||
if (!ormQueryMetrics.isEmpty()) {
|
||||
out("\n-- ORM queries --");
|
||||
@@ -102,6 +112,14 @@ class DumpMetrics {
|
||||
}
|
||||
}
|
||||
|
||||
private void logCount(MetaCountMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(padNameTimed(metric.getName())).append(" ");
|
||||
sb.append(" count:").append(pad(metric.getCount()));
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
private void out(String sb) {
|
||||
System.out.println(sb);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.CountMetric;
|
||||
import io.ebean.metric.CountMetricStats;
|
||||
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* Used to collect counter metrics.
|
||||
*/
|
||||
class DCountMetric implements CountMetric {
|
||||
|
||||
private final MetricType metricType;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final LongAdder count = new LongAdder();
|
||||
|
||||
DCountMetric(MetricType metricType, String name) {
|
||||
this.metricType = metricType;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value. Usually the value is Time or Bytes etc.
|
||||
*/
|
||||
@Override
|
||||
public void add(long value) {
|
||||
count.add(value);
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
count.increment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return count.sum() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
count.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long get(boolean reset) {
|
||||
return reset ? count.sumThenReset() : count.sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MetricVisitor visitor) {
|
||||
|
||||
long val = visitor.isReset() ? count.sumThenReset() : count.sum();
|
||||
if (val > 0) {
|
||||
visitor.visitCount(new DCountMetricStats(metricType, name, val));
|
||||
}
|
||||
}
|
||||
|
||||
private static class DCountMetricStats implements CountMetricStats {
|
||||
|
||||
private final MetricType metricType;
|
||||
private final String name;
|
||||
private final long count;
|
||||
|
||||
private DCountMetricStats(MetricType metricType, String name, long count) {
|
||||
this.metricType = metricType;
|
||||
this.name = name;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricType getMetricType() {
|
||||
return metricType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.metric.CountMetric;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.QueryPlanMetric;
|
||||
import io.ebean.metric.TimedMetric;
|
||||
@@ -22,6 +23,11 @@ public class DMetricFactory implements MetricFactory {
|
||||
return new DTimedMetric(metricType, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CountMetric createCountMetric(MetricType metricType, String name) {
|
||||
return new DCountMetric(metricType, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, ProfileLocation profileLocation, String sql) {
|
||||
return new DQueryPlanMetric(new DQueryPlanMeta(type, label, profileLocation, sql), new DTimedMetric(metricType, label));
|
||||
|
||||
Reference in New Issue
Block a user