Skip to content

Commit 985b50e

Browse files
committed
nlm: improve concurrency of simple lock manager
Motivation: when a large number of concurrent applications competing for file locks, then SimpleLm will serialise all request as a single lock object is used for all files. To reduce lock conjunction and improve concurrency a serialization per lock subject (file) is a better option. Modification: Use Striped lock to partition locks. The number of partition is equal 4x#CPUs. It's guaranteed, that for the same file, the same lock will be used. Result: Better lock throughput. Acked-by: Paul Millar Target: master Require-book: no Require-notes: no
1 parent 6b2284b commit 985b50e

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

core/src/main/java/org/dcache/nfs/v4/nlm/SimpleLm.java

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
import com.google.common.collect.ArrayListMultimap;
2323
import com.google.common.collect.Multimap;
2424
import com.google.common.io.BaseEncoding;
25+
import com.google.common.util.concurrent.Striped;
2526
import java.util.Collection;
2627
import java.util.concurrent.locks.Lock;
27-
import java.util.concurrent.locks.ReentrantLock;
2828

2929
/**
3030
* Simple non-distributed implementation of {@link LockManager}.
@@ -33,10 +33,17 @@
3333
*/
3434
public class SimpleLm extends AbstractLockManager {
3535

36-
/**
37-
* Exclusive lock on file object.
36+
/*
37+
* Use {@link Striped} here to split synchronized block on file locks into
38+
* multiple partitions to increase concurrency, while guaranteeing atomicity
39+
* on a single file.
40+
*
41+
* Use number of stripes equals to 4x#CPU. This matches to number of
42+
* worker threads configured by default.
43+
*
44+
* FIXME: get number of threads from RPC service.
3845
*/
39-
private final Lock objLock = new ReentrantLock();
46+
private final Striped<Lock> objLock = Striped.lock(Runtime.getRuntime().availableProcessors() * 4);
4047

4148
/**
4249
* Exclusive lock on objects locks.
@@ -45,37 +52,42 @@ public class SimpleLm extends AbstractLockManager {
4552

4653
@Override
4754
protected Lock getObjectLock(byte[] objId) {
48-
return objLock;
55+
String key = toKey(objId);
56+
return objLock.get(key);
4957
}
5058

5159
@Override
5260
protected Collection<NlmLock> getActiveLocks(byte[] objId) {
53-
String key = BaseEncoding.base16().lowerCase().encode(objId);
61+
String key = toKey(objId);
5462
return locks.get(key);
5563
}
5664

5765
@Override
5866
protected void add(byte[] objId, NlmLock lock) {
59-
String key = BaseEncoding.base16().lowerCase().encode(objId);
67+
String key = toKey(objId);
6068
locks.put(key, lock);
6169
}
6270

6371
@Override
6472
protected boolean remove(byte[] objId, NlmLock lock) {
65-
String key = BaseEncoding.base16().lowerCase().encode(objId);
73+
String key = toKey(objId);
6674
return locks.remove(key, lock);
6775
}
6876

6977
@Override
7078
protected void addAll(byte[] objId, Collection<NlmLock> locks) {
71-
String key = BaseEncoding.base16().lowerCase().encode(objId);
79+
String key = toKey(objId);
7280
locks.forEach(l -> this.locks.put(key, l));
7381
}
7482

7583
@Override
7684
protected void removeAll(byte[] objId, Collection<NlmLock> locks) {
77-
String key = BaseEncoding.base16().lowerCase().encode(objId);
85+
String key = toKey(objId);
7886
locks.forEach(l -> this.locks.remove(key, l));
7987
}
8088

89+
private final String toKey(byte[] objId) {
90+
return BaseEncoding.base16().lowerCase().encode(objId);
91+
}
92+
8193
}

0 commit comments

Comments
 (0)