Honor expireAfterWrite in the H2CacheImpl

The H2CacheImpl didn't honor the expireAfterWrite. This had an effect
that persisted entries never expired. For example, the web_sessions
cache entries didn't expire after their maxAge was reached.

Change-Id: I3a7c754ee05fe9ac92d96652db4b862bb597eba1
Signed-off-by: Saša Živkov <sasa.zivkov@sap.com>
Signed-off-by: Adrian Görler <adrian.goerler@sap.com>
This commit is contained in:
Saša Živkov
2014-08-06 14:54:33 +02:00
committed by Adrian Görler
parent c07d0d0f04
commit 98adfd5c53
2 changed files with 31 additions and 7 deletions

View File

@@ -161,7 +161,8 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
return defaultFactory.build(def);
}
SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit);
SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit,
def.expireAfterWrite(TimeUnit.SECONDS));
H2CacheImpl<K, V> cache = new H2CacheImpl<K, V>(
executor, store, def.keyType(),
(Cache<K, ValueHolder<V>>) defaultFactory.create(def, true).build());
@@ -182,7 +183,8 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
return defaultFactory.build(def, loader);
}
SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit);
SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit,
def.expireAfterWrite(TimeUnit.SECONDS));
Cache<K, ValueHolder<V>> mem = (Cache<K, ValueHolder<V>>)
defaultFactory.create(def, true)
.build((CacheLoader<K, V>) new H2CacheImpl.Loader<K, V>(
@@ -209,9 +211,11 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
private <V, K> SqlStore<K, V> newSqlStore(
String name,
TypeLiteral<K> keyType,
long maxSize) {
long maxSize,
Long expireAfterWrite) {
File db = new File(cacheDir, name).getAbsoluteFile();
String url = "jdbc:h2:" + db.toURI().toString();
return new SqlStore<>(url, keyType, maxSize);
return new SqlStore<>(url, keyType, maxSize,
expireAfterWrite == null ? 0 : expireAfterWrite.longValue());
}
}

View File

@@ -313,16 +313,19 @@ public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
private final String url;
private final KeyType<K> keyType;
private final long maxSize;
private final long expireAfterWrite;
private final BlockingQueue<SqlHandle> handles;
private final AtomicLong hitCount = new AtomicLong();
private final AtomicLong missCount = new AtomicLong();
private volatile BloomFilter<K> bloomFilter;
private int estimatedSize;
SqlStore(String jdbcUrl, TypeLiteral<K> keyType, long maxSize) {
SqlStore(String jdbcUrl, TypeLiteral<K> keyType, long maxSize,
long expireAfterWrite) {
this.url = jdbcUrl;
this.keyType = KeyType.create(keyType);
this.maxSize = maxSize;
this.expireAfterWrite = expireAfterWrite;
int cores = Runtime.getRuntime().availableProcessors();
int keep = Math.min(cores, 16);
@@ -408,7 +411,7 @@ public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
try {
c = acquire();
if (c.get == null) {
c.get = c.conn.prepareStatement("SELECT v FROM data WHERE k=?");
c.get = c.conn.prepareStatement("SELECT v, created FROM data WHERE k=?");
}
keyType.set(c.get, 1, key);
ResultSet r = c.get.executeQuery();
@@ -418,6 +421,13 @@ public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
return null;
}
Timestamp created = r.getTimestamp(2);
if (expired(created)) {
invalidate(key);
missCount.incrementAndGet();
return null;
}
@SuppressWarnings("unchecked")
V val = (V) r.getObject(1);
ValueHolder<V> h = new ValueHolder<>(val);
@@ -438,6 +448,14 @@ public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
}
}
private boolean expired(Timestamp created) {
if (expireAfterWrite == 0) {
return false;
}
long age = TimeUtil.nowMs() - created.getTime();
return 1000 * expireAfterWrite < age;
}
private void touch(SqlHandle c, K key) throws SQLException {
if (c.touch == null) {
c.touch =c.conn.prepareStatement("UPDATE data SET accessed=? WHERE k=?");
@@ -552,12 +570,14 @@ public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
r = s.executeQuery("SELECT"
+ " k"
+ ",OCTET_LENGTH(k) + OCTET_LENGTH(v)"
+ ",created"
+ " FROM data"
+ " ORDER BY accessed");
try {
while (maxSize < used && r.next()) {
K key = keyType.get(r, 1);
if (mem.getIfPresent(key) != null) {
Timestamp created = r.getTimestamp(3);
if (mem.getIfPresent(key) != null && !expired(created)) {
touch(c, key);
} else {
invalidate(c, key);