Merge "API Clarity: Documented Async Data Broker APIs."
[controller.git] / opendaylight / md-sal / sal-common-api / src / main / java / org / opendaylight / controller / md / sal / common / api / data / AsyncWriteTransaction.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.sal.common.api.data;
9
10 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
11 import org.opendaylight.yangtools.concepts.Path;
12 import org.opendaylight.yangtools.yang.common.RpcResult;
13
14 import com.google.common.util.concurrent.ListenableFuture;
15
16 /**
17  * Write transaction provides mutation capabilities for a data tree.
18  *
19  * <p>
20  * Initial state of write transaction is a stable snapshot of the current data tree.
21  * The state is captured when the transaction is created and its state and underlying
22  * data tree are not affected by other concurrently running transactions.
23  * <p>
24  * Write transactions are isolated from other concurrent write transactions. All
25  * writes are local to the transaction and represent only a proposal of state
26  * change for the data tree and it is not visible to any other concurrently running
27  * transaction.
28  * <p>
29  * Applications publish the changes proposed in the transaction by calling {@link #commit}
30  * on the transaction. This seals the transaction
31  * (preventing any further writes using this transaction) and submits it to be
32  * processed and applied to global conceptual data tree.
33  * <p>
34  * The transaction commit may fail due to a concurrent transaction modifying and committing data in
35  * an incompatible way. See {@link #commit()} for more concrete commit failure examples.
36  *
37  *
38  * <p>
39  * <b>Implementation Note:</b> This interface is not intended to be implemented
40  * by users of MD-SAL, but only to be consumed by them.
41  *
42  * @param <P>
43  *            Type of path (subtree identifier), which represents location in
44  *            tree
45  * @param <D>
46  *            Type of data (payload), which represents data payload
47  */
48 public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
49     /**
50      * Cancels the transaction.
51      *
52      * Transactions can only be cancelled if it's status is
53      * {@link TransactionStatus#NEW} or {@link TransactionStatus#SUBMITED}
54      *
55      * Invoking cancel() on {@link TransactionStatus#FAILED} or
56      * {@link TransactionStatus#CANCELED} will have no effect.
57      *
58      * @throws IllegalStateException
59      *             If transaction status is {@link TransactionStatus#COMMITED}
60      *
61      */
62     public void cancel();
63
64     /**
65      * Store a piece of data at specified path. This acts as an add / replace
66      * operation, which is to say that whole subtree will be replaced by
67      * specified path. Performing the following put operations:
68      *
69      * <pre>
70      * 1) container { list [ a ] }
71      * 2) container { list [ b ] }
72      * </pre>
73      *
74      * will result in the following data being present:
75      *
76      * <pre>
77      * container { list [ b ] }
78      * </pre>
79      *
80      *
81      * If you need to make sure that a parent object exists, but you do not want modify
82      * its preexisting state by using put, consider using
83      * {@link #merge(LogicalDatastoreType, Path, Object)}
84      *
85      * @param store
86      *            Logical data store which should be modified
87      * @param path
88      *            Data object path
89      * @param data
90      *            Data object to be written to specified path
91      * @throws IllegalStateException
92      *             if the transaction is no longer {@link TransactionStatus#NEW}
93      */
94     public void put(LogicalDatastoreType store, P path, D data);
95
96     /**
97      * Store a piece of data at the specified path. This acts as a merge operation,
98      * which is to say that any pre-existing data which is not explicitly
99      * overwritten will be preserved. This means that if you store a container,
100      * its child lists will be merged. Performing the following merge
101      * operations:
102      *
103      * <pre>
104      * 1) container { list [ a ] }
105      * 2) container { list [ b ] }
106      * </pre>
107      *
108      * will result in the following data being present:
109      *
110      * <pre>
111      * container { list [ a, b ] }
112      * </pre>
113      *
114      * This also means that storing the container will preserve any
115      * augmentations which have been attached to it.
116      *<p>
117      * If you require an explicit replace operation, use
118      * {@link #put(LogicalDatastoreType, Path, Object)} instead.
119      *
120      * @param store
121      *            Logical data store which should be modified
122      * @param path
123      *            Data object path
124      * @param data
125      *            Data object to be written to specified path
126      * @throws IllegalStateException
127      *             if the transaction is no longer {@link TransactionStatus#NEW}
128      */
129     public void merge(LogicalDatastoreType store, P path, D data);
130
131     /**
132      * Remove a piece of data from specified path. This operation does not fail
133      * if the specified path does not exist.
134      *
135      * @param store
136      *            Logical data store which should be modified
137      * @param path
138      *            Data object path
139      * @throws IllegalStateException
140      *             if the transaction is no longer {@link TransactionStatus#NEW}
141      */
142     public void delete(LogicalDatastoreType store, P path);
143
144     /**
145      *
146      * Closes transaction and resources allocated to the transaction.
147      *
148      * This call does not change Transaction status. Client SHOULD explicitly
149      * {@link #commit()} or {@link #cancel()} transaction.
150      *
151      * @throws IllegalStateException
152      *             if the transaction has not been updated by invoking
153      *             {@link #commit()} or {@link #cancel()}.
154      */
155     @Override
156     public void close();
157
158     /**
159      * Submits transaction to be applied to update logical data tree.
160      * <p>
161      * This call logically seals the transaction, which prevents the client from
162      * further changing data tree using this transaction. Any subsequent calls to
163      * {@link #put(LogicalDatastoreType, Path, Object)},
164      * {@link #merge(LogicalDatastoreType, Path, Object)} or
165      * {@link #delete(LogicalDatastoreType, Path)} will fail with
166      * {@link IllegalStateException}.
167      *
168      * The transaction is marked as {@link TransactionStatus#SUBMITED} and
169      * enqueued into the data store backed for processing.
170      *
171      * <p>
172      * Whether or not the commit is successful is determined by versioning
173      * of data tree and validation of registered commit participants
174      * {@link AsyncConfigurationCommitHandler}
175      * if transaction changes {@link LogicalDatastoreType#CONFIGURATION} data tree.
176      *<p>
177      * The effects of successful commit of data depends on
178      * other data change listeners {@link AsyncDataChangeListener} and
179      * {@link AsyncConfigurationCommitHandler}, which was registered to the
180      * same {@link AsyncDataBroker}, to which this transaction belongs.
181      *
182      * <h2>Failure scenarios</h2>
183      * <p>
184      * Transaction may fail because of multiple reasons, such as
185      * <ul>
186      * <li>Another transaction finished earlier and modified the same node in
187      * non-compatible way (see below). In this case the returned future will fail with
188      * {@link OptimisticLockFailedException}. It is the responsibility of the
189      * caller to create a new transaction and submit the same modification again in
190      * order to update data tree.</li>
191      * <li>Data change introduced by this transaction did not pass validation by
192      * commit handlers or data was incorrectly structured. Returned future will
193      * fail with {@link DataValidationFailedException}. User should not retry to
194      * create new transaction with same data, since it probably will fail again.
195      * </li>
196      * </ul>
197      *
198      * <h3>Change compatibility</h3>
199      *
200      * There are several sets of changes which could be considered incompatible
201      * between two transactions which are derived from same initial state.
202      * Rules for conflict detection applies recursively for each subtree
203      * level.
204      *
205      * <h4>Change compatibility of leafs, leaf-list items</h4>
206      *
207      * Following table shows  state changes and failures between two concurrent transactions,
208      * which are based on same initial state, Tx 1 completes successfully
209      * before Tx 2 is submitted.
210      *
211      * <table>
212      * <tr><th>Initial state</th><th>Tx 1</th><th>Tx 2</th><th>Result</th></tr>
213      * <tr><td>Empty</td><td>put(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, state is A=1</td></tr>
214      * <tr><td>Empty</td><td>put(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
215      *
216      * <tr><td>Empty</td><td>merge(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, state is A=1</td></tr>
217      * <tr><td>Empty</td><td>merge(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
218      *
219      *
220      * <tr><td>A=0</td><td>put(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, A=1</td></tr>
221      * <tr><td>A=0</td><td>put(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
222      * <tr><td>A=0</td><td>merge(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, A=1</td></tr>
223      * <tr><td>A=0</td><td>merge(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
224      *
225      * <tr><td>A=0</td><td>delete(A)</td><td>put(A,2)</td><td>Tx 2 will fail, A does not exists</td></tr>
226      * <tr><td>A=0</td><td>delete(A)</td><td>merge(A,2)</td><td>A=2</td></tr>
227      * </table>
228      *
229      * <h4>Change compatibility of subtrees</h4>
230      *
231      * Following table shows  state changes and failures between two concurrent transactions,
232      * which are based on same initial state, Tx 1 completes successfully
233      * before Tx 2 is submitted.
234      *
235      * <table>
236      * <tr><th>Initial state</th><th>Tx 1</th><th>Tx 2</th><th>Result</th></tr>
237      *
238      * <tr><td>Empty</td><td>put(TOP,[])</td><td>put(TOP,[])</td><td>Tx 2 will fail, state is TOP=[]</td></tr>
239      * <tr><td>Empty</td><td>put(TOP,[])</td><td>merge(TOP,[])</td><td>TOP=[]</td></tr>
240      *
241      * <tr><td>Empty</td><td>put(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
242      * <tr><td>Empty</td><td>put(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>TOP=[FOO=1,BAR=1]</td></tr>
243      *
244      * <tr><td>Empty</td><td>merge(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
245      * <tr><td>Empty</td><td>merge(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>TOP=[FOO=1,BAR=1]</td></tr>
246      *
247      * <tr><td>TOP=[]</td><td>put(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
248      * <tr><td>TOP=[]</td><td>put(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
249      * <tr><td>TOP=[]</td><td>merge(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
250      * <tr><td>TOP=[]</td><td>merge(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
251      * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is empty store</td></tr>
252      * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>merge(TOP,[BAR=1])</td><td>state is TOP=[BAR=1]</td></tr>
253      *
254      * <tr><td>TOP=[]</td><td>put(TOP/FOO,1)</td><td>put(TOP/BAR,1])</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
255      * <tr><td>TOP=[]</td><td>put(TOP/FOO,1)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
256      * <tr><td>TOP=[]</td><td>merge(TOP/FOO,1)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
257      * <tr><td>TOP=[]</td><td>merge(TOP/FOO,1)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
258      * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>put(TOP/BAR,1)</td><td>Tx 2 will fail, state is empty store</td></tr>
259      * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>merge(TOP/BAR,1]</td><td>Tx 2 will fail, state is empty store</td></tr>
260      *
261      * <tr><td>TOP=[FOO=1]</td><td>put(TOP/FOO,2)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
262      * <tr><td>TOP=[FOO=1]</td><td>put(TOP/FOO,2)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
263      * <tr><td>TOP=[FOO=1]</td><td>merge(TOP/FOO,2)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
264      * <tr><td>TOP=[FOO=1]</td><td>merge(TOP/FOO,2)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
265      * <tr><td>TOP=[FOO=1]</td><td>delete(TOP/FOO)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[BAR=1]</td></tr>
266      * <tr><td>TOP=[FOO=1]</td><td>delete(TOP/FOO)</td><td>merge(TOP/BAR,1]</td><td>state is TOP=[BAR=1]</td></tr>
267      * </table>
268      *
269      *
270      * <h3>Examples of failure scenarios</h3>
271      *
272      * <h4>Conflict of two transactions</h4>
273      *
274      * This example illustrates two concurrent transactions, which derived from
275      * same initial state of data tree and proposes conflicting modifications.
276      *
277      * <pre>
278      * txA = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
279      * txB = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
280      *
281      * txA.put(CONFIGURATION, PATH, A);    // writes to PATH value A
282      * txB.put(CONFIGURATION, PATH, B)     // writes to PATH value B
283      *
284      * ListenableFuture futureA = txA.commit(); // transaction A is sealed and committed
285      * ListenebleFuture futureB = txB.commit(); // transaction B is sealed and committed
286      * </pre>
287      *
288      * Commit of transaction A will be processed asynchronously and data tree
289      * will be updated to contain value <code>A</code> for <code>PATH</code>.
290      * Returned {@link ListenableFuture} will successfully complete once
291      * state is applied to data tree.
292      *
293      * Commit of Transaction B will fail, because previous transaction also
294      * modified path in a concurrent way. The state introduced by transaction B
295      * will not be applied. Returned {@link ListenableFuture} object will fail
296      * with {@link OptimisticLockFailedException} exception, which indicates to
297      * client that concurrent transaction prevented the submitted transaction from being
298      * applied.
299      *
300      * @return Result of the Commit, containing success information or list of
301      *         encountered errors, if commit was not successful. The Future
302      *         blocks until {@link TransactionStatus#COMMITED} is reached.
303      *         Future will fail with {@link TransactionCommitFailedException} if
304      *         Commit of this transaction failed. TODO: Usability: Consider
305      *         change from ListenableFuture to
306      *         {@link com.google.common.util.concurrent.CheckedFuture} which
307      *         will throw {@link TransactionCommitFailedException}.
308      *
309      * @throws IllegalStateException
310      *             if the transaction is not {@link TransactionStatus#NEW}
311      */
312     public ListenableFuture<RpcResult<TransactionStatus>> commit();
313
314 }