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