You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2018/02/26 22:38:43 UTC
[2/2] activemq-artemis git commit: ARTEMIS-1702 ConcurrentLongHashMap
and ConcurrentLongHashSet should avoid volatile set cost on put/remove
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.
Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/60dbeae4
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/60dbeae4
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/60dbeae4
Branch: refs/heads/master
Commit: 60dbeae4381abbc809ae2ccc73ca501557e66093
Parents: 42f3828
Author: Francesco Nigro <ni...@gmail.com>
Authored: Mon Feb 26 10:05:02 2018 +0100
Committer: Clebert Suconic <cl...@apache.org>
Committed: Mon Feb 26 17:38:36 2018 -0500
----------------------------------------------------------------------
.../collections/ConcurrentLongHashMap.java | 22 +++++++++++++-------
.../collections/ConcurrentLongHashSet.java | 18 +++++++++++-----
2 files changed, 28 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/60dbeae4/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashMap.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashMap.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashMap.java
index 34a0e60..29917c9 100644
--- a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashMap.java
+++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashMap.java
@@ -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) {
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/60dbeae4/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashSet.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashSet.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashSet.java
index 8344c57..d2fb907 100644
--- a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashSet.java
+++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/ConcurrentLongHashSet.java
@@ -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) {