Skip to content

Commit 1ae63ac

Browse files
Optimize KeyedLock and related concurrency primitives (#96372)
This class was quite hot in recent benchmarks of shared-cached based searches and we can make instantiating the releasable locks a little cheaper. Also, those same benchmarks showed a lot of visible time spent on dealing with ref counts. I removed one layer of indirection in atomic use from both the release-once and the abstract ref count which should save a little in CPU caches as well.
1 parent 0a7bb64 commit 1ae63ac

File tree

2 files changed

+22
-19
lines changed

2 files changed

+22
-19
lines changed

libs/core/src/main/java/org/elasticsearch/core/Releasables.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,7 @@ public String toString() {
122122
* Wraps a {@link Releasable} such that its {@link Releasable#close()} method can be called multiple times without double-releasing.
123123
*/
124124
public static Releasable releaseOnce(final Releasable releasable) {
125-
final var ref = new AtomicReference<>(releasable);
126-
return new Releasable() {
127-
@Override
128-
public void close() {
129-
final var acquired = ref.getAndSet(null);
130-
if (acquired != null) {
131-
acquired.close();
132-
}
133-
}
134-
135-
@Override
136-
public String toString() {
137-
return "releaseOnce[" + ref.get() + "]";
138-
}
139-
};
125+
return new ReleaseOnce(releasable);
140126
}
141127

142128
public static Releasable assertOnce(final Releasable delegate) {
@@ -165,4 +151,23 @@ public String toString() {
165151
return delegate;
166152
}
167153
}
154+
155+
private static class ReleaseOnce extends AtomicReference<Releasable> implements Releasable {
156+
ReleaseOnce(Releasable releasable) {
157+
super(releasable);
158+
}
159+
160+
@Override
161+
public void close() {
162+
final var acquired = getAndSet(null);
163+
if (acquired != null) {
164+
acquired.close();
165+
}
166+
}
167+
168+
@Override
169+
public String toString() {
170+
return "releaseOnce[" + get() + "]";
171+
}
172+
}
168173
}

server/src/main/java/org/elasticsearch/common/util/concurrent/KeyedLock.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public Releasable acquire(T key) {
4040
return newLock;
4141
}
4242
} else {
43-
assert perNodeLock != null;
4443
int i = perNodeLock.count.get();
4544
if (i > 0 && perNodeLock.count.compareAndSet(i, i + 1)) {
4645
perNodeLock.lock();
@@ -104,10 +103,9 @@ private void release(T key, KeyLock lock) {
104103
assert decrementAndGet >= 0 : decrementAndGet + " must be >= 0 but wasn't";
105104
}
106105

107-
private final class ReleasableLock implements Releasable {
106+
private final class ReleasableLock extends AtomicBoolean implements Releasable {
108107
final T key;
109108
final KeyLock lock;
110-
final AtomicBoolean closed = new AtomicBoolean();
111109

112110
private ReleasableLock(T key, KeyLock lock) {
113111
this.key = key;
@@ -116,7 +114,7 @@ private ReleasableLock(T key, KeyLock lock) {
116114

117115
@Override
118116
public void close() {
119-
if (closed.compareAndSet(false, true)) {
117+
if (compareAndSet(false, true)) {
120118
release(key, lock);
121119
}
122120
}

0 commit comments

Comments
 (0)