BUG-5280: implement transaction dispatch
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / actors / dds / AbstractClientHistory.java
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractClientHistory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractClientHistory.java
new file mode 100644 (file)
index 0000000..f364994
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.databroker.actors.dds;
+
+import com.google.common.base.Preconditions;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for client view of a history. This class has two implementations, one for normal local histories
+ * and the other for single transactions.
+ *
+ * @author Robert Varga
+ */
+abstract class AbstractClientHistory extends LocalAbortable implements Identifiable<LocalHistoryIdentifier> {
+    static enum State {
+        IDLE,
+        TX_OPEN,
+        CLOSED,
+    }
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractClientHistory.class);
+    private static final AtomicReferenceFieldUpdater<AbstractClientHistory, State> STATE_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(AbstractClientHistory.class, State.class, "state");
+
+    private final Map<Long, LocalHistoryIdentifier> histories = new ConcurrentHashMap<>();
+    private final DistributedDataStoreClientBehavior client;
+    private final LocalHistoryIdentifier identifier;
+
+    private volatile State state = State.IDLE;
+
+    AbstractClientHistory(final DistributedDataStoreClientBehavior client, final LocalHistoryIdentifier identifier) {
+        this.client = Preconditions.checkNotNull(client);
+        this.identifier = Preconditions.checkNotNull(identifier);
+        Preconditions.checkArgument(identifier.getCookie() == 0);
+    }
+
+    final State state() {
+        return state;
+    }
+
+    final void updateState(final State expected, final State next) {
+        final boolean success = STATE_UPDATER.compareAndSet(this, expected, next);
+        Preconditions.checkState(success, "Race condition detected, state changed from %s to %s", expected, state);
+    }
+
+    final LocalHistoryIdentifier getHistoryForCookie(final Long cookie) {
+        LocalHistoryIdentifier ret = histories.get(cookie);
+        if (ret == null) {
+            ret = new LocalHistoryIdentifier(identifier.getClientId(), identifier.getHistoryId(), cookie);
+            final LocalHistoryIdentifier existing = histories.putIfAbsent(cookie, ret);
+            if (existing != null) {
+                ret = existing;
+            }
+        }
+
+        return ret;
+    }
+
+    @Override
+    public final LocalHistoryIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    final DistributedDataStoreClientBehavior getClient() {
+        return client;
+    }
+
+    @Override
+    final void localAbort(final Throwable cause) {
+        LOG.debug("Force-closing history {}", getIdentifier(), cause);
+        state = State.CLOSED;
+    }
+
+    /**
+     * Callback invoked from {@link ClientTransaction} when a transaction has been sub
+     *
+     * @param transaction Transaction handle
+     */
+    void onTransactionReady(final ClientTransaction transaction) {
+        client.transactionComplete(transaction);
+    }
+}