This is an automated email from the ASF dual-hosted git repository. tv pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-jcs.git
commit edd0eb57ae83c471cc5f102073c51547e484dc36 Author: Thomas Vandahl <t...@apache.org> AuthorDate: Sat Feb 6 13:22:18 2021 +0100 More streaming, less arrays --- .../auxiliary/disk/indexed/IndexedDiskCache.java | 26 +- .../lateral/LateralCacheNoWaitFacade.java | 145 +++++----- .../lateral/socket/tcp/LateralTCPListener.java | 11 +- .../jcs3/engine/control/CompositeCache.java | 294 +++++++++++---------- .../engine/control/CompositeCacheConfigurator.java | 5 +- .../AbstractDoubleLinkedListMemoryCache.java | 12 +- .../jcs3/utils/discovery/UDPDiscoveryService.java | 46 ++-- .../commons/jcs3/utils/struct/AbstractLRUMap.java | 25 +- .../lateral/LateralCacheNoWaitFacadeUnitTest.java | 8 +- .../control/CompositeCacheDiskUsageUnitTest.java | 40 +-- .../engine/control/CompositeCacheUnitTest.java | 52 ++-- 11 files changed, 290 insertions(+), 374 deletions(-) diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java index 4cec8d0..4866b43 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java @@ -357,26 +357,22 @@ public class IndexedDiskCache<K, V> extends AbstractDiskCache<K, V> log.debug("{0}: Performing inital consistency check", logCacheName); boolean isOk = true; - long fileLength = 0; try { - fileLength = dataFile.length(); + final long fileLength = dataFile.length(); - for (final Map.Entry<K, IndexedDiskElementDescriptor> e : keyHash.entrySet()) - { - final IndexedDiskElementDescriptor ded = e.getValue(); + final IndexedDiskElementDescriptor corruptDed = keyHash.values().stream() + .filter(ded -> ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len > fileLength) + .findFirst() + .orElse(null); - isOk = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len <= fileLength; - - if (!isOk) - { - log.warn("{0}: The dataFile is corrupted!\n raf.length() = {1}\n ded.pos = {2}", - logCacheName, fileLength, ded.pos); - break; - } + if (corruptDed != null) + { + isOk = false; + log.warn("{0}: The dataFile is corrupted!\n raf.length() = {1}\n ded.pos = {2}", + logCacheName, fileLength, corruptDed.pos); } - - if (isOk && checkForDedOverlaps) + else if (checkForDedOverlaps) { isOk = checkForDedOverlaps(createPositionSortedDescriptorList()); } diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java index a64bb5f..7d86610 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java @@ -27,8 +27,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.stream.Collectors; import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache; @@ -56,9 +56,18 @@ public class LateralCacheNoWaitFacade<K, V> /** The logger */ private static final Log log = LogManager.getLog( LateralCacheNoWaitFacade.class ); - /** The queuing facade to the client. */ + /** + * The queuing facade to the client. + * @deprecated Should not have been public in the first place + */ + @Deprecated public LateralCacheNoWait<K, V>[] noWaits; + /** + * The queuing facade to the client. + */ + private final CopyOnWriteArraySet<LateralCacheNoWait<K, V>> noWaitSet; + /** The region name */ private final String cacheName; @@ -82,11 +91,22 @@ public class LateralCacheNoWaitFacade<K, V> log.debug( "CONSTRUCTING NO WAIT FACADE" ); this.listener = listener; this.noWaits = noWaits; + this.noWaitSet = new CopyOnWriteArraySet<>(Arrays.asList(noWaits)); this.cacheName = cattr.getCacheName(); this.lateralCacheAttributes = cattr; } /** + * Return the size of the no wait list (for testing) + * + * @return the noWait list size. + */ + protected int getNoWaitSize() + { + return noWaitSet.size(); + } + + /** * Tells you if the no wait is in the list or not. * <p> * @param noWait @@ -94,12 +114,7 @@ public class LateralCacheNoWaitFacade<K, V> */ public boolean containsNoWait( final LateralCacheNoWait<K, V> noWait ) { - final Optional<LateralCacheNoWait<K, V>> optional = Arrays.stream(noWaits) - // we know noWait isn't null - .filter(nw -> noWait.equals( nw )) - .findFirst(); - - return optional.isPresent(); + return noWaitSet.contains(noWait); } /** @@ -108,6 +123,7 @@ public class LateralCacheNoWaitFacade<K, V> * @param noWait * @return true if it wasn't already contained */ + @SuppressWarnings("unchecked") // No generic arrays in Java public synchronized boolean addNoWait( final LateralCacheNoWait<K, V> noWait ) { if ( noWait == null ) @@ -115,22 +131,15 @@ public class LateralCacheNoWaitFacade<K, V> return false; } - if ( containsNoWait( noWait ) ) + final boolean added = noWaitSet.add(noWait); + + if (!added) { log.debug( "No Wait already contained, [{0}]", noWait ); return false; } - @SuppressWarnings("unchecked") // No generic arrays in java - final - LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length + 1]; - - System.arraycopy( noWaits, 0, newArray, 0, noWaits.length ); - - // set the last position to the new noWait - newArray[noWaits.length] = noWait; - - noWaits = newArray; + noWaits = noWaitSet.toArray(new LateralCacheNoWait[0]); return true; } @@ -141,6 +150,7 @@ public class LateralCacheNoWaitFacade<K, V> * @param noWait * @return true if it was already in the array */ + @SuppressWarnings("unchecked") // No generic arrays in java public synchronized boolean removeNoWait( final LateralCacheNoWait<K, V> noWait ) { if ( noWait == null ) @@ -148,48 +158,31 @@ public class LateralCacheNoWaitFacade<K, V> return false; } - int position = -1; - for ( int i = 0; i < noWaits.length; i++ ) - { - // we know noWait isn't null - if ( noWait.equals( noWaits[i] ) ) - { - position = i; - break; - } - } + final boolean contained = noWaitSet.remove(noWait); - if ( position == -1 ) + if (!contained) { return false; } - @SuppressWarnings("unchecked") // No generic arrays in java - final - LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length - 1]; - - System.arraycopy( noWaits, 0, newArray, 0, position ); - if ( noWaits.length != position ) - { - System.arraycopy( noWaits, position + 1, newArray, position, noWaits.length - position - 1 ); - } - noWaits = newArray; + noWaits = noWaitSet.toArray(new LateralCacheNoWait[0]); return true; } /** - * @param ce + * Update the cache element in all lateral caches + * @param ce the cache element * @throws IOException */ @Override public void update( final ICacheElement<K, V> ce ) throws IOException { - log.debug( "updating through lateral cache facade, noWaits.length = {0}", - noWaits.length ); + log.debug("updating through lateral cache facade, noWaits.length = {0}", + () -> noWaitSet.size()); - for (final LateralCacheNoWait<K, V> nw : noWaits) + for (final LateralCacheNoWait<K, V> nw : noWaitSet) { nw.update( ce ); } @@ -204,17 +197,11 @@ public class LateralCacheNoWaitFacade<K, V> @Override public ICacheElement<K, V> get( final K key ) { - final Optional<ICacheElement<K, V>> optional = Arrays.stream(noWaits) - .map(nw -> nw.get( key )) + return noWaitSet.stream() + .map(nw -> nw.get(key)) .filter(obj -> obj != null) - .findFirst(); - - if (optional.isPresent()) - { - return optional.get(); - } - - return null; + .findFirst() + .orElse(null); } /** @@ -227,7 +214,7 @@ public class LateralCacheNoWaitFacade<K, V> @Override public Map<K, ICacheElement<K, V>> getMultiple(final Set<K> keys) { - if ( keys != null && !keys.isEmpty() ) + if (keys != null && !keys.isEmpty()) { final Map<K, ICacheElement<K, V>> elements = keys.stream() .collect(Collectors.toMap( @@ -254,12 +241,11 @@ public class LateralCacheNoWaitFacade<K, V> @Override public Map<K, ICacheElement<K, V>> getMatching(final String pattern) { - final Map<K, ICacheElement<K, V>> elements = new HashMap<>(); - for (final LateralCacheNoWait<K, V> nw : noWaits) - { - elements.putAll( nw.getMatching( pattern ) ); - } - return elements; + return noWaitSet.stream() + .flatMap(nw -> nw.getMatching(pattern).entrySet().stream()) + .collect(Collectors.toMap( + Entry::getKey, + Entry::getValue)); } /** @@ -271,15 +257,12 @@ public class LateralCacheNoWaitFacade<K, V> public Set<K> getKeySet() throws IOException { final HashSet<K> allKeys = new HashSet<>(); - for (final LateralCacheNoWait<K, V> nw : noWaits) + for (final LateralCacheNoWait<K, V> nw : noWaitSet) { - if ( nw != null ) + final Set<K> keys = nw.getKeySet(); + if (keys != null) { - final Set<K> keys = nw.getKeySet(); - if (keys != null) - { - allKeys.addAll( keys ); - } + allKeys.addAll(keys); } } return allKeys; @@ -294,7 +277,7 @@ public class LateralCacheNoWaitFacade<K, V> @Override public boolean remove( final K key ) { - Arrays.stream(noWaits).forEach(nw -> nw.remove( key )); + noWaitSet.forEach(nw -> nw.remove( key )); return false; } @@ -304,7 +287,7 @@ public class LateralCacheNoWaitFacade<K, V> @Override public void removeAll() { - Arrays.stream(noWaits).forEach(LateralCacheNoWait::removeAll); + noWaitSet.forEach(LateralCacheNoWait::removeAll); } /** Adds a dispose request to the lateral cache. */ @@ -319,7 +302,7 @@ public class LateralCacheNoWaitFacade<K, V> listener = null; } - Arrays.stream(noWaits).forEach(LateralCacheNoWait::dispose); + noWaitSet.forEach(LateralCacheNoWait::dispose); } finally { @@ -373,12 +356,12 @@ public class LateralCacheNoWaitFacade<K, V> return CacheStatus.DISPOSED; } - if (noWaits.length == 0 || listener != null) + if (noWaitSet.isEmpty() || listener != null) { return CacheStatus.ALIVE; } - final List<CacheStatus> statii = Arrays.stream(noWaits) + final List<CacheStatus> statii = noWaitSet.stream() .map(LateralCacheNoWait::getStatus) .collect(Collectors.toList()); @@ -448,19 +431,13 @@ public class LateralCacheNoWaitFacade<K, V> final ArrayList<IStatElement<?>> elems = new ArrayList<>(); - if ( noWaits != null ) + if (noWaitSet != null) { - elems.add(new StatElement<>( "Number of No Waits", Integer.valueOf(noWaits.length) ) ); + elems.add(new StatElement<>("Number of No Waits", Integer.valueOf(noWaitSet.size()))); - for ( final LateralCacheNoWait<K, V> lcnw : noWaits ) - { - if ( lcnw != null ) - { - // get the stats from the super too - final IStats sStats = lcnw.getStatistics(); - elems.addAll(sStats.getStatElements()); - } - } + elems.addAll(noWaitSet.stream() + .flatMap(lcnw -> lcnw.getStatistics().getStatElements().stream()) + .collect(Collectors.toList())); } stats.setStatElements( elems ); diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java index 8f457f8..32111f8 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java @@ -471,17 +471,11 @@ public class LateralTCPListener<K, V> { try { - while ( true ) + // Check to see if we've been asked to exit, and exit + while ( !terminated.get() ) { log.debug( "Waiting for clients to connect " ); - // Check to see if we've been asked to exit, and exit - if (terminated.get()) - { - log.debug("Thread terminated, exiting gracefully"); - break; - } - try { final Socket socket = serverSocket.accept(); @@ -499,6 +493,7 @@ public class LateralTCPListener<K, V> } } + log.debug("Thread terminated, exiting gracefully"); serverSocket.close(); } catch ( final IOException e ) diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java index 011fce1..70d9b6f 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java @@ -21,11 +21,15 @@ package org.apache.commons.jcs3.engine.control; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -82,8 +86,7 @@ public class CompositeCache<K, V> private IElementEventQueue elementEventQ; /** Auxiliary caches. */ - @SuppressWarnings("unchecked") // OK because this is an empty array - private AuxiliaryCache<K, V>[] auxCaches = new AuxiliaryCache[0]; + private CopyOnWriteArrayList<AuxiliaryCache<K, V>> auxCaches = new CopyOnWriteArrayList<>(); /** is this alive? */ private final AtomicBoolean alive; @@ -186,12 +189,27 @@ public class CompositeCache<K, V> /** * This sets the list of auxiliary caches for this region. + * It filters out null caches * <p> * @param auxCaches */ + public void setAuxCaches(final List<AuxiliaryCache<K, V>> auxCaches) + { + this.auxCaches = auxCaches.stream() + .filter(aux -> aux != null) + .collect(Collectors.toCollection(CopyOnWriteArrayList::new)); + } + + /** + * This sets the list of auxiliary caches for this region. + * <p> + * @param auxCaches + * @deprecated Use List method + */ + @Deprecated public void setAuxCaches(final AuxiliaryCache<K, V>[] auxCaches) { - this.auxCaches = auxCaches; + setAuxCaches(Arrays.asList(auxCaches)); } /** @@ -199,12 +217,25 @@ public class CompositeCache<K, V> * <p> * @return an array of auxiliary caches, may be empty, never null */ - public AuxiliaryCache<K, V>[] getAuxCaches() + public List<AuxiliaryCache<K, V>> getAuxCacheList() { return this.auxCaches; } /** + * Get the list of auxiliary caches for this region. + * <p> + * @return an array of auxiliary caches, may be empty, never null + * @deprecated Use List method + */ + @SuppressWarnings("unchecked") // No generic arrays in Java + @Deprecated + public AuxiliaryCache<K, V>[] getAuxCaches() + { + return getAuxCacheList().toArray(new AuxiliaryCache[0]); + } + + /** * Standard update method. * <p> * @param ce @@ -286,7 +317,7 @@ public class CompositeCache<K, V> // more can be added if future auxiliary caches don't fit the model // You could run a database cache as either a remote or a local disk. // The types would describe the purpose. - if (auxCaches.length > 0) + if (!auxCaches.isEmpty()) { log.debug("Updating auxiliary caches"); } @@ -385,7 +416,7 @@ public class CompositeCache<K, V> // SPOOL TO DISK. for (final ICache<K, V> aux : auxCaches) { - if (aux != null && aux.getCacheType() == CacheType.DISK_CACHE) + if (aux.getCacheType() == CacheType.DISK_CACHE) { diskAvailable = true; @@ -496,56 +527,53 @@ public class CompositeCache<K, V> // caches, even if not local look in disk auxiliaries for (final AuxiliaryCache<K, V> aux : auxCaches) { - if (aux != null) + final CacheType cacheType = aux.getCacheType(); + + if (!localOnly || cacheType == CacheType.DISK_CACHE) { - final CacheType cacheType = aux.getCacheType(); + log.debug("Attempting to get from aux [{0}] which is of type: {1}", + () -> aux.getCacheName(), () -> cacheType); - if (!localOnly || cacheType == CacheType.DISK_CACHE) + try + { + element = aux.get(key); + } + catch (final IOException e) { - log.debug("Attempting to get from aux [{0}] which is of type: {1}", - () -> aux.getCacheName(), () -> cacheType); - - try - { - element = aux.get(key); - } - catch (final IOException e) - { - log.error("Error getting from aux", e); - } + log.error("Error getting from aux", e); } + } - log.debug("Got CacheElement: {0}", element); + log.debug("Got CacheElement: {0}", element); - // Item found in one of the auxiliary caches. - if (element != null) + // Item found in one of the auxiliary caches. + if (element != null) + { + if (isExpired(element)) + { + log.debug("{0} - Aux cache[{1}] hit, but element expired.", + () -> cacheAttr.getCacheName(), () -> aux.getCacheName()); + + // This will tell the remotes to remove the item + // based on the element's expiration policy. The elements attributes + // associated with the item when it created govern its behavior + // everywhere. + doExpires(element); + element = null; + } + else { - if (isExpired(element)) - { - log.debug("{0} - Aux cache[{1}] hit, but element expired.", - () -> cacheAttr.getCacheName(), () -> aux.getCacheName()); - - // This will tell the remotes to remove the item - // based on the element's expiration policy. The elements attributes - // associated with the item when it created govern its behavior - // everywhere. - doExpires(element); - element = null; - } - else - { - log.debug("{0} - Aux cache[{1}] hit.", - () -> cacheAttr.getCacheName(), () -> aux.getCacheName()); - - // Update counters - hitCountAux.incrementAndGet(); - copyAuxiliaryRetrievedItemToMemory(element); - } - - found = true; - - break; + log.debug("{0} - Aux cache[{1}] hit.", + () -> cacheAttr.getCacheName(), () -> aux.getCacheName()); + + // Update counters + hitCountAux.incrementAndGet(); + copyAuxiliaryRetrievedItemToMemory(element); } + + found = true; + + break; } } } @@ -699,42 +727,39 @@ public class CompositeCache<K, V> for (final AuxiliaryCache<K, V> aux : auxCaches) { - if (aux != null) - { - final Map<K, ICacheElement<K, V>> elementsFromAuxiliary = - new HashMap<>(); + final Map<K, ICacheElement<K, V>> elementsFromAuxiliary = + new HashMap<>(); - final CacheType cacheType = aux.getCacheType(); - - if (!localOnly || cacheType == CacheType.DISK_CACHE) - { - log.debug("Attempting to get from aux [{0}] which is of type: {1}", - () -> aux.getCacheName(), () -> cacheType); - - try - { - elementsFromAuxiliary.putAll(aux.getMultiple(remainingKeys)); - } - catch (final IOException e) - { - log.error("Error getting from aux", e); - } - } - - log.debug("Got CacheElements: {0}", elementsFromAuxiliary); + final CacheType cacheType = aux.getCacheType(); - processRetrievedElements(aux, elementsFromAuxiliary); - elements.putAll(elementsFromAuxiliary); + if (!localOnly || cacheType == CacheType.DISK_CACHE) + { + log.debug("Attempting to get from aux [{0}] which is of type: {1}", + () -> aux.getCacheName(), () -> cacheType); - if (elements.size() == keys.size()) + try { - break; + elementsFromAuxiliary.putAll(aux.getMultiple(remainingKeys)); } - else + catch (final IOException e) { - remainingKeys = pruneKeysFound(keys, elements); + log.error("Error getting from aux", e); } } + + log.debug("Got CacheElements: {0}", elementsFromAuxiliary); + + processRetrievedElements(aux, elementsFromAuxiliary); + elements.putAll(elementsFromAuxiliary); + + if (elements.size() == keys.size()) + { + break; + } + else + { + remainingKeys = pruneKeysFound(keys, elements); + } } return elements; @@ -840,36 +865,33 @@ public class CompositeCache<K, V> { final Map<K, ICacheElement<K, V>> elements = new HashMap<>(); - for (int i = auxCaches.length - 1; i >= 0; i--) + for (ListIterator<AuxiliaryCache<K, V>> i = auxCaches.listIterator(auxCaches.size()); i.hasPrevious();) { - final AuxiliaryCache<K, V> aux = auxCaches[i]; + final AuxiliaryCache<K, V> aux = i.previous(); - if (aux != null) - { - final Map<K, ICacheElement<K, V>> elementsFromAuxiliary = - new HashMap<>(); + final Map<K, ICacheElement<K, V>> elementsFromAuxiliary = + new HashMap<>(); - final CacheType cacheType = aux.getCacheType(); + final CacheType cacheType = aux.getCacheType(); - if (!localOnly || cacheType == CacheType.DISK_CACHE) - { - log.debug("Attempting to get from aux [{0}] which is of type: {1}", - () -> aux.getCacheName(), () -> cacheType); + if (!localOnly || cacheType == CacheType.DISK_CACHE) + { + log.debug("Attempting to get from aux [{0}] which is of type: {1}", + () -> aux.getCacheName(), () -> cacheType); - try - { - elementsFromAuxiliary.putAll(aux.getMatching(pattern)); - } - catch (final IOException e) - { - log.error("Error getting from aux", e); - } + try + { + elementsFromAuxiliary.putAll(aux.getMatching(pattern)); + } + catch (final IOException e) + { + log.error("Error getting from aux", e); + } - log.debug("Got CacheElements: {0}", elementsFromAuxiliary); + log.debug("Got CacheElements: {0}", elementsFromAuxiliary); - processRetrievedElements(aux, elementsFromAuxiliary); - elements.putAll(elementsFromAuxiliary); - } + processRetrievedElements(aux, elementsFromAuxiliary); + elements.putAll(elementsFromAuxiliary); } } @@ -982,26 +1004,19 @@ public class CompositeCache<K, V> */ public Set<K> getKeySet(final boolean localOnly) { - final HashSet<K> allKeys = new HashSet<>(memCache.getKeySet()); - - for (final AuxiliaryCache<K, V> aux : auxCaches) - { - if (aux != null) - { - if(!localOnly || aux.getCacheType() == CacheType.DISK_CACHE) + return Stream.concat(memCache.getKeySet().stream(), auxCaches.stream() + .filter(aux -> !localOnly || aux.getCacheType() == CacheType.DISK_CACHE) + .flatMap(aux -> { + try { - try - { - allKeys.addAll(aux.getKeySet()); - } - catch (final IOException e) - { - // ignore - } + return aux.getKeySet().stream(); } - } - } - return allKeys; + catch (final IOException e) + { + return Stream.of(); + } + })) + .collect(Collectors.toSet()); } /** @@ -1142,10 +1157,9 @@ public class CompositeCache<K, V> } // Removes from all auxiliary disk caches. - for (final ICache<K, V> aux : auxCaches) - { - if (aux != null && (aux.getCacheType() == CacheType.DISK_CACHE || !localOnly)) - { + auxCaches.stream() + .filter(aux -> aux.getCacheType() == CacheType.DISK_CACHE || !localOnly) + .forEach(aux -> { try { log.debug("Removing All keys from cacheType {0}", @@ -1155,10 +1169,9 @@ public class CompositeCache<K, V> } catch (final IOException ex) { - log.error("Failure removing all from aux", ex); + log.error("Failure removing all from aux " + aux, ex); } - } - } + }); } /** @@ -1274,16 +1287,15 @@ public class CompositeCache<K, V> */ public void save() { - if (alive.compareAndSet(true, false) == false) + if (!alive.get()) { return; } - for (final ICache<K, V> aux : auxCaches) - { - try - { - if (aux.getStatus() == CacheStatus.ALIVE) + auxCaches.stream() + .filter(aux -> aux.getStatus() == CacheStatus.ALIVE) + .forEach(aux -> { + try { for (final K key : memCache.getKeySet()) { @@ -1295,12 +1307,11 @@ public class CompositeCache<K, V> } } } - } - catch (final IOException ex) - { - log.error("Failure saving aux caches.", ex); - } - } + catch (final IOException ex) + { + log.error("Failure saving aux caches.", ex); + } + }); log.debug("Called save for [{0}]", () -> cacheAttr.getCacheName()); } @@ -1369,15 +1380,12 @@ public class CompositeCache<K, V> stats.setStatElements(elems); // memory + aux, memory is not considered an auxiliary internally - final int total = auxCaches.length + 1; - final ArrayList<IStats> auxStats = new ArrayList<>(total); + final ArrayList<IStats> auxStats = new ArrayList<>(auxCaches.size() + 1); auxStats.add(getMemoryCache().getStatistics()); - - for (final AuxiliaryCache<K, V> aux : auxCaches) - { - auxStats.add(aux.getStatistics()); - } + auxStats.addAll(auxCaches.stream() + .map(AuxiliaryCache::getStatistics) + .collect(Collectors.toList())); // store the auxiliary stats stats.setAuxiliaryCacheStats(auxStats); diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java index 5ecae58..f50ed6b 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java @@ -267,10 +267,7 @@ public class CompositeCacheConfigurator } // Associate the auxiliaries with the cache - @SuppressWarnings("unchecked") // No generic arrays in java - final - AuxiliaryCache<K, V>[] auxArray = auxList.toArray( new AuxiliaryCache[0] ); - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(auxList); } // Return the new cache diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java index 422530d..ca533ff 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java @@ -162,14 +162,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract try { - for (int i = 0; i < chunkSizeCorrected; i++) - { - final ICacheElement<K, V> lastElement = spoolLastElement(); - if (lastElement == null) - { - break; - } - } + freeElements(chunkSizeCorrected); // If this is out of the sync block it can detect a mismatch // where there is none. @@ -197,10 +190,9 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract * @param numberToFree * @return the number that were removed. if you ask to free 5, but there are only 3, you will * get 3. - * @throws IOException */ @Override - public int freeElements(final int numberToFree) throws IOException + public int freeElements(final int numberToFree) { int freed = 0; diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java index fcb301a..bbe4b4e 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java @@ -24,6 +24,8 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -65,7 +67,7 @@ public class UDPDiscoveryService private AtomicBoolean shutdown = new AtomicBoolean(false); /** This is a set of services that have been discovered. */ - private final Set<DiscoveredService> discoveredServices = new CopyOnWriteArraySet<>(); + private final ConcurrentMap<Integer, DiscoveredService> discoveredServices = new ConcurrentHashMap<>(); /** This a list of regions that are configured to use discovery. */ private final Set<String> cacheNames = new CopyOnWriteArraySet<>(); @@ -260,9 +262,7 @@ public class UDPDiscoveryService */ public void removeDiscoveredService( final DiscoveredService service ) { - final boolean contained = getDiscoveredServices().remove( service ); - - if ( contained ) + if (discoveredServices.remove(service.hashCode()) != null) { log.info( "Removing {0}", service ); } @@ -277,39 +277,29 @@ public class UDPDiscoveryService */ protected void addOrUpdateService( final DiscoveredService discoveredService ) { - final Set<DiscoveredService> discoveredServices = getDiscoveredServices(); - // Since this is a set we can add it over an over. // We want to replace the old one, since we may add info that is not part of the equals. // The equals method on the object being added is intentionally restricted. - if ( !discoveredServices.contains( discoveredService ) ) - { - log.info( "Set does not contain service. I discovered {0}", discoveredService ); - log.debug( "Adding service in the set {0}", discoveredService ); - discoveredServices.add( discoveredService ); - } - else - { + discoveredServices.merge(discoveredService.hashCode(), discoveredService, (oldService, newService) -> { log.debug( "Set contains service." ); - log.debug( "Updating service in the set {0}", discoveredService ); + log.debug( "Updating service in the set {0}", newService ); // Update the list of cache names if it has changed. // need to update the time this sucks. add has no effect convert to a map - DiscoveredService theOldServiceInformation = discoveredServices.stream() - .filter(service -> discoveredService.equals(service)) - .findFirst() - .orElse(null); + if (!oldService.getCacheNames().equals(newService.getCacheNames())) + { + log.info( "List of cache names changed for service: {0}", newService ); + + // replace it, we want to reset the payload and the last heard from time. + return newService; + } - if (theOldServiceInformation != null && - !theOldServiceInformation.getCacheNames().equals(discoveredService.getCacheNames())) + if (oldService.getLastHearFromTime() != newService.getLastHearFromTime()) { - log.info( "List of cache names changed for service: {0}", - discoveredService ); + return newService; } - // replace it, we want to reset the payload and the last heard from time. - discoveredServices.remove( discoveredService ); - discoveredServices.add( discoveredService ); - } + return oldService; + }); // Always Notify the listeners // If we don't do this, then if a region using the default config is initialized after notification, @@ -397,7 +387,7 @@ public class UDPDiscoveryService */ public Set<DiscoveredService> getDiscoveredServices() { - return discoveredServices; + return new HashSet<>(discoveredServices.values()); } /** diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java index b1a247d..53b56b0 100644 --- a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java +++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java @@ -441,19 +441,16 @@ public abstract class AbstractLRUMap<K, V> } log.trace( "verifycache: checking via keysets!" ); - map.forEach((key, value) -> { - boolean found = false; - - for (LRUElementDescriptor<K, V> li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor<K, V>) li2.next ) - { - if ( key.equals( li2.getKey() ) ) + map.keySet().stream() + .filter(key -> { + for (LRUElementDescriptor<K, V> li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor<K, V>) li2.next ) { - found = true; - break; + if ( key.equals( li2.getKey() ) ) + { + return true; + } } - } - if ( !found ) - { + log.error( "verifycache: key not found in list : {0}", key ); dumpCacheEntries(); if ( map.containsKey( key ) ) @@ -464,8 +461,10 @@ public abstract class AbstractLRUMap<K, V> { log.error( "verifycache: map does NOT contain key, what the HECK!" ); } - } - }); + + return false; + }) + .findFirst(); } /** diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java index 02eb6f8..a8e6133 100644 --- a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java +++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java @@ -56,7 +56,7 @@ public class LateralCacheNoWaitFacadeUnitTest facade.removeNoWait( noWait ); // VERIFY - assertEquals( "Should have 0", 0, facade.noWaits.length ); + assertEquals( "Should have 0", 0, facade.getNoWaitSize() ); assertFalse( "Should not be in the list. ", facade.containsNoWait( noWait ) ); } @@ -83,7 +83,7 @@ public class LateralCacheNoWaitFacadeUnitTest facade.addNoWait( noWait2 ); // VERIFY - assertEquals( "Should have 2", 2, facade.noWaits.length ); + assertEquals( "Should have 2", 2, facade.getNoWaitSize() ); assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) ); assertTrue( "Should be in the list.", facade.containsNoWait( noWait2 ) ); @@ -91,7 +91,7 @@ public class LateralCacheNoWaitFacadeUnitTest facade.removeNoWait( noWait ); // VERIFY - assertEquals( "Should only have 1", 1, facade.noWaits.length ); + assertEquals( "Should only have 1", 1, facade.getNoWaitSize() ); assertFalse( "Should not be in the list. ", facade.containsNoWait( noWait ) ); assertTrue( "Should be in the list.", facade.containsNoWait( noWait2 ) ); } @@ -119,7 +119,7 @@ public class LateralCacheNoWaitFacadeUnitTest // VERIFY assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) ); - assertEquals( "Should only have 1", 1, facade.noWaits.length ); + assertEquals( "Should only have 1", 1, facade.getNoWaitSize() ); } /** diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java index 3117f25..d4aab45 100644 --- a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java +++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java @@ -20,6 +20,7 @@ package org.apache.commons.jcs3.engine.control; */ import java.io.IOException; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -29,17 +30,16 @@ import org.apache.commons.jcs3.JCS; import org.apache.commons.jcs3.access.CacheAccess; import org.apache.commons.jcs3.access.exception.CacheException; import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache; -import org.apache.commons.jcs3.auxiliary.AuxiliaryCache; import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes; import org.apache.commons.jcs3.engine.CacheElement; import org.apache.commons.jcs3.engine.CacheStatus; import org.apache.commons.jcs3.engine.CompositeCacheAttributes; import org.apache.commons.jcs3.engine.ElementAttributes; import org.apache.commons.jcs3.engine.behavior.ICacheElement; +import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType; import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes; import org.apache.commons.jcs3.engine.behavior.IElementAttributes; import org.apache.commons.jcs3.engine.behavior.IElementSerializer; -import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType; import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger; import org.apache.commons.jcs3.engine.stats.behavior.IStats; @@ -107,11 +107,7 @@ public class CompositeCacheDiskUsageUnitTest final MockAuxCache<String, String> mock = new MockAuxCache<>(); mock.cacheType = CacheType.DISK_CACHE; - - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock }; - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(Arrays.asList(mock)); final ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" ); @@ -140,11 +136,7 @@ public class CompositeCacheDiskUsageUnitTest final MockAuxCache<String, String> mock = new MockAuxCache<>(); mock.cacheType = CacheType.DISK_CACHE; - - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock }; - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(Arrays.asList(mock)); final ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" ); @@ -177,11 +169,7 @@ public class CompositeCacheDiskUsageUnitTest final MockAuxCache<String, String> mock = new MockAuxCache<>(); mock.cacheType = CacheType.DISK_CACHE; - - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock }; - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(Arrays.asList(mock)); final ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" ); @@ -216,11 +204,7 @@ public class CompositeCacheDiskUsageUnitTest final MockAuxCache<String, String> mock = new MockAuxCache<>(); mock.cacheType = CacheType.DISK_CACHE; - - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock }; - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(Arrays.asList(mock)); final ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" ); @@ -255,11 +239,7 @@ public class CompositeCacheDiskUsageUnitTest final MockAuxCache<String, String> mock = new MockAuxCache<>(); mock.cacheType = CacheType.DISK_CACHE; - - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock }; - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(Arrays.asList(mock)); final ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" ); @@ -295,11 +275,7 @@ public class CompositeCacheDiskUsageUnitTest final MockAuxCache<String, String> mockLateral = new MockAuxCache<>(); mockLateral.cacheType = CacheType.LATERAL_CACHE; - - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock, mockLateral }; - cache.setAuxCaches( auxArray ); + cache.setAuxCaches(Arrays.asList(mock, mockLateral)); final ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" ); diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java index 78931e2..6da9fd8 100644 --- a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java +++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java @@ -1,5 +1,19 @@ package org.apache.commons.jcs3.engine.control; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +import org.apache.commons.jcs3.auxiliary.MockAuxiliaryCache; +import org.apache.commons.jcs3.engine.CacheElement; +import org.apache.commons.jcs3.engine.CompositeCacheAttributes; +import org.apache.commons.jcs3.engine.ElementAttributes; +import org.apache.commons.jcs3.engine.behavior.ICacheElement; +import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType; +import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes; +import org.apache.commons.jcs3.engine.behavior.IElementAttributes; +import org.apache.commons.jcs3.engine.memory.MockMemoryCache; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -21,19 +35,6 @@ package org.apache.commons.jcs3.engine.control; import junit.framework.TestCase; -import org.apache.commons.jcs3.auxiliary.MockAuxiliaryCache; -import org.apache.commons.jcs3.engine.memory.MockMemoryCache; -import org.apache.commons.jcs3.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs3.engine.CacheElement; -import org.apache.commons.jcs3.engine.CompositeCacheAttributes; -import org.apache.commons.jcs3.engine.ElementAttributes; -import org.apache.commons.jcs3.engine.behavior.ICacheElement; -import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs3.engine.behavior.IElementAttributes; -import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType; -import java.io.IOException; -import java.util.Map; - /** * Tests that directly engage the composite cache. * <p> @@ -63,10 +64,7 @@ public class CompositeCacheUnitTest final MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>(); diskMock.cacheType = CacheType.DISK_CACHE; - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock }; - cache.setAuxCaches( aux ); + cache.setAuxCaches(Arrays.asList(diskMock)); // DO WORK final int numToInsert = 10; @@ -104,10 +102,7 @@ public class CompositeCacheUnitTest final MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>(); diskMock.cacheType = CacheType.REMOTE_CACHE; - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock }; - cache.setAuxCaches( aux ); + cache.setAuxCaches(Arrays.asList(diskMock)); // DO WORK final int numToInsert = 10; @@ -148,10 +143,7 @@ public class CompositeCacheUnitTest final MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>(); diskMock.cacheType = CacheType.DISK_CACHE; - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock }; - cache.setAuxCaches( aux ); + cache.setAuxCaches(Arrays.asList(diskMock)); // DO WORK final int numToInsertPrefix1 = 10; @@ -201,10 +193,7 @@ public class CompositeCacheUnitTest final MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>(); diskMock.cacheType = CacheType.DISK_CACHE; - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock }; - cache.setAuxCaches( aux ); + cache.setAuxCaches(Arrays.asList(diskMock)); // DO WORK cache.getMatching( "junk" ); @@ -236,10 +225,7 @@ public class CompositeCacheUnitTest final MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>(); diskMock.cacheType = CacheType.REMOTE_CACHE; - @SuppressWarnings("unchecked") - final - AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock }; - cache.setAuxCaches( aux ); + cache.setAuxCaches(Arrays.asList(diskMock)); // DO WORK cache.getMatching( "junk" );