This is an automated email from the ASF dual-hosted git repository.
kturner pushed a commit to branch 2.1
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/2.1 by this push:
new 2cdefa30b8 reduce scan thread contention on native maps (#4910)
2cdefa30b8 is described below
commit 2cdefa30b83366cb3fc8115083333a95b51285d6
Author: Keith Turner <[email protected]>
AuthorDate: Fri Sep 20 16:33:54 2024 -0400
reduce scan thread contention on native maps (#4910)
Observed many scan threads in the native map code attempting to create
a native map iterator and blocking in registering a cleaner for the
iterator. The block was happening in
jdk.internal.rf.PhantomCleanable.insert()
which has a synchronized code block. There is a single static cleaner
object on the accumulo code so all scan threads that internact with a
native map could end up contending on this single lock in the process.
This change creates 8 cleaners and therefore 8 locks to reduce the
contention between scan threads.
Co-authored-by: Christopher Tubbs <[email protected]>
---
.../accumulo/tserver/NativeMapCleanerUtil.java | 27 ++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git
a/server/tserver/src/main/java/org/apache/accumulo/tserver/NativeMapCleanerUtil.java
b/server/tserver/src/main/java/org/apache/accumulo/tserver/NativeMapCleanerUtil.java
index 944789c1aa..12c1509807 100644
---
a/server/tserver/src/main/java/org/apache/accumulo/tserver/NativeMapCleanerUtil.java
+++
b/server/tserver/src/main/java/org/apache/accumulo/tserver/NativeMapCleanerUtil.java
@@ -20,6 +20,7 @@ package org.apache.accumulo.tserver;
import static java.util.Objects.requireNonNull;
+import java.lang.ref.Cleaner;
import java.lang.ref.Cleaner.Cleanable;
import java.util.concurrent.atomic.AtomicLong;
@@ -43,14 +44,36 @@ public class NativeMapCleanerUtil {
});
}
+ // Chose 7 cleaners because each cleaner creates a thread, so do not want
too many threads. This
+ // should reduce lock contention for scans by a 7th vs a single cleaner, so
that is good
+ // reduction and 7 does not seem like too many threads to add. This array is
indexed using
+ // pointers addresses from native code, so there is a good chance those are
memory aligned on
+ // a multiple of 4, 8, 16, etc. So if changing the array size avoid
multiples of 2.
+ private static final Cleaner[] NMI_CLEANERS = new Cleaner[7];
+
+ static {
+ for (int i = 0; i < NMI_CLEANERS.length; i++) {
+ NMI_CLEANERS[i] = Cleaner.create();
+ }
+ }
+
public static Cleanable deleteNMIterator(Object obj, AtomicLong nmiPtr) {
requireNonNull(nmiPtr);
- return CleanerUtil.CLEANER.register(obj, () -> {
+
+ int cleanerIndex = (int) (nmiPtr.get() % NMI_CLEANERS.length);
+ if (cleanerIndex < 0) {
+ cleanerIndex += NMI_CLEANERS.length;
+ }
+
+ // This method can be called very frequently by many scan threads. The
register call on cleaner
+ // acquires a lock which can cause lock contention between threads. Having
multiple cleaners for
+ // this case lowers the amount of lock contention among scan threads. This
locking was observed
+ // in jdk.internal.rf.PhantomCleanable.insert() which currently has a
synchronized code block.
+ return NMI_CLEANERS[cleanerIndex].register(obj, () -> {
long nmiPointer = nmiPtr.get();
if (nmiPointer != 0) {
NativeMap._deleteNMI(nmiPointer);
}
});
}
-
}