241c9dd882741a20dcfeb5aaae01edef7db4e11c
[mdsal.git] / common / mdsal-common-api / src / main / java / org / opendaylight / mdsal / common / api / 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.mdsal.common.api;
9
10 import com.google.common.util.concurrent.CheckedFuture;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import org.opendaylight.yangtools.concepts.Path;
13
14 /**
15  * Write transaction provides mutation capabilities for a data tree.
16  *
17  * <p>
18  * Initial state of write transaction is a stable snapshot of the current data tree.
19  * The state is captured when the transaction is created and its state and underlying
20  * data tree are not affected by other concurrently running transactions.
21  * <p>
22  * Write transactions are isolated from other concurrent write transactions. All
23  * writes are local to the transaction and represent only a proposal of state
24  * change for the data tree and it is not visible to any other concurrently running
25  * transaction.
26  * <p>
27  * Applications make changes to the local data tree in the transaction by via the
28  * <b>put</b>, <b>merge</b>, and <b>delete</b> operations.
29  *
30  * <h2>Put operation</h2>
31  * Stores a piece of data at a specified path. This acts as an add / replace
32  * operation, which is to say that whole subtree will be replaced by the
33  * specified data.
34  * <p>
35  * Performing the following put operations:
36  *
37  * <pre>
38  * 1) container { list [ a ] }
39  * 2) container { list [ b ] }
40  * </pre>
41  *
42  * will result in the following data being present:
43  *
44  * <pre>
45  * container { list [ b ] }
46  * </pre>
47  * <h2>Merge operation</h2>
48  * Merges a piece of data with the existing data at a specified path. Any pre-existing data
49  * which is not explicitly overwritten will be preserved. This means that if you store a container,
50  * its child lists will be merged.
51  * <p>
52  * Performing the following merge operations:
53  *
54  * <pre>
55  * 1) container { list [ a ] }
56  * 2) container { list [ b ] }
57  * </pre>
58  *
59  * will result in the following data being present:
60  *
61  * <pre>
62  * container { list [ a, b ] }
63  * </pre>
64  *
65  * This also means that storing the container will preserve any
66  * augmentations which have been attached to it.
67  *
68  * <h2>Delete operation</h2>
69  * Removes a piece of data from a specified path.
70  * <p>
71  * After applying changes to the local data tree, applications publish the changes proposed in the
72  * transaction by calling {@link #submit} on the transaction. This seals the transaction
73  * (preventing any further writes using this transaction) and submits it to be
74  * processed and applied to global conceptual data tree.
75  * <p>
76  * The transaction commit may fail due to a concurrent transaction modifying and committing data in
77  * an incompatible way. See {@link #submit} for more concrete commit failure examples.
78  * <p>
79  * <b>Implementation Note:</b> This interface is not intended to be implemented
80  * by users of MD-SAL, but only to be consumed by them.
81  *
82  * @param <P>
83  *            Type of path (subtree identifier), which represents location in
84  *            tree
85  * @param <D>
86  *            Type of data (payload), which represents data payload
87  */
88 public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
89     /**
90      * Cancels the transaction.
91      *
92      * Transactions can only be cancelled if it was not yet submited.
93      *
94      * Invoking cancel() on failed or already canceled will have no effect, and transaction is
95      * considered cancelled.
96      *
97      * Invoking cancel() on finished transaction (future returned by {@link #submit()} already
98      * successfully completed) will always fail (return false).
99      *
100      * @return <tt>false</tt> if the task could not be cancelled, typically because it has already
101      *         completed normally; <tt>true</tt> otherwise
102      *
103      */
104     boolean cancel();
105
106     /**
107      * Removes a piece of data from specified path. This operation does not fail if the specified
108      * path does not exist.
109      *
110      * @param store Logical data store which should be modified
111      * @param path Data object path
112      * @throws IllegalStateException if the transaction was submitted or canceled.
113      */
114     void delete(LogicalDatastoreType store, P path);
115
116     /**
117      * Submits this transaction to be asynchronously applied to update the logical data tree. The
118      * returned CheckedFuture conveys the result of applying the data changes.
119      * <p>
120      * <b>Note:</b> It is strongly recommended to process the CheckedFuture result in an
121      * asynchronous manner rather than using the blocking get() method. See example usage below.
122      * <p>
123      * This call logically seals the transaction, which prevents the client from further changing
124      * data tree using this transaction. Any subsequent calls to
125      * <code>put(LogicalDatastoreType, Path, Object)</code>,
126      * <code>merge(LogicalDatastoreType, Path, Object)</code>,
127      * <code>delete(LogicalDatastoreType, Path)</code> will fail with {@link IllegalStateException}.
128      *
129      * The transaction is marked as submitted and enqueued into the data store back-end for
130      * processing.
131      *
132      * <p>
133      * Whether or not the commit is successful is determined by versioning of the data tree and
134      * validation of registered commit participants if the transaction changes the data tree.
135      * <p>
136      * The effects of a successful commit of data depends on listeners 
137      * and commit participants that are registered with the data
138      * broker.
139      * <p>
140      * <h3>Example usage:</h3>
141      *
142      * <pre>
143      *  private void doWrite( final int tries ) {
144      *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
145      * 
146      *      MyDataObject data = ...;
147      *      InstanceIdentifier&lt;MyDataObject&gt; path = ...;
148      *      writeTx.put( LogicalDatastoreType.OPERATIONAL, path, data );
149      * 
150      *      Futures.addCallback( writeTx.submit(), new FutureCallback&lt;Void&gt;() {
151      *          public void onSuccess( Void result ) {
152      *              // succeeded
153      *          }
154      * 
155      *          public void onFailure( Throwable t ) {
156      *              if( t instanceof OptimisticLockFailedException ) {
157      *                  if( ( tries - 1 ) &gt; 0 ) {
158      *                      // do retry
159      *                      doWrite( tries - 1 );
160      *                  } else {
161      *                      // out of retries
162      *                  }
163      *              } else {
164      *                  // failed due to another type of TransactionCommitFailedException.
165      *              }
166      *          } );
167      * }
168      * ...
169      * doWrite( 2 );
170      * </pre>
171      *
172      * <h2>Failure scenarios</h2>
173      * <p>
174      * Transaction may fail because of multiple reasons, such as
175      * <ul>
176      * <li>Another transaction finished earlier and modified the same node in a non-compatible way
177      * (see below). In this case the returned future will fail with an
178      * {@link OptimisticLockFailedException}. It is the responsibility of the caller to create a new
179      * transaction and submit the same modification again in order to update data tree.
180      * <i><b>Warning</b>: In most cases, retrying after an OptimisticLockFailedException will result
181      * in a high probability of success. However, there are scenarios, albeit unusual, where any
182      * number of retries will not succeed. Therefore it is strongly recommended to limit the number
183      * of retries (2 or 3) to avoid an endless loop.</i></li>
184      * <li>Data change introduced by this transaction did not pass validation by commit handlers or
185      * data was incorrectly structured. Returned future will fail with a
186      * {@link DataValidationFailedException}. User should not retry to create new transaction with
187      * same data, since it probably will fail again.</li>
188      * </ul>
189      *
190      * <h3>Change compatibility</h3>
191      *
192      * There are several sets of changes which could be considered incompatible between two
193      * transactions which are derived from same initial state. Rules for conflict detection applies
194      * recursively for each subtree level.
195      *
196      * <h4>Change compatibility of leafs, leaf-list items</h4>
197      *
198      * Following table shows state changes and failures between two concurrent transactions, which
199      * are based on same initial state, Tx 1 completes successfully before Tx 2 is submitted.
200      *
201      * <table summary="Change compatibility of leaf values">
202      * <tr>
203      * <th>Initial state</th>
204      * <th>Tx 1</th>
205      * <th>Tx 2</th>
206      * <th>Result</th>
207      * </tr>
208      * <tr>
209      * <td>Empty</td>
210      * <td>put(A,1)</td>
211      * <td>put(A,2)</td>
212      * <td>Tx 2 will fail, state is A=1</td>
213      * </tr>
214      * <tr>
215      * <td>Empty</td>
216      * <td>put(A,1)</td>
217      * <td>merge(A,2)</td>
218      * <td>A=2</td>
219      * </tr>
220      *
221      * <tr>
222      * <td>Empty</td>
223      * <td>merge(A,1)</td>
224      * <td>put(A,2)</td>
225      * <td>Tx 2 will fail, state is A=1</td>
226      * </tr>
227      * <tr>
228      * <td>Empty</td>
229      * <td>merge(A,1)</td>
230      * <td>merge(A,2)</td>
231      * <td>A=2</td>
232      * </tr>
233      *
234      *
235      * <tr>
236      * <td>A=0</td>
237      * <td>put(A,1)</td>
238      * <td>put(A,2)</td>
239      * <td>Tx 2 will fail, A=1</td>
240      * </tr>
241      * <tr>
242      * <td>A=0</td>
243      * <td>put(A,1)</td>
244      * <td>merge(A,2)</td>
245      * <td>A=2</td>
246      * </tr>
247      * <tr>
248      * <td>A=0</td>
249      * <td>merge(A,1)</td>
250      * <td>put(A,2)</td>
251      * <td>Tx 2 will fail, A=1</td>
252      * </tr>
253      * <tr>
254      * <td>A=0</td>
255      * <td>merge(A,1)</td>
256      * <td>merge(A,2)</td>
257      * <td>A=2</td>
258      * </tr>
259      *
260      * <tr>
261      * <td>A=0</td>
262      * <td>delete(A)</td>
263      * <td>put(A,2)</td>
264      * <td>Tx 2 will fail, A does not exists</td>
265      * </tr>
266      * <tr>
267      * <td>A=0</td>
268      * <td>delete(A)</td>
269      * <td>merge(A,2)</td>
270      * <td>A=2</td>
271      * </tr>
272      * </table>
273      *
274      * <h4>Change compatibility of subtrees</h4>
275      *
276      * Following table shows state changes and failures between two concurrent transactions, which
277      * are based on same initial state, Tx 1 completes successfully before Tx 2 is submitted.
278      *
279      * <table summary="Change compatibility of containers">
280      * <tr>
281      * <th>Initial state</th>
282      * <th>Tx 1</th>
283      * <th>Tx 2</th>
284      * <th>Result</th>
285      * </tr>
286      *
287      * <tr>
288      * <td>Empty</td>
289      * <td>put(TOP,[])</td>
290      * <td>put(TOP,[])</td>
291      * <td>Tx 2 will fail, state is TOP=[]</td>
292      * </tr>
293      * <tr>
294      * <td>Empty</td>
295      * <td>put(TOP,[])</td>
296      * <td>merge(TOP,[])</td>
297      * <td>TOP=[]</td>
298      * </tr>
299      *
300      * <tr>
301      * <td>Empty</td>
302      * <td>put(TOP,[FOO=1])</td>
303      * <td>put(TOP,[BAR=1])</td>
304      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
305      * </tr>
306      * <tr>
307      * <td>Empty</td>
308      * <td>put(TOP,[FOO=1])</td>
309      * <td>merge(TOP,[BAR=1])</td>
310      * <td>TOP=[FOO=1,BAR=1]</td>
311      * </tr>
312      *
313      * <tr>
314      * <td>Empty</td>
315      * <td>merge(TOP,[FOO=1])</td>
316      * <td>put(TOP,[BAR=1])</td>
317      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
318      * </tr>
319      * <tr>
320      * <td>Empty</td>
321      * <td>merge(TOP,[FOO=1])</td>
322      * <td>merge(TOP,[BAR=1])</td>
323      * <td>TOP=[FOO=1,BAR=1]</td>
324      * </tr>
325      *
326      * <tr>
327      * <td>TOP=[]</td>
328      * <td>put(TOP,[FOO=1])</td>
329      * <td>put(TOP,[BAR=1])</td>
330      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
331      * </tr>
332      * <tr>
333      * <td>TOP=[]</td>
334      * <td>put(TOP,[FOO=1])</td>
335      * <td>merge(TOP,[BAR=1])</td>
336      * <td>state is TOP=[FOO=1,BAR=1]</td>
337      * </tr>
338      * <tr>
339      * <td>TOP=[]</td>
340      * <td>merge(TOP,[FOO=1])</td>
341      * <td>put(TOP,[BAR=1])</td>
342      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
343      * </tr>
344      * <tr>
345      * <td>TOP=[]</td>
346      * <td>merge(TOP,[FOO=1])</td>
347      * <td>merge(TOP,[BAR=1])</td>
348      * <td>state is TOP=[FOO=1,BAR=1]</td>
349      * </tr>
350      * <tr>
351      * <td>TOP=[]</td>
352      * <td>delete(TOP)</td>
353      * <td>put(TOP,[BAR=1])</td>
354      * <td>Tx 2 will fail, state is empty store</td>
355      * </tr>
356      * <tr>
357      * <td>TOP=[]</td>
358      * <td>delete(TOP)</td>
359      * <td>merge(TOP,[BAR=1])</td>
360      * <td>state is TOP=[BAR=1]</td>
361      * </tr>
362      *
363      * <tr>
364      * <td>TOP=[]</td>
365      * <td>put(TOP/FOO,1)</td>
366      * <td>put(TOP/BAR,1])</td>
367      * <td>state is TOP=[FOO=1,BAR=1]</td>
368      * </tr>
369      * <tr>
370      * <td>TOP=[]</td>
371      * <td>put(TOP/FOO,1)</td>
372      * <td>merge(TOP/BAR,1)</td>
373      * <td>state is TOP=[FOO=1,BAR=1]</td>
374      * </tr>
375      * <tr>
376      * <td>TOP=[]</td>
377      * <td>merge(TOP/FOO,1)</td>
378      * <td>put(TOP/BAR,1)</td>
379      * <td>state is TOP=[FOO=1,BAR=1]</td>
380      * </tr>
381      * <tr>
382      * <td>TOP=[]</td>
383      * <td>merge(TOP/FOO,1)</td>
384      * <td>merge(TOP/BAR,1)</td>
385      * <td>state is TOP=[FOO=1,BAR=1]</td>
386      * </tr>
387      * <tr>
388      * <td>TOP=[]</td>
389      * <td>delete(TOP)</td>
390      * <td>put(TOP/BAR,1)</td>
391      * <td>Tx 2 will fail, state is empty store</td>
392      * </tr>
393      * <tr>
394      * <td>TOP=[]</td>
395      * <td>delete(TOP)</td>
396      * <td>merge(TOP/BAR,1]</td>
397      * <td>Tx 2 will fail, state is empty store</td>
398      * </tr>
399      *
400      * <tr>
401      * <td>TOP=[FOO=1]</td>
402      * <td>put(TOP/FOO,2)</td>
403      * <td>put(TOP/BAR,1)</td>
404      * <td>state is TOP=[FOO=2,BAR=1]</td>
405      * </tr>
406      * <tr>
407      * <td>TOP=[FOO=1]</td>
408      * <td>put(TOP/FOO,2)</td>
409      * <td>merge(TOP/BAR,1)</td>
410      * <td>state is TOP=[FOO=2,BAR=1]</td>
411      * </tr>
412      * <tr>
413      * <td>TOP=[FOO=1]</td>
414      * <td>merge(TOP/FOO,2)</td>
415      * <td>put(TOP/BAR,1)</td>
416      * <td>state is TOP=[FOO=2,BAR=1]</td>
417      * </tr>
418      * <tr>
419      * <td>TOP=[FOO=1]</td>
420      * <td>merge(TOP/FOO,2)</td>
421      * <td>merge(TOP/BAR,1)</td>
422      * <td>state is TOP=[FOO=2,BAR=1]</td>
423      * </tr>
424      * <tr>
425      * <td>TOP=[FOO=1]</td>
426      * <td>delete(TOP/FOO)</td>
427      * <td>put(TOP/BAR,1)</td>
428      * <td>state is TOP=[BAR=1]</td>
429      * </tr>
430      * <tr>
431      * <td>TOP=[FOO=1]</td>
432      * <td>delete(TOP/FOO)</td>
433      * <td>merge(TOP/BAR,1]</td>
434      * <td>state is TOP=[BAR=1]</td>
435      * </tr>
436      * </table>
437      *
438      *
439      * <h3>Examples of failure scenarios</h3>
440      *
441      * <h4>Conflict of two transactions</h4>
442      *
443      * This example illustrates two concurrent transactions, which derived from same initial state
444      * of data tree and proposes conflicting modifications.
445      *
446      * <pre>
447      * txA = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
448      * txB = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
449      * 
450      * txA.put(CONFIGURATION, PATH, A);    // writes to PATH value A
451      * txB.put(CONFIGURATION, PATH, B)     // writes to PATH value B
452      * 
453      * ListenableFuture futureA = txA.submit(); // transaction A is sealed and submitted
454      * ListenebleFuture futureB = txB.submit(); // transaction B is sealed and submitted
455      * </pre>
456      *
457      * Commit of transaction A will be processed asynchronously and data tree will be updated to
458      * contain value <code>A</code> for <code>PATH</code>. Returned {@link ListenableFuture} will
459      * successfully complete once state is applied to data tree.
460      *
461      * Commit of Transaction B will fail, because previous transaction also modified path in a
462      * concurrent way. The state introduced by transaction B will not be applied. Returned
463      * {@link ListenableFuture} object will fail with {@link OptimisticLockFailedException}
464      * exception, which indicates to client that concurrent transaction prevented the submitted
465      * transaction from being applied. <br>
466      *
467      * @return a CheckFuture containing the result of the commit. The Future blocks until the commit
468      *         operation is complete. A successful commit returns nothing. On failure, the Future
469      *         will fail with a {@link TransactionCommitFailedException} or an exception derived
470      *         from TransactionCommitFailedException.
471      *
472      * @throws IllegalStateException if the transaction is already submitted or was canceled.
473      */
474     CheckedFuture<Void,TransactionCommitFailedException> submit();
475
476 }