Skip to content

Commit 76a633e

Browse files
Nico Verweradamretter
authored andcommitted
[feature] add expireAfterWrite to cache configuration
1 parent 50393f8 commit 76a633e

File tree

5 files changed

+54
-4
lines changed

5 files changed

+54
-4
lines changed

extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/Cache.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public Cache(final CacheConfig config) {
4848

4949
config.getMaximumSize().map(cacheBuilder::maximumSize);
5050
config.getExpireAfterAccess().map(ms -> cacheBuilder.expireAfterAccess(ms, TimeUnit.MILLISECONDS));
51+
config.getExpireAfterWrite().map(ms -> cacheBuilder.expireAfterWrite(ms, TimeUnit.MILLISECONDS));
5152

5253
this.store = cacheBuilder.build();
5354
}

extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheConfig.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,19 @@ public class CacheConfig {
3333
private final Optional<Permissions> permissions;
3434
private final Optional<Long> maximumSize;
3535
private final Optional<Long> expireAfterAccess;
36+
private final Optional<Long> expireAfterWrite;
3637

3738
/**
3839
* @param permissions Any restrictions on cache operations
3940
* @param maximumSize The maximimum number of entries in the cache
4041
* @param expireAfterAccess The time in milliseconds after the entry is last accessed, that it should expire
42+
* @param expireAfterWrite The time in milliseconds after the entry is last modified, that it should expire
4143
*/
42-
public CacheConfig(final Optional<Permissions> permissions, final Optional<Long> maximumSize, final Optional<Long> expireAfterAccess) {
44+
public CacheConfig(final Optional<Permissions> permissions, final Optional<Long> maximumSize, final Optional<Long> expireAfterAccess, final Optional<Long> expireAfterWrite) {
4345
this.permissions = permissions;
4446
this.maximumSize = maximumSize;
4547
this.expireAfterAccess = expireAfterAccess;
48+
this.expireAfterWrite = expireAfterWrite;
4649
}
4750

4851
public Optional<Permissions> getPermissions() {
@@ -57,6 +60,10 @@ public Optional<Long> getExpireAfterAccess() {
5760
return expireAfterAccess;
5861
}
5962

63+
public Optional<Long> getExpireAfterWrite() {
64+
return expireAfterWrite;
65+
}
66+
6067
public static class Permissions {
6168
private final Optional<String> putGroup;
6269
private final Optional<String> getGroup;

extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheFunctions.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public class CacheFunctions extends BasicFunction {
6262
"Explicitly create a cache with a specific configuration",
6363
returns(Type.BOOLEAN, "true if the cache was created, false if the cache already exists"),
6464
FS_PARAM_CACHE_NAME,
65-
param("config", Type.MAP, "A map with configuration for the cache. At present cache LRU and permission groups may be specified, for operations on the cache. `maximumSize` is optional and specifies the maximum number of entries. `expireAfterAccess` is optional and specifies the expiry period for infrequently accessed entries (in milliseconds). If a permission group is not specified for an operation, then permissions are not checked for that operation. Should have the format: map { \"maximumSize\": 1000, \"expireAfterAccess\": 120000, \"permissions\": map { \"put-group\": \"group1\", \"get-group\": \"group2\", \"remove-group\": \"group3\", \"clear-group\": \"group4\"} }")
65+
param("config", Type.MAP, "A map with configuration for the cache. At present cache LRU and permission groups may be specified, for operations on the cache. `maximumSize` is optional and specifies the maximum number of entries. `expireAfterAccess` is optional and specifies the expiry period for infrequently accessed entries (in milliseconds). `expireAfterWrite` is optional and specifies the expiry period after the entry's creation, or the most recent replacement of its value (in milliseconds). If a permission group is not specified for an operation, then permissions are not checked for that operation. Should have the format: map { \"maximumSize\": 1000, \"expireAfterAccess\": 120000, \"expireAfterWrite\": 240000, \"permissions\": map { \"put-group\": \"group1\", \"get-group\": \"group2\", \"remove-group\": \"group3\", \"clear-group\": \"group4\"} }")
6666
);
6767

6868
private static final String FS_NAMES_NAME = "names";
@@ -277,7 +277,16 @@ private CacheConfig extractCacheConfig(final MapType configMap) throws XPathExce
277277
expireAfterAccess = Optional.empty();
278278
}
279279

280-
return new CacheConfig(permissions, maximumSize, expireAfterAccess);
280+
final Sequence expireAfterWriteSeq = configMap.get(new StringValue(this, "expireAfterWrite"));
281+
final Optional<Long> expireAfterWrite;
282+
if(expireAfterWriteSeq != null && expireAfterWriteSeq.getItemCount() == 1) {
283+
final long l = expireAfterWriteSeq.itemAt(0).toJavaObject(Long.class);
284+
expireAfterWrite = Optional.of(l);
285+
} else {
286+
expireAfterWrite = Optional.empty();
287+
}
288+
289+
return new CacheConfig(permissions, maximumSize, expireAfterAccess, expireAfterWrite);
281290
}
282291

283292
private Optional<String> getStringValue(final String key, final AbstractMapType map) {

extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheModule.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,15 @@ public class CacheModule extends AbstractInternalModule {
7171
private static final String PARAM_NAME_ENABLE_LAZY_CREATION = "enableLazyCreation";
7272
private static final String PARAM_NAME_LAZY_MAXIMUM_SIZE = "lazy.maximumSize";
7373
private static final String PARAM_NAME_LAZY_EXPIRE_AFTER_ACCESS = "lazy.expireAfterAccess";
74+
private static final String PARAM_NAME_LAZY_EXPIRE_AFTER_WRITE = "lazy.expireAfterWrite";
7475
private static final String PARAM_NAME_LAZY_PUT_GROUP = "lazy.putGroup";
7576
private static final String PARAM_NAME_LAZY_GET_GROUP = "lazy.getGroup";
7677
private static final String PARAM_NAME_LAZY_REMOVE_GROUP = "lazy.removeGroup";
7778
private static final String PARAM_NAME_LAZY_CLEAR_GROUP = "lazy.clearGroup";
7879

7980
private static final long DEFAULT_LAZY_MAXIMUM_SIZE = 128; // 128 items
8081
private static final long DEFAULT_LAZY_EXPIRE_AFTER_ACCESS = 1000 * 60 * 5; // 5 minutes
82+
private static final long DEFAULT_LAZY_EXPIRE_AFTER_WRITE = 1000 * 60 * 5; // 5 minutes
8183

8284
static final Map<String, Cache> caches = new ConcurrentHashMap<>();
8385

@@ -167,8 +169,18 @@ private static Optional<CacheConfig> parseParameters(final Map<String, List<?>>
167169
}
168170
});
169171

172+
final Optional<Long> expireAfterWrite = getFirstString(parameters, PARAM_NAME_LAZY_EXPIRE_AFTER_WRITE)
173+
.map(s -> {
174+
try {
175+
return Long.parseLong(s);
176+
} catch (final NumberFormatException e) {
177+
LOG.warn("Unable to set {} to: {}. Using default: ", PARAM_NAME_LAZY_EXPIRE_AFTER_WRITE, s, DEFAULT_LAZY_EXPIRE_AFTER_WRITE);
178+
return DEFAULT_LAZY_EXPIRE_AFTER_ACCESS;
179+
}
180+
});
181+
170182

171-
return Optional.of(new CacheConfig(permissions, maximumSize, expireAfterAccess));
183+
return Optional.of(new CacheConfig(permissions, maximumSize, expireAfterAccess, expireAfterWrite));
172184
}
173185

174186
private static Optional<String> getFirstString(final Map<String, List<?>> parameters, final String paramName) {

extensions/modules/cache/src/test/xquery/modules/cache/cache.xqm

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ declare variable $c:maximumSize := 5;
3333
declare variable $c:maximumSize-options := map { "maximumSize": $c:maximumSize };
3434
declare variable $c:expireAfterAccess := 1000;
3535
declare variable $c:expireAfterAccess-options := map { "expireAfterAccess": $c:expireAfterAccess };
36+
declare variable $c:expireAfterWrite := 1000;
37+
declare variable $c:expireAfterWrite-options := map { "expireAfterWrite": $c:expireAfterWrite };
3638

3739
declare function c:_create-simple() {
3840
cache:create($c:cache-name, $c:simple-options)
@@ -46,6 +48,10 @@ declare function c:_create-expireAfterAccess() {
4648
cache:create($c:cache-name, $c:expireAfterAccess-options)
4749
};
4850

51+
declare function c:_create-expireAfterWrite() {
52+
cache:create($c:cache-name, $c:expireAfterWrite-options)
53+
};
54+
4955
declare function c:_populate($size as xs:integer) {
5056
(1 to $size) ! cache:put($c:cache-name, "foo" || ., "bar" || .)
5157
};
@@ -171,6 +177,21 @@ function c:exercise-expireAfterAccess() {
171177
count(c:_keys())
172178
};
173179

180+
declare
181+
%test:assertEquals(0)
182+
function c:exercise-expireAfterWrite() {
183+
let $setup :=
184+
(
185+
c:_destroy(),
186+
c:_create-expireAfterWrite(),
187+
c:_populate(5),
188+
util:wait($c:expireAfterWrite * 1.1),
189+
c:_cleanup()
190+
)
191+
return
192+
count(c:_keys())
193+
};
194+
174195
declare
175196
%test:assertEquals("bar5")
176197
function c:get() {

0 commit comments

Comments
 (0)