Skip to content

Commit 805c7b4

Browse files
committed
nlm: use ConcurrentHashMap to store the locks
Though access to the lock storage serialized for the same file, the Multimap still throws ConcurrentModificationException. Use ConcurrentHashMap to store locks as it gives a better throughput: // Multimaps#synchronizedListMultimap Result "org.dcache.nfs.v4.nlm.SimpleLmBenchmark.benchmarkConcurrentLocking": 437057.460 ±(99.9%) 18574.458 ops/s [Average] (min, avg, max) = (372606.415, 437057.460, 467748.621), stdev = 24796.370 CI (99.9%): [418483.001, 455631.918] (assumes normal distribution) // ConcurrentHashMap Result "org.dcache.nfs.v4.nlm.SimpleLmBenchmark.benchmarkConcurrentLocking": 744594.337 ±(99.9%) 45860.571 ops/s [Average] (min, avg, max) = (592325.817, 744594.337, 847798.786), stdev = 61222.550 CI (99.9%): [698733.766, 790454.908] (assumes normal distribution) Fixes: #70 Acked-by: Paul Millar Target: master, 0.17
1 parent 92e12da commit 805c7b4

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

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

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
*/
2020
package org.dcache.nfs.v4.nlm;
2121

22-
import com.google.common.collect.ArrayListMultimap;
23-
import com.google.common.collect.Multimap;
2422
import com.google.common.io.BaseEncoding;
2523
import com.google.common.util.concurrent.Striped;
24+
import java.util.ArrayList;
2625
import java.util.Collection;
26+
import java.util.Collections;
27+
import java.util.List;
28+
import java.util.concurrent.ConcurrentHashMap;
2729
import java.util.concurrent.locks.Lock;
2830

2931
/**
@@ -48,7 +50,7 @@ public class SimpleLm extends AbstractLockManager {
4850
/**
4951
* Exclusive lock on objects locks.
5052
*/
51-
private final Multimap<String, NlmLock> locks = ArrayListMultimap.create();
53+
private final ConcurrentHashMap<String, List<NlmLock>> locks = new ConcurrentHashMap<>();
5254

5355
@Override
5456
protected Lock getObjectLock(byte[] objId) {
@@ -59,31 +61,47 @@ protected Lock getObjectLock(byte[] objId) {
5961
@Override
6062
protected Collection<NlmLock> getActiveLocks(byte[] objId) {
6163
String key = toKey(objId);
62-
return locks.get(key);
64+
return locks.getOrDefault(key, Collections.emptyList());
6365
}
6466

6567
@Override
6668
protected void add(byte[] objId, NlmLock lock) {
6769
String key = toKey(objId);
68-
locks.put(key, lock);
70+
Collection<NlmLock> l = locks.computeIfAbsent(key, k -> new ArrayList<>());
71+
l.add(lock);
6972
}
7073

7174
@Override
7275
protected boolean remove(byte[] objId, NlmLock lock) {
7376
String key = toKey(objId);
74-
return locks.remove(key, lock);
77+
Collection<NlmLock> l = locks.get(key);
78+
boolean isRemoved = false;
79+
if (l != null) {
80+
isRemoved = l.remove(lock);
81+
if (l.isEmpty()) {
82+
locks.remove(key);
83+
}
84+
}
85+
return isRemoved;
7586
}
7687

7788
@Override
7889
protected void addAll(byte[] objId, Collection<NlmLock> locks) {
7990
String key = toKey(objId);
80-
locks.forEach(l -> this.locks.put(key, l));
91+
Collection<NlmLock> l = this.locks.computeIfAbsent(key, k -> new ArrayList<>());
92+
l.addAll(locks);
8193
}
8294

8395
@Override
8496
protected void removeAll(byte[] objId, Collection<NlmLock> locks) {
8597
String key = toKey(objId);
86-
locks.forEach(l -> this.locks.remove(key, l));
98+
Collection<NlmLock> l = this.locks.get(key);
99+
if (l != null) {
100+
l.removeAll(locks);
101+
if (l.isEmpty()) {
102+
this.locks.remove(key);
103+
}
104+
}
87105
}
88106

89107
private final String toKey(byte[] objId) {

0 commit comments

Comments
 (0)