2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.dom.api;
10 import com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.util.concurrent.Executor;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.concepts.Registration;
17 import org.opendaylight.yangtools.yang.common.Empty;
20 * A chain of transactions. Transactions in a chain need to be committed in sequence and each transaction should see
21 * the effects of previous committed transactions as they occurred. A chain makes no guarantees of atomicity across
22 * the chained transactions - the transactions are committed as soon as possible in the order that they were committed.
23 * This behaviour is different from the default AsyncDataBroker, where a transaction is always created from the current
24 * global state, not taking into account any transactions previously committed by the calling thread. Due to
25 * the asynchronous nature of transaction submission this can lead to surprising results. If a thread executes
26 * the following sequence sufficiently quickly:
29 * DOMWriteTransaction t1 = broker.newWriteOnlyTransaction();
33 * DOMReadTransaction t2 = broker.newReadOnlyTransaction();
34 * Optional<?> maybeData = t2.read(id).get();
36 * it may happen, that it sees maybeData.isPresent() == false, simply because t1 has not completed the processes
37 * of being applied and t2 is actually allocated from the previous state. This is obviously bad for users who create
38 * incremental state in the datastore and actually read what they write in subsequent transactions.
39 * Using a TransactionChain instead of a broker solves this particular problem, and leads to expected behavior: t2 will
40 * always see the data written in t1
43 public interface DOMTransactionChain extends Registration, DOMTransactionFactory {
45 * Create a new read only transaction which will continue the chain.
48 * The previous write transaction has to be either SUBMITTED ({@link DOMDataTreeWriteTransaction#commit commit} was
49 * invoked) or CANCELLED ({@link #close close} was invoked).
52 * The returned read-only transaction presents an isolated view of the data if the previous write transaction was
53 * successful - in other words, this read-only transaction will see the state changes made by the previous write
54 * transaction in the chain. However, state which was introduced by other transactions outside this transaction
55 * chain after creation of the previous transaction is not visible.
57 * @return New transaction in the chain.
58 * @throws IllegalStateException if the previous transaction was not SUBMITTED or CANCELLED.
59 * @throws DOMTransactionChainClosedException if the chain has been closed.
62 DOMDataTreeReadTransaction newReadOnlyTransaction();
65 * Create a new write-only transaction which will continue the chain.
68 * The previous write transaction has to be either SUBMITTED ({@link DOMDataTreeWriteTransaction#commit commit} was
69 * invoked) or CANCELLED ({@link #close close} was invoked)
72 * The returned write-only transaction presents an isolated view of the data if the previous write transaction was
73 * successful - in other words, this write-only transaction will see the state changes made by the previous write
74 * transaction in the chain. However, state which was introduced by other transactions outside this transaction
75 * chain after creation of the previous transaction is not visible
78 * Committing this write-only transaction using {@link DOMDataTreeWriteTransaction#commit commit} will commit
79 * the state changes in this transaction to be visible to any subsequent transaction in this chain and also to any
80 * transaction outside this chain.
82 * @return New transaction in the chain.
83 * @throws IllegalStateException if the previous transaction was not SUBMITTED or CANCELLED.
84 * @throws DOMTransactionChainClosedException if the chain has been closed.
87 DOMDataTreeWriteTransaction newWriteOnlyTransaction();
90 * Create a new read-write transaction which will continue the chain.
93 * The previous write transaction has to be either SUBMITTED ({@link DOMDataTreeWriteTransaction#commit commit} was
94 * invoked) or CANCELLED ({@link #close close} was invoked).
97 * The returned read-write transaction presents an isolated view of the data if the previous write transaction was
98 * successful - in other words, this read-write transaction will see the state changes made by the previous write
99 * transaction in the chain. However, state which was introduced by other transactions outside this transaction
100 * chain after creation of the previous transaction is not visible.
103 * Committing this read-write transaction using {@link DOMDataTreeReadWriteTransaction#commit commit} will commit
104 * the state changes in this transaction to be visible to any subsequent transaction in this chain and also to any
105 * transaction outside this chain.
107 * @return New transaction in the chain.
108 * @throws IllegalStateException if the previous transaction was not SUBMITTED or CANCELLED.
109 * @throws DOMTransactionChainClosedException if the chain has been closed.
112 DOMDataTreeReadWriteTransaction newReadWriteTransaction();
115 * Add a completion callback to execute when {@link #future()} completes. This is a shorthand for
116 * {@code Futures.addCallback(future(), callback, MoreExecutors.directExecutor())}.
118 * @param callback completion callback
120 default void addCallback(final FutureCallback<Empty> callback) {
121 addCallback(callback, MoreExecutors.directExecutor());
125 * Add a completion callback to execute on specified executor when {@link #future()} completes. This is a shorthand
126 * for {@code Futures.addCallback(future(), callback, executor)}.
128 * @param callback completion callback
129 * @param executor executor on which to execute the callback
131 default void addCallback(final FutureCallback<Empty> callback, final Executor executor) {
132 Futures.addCallback(future(), callback, executor);
136 * Return a {@link ListenableFuture} which completes when this chain completes.
138 * @return A {@link ListenableFuture}
140 @NonNull ListenableFuture<Empty> future();