From 49babef495fac35161555e5d03d281c617650470 Mon Sep 17 00:00:00 2001
From: rbygrave
Date: Tue, 30 Jun 2015 00:56:11 +1200
Subject: [PATCH] #314 - ServerCache API - change from int to long for
ServerCacheStatistics (hitCount, missCount) and ServerCache remove
putIfAbsent() method
---
.../avaje/ebean/annotation/CacheTuning.java | 8 +
.../com/avaje/ebean/cache/ServerCache.java | 6 -
.../avaje/ebean/cache/ServerCacheOptions.java | 29 +-
.../ebean/cache/ServerCacheStatistics.java | 198 ++++-
.../server/cache/DefaultServerCache.java | 695 +++++++++---------
.../server/core/DefaultContainer.java | 11 +-
.../server/cache/DefaultServerCacheTest.java | 59 ++
.../com/avaje/tests/cache/TestCacheBasic.java | 2 +-
8 files changed, 631 insertions(+), 377 deletions(-)
create mode 100644 src/test/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheTest.java
diff --git a/src/main/java/com/avaje/ebean/annotation/CacheTuning.java b/src/main/java/com/avaje/ebean/annotation/CacheTuning.java
index 4b5924e30..85b400936 100644
--- a/src/main/java/com/avaje/ebean/annotation/CacheTuning.java
+++ b/src/main/java/com/avaje/ebean/annotation/CacheTuning.java
@@ -44,4 +44,12 @@ public @interface CacheTuning {
*
*/
int maxSecsToLive() default 0;
+
+ /**
+ * The frequency (in seconds) that cache trimming should occur.
+ *
+ * This is a hint for cache implementations that use background cache trimming.
+ *
+ */
+ int trimFrequency() default 0;
}
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCache.java b/src/main/java/com/avaje/ebean/cache/ServerCache.java
index 00a105166..195446c20 100644
--- a/src/main/java/com/avaje/ebean/cache/ServerCache.java
+++ b/src/main/java/com/avaje/ebean/cache/ServerCache.java
@@ -48,12 +48,6 @@ public interface ServerCache {
*/
Object put(Object id, Object value);
- /**
- * Put the value in the cache but only if a matching value is not already in
- * the cache.
- */
- Object putIfAbsent(Object id, Object value);
-
/**
* Remove a entry from the cache given its id.
*/
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java b/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java
index a26be30b7..21b0d1c65 100644
--- a/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java
+++ b/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java
@@ -10,6 +10,7 @@ public class ServerCacheOptions {
private int maxSize;
private int maxIdleSecs;
private int maxSecsToLive;
+ private int trimFrequency;
/**
* Construct with no set options.
@@ -25,15 +26,17 @@ public class ServerCacheOptions {
this.maxSize = cacheTuning.maxSize();
this.maxIdleSecs = cacheTuning.maxIdleSecs();
this.maxSecsToLive = cacheTuning.maxSecsToLive();
+ this.trimFrequency = cacheTuning.trimFrequency();
}
/**
* Create merging default options with the deployment specified ones.
*/
- public ServerCacheOptions(ServerCacheOptions d) {
- this.maxSize = d.getMaxSize();
- this.maxIdleSecs = d.getMaxIdleSecs();
- this.maxSecsToLive = d.getMaxIdleSecs();
+ public ServerCacheOptions(ServerCacheOptions defaults) {
+ this.maxSize = defaults.getMaxSize();
+ this.maxIdleSecs = defaults.getMaxIdleSecs();
+ this.maxSecsToLive = defaults.getMaxIdleSecs();
+ this.trimFrequency = defaults.getTrimFrequency();
}
/**
@@ -50,6 +53,9 @@ public class ServerCacheOptions {
if (maxSecsToLive == 0) {
maxSecsToLive = defaults.getMaxSecsToLive();
}
+ if (trimFrequency == 0) {
+ trimFrequency = defaults.getTrimFrequency();
+ }
}
/**
@@ -61,7 +67,7 @@ public class ServerCacheOptions {
copy.maxSize = maxSize;
copy.maxIdleSecs = maxIdleSecs;
copy.maxSecsToLive = maxSecsToLive;
-
+ copy.trimFrequency = trimFrequency;
return copy;
}
@@ -107,4 +113,17 @@ public class ServerCacheOptions {
this.maxSecsToLive = maxSecsToLive;
}
+ /**
+ * Return the trim frequency in seconds.
+ */
+ public int getTrimFrequency() {
+ return trimFrequency;
+ }
+
+ /**
+ * Set the trim frequency in seconds.
+ */
+ public void setTrimFrequency(int trimFrequency) {
+ this.trimFrequency = trimFrequency;
+ }
}
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java b/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java
index 969418917..ed048cd5e 100644
--- a/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java
+++ b/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java
@@ -5,9 +5,9 @@ package com.avaje.ebean.cache;
*
* These can be monitored to review the effectiveness of a particular cache.
*
- *
- * @author rbygrave
- *
+ *
+ * Depending on the cache implementation not all the statistics may be collected.
+ *
*/
public class ServerCacheStatistics {
@@ -17,21 +17,63 @@ public class ServerCacheStatistics {
protected int size;
- protected int hitCount;
+ protected long hitCount;
- protected int missCount;
+ protected long missCount;
+
+ protected long insertCount;
+
+ protected long updateCount;
+
+ protected long removeCount;
+
+ protected long clearCount;
+
+ protected long evictionRunCount;
+
+ protected long evictionRunMicros;
+
+ protected long evictByIdle;
+
+ protected long evictByTTL;
+
+ protected long evictByLRU;
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(cacheName);
+ sb.append(" maxSize:").append(maxSize);
sb.append(" size:").append(size);
sb.append(" hitRatio:").append(getHitRatio());
- sb.append(" hitCount:").append(hitCount);
- sb.append(" missCount:").append(missCount);
- sb.append(" maxSize:").append(maxSize);
+ sb.append(" hit:").append(hitCount);
+ sb.append(" miss:").append(missCount);
+ sb.append(" insert:").append(insertCount);
+ sb.append(" update:").append(updateCount);
+ 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);
return sb.toString();
}
+ /**
+ * Returns an int from 0 to 100 (percentage) for the hit ratio.
+ *
+ * A hit ratio of 100 means every get request against the cache hits an entry.
+ *
+ */
+ public int getHitRatio() {
+ long totalCount = hitCount + missCount;
+ if (totalCount == 0) {
+ return 0;
+ } else {
+ return (int)(hitCount * 100 / totalCount);
+ }
+ }
+
/**
* Return the name of the cache.
*/
@@ -49,28 +91,28 @@ public class ServerCacheStatistics {
/**
* Return the hit count. The number of successful gets.
*/
- public int getHitCount() {
+ public long getHitCount() {
return hitCount;
}
/**
* Set the hit count.
*/
- public void setHitCount(int hitCount) {
+ public void setHitCount(long hitCount) {
this.hitCount = hitCount;
}
/**
* Return the miss count. The number of gets that returned null.
*/
- public int getMissCount() {
+ public long getMissCount() {
return missCount;
}
/**
* Set the miss count.
*/
- public void setMissCount(int missCount) {
+ public void setMissCount(long missCount) {
this.missCount = missCount;
}
@@ -107,18 +149,128 @@ public class ServerCacheStatistics {
}
/**
- * Returns an int from 0 to 100 (percentage) for the hit ratio.
- *
- * A hit ratio of 100 means every get request against the cache hits an entry.
- *
+ * Set the put insert count.
*/
- public int getHitRatio() {
- int totalCount = hitCount + missCount;
- if (totalCount == 0) {
- return 0;
- } else {
- return hitCount * 100 / totalCount;
- }
+ public void setInsertCount(long insertCount) {
+ this.insertCount = insertCount;
}
+ /**
+ * 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;
+ }
+
+ /**
+ * Set the remove count.
+ */
+ public void setRemoveCount(long removeCount) {
+ this.removeCount = removeCount;
+ }
+
+ /**
+ * Return the remove count.
+ */
+ public long getRemoveCount() {
+ return removeCount;
+ }
+
+ /**
+ * Set the clear count.
+ */
+ public void setClearCount(long clearCount) {
+ this.clearCount = clearCount;
+ }
+
+ /**
+ * Return the clear count.
+ */
+ public long getClearCount() {
+ 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;
+ }
+
+ /**
+ * Return the count of entries evicted due to idle time.
+ */
+ public long getEvictByIdle() {
+ return evictByIdle;
+ }
+
+ /**
+ * 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;
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java
index f14dcec37..851933071 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java
@@ -1,22 +1,18 @@
package com.avaje.ebeaninternal.server.cache;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.cache.ServerCache;
import com.avaje.ebean.cache.ServerCacheOptions;
import com.avaje.ebean.cache.ServerCacheStatistics;
+import com.avaje.ebeaninternal.server.util.LongAdder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.Serializable;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
/**
* The default cache implementation.
@@ -27,375 +23,392 @@ import org.slf4j.LoggerFactory;
*/
public class DefaultServerCache implements ServerCache {
- private static final Logger logger = LoggerFactory.getLogger(DefaultServerCache.class);
+ protected static final Logger logger = LoggerFactory.getLogger(DefaultServerCache.class);
- private static final CacheEntryComparator comparator = new CacheEntryComparator();
-
- private final ConcurrentHashMap