X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatabroker%2Factors%2Fdds%2FAbstractProxyTransaction.java;h=549cab269fb7682b4575c141243dda12b028d23f;hb=4ddfbaf460366ef4194e15c19649039a7d616399;hp=bf56376fcee3d538d483a063d652ae6d3d5a5654;hpb=7933189a19f5c0f58b91baea300a2f512aac154f;p=controller.git diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractProxyTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractProxyTransaction.java index bf56376fce..549cab269f 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractProxyTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractProxyTransaction.java @@ -91,7 +91,10 @@ abstract class AbstractProxyTransaction implements Identifiable + * When a user operation encounters this state, it synchronizes on the it and wait until reconnection completes, + * at which point the request is routed to the successor transaction. This is a relatively heavy-weight solution + * to the problem of state transfer, but the user will observe it only if the race condition is hit. + */ private static final class SuccessorState extends State { private final CountDownLatch latch = new CountDownLatch(1); private AbstractProxyTransaction successor; private State prevState; SuccessorState() { - super("successor"); + super("SUCCESSOR"); } // Synchronize with succession process and return the successor @@ -135,7 +148,8 @@ abstract class AbstractProxyTransaction implements Identifiable STATE_UPDATER = AtomicReferenceFieldUpdater.newUpdater(AbstractProxyTransaction.class, State.class, "state"); - private static final State OPEN = new State("open"); - private static final State SEALED = new State("sealed"); - private static final State FLUSHED = new State("flushed"); + + /** + * Transaction has been open and is being actively worked on. + */ + private static final State OPEN = new State("OPEN"); + + /** + * Transaction has been sealed by the user, but it has not completed flushing to the backed, yet. This is + * a transition state, as we are waiting for the user to initiate commit procedures. + * + *

+ * Since the reconnect mechanics relies on state replay for transactions, this state needs to be flushed into the + * queue to re-create state in successor transaction (which may be based on different messages as locality may have + * changed). Hence the transition to {@link #FLUSHED} state needs to be handled in a thread-safe manner. + */ + private static final State SEALED = new State("SEALED"); + + /** + * Transaction state has been flushed into the queue, i.e. it is visible by the successor and potentially + * the backend. At this point the transaction does not hold any state besides successful requests, all other state + * is held either in the connection's queue or the successor object. + * + *

+ * Transition to this state indicates we have all input from the user we need to initiate the correct commit + * protocol. + */ + private static final State FLUSHED = new State("FLUSHED"); + + /** + * Transaction state has been completely resolved, we have received confirmation of the transaction fate from + * the backend. The only remaining task left to do is finishing up the state cleanup, which is done via purge + * request. We need to hang on to the transaction until that is done, as we have to make sure backend completes + * purging its state -- otherwise we could have a leak on the backend. + */ + private static final State DONE = new State("DONE"); // Touched from client actor thread only private final Deque successfulRequests = new ArrayDeque<>(); @@ -543,9 +590,13 @@ abstract class AbstractProxyTransaction implements Identifiable enqueuedEntries) { + final void replayMessages(final ProxyHistory successorHistory, final Iterable enqueuedEntries) { final SuccessorState local = getSuccessorState(); + final State prevState = local.getPrevState(); + + final AbstractProxyTransaction successor = successorHistory.createTransactionProxy(getIdentifier(), + isSnapshotOnly()); + LOG.debug("{} created successor transaction proxy {}", this, successor); local.setSuccessor(successor); // Replay successful requests first @@ -593,7 +644,6 @@ abstract class AbstractProxyTransaction implements Identifiable