Use java.lang.ref.Cleaner for ClientBackedTransaction
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / actors / dds / AbstractClientHandle.java
index 1246c2f7c740a3a6fa4a9183cf6320d989934cbd..842bc00d916ab1eae6c531cb4ceeddc971bdbc4c 100644 (file)
@@ -13,10 +13,9 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import java.util.Collection;
-import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import java.util.function.Function;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
 import org.opendaylight.yangtools.concepts.Identifiable;
@@ -98,22 +97,25 @@ public abstract class AbstractClientHandle<T extends AbstractProxyTransaction> e
      *         closed, too.
      */
     final @Nullable Collection<T> ensureClosed() {
-        @SuppressWarnings("unchecked")
-        final State<T> local = STATE_UPDATER.getAndSet(this, null);
-        return local == null ? null : local.values();
+        // volatile read and a conditional CAS. This ends up being better in the typical case when we are invoked more
+        // than once (see ClientBackedTransaction) than performing a STATE_UPDATER.getAndSet().
+        final State<T> local = state;
+        return local != null && STATE_UPDATER.compareAndSet(this, local, null) ? local.values() : null;
     }
 
-    final T ensureProxy(final YangInstanceIdentifier path, final Function<Long, T> createProxy) {
-        final Map<Long, T> local = getState();
+    final T ensureProxy(final YangInstanceIdentifier path) {
+        final State<T> local = getState();
         final Long shard = parent.resolveShardForPath(path);
 
-        return local.computeIfAbsent(shard, createProxy);
+        return local.computeIfAbsent(shard, this::createProxy);
     }
 
     final AbstractClientHistory parent() {
         return parent;
     }
 
+    abstract @NonNull T createProxy(@NonNull Long shard);
+
     private State<T> getState() {
         final State<T> local = state;
         checkState(local != null, "Transaction %s is closed", transactionId);