This is an automated email from the ASF dual-hosted git repository. rvesse pushed a commit to branch gh-2230 in repository https://gitbox.apache.org/repos/asf/jena.git
commit 6633e7bfd6c6865854d5163905e17d502dd3ec0a Author: Rob Vesse <[email protected]> AuthorDate: Thu Mar 14 14:35:59 2024 +0000 GH-2230: 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 | 475 --------------------- .../index/CacheConfigurationTest.java | 79 ++++ 15 files changed, 208 insertions(+), 1335 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..f71024ddb2 --- /dev/null +++ b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/index/CacheConfiguration.java @@ -0,0 +1,67 @@ +/* + * 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.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 b7129a1938..0000000000 --- a/jena-geosparql/src/test/java/org/apache/jena/ext/io/github/galbiston/expiring_map/ExpiringMapTest.java +++ /dev/null @@ -1,475 +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 org.junit.After; -import org.junit.AfterClass; - -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.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * - * - */ -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 - */ - @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..b0d5c67554 --- /dev/null +++ b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/CacheConfigurationTest.java @@ -0,0 +1,79 @@ +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(); + } + } +}
