ARTEMIS-2321 PageCursorProviderImpl can use primitive maps

This commit is contained in:
Francesco Nigro 2019-04-26 00:22:21 +02:00 committed by Clebert Suconic
parent 30c82f43b0
commit 49836eca52
4 changed files with 105 additions and 79 deletions

View File

@ -21,26 +21,26 @@ import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicLong;
import io.netty.util.collection.LongObjectHashMap;
import io.netty.util.collection.LongObjectMap;
import org.jboss.logging.Logger;
public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implements Map<K, V> {
public class SoftValueLongObjectHashMap<V extends SoftValueLongObjectHashMap.ValueCache> implements LongObjectMap<V> {
private static final Logger logger = Logger.getLogger(SoftValueHashMap.class);
private static final Logger logger = Logger.getLogger(SoftValueLongObjectHashMap.class);
// The soft references that are already good.
// too bad there's no way to override the queue method on ReferenceQueue, so I wouldn't need this
private final ReferenceQueue<V> refQueue = new ReferenceQueue<>();
private final Map<K, AggregatedSoftReference> mapDelegate = new HashMap<>();
private final LongObjectMap<AggregatedSoftReference<V>> mapDelegate = new LongObjectHashMap<>();
private final AtomicLong usedCounter = new AtomicLong(0);
private long usedCounter = 0;
private int maxElements;
@ -57,7 +57,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
// Constructors --------------------------------------------------
public SoftValueHashMap(final int maxElements) {
public SoftValueLongObjectHashMap(final int maxElements) {
this.maxElements = maxElements;
}
@ -96,8 +96,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
*/
@Override
public boolean containsKey(final Object key) {
processQueue();
return mapDelegate.containsKey(key);
return containsKey(objectToKey(key));
}
/**
@ -107,7 +106,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
@Override
public boolean containsValue(final Object value) {
processQueue();
for (AggregatedSoftReference valueIter : mapDelegate.values()) {
for (AggregatedSoftReference<V> valueIter : mapDelegate.values()) {
V valueElement = valueIter.get();
if (valueElement != null && value.equals(valueElement)) {
return true;
@ -117,16 +116,31 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
return false;
}
private static long objectToKey(Object key) {
return ((Long) key).longValue();
}
/**
* @param key
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public V get(final Object key) {
return get(objectToKey(key));
}
@Override
public V put(Long key, V value) {
return put(objectToKey(key), value);
}
@Override
public V get(long key) {
processQueue();
AggregatedSoftReference value = mapDelegate.get(key);
AggregatedSoftReference<V> value = mapDelegate.get(key);
if (value != null) {
value.used();
usedCounter++;
value.used(usedCounter);
return value.get();
} else {
return null;
@ -139,12 +153,13 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
public V put(final K key, final V value) {
public V put(final long key, final V value) {
processQueue();
AggregatedSoftReference newRef = createReference(key, value);
AggregatedSoftReference oldRef = mapDelegate.put(key, newRef);
AggregatedSoftReference<V> newRef = createReference(key, value);
AggregatedSoftReference<V> oldRef = mapDelegate.put(key, newRef);
checkCacheSize();
newRef.used();
usedCounter++;
newRef.used(usedCounter);
if (oldRef != null) {
return oldRef.get();
} else {
@ -152,11 +167,22 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
}
}
@Override
public V remove(long key) {
processQueue();
AggregatedSoftReference<V> ref = mapDelegate.remove(key);
if (ref != null) {
return ref.get();
} else {
return null;
}
}
private void checkCacheSize() {
if (maxElements > 0 && mapDelegate.size() > maxElements) {
TreeSet<AggregatedSoftReference> usedReferences = new TreeSet<>(new ComparatorAgregated());
for (AggregatedSoftReference ref : mapDelegate.values()) {
for (AggregatedSoftReference<V> ref : mapDelegate.values()) {
V v = ref.get();
if (v != null && !v.isLive()) {
@ -169,7 +195,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
Object removed = mapDelegate.remove(ref.key);
if (logger.isTraceEnabled()) {
logger.trace("Removing " + removed + " with id = " + ref.key + " from SoftValueHashMap");
logger.trace("Removing " + removed + " with id = " + ref.key + " from SoftValueLongObjectHashMap");
}
if (mapDelegate.size() <= maxElements) {
@ -210,13 +236,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
*/
@Override
public V remove(final Object key) {
processQueue();
AggregatedSoftReference ref = mapDelegate.remove(key);
if (ref != null) {
return ref.get();
} else {
return null;
}
return remove(objectToKey(key));
}
/**
@ -224,10 +244,17 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
public void putAll(final Map<? extends K, ? extends V> m) {
public void putAll(final Map<? extends Long, ? extends V> m) {
processQueue();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
put(e.getKey(), e.getValue());
if (m instanceof LongObjectMap) {
final LongObjectMap<? extends V> primitiveMap = (LongObjectMap<? extends V>) m;
for (PrimitiveEntry<? extends V> entry : primitiveMap.entries()) {
put(entry.key(), entry.value());
}
} else {
for (Map.Entry<? extends Long, ? extends V> e : m.entrySet()) {
put(e.getKey(), e.getValue());
}
}
}
@ -243,7 +270,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
* @see java.util.Map#keySet()
*/
@Override
public Set<K> keySet() {
public Set<Long> keySet() {
processQueue();
return mapDelegate.keySet();
}
@ -256,7 +283,7 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
processQueue();
ArrayList<V> list = new ArrayList<>();
for (AggregatedSoftReference refs : mapDelegate.values()) {
for (AggregatedSoftReference<V> refs : mapDelegate.values()) {
V value = refs.get();
if (value != null) {
list.add(value);
@ -266,20 +293,29 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
return list;
}
/**
* @see java.util.Map#entrySet()
*/
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
public Set<Entry<Long, V>> entrySet() {
return null;
}
@Override
public Iterable<PrimitiveEntry<V>> entries() {
processQueue();
HashSet<Map.Entry<K, V>> set = new HashSet<>();
for (Map.Entry<K, AggregatedSoftReference> pair : mapDelegate.entrySet()) {
V value = pair.getValue().get();
final int size = mapDelegate.size();
final List<PrimitiveEntry<V>> entries = new ArrayList<>(size);
for (PrimitiveEntry<AggregatedSoftReference<V>> pair : mapDelegate.entries()) {
V value = pair.value().get();
if (value != null) {
set.add(new EntryElement<>(pair.getKey(), value));
entries.add(new EntryElement<>(pair.key(), value));
}
}
return set;
return entries;
}
@Override
public boolean containsKey(long key) {
processQueue();
return mapDelegate.containsKey(key);
}
/**
@ -315,15 +351,15 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
}
}
private AggregatedSoftReference createReference(final K key, final V value) {
return new AggregatedSoftReference(key, value);
private AggregatedSoftReference createReference(final long key, final V value) {
return new AggregatedSoftReference(key, value, refQueue);
}
// Inner classes -------------------------------------------------
class AggregatedSoftReference extends SoftReference<V> {
static final class AggregatedSoftReference<V> extends SoftReference<V> {
final K key;
final long key;
long used = 0;
@ -331,11 +367,11 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
return used;
}
public void used() {
used = usedCounter.incrementAndGet();
public void used(long value) {
this.used = value;
}
AggregatedSoftReference(final K key, final V referent) {
AggregatedSoftReference(final long key, final V referent, ReferenceQueue<V> refQueue) {
super(referent, refQueue);
this.key = key;
}
@ -346,40 +382,31 @@ public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implemen
}
}
static final class EntryElement<K, V> implements Map.Entry<K, V> {
static final class EntryElement<V> implements LongObjectMap.PrimitiveEntry<V> {
final K key;
final long key;
volatile V value;
final V value;
EntryElement(final K key, final V value) {
EntryElement(final long key, final V value) {
this.key = key;
this.value = value;
}
/* (non-Javadoc)
* @see java.util.Map.Entry#getKey()
*/
@Override
public K getKey() {
public long key() {
return key;
}
/* (non-Javadoc)
* @see java.util.Map.Entry#getValue()
*/
@Override
public V getValue() {
public V value() {
return value;
}
/* (non-Javadoc)
* @see java.util.Map.Entry#setValue(java.lang.Object)
*/
@Override
public V setValue(final V value) {
this.value = value;
return value;
@Deprecated
public void setValue(V value) {
throw new UnsupportedOperationException();
}
}

View File

@ -17,9 +17,9 @@
package org.apache.activemq.artemis.core.paging.cursor;
import org.apache.activemq.artemis.core.paging.PagedMessage;
import org.apache.activemq.artemis.utils.SoftValueHashMap;
import org.apache.activemq.artemis.utils.SoftValueLongObjectHashMap;
public interface PageCache extends SoftValueHashMap.ValueCache {
public interface PageCache extends SoftValueLongObjectHashMap.ValueCache {
long getPageId();

View File

@ -19,8 +19,6 @@ package org.apache.activemq.artemis.core.paging.cursor.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@ -39,8 +37,9 @@ import org.apache.activemq.artemis.core.persistence.StorageManager;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.transaction.Transaction;
import org.apache.activemq.artemis.core.transaction.impl.TransactionImpl;
import org.apache.activemq.artemis.utils.SoftValueHashMap;
import org.apache.activemq.artemis.utils.SoftValueLongObjectHashMap;
import org.apache.activemq.artemis.utils.actors.ArtemisExecutor;
import org.apache.activemq.artemis.utils.collections.ConcurrentLongHashMap;
import org.jboss.logging.Logger;
/**
@ -70,9 +69,9 @@ public class PageCursorProviderImpl implements PageCursorProvider {
// This is the same executor used at the PageStoreImpl. One Executor per pageStore
private final ArtemisExecutor executor;
private final SoftValueHashMap<Long, PageCache> softCache;
private final SoftValueLongObjectHashMap<PageCache> softCache;
private final ConcurrentMap<Long, PageSubscription> activeCursors = new ConcurrentHashMap<>();
private final ConcurrentLongHashMap<PageSubscription> activeCursors = new ConcurrentLongHashMap<>();
// Static --------------------------------------------------------
@ -85,7 +84,7 @@ public class PageCursorProviderImpl implements PageCursorProvider {
this.pagingStore = pagingStore;
this.storageManager = storageManager;
this.executor = executor;
this.softCache = new SoftValueHashMap<>(maxCacheSize);
this.softCache = new SoftValueLongObjectHashMap<>(maxCacheSize);
}
// Public --------------------------------------------------------

View File

@ -17,7 +17,7 @@
package org.apache.activemq.artemis.tests.unit.util;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.apache.activemq.artemis.utils.SoftValueHashMap;
import org.apache.activemq.artemis.utils.SoftValueLongObjectHashMap;
import org.junit.Test;
public class SoftValueMapTest extends ActiveMQTestBase {
@ -40,7 +40,7 @@ public class SoftValueMapTest extends ActiveMQTestBase {
// each buffer will be 1/10th of the maxMemory
int bufferSize = (int) (maxMemory / 100);
SoftValueHashMap<Long, Value> softCache = new SoftValueHashMap<>(100);
SoftValueLongObjectHashMap<Value> softCache = new SoftValueLongObjectHashMap<>(100);
final int MAX_ELEMENTS = 1000;
@ -59,7 +59,7 @@ public class SoftValueMapTest extends ActiveMQTestBase {
public void testEvictionsLeastUsed() {
forceGC();
SoftValueHashMap<Long, Value> softCache = new SoftValueHashMap<>(200);
SoftValueLongObjectHashMap<Value> softCache = new SoftValueLongObjectHashMap<>(200);
for (long i = 0; i < 100; i++) {
Value v = new Value(new byte[1]);
@ -99,7 +99,7 @@ public class SoftValueMapTest extends ActiveMQTestBase {
Value two = new Value(new byte[100]);
Value three = new Value(new byte[100]);
SoftValueHashMap<Integer, Value> softCache = new SoftValueHashMap<>(2);
SoftValueLongObjectHashMap<Value> softCache = new SoftValueLongObjectHashMap<>(2);
softCache.put(3, three);
softCache.put(2, two);
softCache.put(1, one);
@ -110,7 +110,7 @@ public class SoftValueMapTest extends ActiveMQTestBase {
}
class Value implements SoftValueHashMap.ValueCache {
class Value implements SoftValueLongObjectHashMap.ValueCache {
byte[] payload;
@ -121,7 +121,7 @@ public class SoftValueMapTest extends ActiveMQTestBase {
}
/* (non-Javadoc)
* @see org.apache.activemq.artemis.utils.SoftValueHashMap.ValueCache#isLive()
* @see org.apache.activemq.artemis.utils.SoftValueLongObjectHashMap.ValueCache#isLive()
*/
@Override
public boolean isLive() {