From a251ab61bbdec24e2637bd7558648aa1a19a5bf7 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 19 Aug 2019 17:07:09 +0200 Subject: [PATCH] Relax read-only snapshot memory fencing With Java 9 we can use VarHandles to reduce memory ordering guarantees from volatile to acquire/releases. Use this facility to disconnect ReadOnlyTrieMap from other volatiles, potentially helping the compiler to do a better job optimizing. Change-Id: Ibd266a5a341bcdaae25702476610c10eeb0ea374 Signed-off-by: Robert Varga --- .../yangtools/util/ReadOnlyTrieMap.java | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/ReadOnlyTrieMap.java b/common/util/src/main/java/org/opendaylight/yangtools/util/ReadOnlyTrieMap.java index c0402840b7..2407ed7ad1 100644 --- a/common/util/src/main/java/org/opendaylight/yangtools/util/ReadOnlyTrieMap.java +++ b/common/util/src/main/java/org/opendaylight/yangtools/util/ReadOnlyTrieMap.java @@ -10,8 +10,8 @@ package org.opendaylight.yangtools.util; import static java.util.Objects.requireNonNull; import com.google.common.collect.ForwardingMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tech.pantheon.triemap.ImmutableTrieMap; @@ -25,39 +25,50 @@ import tech.pantheon.triemap.MutableTrieMap; * changes, we can cache it for future reference. */ final class ReadOnlyTrieMap extends ForwardingMap { - @SuppressWarnings("rawtypes") - private static final AtomicReferenceFieldUpdater UPDATER = - AtomicReferenceFieldUpdater.newUpdater(ReadOnlyTrieMap.class, ImmutableTrieMap.class, "readOnly"); private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTrieMap.class); + private static final VarHandle READ_ONLY; + + static { + try { + READ_ONLY = MethodHandles.lookup().findVarHandle(ReadOnlyTrieMap.class, "readOnly", ImmutableTrieMap.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } + private final MutableTrieMap readWrite; private final int size; - private volatile ImmutableTrieMap readOnly; + + // Used via the varhandle + @SuppressWarnings("unused") + private ImmutableTrieMap readOnly; ReadOnlyTrieMap(final MutableTrieMap map, final int size) { this.readWrite = requireNonNull(map); this.size = size; } - Map toReadWrite() { - final Map ret = new ReadWriteTrieMap<>(readWrite.mutableSnapshot(), size); + ReadWriteTrieMap toReadWrite() { + final ReadWriteTrieMap ret = new ReadWriteTrieMap<>(readWrite.mutableSnapshot(), size); LOG.trace("Converted read-only TrieMap {} to read-write {}", this, ret); return ret; } @Override - protected Map delegate() { - ImmutableTrieMap ret = readOnly; - if (ret == null) { - ret = readWrite.immutableSnapshot(); - if (!UPDATER.compareAndSet(this, null, ret)) { - ret = readOnly; - } - } - return ret; + protected ImmutableTrieMap delegate() { + final ImmutableTrieMap ret = (ImmutableTrieMap) READ_ONLY.getAcquire(this); + return ret != null ? ret : loadReadOnly(); } @Override public int size() { return size; } + + @SuppressWarnings("unchecked") + private ImmutableTrieMap loadReadOnly() { + final ImmutableTrieMap ret = readWrite.immutableSnapshot(); + final Object witness = READ_ONLY.compareAndExchangeRelease(this, null, ret); + return witness == null ? ret : (ImmutableTrieMap) witness; + } } -- 2.36.6