This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 73fb6995cd GH-2330: Replace ExpiringMap with Cache API
73fb6995cd is described below
commit 73fb6995cd74ea3fddbaa81cd32b039da2791032
Author: Rob Vesse <[email protected]>
AuthorDate: Thu Mar 14 14:35:59 2024 +0000
GH-2330: Replace ExpiringMap with Cache API
Replaces the usage of the ExpiringMap API with Jena's existing Cache
API, this entails some related changes to the configuration portions of
the GeoSPARQL module.
---
.../apache/jena/atlas/lib/cache/CacheCaffeine.java | 7 +
.../github/galbiston/expiring_map/ExpiringMap.java | 350 ---------------
.../galbiston/expiring_map/ExpiringMap2.java | 46 --
.../galbiston/expiring_map/ExpiringMapCleaner.java | 98 -----
.../galbiston/expiring_map/ExpiringMaps.java | 28 --
.../galbiston/expiring_map/KeyTimestampPair.java | 106 -----
.../galbiston/expiring_map/MapDefaultValues.java | 35 --
.../geosparql/configuration/GeoSPARQLConfig.java | 40 +-
.../implementation/index/CacheConfiguration.java | 67 +++
.../implementation/index/GeometryLiteralIndex.java | 58 +--
.../index/GeometryTransformIndex.java | 41 +-
.../implementation/index/IndexConfiguration.java | 40 +-
.../implementation/index/QueryRewriteIndex.java | 73 +---
.../galbiston/expiring_map/ExpiringMapTest.java | 472 ---------------------
.../index/CacheConfigurationTest.java | 97 +++++
15 files changed, 226 insertions(+), 1332 deletions(-)
diff --git
a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheCaffeine.java
b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheCaffeine.java
index 73426e92f8..9f6721f5b7 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheCaffeine.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheCaffeine.java
@@ -131,5 +131,12 @@ final public class CacheCaffeine<K,V> implements Cache<K,
V>
public long size() {
return cache.estimatedSize() ;
}
+
+ /**
+ * Forces the cache to clean up stale entries
+ */
+ public void cleanUp() {
+ this.cache.cleanUp();
+ }
}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMap.java
b/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMap.java
deleted file mode 100644
index a64196c7d0..0000000000
---
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMap.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- * See the notice.md file distributed with this work for additional
- * information regarding copyright ownership.
- *
- * Licensed 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.jena.ext.io.github.galbiston.expiring_map;
-
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.*;
-
-import java.lang.invoke.MethodHandles;
-import java.util.Timer;
-import java.util.concurrent.ConcurrentHashMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Expiring Map for storage of entries which expire if unused for a period of
- * time.
- * <br>Size of map, duration until expiry and frequency of cleaning can all be
- * controlled.
- *
- * @param <K> Key entry object.
- * @param <V> Value entry object.
- */
-public class ExpiringMap<K, V> extends ConcurrentHashMap<K, V> {
-
- private static final Logger LOGGER =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private String label;
- private boolean running;
- private boolean expiring;
- private long maxSize;
- private long expiryInterval;
- private long cleanerInterval;
- private long fullMapWarningInterval;
- private long fullMapWarning;
- private ExpiringMapCleaner mapCleaner;
- private Timer cleanerTimer;
-
- /**
- * Instance of Expiring Map that will not remove items and has no limit on
- * size.
- *
- * @param label Name of the map.
- */
- public ExpiringMap(String label) {
- this(label, UNLIMITED_MAP, UNLIMITED_EXPIRY, MAP_CLEANER_INTERVAL,
FULL_MAP_WARNING_INTERVAL);
- }
-
- /**
- * Instance of Expiring Map that will not remove items.
- *
- * @param label Name of the map.
- * @param maxSize Maximum size of the map when items will no longer be
added
- * or unlimited size (-1).
- */
- public ExpiringMap(String label, int maxSize) {
- this(label, maxSize, UNLIMITED_EXPIRY, MAP_CLEANER_INTERVAL,
FULL_MAP_WARNING_INTERVAL);
- }
-
- /**
- * Instance of Expiring Map that will remove items after a period of time
- * which have not been accessed.
- *
- * @param label Name of the map.
- * @param maxSize Maximum size of the map when items will no longer be
- * added. Unlimited size (-1) will still remove expired items.
- * @param expiryInterval Duration that items remain in map.
- */
- public ExpiringMap(String label, int maxSize, long expiryInterval) {
- this(label, maxSize, expiryInterval, MAP_CLEANER_INTERVAL,
FULL_MAP_WARNING_INTERVAL);
- }
-
- /**
- * Instance of Expiring Map that will remove items after a period of time
- * which have not been accessed.
- *
- * @param label Name of the map.
- * @param maxSize Maximum size of the map when items will no longer be
- * added. Unlimited size (-1) will still remove expired items.
- * @param expiryInterval Duration that items remain in map.
- * @param cleanerInterval Frequency that items are checked for removal from
- * map.
- */
- public ExpiringMap(String label, int maxSize, long expiryInterval, long
cleanerInterval) {
- this(label, maxSize, expiryInterval, cleanerInterval,
FULL_MAP_WARNING_INTERVAL);
- }
-
- /**
- * Instance of Expiring Map that will remove items after a period of time
- * which have not been accessed.
- *
- * @param label Name of the map.
- * @param maxSize Maximum size of the map when items will no longer be
- * added. Unlimited size (-1) will still remove expired items.
- * @param expiryInterval Duration that items remain in map.
- * @param cleanerInterval Frequency that items are checked for removal from
- * map.
- * @param fullMapWarningInterval Full map warning frequency.
- */
- public ExpiringMap(String label, int maxSize, long expiryInterval, long
cleanerInterval, long fullMapWarningInterval) {
- super(maxSize > UNLIMITED_MAP ? maxSize : UNLIMITED_INITIAL_CAPACITY);
- this.label = label;
- setMaxSize(maxSize);
- this.running = false;
- this.expiring = false;
- this.cleanerTimer = null;
- this.mapCleaner = null;
- setCleanerInterval(cleanerInterval);
- setExpiryInterval(expiryInterval); //Can set expiryInterval,
mapCleaner and expiring.
- this.fullMapWarningInterval = fullMapWarningInterval;
- this.fullMapWarning = System.currentTimeMillis();
-
- }
-
- @Override
- public V put(K key, V value) {
- if (super.mappingCount() < maxSize) {
- mapCleaner.put(key);
- return super.put(key, value);
- } else {
- long currentSystemTime = System.currentTimeMillis();
- long difference = currentSystemTime - fullMapWarning;
- if (difference > fullMapWarningInterval) {
- fullMapWarning = currentSystemTime;
- LOGGER.warn("{} Map Full: {} - Warning suppressed for {}ms",
label, maxSize, fullMapWarningInterval);
- }
- }
-
- return null;
- }
-
- @Override
- public boolean containsKey(Object key) {
- boolean isContained = super.containsKey(key);
- if (isContained) {
- mapCleaner.refresh(key);
- }
- return isContained;
- }
-
- @Override
- public V get(Object key) {
- V value = super.get(key);
- if (value != null) {
- mapCleaner.refresh(key);
- }
- return value;
- }
-
- /**
- * Clear the map.
- */
- @Override
- public void clear() {
- super.clear();
- mapCleaner.clear();
- }
-
- /**
- *
- * @return Maximum number of items in the map.
- */
- public long getMaxSize() {
- return maxSize;
- }
-
- /**
- * Maximum number of items in the map.<br>
- * Capacity will not be reduced.
- *
- * @param maxSize
- */
- public final void setMaxSize(long maxSize) {
- this.maxSize = maxSize > UNLIMITED_MAP ? maxSize : Long.MAX_VALUE;
- }
-
- /**
- *
- * @return Frequency that items are checked for removal from map.
- */
- public long getCleanerInterval() {
- return cleanerInterval;
- }
-
- /**
- * Frequency that items are checked for removal from map.
- *
- * @param cleanerInterval Milliseconds
- */
- public final void setCleanerInterval(long cleanerInterval) {
-
- boolean isChanged = applyCleanerInterval(cleanerInterval);
-
- //Reset the expiry if running and changed.
- if (running && isChanged) {
- startExpiry();
- }
- }
-
- private boolean applyCleanerInterval(long cleanerInterval) {
- long originalCleanerInterval = this.cleanerInterval;
- if (MINIMUM_MAP_CLEANER_INTERVAL < cleanerInterval) {
- this.cleanerInterval = cleanerInterval;
- } else {
- LOGGER.warn("Cleaner Interval: {} less than minimum: {}. Setting
to minimum.", cleanerInterval, MINIMUM_MAP_CLEANER_INTERVAL);
- this.cleanerInterval = MINIMUM_MAP_CLEANER_INTERVAL;
- }
- return originalCleanerInterval != this.cleanerInterval;
- }
-
- /**
- *
- * @return Duration that items remain in map.
- */
- public long getExpiryInterval() {
- return expiryInterval;
- }
-
- /**
- * Duration that items remain in map.<br>
- * Items will not be removed until next cleaner interval.
- *
- * @param expiryInterval Milliseconds
- */
- public final void setExpiryInterval(long expiryInterval) {
-
- this.expiring = expiryInterval > UNLIMITED_EXPIRY;
-
- long minimum_interval = cleanerInterval + 1;
- if (expiryInterval < minimum_interval) {
- if (this.expiring) {
- //Ensure that the expiry interval is greater than the cleaner
interval and warn that value has been changed.
- LOGGER.warn("Expiry Interval: {} cannot be less than Cleaner
Interval: {}. Setting to Minimum Interval: {}", expiryInterval,
cleanerInterval, minimum_interval);
- }
- this.expiryInterval = minimum_interval;
- } else {
- this.expiryInterval = expiryInterval;
- }
-
- if (this.mapCleaner == null) {
- this.mapCleaner = new ExpiringMapCleaner(this, expiryInterval);
- } else {
- this.mapCleaner.setExpiryInterval(this.expiryInterval);
- }
- }
-
- /**
- *
- * @return Delay between warnings the map is full.
- */
- public long getFullMapWarningInterval() {
- return fullMapWarningInterval;
- }
-
- /**
- * Delay between warnings the map is full.
- *
- * @param fullMapWarningInterval Milliseconds
- */
- public void setFullMapWarningInterval(long fullMapWarningInterval) {
- this.fullMapWarningInterval = fullMapWarningInterval;
- }
-
- /**
- *
- * @return Label of the Expiring Map.
- */
- public String getLabel() {
- return label;
- }
-
- /**
- * Set the label of the Expiring Map.
- *
- * @param label
- */
- public void setLabel(String label) {
- this.label = label;
- }
-
- /**
- * Start expiring items from the map.
- */
- public void startExpiry() {
- startExpiry(cleanerInterval);
- }
-
- /**
- * Start expiring items from the map with adjusted cleaner interval.
- *
- * @param cleanerInterval Milliseconds between checks for expiry.
- */
- public void startExpiry(long cleanerInterval) {
- stopExpiry();
- if (expiring) {
- applyCleanerInterval(cleanerInterval);
- cleanerTimer = new Timer(label, true);
- mapCleaner = new ExpiringMapCleaner(mapCleaner);
- cleanerTimer.scheduleAtFixedRate(mapCleaner, this.cleanerInterval,
this.cleanerInterval);
- }
-
- running = true;
- }
-
- /**
- * Stop expiring items from the map.
- */
- public void stopExpiry() {
- if (cleanerTimer != null) {
- cleanerTimer.cancel();
- cleanerTimer = null;
- }
-
- running = false;
- }
-
- /**
- *
- * @return True if the Expiring Map is running.
- */
- public boolean isRunning() {
- return running;
- }
-
- /**
- *
- * @return True if the Expiring Map will remove items.
- */
- public boolean isExpiring() {
- return expiring;
- }
-
- @Override
- public String toString() {
- return "ExpiringMap{" + "label=" + label + ", running=" + running + ",
expiring=" + expiring + ", maxSize=" + maxSize + ", expiryInterval=" +
expiryInterval + ", cleanerInterval=" + cleanerInterval + ",
fullMapWarningInterval=" + fullMapWarningInterval + ", fullMapWarning=" +
fullMapWarning + ", mapCleaner=" + mapCleaner + ", cleanerTimer=" +
cleanerTimer + '}';
- }
-
-}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMap2.java
b/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMap2.java
deleted file mode 100644
index b119f5f00a..0000000000
---
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMap2.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.jena.ext.io.github.galbiston.expiring_map;
-
-import java.util.AbstractMap;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-
-public class ExpiringMap2<K,V> extends AbstractMap<K,V> {
-
- private Cache<K,V> cache;
-
- ExpiringMap2(int size) {
- @SuppressWarnings("unchecked")
- Caffeine<K,V> builder = (Caffeine<K,V>)Caffeine.newBuilder()
- .maximumSize(size)
- .executor(c->c.run())
- .expireAfterAccess(5000, TimeUnit.MILLISECONDS)
- ;
- Cache<K,V> cache = builder.build();
- }
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- return null;
- }
-}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapCleaner.java
b/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapCleaner.java
deleted file mode 100644
index 7b1c5e967d..0000000000
---
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapCleaner.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- * See the notice.md file distributed with this work for additional
- * information regarding copyright ownership.
- *
- * Licensed 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.jena.ext.io.github.galbiston.expiring_map;
-
-import java.util.Collections;
-import java.util.SortedSet;
-import java.util.TimerTask;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- *
- *
- */
-public class ExpiringMapCleaner extends TimerTask {
-
- //private static final Logger LOGGER =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private final SortedSet<KeyTimestampPair> tracking =
Collections.synchronizedSortedSet(new TreeSet<>());
- private final ConcurrentHashMap<Object, Long> refresh = new
ConcurrentHashMap<>();
- private final ExpiringMap<? , ? > map;
- private long expiryInterval;
-
- public ExpiringMapCleaner(ExpiringMap<?,?> map, long expiryInterval) {
- this.map = map;
- this.expiryInterval = expiryInterval;
- }
-
- public ExpiringMapCleaner(ExpiringMapCleaner mapCleaner) {
- this.map = mapCleaner.map;
- this.expiryInterval = mapCleaner.expiryInterval;
- tracking.addAll(mapCleaner.tracking);
- refresh.putAll(mapCleaner.refresh);
- }
-
- @Override
- public void run() {
-
- //LOGGER.info("Run Start - Tracker: {}, Refresh: {}, Map: {}",
tracking.size(), refresh.size(), map.size());
- long thresholdTimestamp = System.currentTimeMillis() - expiryInterval;
- boolean isEarlier = true;
- while (isEarlier) {
- if (tracking.isEmpty()) {
- return;
- }
-
- KeyTimestampPair current = tracking.first();
- isEarlier = current.isEarlier(thresholdTimestamp);
- if (isEarlier) {
- Object key = current.getKey();
- tracking.remove(current);
- if (refresh.containsKey(key)) {
- //Check whether the refresh is still valid.
- Long timestamp = refresh.get(key);
- if (thresholdTimestamp < timestamp) {
- tracking.add(new KeyTimestampPair(key, timestamp));
- }
- refresh.remove(key);
- } else {
- map.remove(key);
- }
-
- }
- }
- //LOGGER.info("Run End - Tracker: {}, Refresh: {}, Map: {}",
tracking.size(), refresh.size(), map.size());
- }
-
- public synchronized void refresh(Object key) {
- refresh.put(key, System.currentTimeMillis());
- }
-
- public synchronized void put(Object key) {
- tracking.add(new KeyTimestampPair(key, System.currentTimeMillis()));
- }
-
- public synchronized void setExpiryInterval(long expiryInterval) {
- this.expiryInterval = expiryInterval;
- }
-
- public synchronized void clear() {
- tracking.clear();
- }
-
-}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMaps.java
b/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMaps.java
deleted file mode 100644
index 69a07668d6..0000000000
---
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMaps.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.jena.ext.io.github.galbiston.expiring_map;
-
-public class ExpiringMaps {
-
- public static <K,V> ExpiringMap<K,V> newExpiringMap(String label, int
maxSize, long expiryInterval) {
- return new ExpiringMap<>(label, maxSize, expiryInterval);
- }
-
-
-}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/KeyTimestampPair.java
b/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/KeyTimestampPair.java
deleted file mode 100644
index 13e8ae3e8d..0000000000
---
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/KeyTimestampPair.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- * See the notice.md file distributed with this work for additional
- * information regarding copyright ownership.
- *
- * Licensed 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.jena.ext.io.github.galbiston.expiring_map;
-
-import java.util.Objects;
-
-/**
- *
- *
- */
-public class KeyTimestampPair implements Comparable<KeyTimestampPair> {
-
- private final Object key;
- private long timestamp;
-
- public KeyTimestampPair(Object key, long timestamp) {
- this.key = key;
- this.timestamp = timestamp;
- }
-
- public boolean hasKey(Object key) {
- return this.key.equals(key);
- }
-
- public Object getKey() {
- return key;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
- public boolean isEarlier(long timestamp) {
- return this.timestamp < timestamp;
- }
-
- public void setTimestamp(long timestamp) {
- this.timestamp = timestamp;
- }
-
- @Override
- public int compareTo(KeyTimestampPair o) {
-
- if (o == null) {
- throw new NullPointerException();
- }
-
- if (timestamp < o.timestamp) {
- return -1;
- } else if (timestamp > o.timestamp) {
- return 1;
- } else {
- if (key.equals(o.key)) {
- return 0;
- } else {
- return -1;
- }
- }
- }
-
- @Override
- public int hashCode() {
- int hash = 7;
- hash = 67 * hash + Objects.hashCode(this.key);
- hash = 67 * hash + (int) (this.timestamp ^ (this.timestamp >>> 32));
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final KeyTimestampPair other = (KeyTimestampPair) obj;
- if (this.timestamp != other.timestamp) {
- return false;
- }
- return Objects.equals(this.key, other.key);
- }
-
- @Override
- public String toString() {
- return "KeyTimestampPair{" + "key=" + key + ", timestamp=" + timestamp
+ '}';
- }
-}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/MapDefaultValues.java
b/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/MapDefaultValues.java
deleted file mode 100644
index a91695db0d..0000000000
---
a/jena-geosparql/src/main/java/org/apache/jena/ext/io/github/galbiston/expiring_map/MapDefaultValues.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- * See the notice.md file distributed with this work for additional
- * information regarding copyright ownership.
- *
- * Licensed 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.jena.ext.io.github.galbiston.expiring_map;
-
-/**
- *
- *
- */
-public interface MapDefaultValues {
-
- public static final int UNLIMITED_MAP = -1;
- public static final long UNLIMITED_EXPIRY = 0;
-
- public static final int NO_MAP = 0;
- public static final long MAP_EXPIRY_INTERVAL = 5000l;
- public static final long MAP_CLEANER_INTERVAL = 1000l;
- public static final long FULL_MAP_WARNING_INTERVAL = 30000l;
- public static final long MINIMUM_MAP_CLEANER_INTERVAL = 100l;
- public static final int UNLIMITED_INITIAL_CAPACITY = 50000;
-}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/configuration/GeoSPARQLConfig.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/configuration/GeoSPARQLConfig.java
index 5d966059f8..759e5f11f2 100644
---
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/configuration/GeoSPARQLConfig.java
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/configuration/GeoSPARQLConfig.java
@@ -22,6 +22,8 @@ import java.io.File;
import org.apache.jena.geosparql.geof.topological.RelateFF;
import org.apache.jena.geosparql.implementation.datatype.GeometryDatatype;
import org.apache.jena.geosparql.implementation.function_registration.*;
+import org.apache.jena.geosparql.implementation.index.GeometryLiteralIndex;
+import org.apache.jena.geosparql.implementation.index.GeometryTransformIndex;
import org.apache.jena.geosparql.implementation.index.IndexConfiguration;
import
org.apache.jena.geosparql.implementation.index.IndexConfiguration.IndexOption;
import org.apache.jena.geosparql.implementation.index.QueryRewriteIndex;
@@ -92,38 +94,6 @@ public class GeoSPARQLConfig {
setup(IndexOption.MEMORY, isQueryRewriteEnabled);
}
- /**
- * Initialise all GeoSPARQL property and filter functions with memory
- * indexing.
- * <br>Use this for in-memory indexing GeoSPARQL setup and to control the
- * index sizes. Expiry is defaulted to 5,000 milliseconds.
- * <br>This does not affect the use of Spatial Indexes for Datasets.
- *
- * @param geometryLiteralIndex
- * @param geometryTransformIndex
- * @param queryRewriteIndex
- */
- public static final void setupMemoryIndexSize(Integer
geometryLiteralIndex, Integer geometryTransformIndex, Integer
queryRewriteIndex) {
- setup(IndexOption.MEMORY, true);
- IndexConfiguration.setIndexMaxSize(geometryLiteralIndex,
geometryTransformIndex, queryRewriteIndex);
- }
-
- /**
- * Initialise all GeoSPARQL property and filter functions with memory
- * indexing.
- * <br>Use this for in-memory indexing GeoSPARQL setup and to control the
- * index expiry rate (milliseconds). Size is defaulted to unlimited.
- * <br>This does not affect the use of Spatial Indexes for Datasets.
- *
- * @param geometryLiteralIndex
- * @param geometryTransformIndex
- * @param queryRewriteIndex
- */
- public static final void setupMemoryIndexExpiry(Long geometryLiteralIndex,
Long geometryTransformIndex, Long queryRewriteIndex) {
- setup(IndexOption.MEMORY, true);
- IndexConfiguration.setIndexExpiry(geometryLiteralIndex,
geometryTransformIndex, queryRewriteIndex);
- }
-
/**
* Initialise all GeoSPARQL property and filter functions with memory
* indexing.
@@ -142,8 +112,10 @@ public class GeoSPARQLConfig {
*/
public static final void setupMemoryIndex(Integer geometryLiteralIndex,
Integer geometryTransformIndex, Integer queryRewriteIndex, Long
geometryLiteralIndexExpiry, Long geometryTransformIndexExpiry, Long
queryRewriteIndexExpiry, Boolean isQueryRewriteEnabled) {
setup(IndexOption.MEMORY, isQueryRewriteEnabled);
- IndexConfiguration.setIndexMaxSize(geometryLiteralIndex,
geometryTransformIndex, queryRewriteIndex);
- IndexConfiguration.setIndexExpiry(geometryLiteralIndexExpiry,
geometryTransformIndexExpiry, queryRewriteIndexExpiry);
+ GeometryLiteralIndex.reset(geometryLiteralIndex,
geometryLiteralIndexExpiry);
+ GeometryTransformIndex.reset(geometryTransformIndex,
geometryTransformIndexExpiry);
+ QueryRewriteIndex.setMaxSize(queryRewriteIndex);
+ QueryRewriteIndex.setExpiry(queryRewriteIndexExpiry);
}
/**
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/CacheConfiguration.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/CacheConfiguration.java
new file mode 100644
index 0000000000..9ebd64400a
--- /dev/null
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/CacheConfiguration.java
@@ -0,0 +1,67 @@
+/*
+ * 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.jena.geosparql.implementation.index;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.apache.jena.atlas.lib.Cache;
+import org.apache.jena.atlas.lib.CacheFactory;
+import org.apache.jena.atlas.lib.cache.CacheCaffeine;
+
+import java.time.Duration;
+
+/**
+ *
+ */
+public class CacheConfiguration {
+
+ public static final int UNLIMITED_MAP = -1;
+ public static final int NO_MAP = 0;
+ public static final long MAP_EXPIRY_INTERVAL = 5000l;
+ public static final int UNLIMITED_INITIAL_CAPACITY = 50000;
+
+ private CacheConfiguration() {
+ }
+
+ /**
+ * Creates a cache
+ *
+ * @param maxSize Maximum size, use {@value #NO_MAP} to disable
caching, or {@value #UNLIMITED_MAP} to
+ * have an unlimited cache size
+ * @param expiryMilliseconds Expiry duration in milliseconds, entries
which have not been accessed within this
+ * interval will be automatically expired from
the cache
+ */
+ public static <K, V> Cache<K, V> create(long maxSize, long
expiryMilliseconds) {
+ if (maxSize == NO_MAP) {
+ return CacheFactory.createNullCache();
+ }
+
+ long actualMaxSize = maxSize > UNLIMITED_MAP ? maxSize :
Long.MAX_VALUE;
+ int actualInitialCapacity =
+ actualMaxSize == Long.MAX_VALUE ? UNLIMITED_INITIAL_CAPACITY :
(int) actualMaxSize / 4;
+ return new CacheCaffeine<>(expiryMilliseconds > 0 ?
Caffeine.newBuilder()
+
.maximumSize(actualMaxSize)
+
.initialCapacity(actualInitialCapacity)
+
.expireAfterAccess(
+
Duration.ofMillis(expiryMilliseconds))
+ .build() :
+ Caffeine.newBuilder()
+ .maximumSize(actualMaxSize)
+
.initialCapacity(actualInitialCapacity)
+ .build());
+ }
+}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryLiteralIndex.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryLiteralIndex.java
index 05c72cd173..3d11f83012 100644
---
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryLiteralIndex.java
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryLiteralIndex.java
@@ -17,13 +17,10 @@
*/
package org.apache.jena.geosparql.implementation.index;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.MAP_EXPIRY_INTERVAL;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.UNLIMITED_MAP;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.MAP_EXPIRY_INTERVAL;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.UNLIMITED_MAP;
-import java.util.Map;
-
-import org.apache.jena.ext.io.github.galbiston.expiring_map.ExpiringMap;
-import org.apache.jena.ext.io.github.galbiston.expiring_map.ExpiringMaps;
+import org.apache.jena.atlas.lib.Cache;
import org.apache.jena.geosparql.implementation.GeometryWrapper;
import org.apache.jena.geosparql.implementation.datatype.GeometryDatatype;
@@ -34,10 +31,9 @@ import
org.apache.jena.geosparql.implementation.datatype.GeometryDatatype;
public class GeometryLiteralIndex {
private static boolean INDEX_ACTIVE = false;
- private static final String PRIMARY_INDEX_LABEL = "Primary Geometry
Literal Index";
- private static final String SECONDARY_INDEX_LABEL = "Secondary Geometry
Literal Index";
- private static ExpiringMap<String, GeometryWrapper> PRIMARY_INDEX =
ExpiringMaps.newExpiringMap(PRIMARY_INDEX_LABEL, UNLIMITED_MAP,
MAP_EXPIRY_INTERVAL);
- private static ExpiringMap<String, GeometryWrapper> SECONDARY_INDEX =
ExpiringMaps.newExpiringMap(SECONDARY_INDEX_LABEL, UNLIMITED_MAP,
MAP_EXPIRY_INTERVAL);
+ private static Cache<String, GeometryWrapper>
+ PRIMARY_INDEX = CacheConfiguration.create(UNLIMITED_MAP,
MAP_EXPIRY_INTERVAL);
+ private static Cache<String, GeometryWrapper> SECONDARY_INDEX =
CacheConfiguration.create(UNLIMITED_MAP, MAP_EXPIRY_INTERVAL);
public enum GeometryIndex {
PRIMARY, SECONDARY
@@ -57,15 +53,15 @@ public class GeometryLiteralIndex {
return geometryWrapper;
}
- private static GeometryWrapper retrieveMemoryIndex(String geometryLiteral,
GeometryDatatype geometryDatatype, Map<String, GeometryWrapper> index,
Map<String, GeometryWrapper> otherIndex) {
+ private static GeometryWrapper retrieveMemoryIndex(String geometryLiteral,
GeometryDatatype geometryDatatype, Cache<String, GeometryWrapper> index,
Cache<String, GeometryWrapper> otherIndex) {
GeometryWrapper geometryWrapper;
if (INDEX_ACTIVE) {
- geometryWrapper = index.get(geometryLiteral);
+ geometryWrapper = index.getIfPresent(geometryLiteral);
if (geometryWrapper == null) {
- geometryWrapper = otherIndex.get(geometryLiteral);
+ geometryWrapper = otherIndex.getIfPresent(geometryLiteral);
if (geometryWrapper == null) {
geometryWrapper = geometryDatatype.read(geometryLiteral);
}
@@ -87,33 +83,12 @@ public class GeometryLiteralIndex {
SECONDARY_INDEX.clear();
}
- /**
- * Sets the maximum size of Geometry Literal Index.
- *
- * @param maxSize : use -1 for unlimited size
- */
- public static final void setMaxSize(int maxSize) {
- PRIMARY_INDEX.setMaxSize(maxSize);
- SECONDARY_INDEX.setMaxSize(maxSize);
- }
-
- /**
- * Sets the expiry time in milliseconds of the Geometry Literal Indexes, if
- * active.
- *
- * @param expiryInterval : use 0 or negative for unlimited timeout
- */
- public static final void setExpiry(long expiryInterval) {
- PRIMARY_INDEX.setExpiryInterval(expiryInterval);
- SECONDARY_INDEX.setExpiryInterval(expiryInterval);
- }
-
/**
*
* @return Number of items in the primary index.
*/
public static final long getPrimaryIndexSize() {
- return PRIMARY_INDEX.mappingCount();
+ return PRIMARY_INDEX.size();
}
/**
@@ -121,7 +96,7 @@ public class GeometryLiteralIndex {
* @return Number of items in the secondary index.
*/
public static final long getSecondaryIndexSize() {
- return SECONDARY_INDEX.mappingCount();
+ return SECONDARY_INDEX.size();
}
/**
@@ -139,13 +114,6 @@ public class GeometryLiteralIndex {
*/
public static void setIndexActive(boolean indexActive) {
INDEX_ACTIVE = indexActive;
- if (INDEX_ACTIVE) {
- PRIMARY_INDEX.startExpiry();
- SECONDARY_INDEX.startExpiry();
- } else {
- PRIMARY_INDEX.stopExpiry();
- SECONDARY_INDEX.stopExpiry();
- }
}
/**
@@ -156,8 +124,8 @@ public class GeometryLiteralIndex {
* @param expiryInterval
*/
public static void reset(int maxSize, long expiryInterval) {
- PRIMARY_INDEX = ExpiringMaps.newExpiringMap(PRIMARY_INDEX_LABEL,
maxSize, expiryInterval);
- SECONDARY_INDEX = ExpiringMaps.newExpiringMap(SECONDARY_INDEX_LABEL,
maxSize, expiryInterval);
+ PRIMARY_INDEX = CacheConfiguration.create(maxSize, expiryInterval);
+ SECONDARY_INDEX = CacheConfiguration.create(maxSize, expiryInterval);
}
}
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndex.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndex.java
index 7115e18a47..fd19d64dbc 100644
---
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndex.java
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndex.java
@@ -17,13 +17,12 @@
*/
package org.apache.jena.geosparql.implementation.index;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.MAP_EXPIRY_INTERVAL;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.UNLIMITED_MAP;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.MAP_EXPIRY_INTERVAL;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.UNLIMITED_MAP;
import java.util.Objects;
-import org.apache.jena.ext.io.github.galbiston.expiring_map.ExpiringMap;
-import org.apache.jena.ext.io.github.galbiston.expiring_map.ExpiringMaps;
+import org.apache.jena.atlas.lib.Cache;
import org.apache.jena.geosparql.implementation.DimensionInfo;
import org.apache.jena.geosparql.implementation.GeometryWrapper;
import org.apache.jena.geosparql.implementation.jts.GeometryTransformation;
@@ -43,8 +42,8 @@ import org.opengis.util.FactoryException;
public class GeometryTransformIndex {
private static boolean INDEX_ACTIVE = false;
- private static final String GEOMETRY_TRANSFORM_LABEL = "Geometry
Transform";
- private static ExpiringMap<IndexKey, GeometryWrapper>
GEOMETRY_TRANSFORM_INDEX =
ExpiringMaps.newExpiringMap(GEOMETRY_TRANSFORM_LABEL, UNLIMITED_MAP,
MAP_EXPIRY_INTERVAL);
+ private static Cache<IndexKey, GeometryWrapper>
+ GEOMETRY_TRANSFORM_INDEX =
CacheConfiguration.create(UNLIMITED_MAP, MAP_EXPIRY_INTERVAL);
/**
*
@@ -62,7 +61,7 @@ public class GeometryTransformIndex {
if (INDEX_ACTIVE && storeSRSTransform) {
- transformedGeometryWrapper = GEOMETRY_TRANSFORM_INDEX.get(key);
+ transformedGeometryWrapper =
GEOMETRY_TRANSFORM_INDEX.getIfPresent(key);
if (transformedGeometryWrapper == null) {
transformedGeometryWrapper = transform(sourceGeometryWrapper,
srsURI);
GEOMETRY_TRANSFORM_INDEX.put(key, transformedGeometryWrapper);
@@ -97,31 +96,12 @@ public class GeometryTransformIndex {
GEOMETRY_TRANSFORM_INDEX.clear();
}
- /**
- * Sets whether the maximum size of the Geometry Transform Index.
- *
- * @param maxSize : use -1 for unlimited size
- */
- public static final void setMaxSize(int maxSize) {
- GEOMETRY_TRANSFORM_INDEX.setMaxSize(maxSize);
- }
-
- /**
- * Sets the expiry time in milliseconds of the Geometry Transform Index, if
- * active.
- *
- * @param expiryInterval : use 0 or negative for unlimited timeout
- */
- public static final void setExpiry(long expiryInterval) {
- GEOMETRY_TRANSFORM_INDEX.setExpiryInterval(expiryInterval);
- }
-
/**
*
* @return Number of items in the index.
*/
public static final long getGeometryTransformIndexSize() {
- return GEOMETRY_TRANSFORM_INDEX.mappingCount();
+ return GEOMETRY_TRANSFORM_INDEX.size();
}
/**
@@ -139,11 +119,6 @@ public class GeometryTransformIndex {
*/
public static void setIndexActive(boolean indexActive) {
INDEX_ACTIVE = indexActive;
- if (INDEX_ACTIVE) {
- GEOMETRY_TRANSFORM_INDEX.startExpiry();
- } else {
- GEOMETRY_TRANSFORM_INDEX.stopExpiry();
- }
}
/**
@@ -154,7 +129,7 @@ public class GeometryTransformIndex {
* @param expiryInterval
*/
public static void reset(int maxSize, long expiryInterval) {
- GEOMETRY_TRANSFORM_INDEX =
ExpiringMaps.newExpiringMap(GEOMETRY_TRANSFORM_LABEL, maxSize, expiryInterval);
+ GEOMETRY_TRANSFORM_INDEX = CacheConfiguration.create(maxSize,
expiryInterval);
}
private static class IndexKey {
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/IndexConfiguration.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/IndexConfiguration.java
index ce905c639f..19617a0b3b 100644
---
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/IndexConfiguration.java
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/IndexConfiguration.java
@@ -17,10 +17,11 @@
*/
package org.apache.jena.geosparql.implementation.index;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.NO_MAP;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.UNLIMITED_MAP;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.NO_MAP;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.UNLIMITED_MAP;
import java.util.UUID;
+
import org.apache.jena.geosparql.implementation.registry.MathTransformRegistry;
import org.apache.jena.geosparql.implementation.registry.SRSRegistry;
@@ -57,8 +58,8 @@ public class IndexConfiguration {
private static void setupNoIndex() {
IndexConfiguration.resetIndexes();
IndexConfiguration.stopIndexes();
- GeometryLiteralIndex.setMaxSize(NO_MAP);
- GeometryTransformIndex.setMaxSize(NO_MAP);
+ GeometryLiteralIndex.reset(NO_MAP, 0);
+ GeometryTransformIndex.reset(NO_MAP, 0);
QueryRewriteIndex.setMaxSize(NO_MAP);
}
@@ -66,8 +67,8 @@ public class IndexConfiguration {
* Indexes are set to unlimited storage and started.
*/
private static void setupMemoryIndex() {
- GeometryLiteralIndex.setMaxSize(UNLIMITED_MAP);
- GeometryTransformIndex.setMaxSize(UNLIMITED_MAP);
+ GeometryLiteralIndex.reset(UNLIMITED_MAP, 0);
+ GeometryTransformIndex.reset(UNLIMITED_MAP, 0);
QueryRewriteIndex.setMaxSize(UNLIMITED_MAP);
IndexConfiguration.startIndexes();
}
@@ -90,33 +91,6 @@ public class IndexConfiguration {
//QueryRewriteIndex are on a Dataset basis.
}
- /**
- * Set the maximum size of the indexes.<br>
- * Zero for no index and -1 for unlimited size.
- *
- * @param geometryLiteralIndex
- * @param geometryTransformIndex
- * @param queryRewriteIndex
- */
- public static final void setIndexMaxSize(int geometryLiteralIndex, int
geometryTransformIndex, int queryRewriteIndex) {
- GeometryLiteralIndex.setMaxSize(geometryLiteralIndex);
- GeometryTransformIndex.setMaxSize(geometryTransformIndex);
- QueryRewriteIndex.setMaxSize(queryRewriteIndex);
- }
-
- /**
- * Set the index expiry interval in milliseconds.
- *
- * @param geometryLiteralIndex
- * @param geometryTransformIndex
- * @param queryRewriteIndex
- */
- public static final void setIndexExpiry(long geometryLiteralIndex, long
geometryTransformIndex, long queryRewriteIndex) {
- GeometryLiteralIndex.setExpiry(geometryLiteralIndex);
- GeometryTransformIndex.setExpiry(geometryTransformIndex);
- QueryRewriteIndex.setExpiry(queryRewriteIndex);
- }
-
public static final void resetIndexes() {
GeometryLiteralIndex.clear();
GeometryTransformIndex.clear();
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/QueryRewriteIndex.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/QueryRewriteIndex.java
index 56c4fac2a1..6045174e65 100644
---
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/QueryRewriteIndex.java
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/QueryRewriteIndex.java
@@ -17,11 +17,7 @@
*/
package org.apache.jena.geosparql.implementation.index;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.MAP_EXPIRY_INTERVAL;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.UNLIMITED_MAP;
-
-import org.apache.jena.ext.io.github.galbiston.expiring_map.ExpiringMap;
-import org.apache.jena.ext.io.github.galbiston.expiring_map.ExpiringMaps;
+import org.apache.jena.atlas.lib.Cache;
import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
import org.apache.jena.geosparql.geo.topological.GenericPropertyFunction;
import org.apache.jena.graph.Graph;
@@ -36,34 +32,31 @@ import org.apache.jena.sparql.graph.GraphFactory;
import org.apache.jena.sparql.util.Context;
import org.apache.jena.sparql.util.Symbol;
+import java.util.Iterator;
+
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.MAP_EXPIRY_INTERVAL;
+import static
org.apache.jena.geosparql.implementation.index.CacheConfiguration.UNLIMITED_MAP;
+
/**
*
*/
public class QueryRewriteIndex {
private boolean indexActive;
- private final String queryRewriteLabel;
- private ExpiringMap<Triple, Boolean> index;
- private static String LABEL_DEFAULT = "Query Rewrite";
+ private Cache<Triple, Boolean> index;
private static int MAP_SIZE_DEFAULT = UNLIMITED_MAP;
private static long MAP_EXPIRY_INTERVAL_DEFAULT = MAP_EXPIRY_INTERVAL;
public static final Symbol QUERY_REWRITE_INDEX_SYMBOL =
Symbol.create("http://jena.apache.org/spatial#query-index");
public QueryRewriteIndex() {
- this.queryRewriteLabel = LABEL_DEFAULT;
this.indexActive = GeoSPARQLConfig.isQueryRewriteEnabled();
- this.index = ExpiringMaps.newExpiringMap(queryRewriteLabel,
MAP_SIZE_DEFAULT, MAP_EXPIRY_INTERVAL_DEFAULT);
- if (indexActive) {
- index.startExpiry();
- }
+ this.index = CacheConfiguration.create(MAP_SIZE_DEFAULT,
MAP_EXPIRY_INTERVAL_DEFAULT);
}
public QueryRewriteIndex(String queryRewriteLabel, int maxSize, long
expiryInterval) {
- this.queryRewriteLabel = queryRewriteLabel;
this.indexActive = true;
- this.index = ExpiringMaps.newExpiringMap(queryRewriteLabel, maxSize,
expiryInterval);
- this.index.startExpiry();
+ this.index = CacheConfiguration.create(maxSize, expiryInterval);
}
/**
@@ -83,7 +76,7 @@ public class QueryRewriteIndex {
if (indexActive) {
Triple key = Triple.create(subjectGeometryLiteral, predicate,
objectGeometryLiteral);
try {
- return index.computeIfAbsent(key, k ->
propertyFunction.testFilterFunction(subjectGeometryLiteral,
objectGeometryLiteral));
+ return index.get(key, k ->
propertyFunction.testFilterFunction(subjectGeometryLiteral,
objectGeometryLiteral));
} catch (NullPointerException ex) {
//Catch NullPointerException and fall through to default
action.
}
@@ -99,26 +92,6 @@ public class QueryRewriteIndex {
index.clear();
}
- /**
- * Sets whether the Query Rewrite Index is active.
- * <br> The index will be empty after this process.
- *
- * @param maxSize : use -1 for unlimited size
- */
- public final void setMapSize(int maxSize) {
- index.setMaxSize(maxSize);
- }
-
- /**
- * Sets the expiry time in milliseconds of the Query Rewrite Index, if
- * active.
- *
- * @param expiryInterval : use 0 or negative for unlimited timeout
- */
- public final void setMapExpiry(long expiryInterval) {
- index.setExpiryInterval(expiryInterval);
- }
-
/**
*
* @return True if index is active.
@@ -128,17 +101,19 @@ public class QueryRewriteIndex {
}
/**
- * COnverts the index to a model of asserted spatial relation statements.
+ * Converts the index to a model of asserted spatial relation statements.
*
* @return Model containing all true assertions.
*/
public Model toModel() {
Graph graph = GraphFactory.createDefaultGraph();
- index.forEach((key, value) -> {
- if (value) {
+ for (Iterator<Triple> it = index.keys(); it.hasNext(); ) {
+ Triple key = it.next();
+ Boolean value = index.getIfPresent(key);
+ if (value != null && value) {
graph.add(key);
}
- });
+ }
return ModelFactory.createModelForGraph(graph);
}
@@ -149,12 +124,6 @@ public class QueryRewriteIndex {
*/
public final void setActive(boolean indexActive) {
this.indexActive = indexActive;
-
- if (indexActive) {
- index.startExpiry();
- } else {
- index.stopExpiry();
- }
}
/**
@@ -162,18 +131,18 @@ public class QueryRewriteIndex {
* @return Number of items in the index.
*/
public final long getIndexSize() {
- return index.mappingCount();
+ return index.size();
}
/**
* Reset the index to the provided max size and expiry interval.<br>
* All contents will be lost.
*
- * @param maxSize
- * @param expiryInterval
+ * @param maxSize Maximum size
+ * @param expiryInterval Expiry interval
*/
public void reset(int maxSize, long expiryInterval) {
- index = ExpiringMaps.newExpiringMap(queryRewriteLabel, maxSize,
expiryInterval);
+ index = CacheConfiguration.create(maxSize, expiryInterval);
}
/**
@@ -262,7 +231,7 @@ public class QueryRewriteIndex {
* @return QueryRewriteIndex contained in the Context.
*/
public static final QueryRewriteIndex retrieve(Context context) {
- QueryRewriteIndex queryRewriteIndex = (QueryRewriteIndex)
context.get(QUERY_REWRITE_INDEX_SYMBOL, null);
+ QueryRewriteIndex queryRewriteIndex =
context.get(QUERY_REWRITE_INDEX_SYMBOL, null);
if (queryRewriteIndex == null) {
queryRewriteIndex = createDefault();
diff --git
a/jena-geosparql/src/test/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapTest.java
b/jena-geosparql/src/test/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapTest.java
deleted file mode 100644
index ac22947475..0000000000
---
a/jena-geosparql/src/test/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapTest.java
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- * See the notice.md file distributed with this work for additional
- * information regarding copyright ownership.
- *
- * Licensed 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.jena.ext.io.github.galbiston.expiring_map;
-
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.MAP_CLEANER_INTERVAL;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.MINIMUM_MAP_CLEANER_INTERVAL;
-import static
org.apache.jena.ext.io.github.galbiston.expiring_map.MapDefaultValues.UNLIMITED_EXPIRY;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.*;
-
-/**
- *
- *
- */
-public class ExpiringMapTest {
-
- public ExpiringMapTest() {
- }
-
- @BeforeClass
- public static void setUpClass() {
- }
-
- @AfterClass
- public static void tearDownClass() {
- }
-
- @Before
- public void setUp() {
- }
-
- @After
- public void tearDown() {
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testExpiry() throws InterruptedException {
- //System.out.println("expiry");
-
- long expiryInterval = 2000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 5,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + 100);
- instance.put("key5", "value5"); //Should be rejected.
- instance.put("key6", "value6");
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(halfExpiryInterval + cleanerInterval);
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 1;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testExpiry_none() throws InterruptedException {
- //System.out.println("expiry_none");
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test");
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(1000);
- instance.put("key5", "value5");
- instance.put("key6", "value6");
-
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(1000);
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 6;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testRefresh() throws InterruptedException {
- //System.out.println("refresh");
-
- long expiryInterval = 2000l;
- long halfExpiryInterval = expiryInterval / 2;
- long quarterExpiryInterval = expiryInterval / 3 * 4;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 5,
expiryInterval, halfExpiryInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + quarterExpiryInterval);
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(halfExpiryInterval);
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 2;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testEmpty() throws InterruptedException {
- //System.out.println("empty");
-
- long expiryInterval = 2000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 5,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval);
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(expiryInterval + cleanerInterval);
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 0;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of setCleanerInterval method, of class ExpiringMap.
- */
- @Test
- public void testSetCleanerInterval() {
- //System.out.println("setCleanerInterval");
- long cleanerInterval = 2000L;
- ExpiringMap<?,?> instance = new ExpiringMap<>("Test", 5);
- instance.setCleanerInterval(cleanerInterval);
- long expResult = cleanerInterval;
- long result = instance.getCleanerInterval();
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of setCleanerInterval method, of class ExpiringMap.
- */
- @Test
- public void testSetCleanerInterval_minimum() {
- //System.out.println("setCleanerInterval_minimum");
- long cleanerInterval = 0L;
- ExpiringMap<?,?> instance = new ExpiringMap<>("Test", 5);
- instance.setCleanerInterval(cleanerInterval);
- long expResult = MINIMUM_MAP_CLEANER_INTERVAL;
- long result = instance.getCleanerInterval();
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of setExpiryInterval method, of class ExpiringMap.
- */
- @Test
- public void testSetExpiryInterval() {
- //System.out.println("setExpiryInterval");
- long expiryInterval = 2000L;
- ExpiringMap<?,?> instance = new ExpiringMap<>("Test", 5);
- instance.setExpiryInterval(expiryInterval);
- long expResult = expiryInterval;
- long result = instance.getExpiryInterval();
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of setExpiryInterval method, of class ExpiringMap.
- */
- @Test
- public void testSetExpiryInterval_minimum() {
- //System.out.println("setExpiryInterval_minimum");
- long expiryInterval = 0L;
- ExpiringMap<?,?> instance = new ExpiringMap<>("Test", 5);
- instance.setExpiryInterval(expiryInterval);
- long expResult = MAP_CLEANER_INTERVAL + 1;
- long result = instance.getExpiryInterval();
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of isExpiring method, of class ExpiringMap.
- */
- @Test
- public void testIsExpiring() {
- //System.out.println("isExpiring");
- long expiryInterval = 1000L;
- ExpiringMap<?,?> instance = new ExpiringMap<>("Test", 5);
- instance.setExpiryInterval(expiryInterval);
- boolean expResult = true;
- boolean result = instance.isExpiring();
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of isExpiring method, of class ExpiringMap.
- */
- @Test
- public void testIsExpiring_false() {
- //System.out.println("isExpiring_false");
- long expiryInterval = UNLIMITED_EXPIRY;
- ExpiringMap<?,?> instance = new ExpiringMap<>("Test", 5);
- instance.setExpiryInterval(expiryInterval);
- boolean expResult = false;
- boolean result = instance.isExpiring();
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testExpiry_change_max_size() throws InterruptedException {
- //System.out.println("expiry_change_max_size");
-
- long expiryInterval = 2000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 5,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + 100);
- instance.setMaxSize(10);
- instance.put("key5", "value5");
- instance.put("key6", "value6");
- ////System.out.println("Size Before: " + instance.size());
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 6;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testExpiry_change_max_size_reduced() throws
InterruptedException {
- //System.out.println("expiry_change_max_size_reduced");
-
- long expiryInterval = 2000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 10,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + 100);
-
- instance.put("key5", "value5");
- instance.put("key6", "value6");
- instance.setMaxSize(5);
- instance.put("key7", "value7"); //Should be rejected.
- ////System.out.println("Size Before: " + instance.size());
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 6; //Over max size but don't remove until expired.
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testExpiry_change_expiry_interval() throws
InterruptedException {
- //System.out.println("expiry_change_expiry_interval");
-
- long expiryInterval = 2000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 10,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + 100);
- instance.put("key5", "value5");
- instance.put("key6", "value6");
- instance.setExpiryInterval(4000l);
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(halfExpiryInterval + cleanerInterval); //No cleaning
should have taken place.
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 6;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Test
- public void testExpiry_change_expiry_interval_reduced() throws
InterruptedException {
- //System.out.println("expiry_change_expiry_interval_reduced");
-
- long expiryInterval = 4000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 10,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + 100);
- instance.put("key5", "value5");
- instance.put("key6", "value6");
- instance.setExpiryInterval(2000l);
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(halfExpiryInterval + cleanerInterval); //All should have
been removed.
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 0;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of put method, of class ExpiringMap.
- *
- * @throws java.lang.InterruptedException
- */
- @Ignore // This test is not stable on loaded CI servers.
- @Test
- public void testExpiry_set_cleaner() throws InterruptedException {
- //System.out.println("expiry_set_cleaner");
-
- long expiryInterval = 2000l;
- long cleanerInterval = 1000l;
- long halfExpiryInterval = expiryInterval / 2;
-
- ExpiringMap<String, String> instance = new ExpiringMap<>("Test", 5,
expiryInterval, cleanerInterval);
-
- instance.put("key1", "value1");
- instance.put("key2", "value2");
- instance.put("key3", "value3");
- instance.put("key4", "value4");
- instance.startExpiry();
- Thread.sleep(halfExpiryInterval + 100);
- instance.setCleanerInterval(500l); //No obvious effect should occur.
- instance.put("key5", "value5"); //Should be rejected.
- instance.put("key6", "value6");
- ////System.out.println("Size Before: " + instance.size());
- Thread.sleep(halfExpiryInterval + cleanerInterval);
- instance.stopExpiry();
- ////System.out.println("Size After: " + instance.size());
- int result = instance.size();
- int expResult = 1;
-
- ////System.out.println("Exp: " + expResult);
- ////System.out.println("Res: " + result);
- assertEquals(expResult, result);
- }
-
-}
diff --git
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/CacheConfigurationTest.java
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/CacheConfigurationTest.java
new file mode 100644
index 0000000000..97e6de54f0
--- /dev/null
+++
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/CacheConfigurationTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.jena.geosparql.implementation.index;
+
+import org.apache.jena.atlas.lib.Cache;
+import org.apache.jena.atlas.lib.cache.CacheCaffeine;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CacheConfigurationTest {
+
+ @Test
+ public void cache_creation_null() {
+ Cache<String, String> cache =
CacheConfiguration.create(CacheConfiguration.NO_MAP, 0L);
+ cache.put("test", "test");
+ Assert.assertFalse(cache.containsKey("test"));
+ }
+
+ @Test
+ public void cache_creation_simple_01() {
+ Cache<Integer, String> cache = CacheConfiguration.create(100, 0L);
+
+ for (int i = 0; i < 1_000; i++) {
+ cache.put(i, Integer.toString(i));
+ }
+
+ // Should be fewer items than we added since we exceeded the max size
+ forceCleanUp(cache);
+ Assert.assertNotEquals(1_000, cache.size());
+ }
+
+ @Test
+ public void cache_creation_simple_02() {
+ Cache<Integer, String> cache = CacheConfiguration.create(100_000, 0L);
+
+ for (int i = 0; i < 1_000; i++) {
+ cache.put(i, Integer.toString(i));
+ }
+
+ // Should be exactly as many items as we added as we aren't remotely
near the max size
+ forceCleanUp(cache);
+ Assert.assertEquals(1_000, cache.size());
+ }
+
+ @Test
+ public void cache_creation_unlimited() {
+ Cache<Integer, String> cache =
CacheConfiguration.create(CacheConfiguration.UNLIMITED_MAP, 0L);
+
+ for (int i = 0; i < 1_000; i++) {
+ cache.put(i, Integer.toString(i));
+ }
+
+ // Should be exactly as many items as we added as we aren't remotely
near the max size
+ forceCleanUp(cache);
+ Assert.assertEquals(1_000, cache.size());
+ }
+
+ @Test
+ public void cache_creation_expiring() throws InterruptedException {
+ Cache<Integer, String> cache = CacheConfiguration.create(100, 100);
+
+ for (int i = 0; i < 1_000; i++) {
+ cache.put(i, Integer.toString(i));
+ }
+
+ // Should be fewer items than we added since we exceeded the max size
+ forceCleanUp(cache);
+ Assert.assertNotEquals(1_000L, cache.size());
+
+ // Wait for everything to expire and check now empty
+ Thread.sleep(250L);
+ forceCleanUp(cache);
+ Assert.assertEquals(0L, cache.size());
+ }
+
+ private static <K, V> void forceCleanUp(Cache<K, V> cache) {
+ if (cache instanceof CacheCaffeine<K, V> caffeine) {
+ caffeine.cleanUp();
+ }
+ }
+}