From 3ad279b8fd02d695d04f47862e372760712c26a0 Mon Sep 17 00:00:00 2001 From: Brian Murphy Date: Tue, 21 Apr 2015 13:58:21 -0400 Subject: [PATCH] Add `fairness` option to KeyedLock. This change adds the ability of a `KeyedLock` to be `fair` this means that threads will aquire the lock in the order they ask for it. --- .../common/util/concurrent/KeyedLock.java | 31 +++++++++++++++++-- .../transport/netty/KeyedLockTests.java | 2 +- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/elasticsearch/common/util/concurrent/KeyedLock.java b/src/main/java/org/elasticsearch/common/util/concurrent/KeyedLock.java index 862bc6d9645..523f7b92f74 100644 --- a/src/main/java/org/elasticsearch/common/util/concurrent/KeyedLock.java +++ b/src/main/java/org/elasticsearch/common/util/concurrent/KeyedLock.java @@ -39,6 +39,19 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * */ public class KeyedLock { + private final boolean fair; + + /** + * @param fair Use fair locking, ie threads get the lock in the order they requested it + */ + public KeyedLock(boolean fair) { + this.fair = fair; + } + + public KeyedLock() { + this(false); + } + private final ConcurrentMap map = ConcurrentCollections.newConcurrentMap(); protected final ThreadLocal threadLocal = new ThreadLocal<>(); @@ -52,7 +65,7 @@ public class KeyedLock { } KeyLock perNodeLock = map.get(key); if (perNodeLock == null) { - KeyLock newLock = new KeyLock(); + KeyLock newLock = new KeyLock(fair); perNodeLock = map.putIfAbsent(key, newLock); if (perNodeLock == null) { newLock.lock(); @@ -92,6 +105,10 @@ public class KeyedLock { @SuppressWarnings("serial") private final static class KeyLock extends ReentrantLock { + KeyLock(boolean fair) { + super(fair); + } + private final AtomicInteger count = new AtomicInteger(1); } @@ -105,7 +122,17 @@ public class KeyedLock { */ public final static class GlobalLockable extends KeyedLock { - private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + private final ReadWriteLock lock; + + public GlobalLockable(boolean fair){ + super(fair); + lock = new ReentrantReadWriteLock(fair); + } + + public GlobalLockable() { + this(false); + } @Override public void acquire(T key) { diff --git a/src/test/java/org/elasticsearch/transport/netty/KeyedLockTests.java b/src/test/java/org/elasticsearch/transport/netty/KeyedLockTests.java index 07d5751ba96..d8be9b704c6 100644 --- a/src/test/java/org/elasticsearch/transport/netty/KeyedLockTests.java +++ b/src/test/java/org/elasticsearch/transport/netty/KeyedLockTests.java @@ -40,7 +40,7 @@ public class KeyedLockTests extends ElasticsearchTestCase { public void checkIfMapEmptyAfterLotsOfAcquireAndReleases() throws InterruptedException { ConcurrentHashMap counter = new ConcurrentHashMap<>(); ConcurrentHashMap safeCounter = new ConcurrentHashMap<>(); - KeyedLock connectionLock = randomBoolean() ? new KeyedLock.GlobalLockable() : new KeyedLock(); + KeyedLock connectionLock = randomBoolean() ? new KeyedLock.GlobalLockable(randomBoolean()) : new KeyedLock(randomBoolean()); String[] names = new String[randomIntBetween(1, 40)]; for (int i = 0; i < names.length; i++) { names[i] = randomRealisticUnicodeOfLengthBetween(10, 20);