ARTEMIS-1702 ConcurrentLongHashMap and ConcurrentLongHashSet should avoid volatile set cost on put/remove

Most of the visibility guarantees of size/capacity fields modifications are already provided through optimistic locking, hence it could be used it instead of volatile set(s) on put/remove, making those methods more efficient.
This commit is contained in:
Francesco Nigro 2018-02-26 10:05:02 +01:00 committed by Clebert Suconic
parent 42f3828a37
commit 60dbeae438
2 changed files with 28 additions and 12 deletions

View File

@ -20,17 +20,17 @@
*/
package org.apache.activemq.artemis.utils.collections;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.locks.StampedLock;
import java.util.function.LongFunction;
import com.google.common.collect.Lists;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Map from long to an Object.
*
@ -81,6 +81,9 @@ public class ConcurrentLongHashMap<V> {
public int size() {
int size = 0;
for (Section<V> s : sections) {
//read-acquire s.size that was write-released by s.unlockWrite
s.tryOptimisticRead();
//a stale value won't hurt: anyway it's subject to concurrent modifications
size += s.size;
}
return size;
@ -104,6 +107,9 @@ public class ConcurrentLongHashMap<V> {
public boolean isEmpty() {
for (Section<V> s : sections) {
//read-acquire s.size that was write-released by s.unlockWrite
s.tryOptimisticRead();
//a stale value won't hurt: anyway it's subject to concurrent modifications
if (s.size != 0) {
return false;
}
@ -196,11 +202,13 @@ public class ConcurrentLongHashMap<V> {
// A section is a portion of the hash map that is covered by a single
@SuppressWarnings("serial")
private static final class Section<V> extends StampedLock {
private static final AtomicIntegerFieldUpdater<Section> CAPACITY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Section.class, "capacity");
private long[] keys;
private V[] values;
private volatile int capacity;
private volatile int size;
private int size;
private int usedBuckets;
private int resizeThreshold;
@ -460,8 +468,8 @@ public class ConcurrentLongHashMap<V> {
keys = newKeys;
values = newValues;
usedBuckets = size;
capacity = newCapacity;
resizeThreshold = (int) (capacity * MapFillFactor);
CAPACITY_UPDATER.lazySet(this, newCapacity);
resizeThreshold = (int) (newCapacity * MapFillFactor);
}
private static <V> void insertKeyValueNoLock(long[] keys, V[] values, long key, V value) {

View File

@ -20,13 +20,14 @@
*/
package org.apache.activemq.artemis.utils.collections;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.locks.StampedLock;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Concurrent hash set for primitive longs
*
@ -77,6 +78,9 @@ public class ConcurrentLongHashSet {
public int size() {
int size = 0;
for (Section s : sections) {
//read-acquire s.size that was write-released by s.unlockWrite
s.tryOptimisticRead();
//a stale value won't hurt: anyway it's subject to concurrent modifications
size += s.size;
}
return size;
@ -92,6 +96,9 @@ public class ConcurrentLongHashSet {
public boolean isEmpty() {
for (Section s : sections) {
//read-acquire s.size that was write-released by s.unlockWrite
s.tryOptimisticRead();
//a stale value won't hurt: anyway it's subject to concurrent modifications
if (s.size != 0) {
return false;
}
@ -162,11 +169,12 @@ public class ConcurrentLongHashSet {
// A section is a portion of the hash map that is covered by a single
@SuppressWarnings("serial")
private static final class Section extends StampedLock {
private static final AtomicIntegerFieldUpdater<Section> CAPACITY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Section.class, "capacity");
// Keys and values are stored interleaved in the table array
private long[] table;
private volatile int capacity;
private volatile int size;
private int size;
private int usedBuckets;
private int resizeThreshold;
@ -376,8 +384,8 @@ public class ConcurrentLongHashSet {
table = newTable;
usedBuckets = size;
capacity = newCapacity;
resizeThreshold = (int) (capacity * SetFillFactor);
CAPACITY_UPDATER.lazySet(this, newCapacity);
resizeThreshold = (int) (newCapacity * SetFillFactor);
}
private static void insertKeyValueNoLock(long[] table, int capacity, long item) {