Fixup checkstyle
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / actors / dds / AbstractClientHandle.java
index b87819c34337a0435b02a3f98209f73a29aef7fe..d10627dcf93e065df03c5f5130da50303d9ecc79 100644 (file)
@@ -7,14 +7,17 @@
  */
 package org.opendaylight.controller.cluster.databroker.actors.dds;
 
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-import java.util.Collection;
+import com.google.common.base.MoreObjects;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import java.util.function.Function;
-import javax.annotation.Nullable;
+import java.util.stream.Stream;
+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;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -41,19 +44,20 @@ public abstract class AbstractClientHandle<T extends AbstractProxyTransaction> e
     private static final AtomicReferenceFieldUpdater<AbstractClientHandle, State> STATE_UPDATER =
             AtomicReferenceFieldUpdater.newUpdater(AbstractClientHandle.class, State.class, "state");
 
-    private final TransactionIdentifier transactionId;
-    private final AbstractClientHistory parent;
+    private final @NonNull TransactionIdentifier transactionId;
+    private final @NonNull AbstractClientHistory parent;
 
     private volatile State<T> state = new State<>();
 
     // Hidden to prevent outside instantiation
     AbstractClientHandle(final AbstractClientHistory parent, final TransactionIdentifier transactionId) {
-        this.transactionId = Preconditions.checkNotNull(transactionId);
-        this.parent = Preconditions.checkNotNull(parent);
+        this.transactionId = requireNonNull(transactionId);
+        this.parent = requireNonNull(parent);
     }
 
     @Override
-    public final TransactionIdentifier getIdentifier() {
+    // Non-final for mocking
+    public TransactionIdentifier getIdentifier() {
         return transactionId;
     }
 
@@ -62,7 +66,8 @@ public abstract class AbstractClientHandle<T extends AbstractProxyTransaction> e
      *
      * @return True if this transaction became closed during this call
      */
-    public final boolean abort() {
+    // Non-final for mocking
+    public boolean abort() {
         if (commonAbort()) {
             parent.onTransactionAbort(this);
             return true;
@@ -72,12 +77,13 @@ public abstract class AbstractClientHandle<T extends AbstractProxyTransaction> e
     }
 
     private boolean commonAbort() {
-        final Collection<T> toClose = ensureClosed();
+        final Map<Long, T> toClose = ensureClosed();
         if (toClose == null) {
             return false;
         }
 
-        toClose.forEach(AbstractProxyTransaction::abort);
+        toClose.values().forEach(AbstractProxyTransaction::abort);
+        parent.onTransactionShardsBound(transactionId, toClose.keySet());
         return true;
     }
 
@@ -91,29 +97,44 @@ public abstract class AbstractClientHandle<T extends AbstractProxyTransaction> e
      * Make sure this snapshot is closed. If it became closed as the effect of this call, return a collection of
      * {@link AbstractProxyTransaction} handles which need to be closed, too.
      *
-     * @return null if this snapshot has already been closed, otherwise a collection of proxies, which need to be
+     * @return null if this snapshot has already been closed, otherwise a State with of proxies, which need to be
      *         closed, too.
      */
-    @Nullable final Collection<T> ensureClosed() {
-        @SuppressWarnings("unchecked")
-        final State<T> local = STATE_UPDATER.getAndSet(this, null);
-        return local == null ? null : local.values();
+    final @Nullable Map<Long, T> ensureClosed() {
+        // 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 : null;
     }
 
-    final T ensureProxy(final YangInstanceIdentifier path, final Function<Long, T> createProxy) {
-        final Map<Long, T> local = getState();
-        final Long shard = parent.resolveShardForPath(path);
+    final T ensureProxy(final YangInstanceIdentifier path) {
+        return ensureProxy(getState(), parent.resolveShardForPath(path));
+    }
+
+    private T ensureProxy(final State<T> localState, final Long shard) {
+        return localState.computeIfAbsent(shard, this::createProxy);
+    }
 
-        return local.computeIfAbsent(shard, createProxy);
+    final Stream<T> ensureAllProxies() {
+        final var local = getState();
+        return parent.resolveAllShards().map(shard -> ensureProxy(local, shard));
     }
 
     final AbstractClientHistory parent() {
         return parent;
     }
 
+    abstract @NonNull T createProxy(@NonNull Long shard);
+
     private State<T> getState() {
         final State<T> local = state;
-        Preconditions.checkState(local != null, "Transaction %s is closed", transactionId);
+        checkState(local != null, "Transaction %s is closed", transactionId);
         return local;
     }
+
+    @Override
+    public final String toString() {
+        return MoreObjects.toStringHelper(this).omitNullValues().add("identifier", transactionId).add("state", state)
+                .toString();
+    }
 }