2da17bd6f42831e3cfb4b455338688fd2b79428a
[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> Type of path (subtree identifier), which represents location in tree
89  * @param <D> Type of data (payload), which represents data payload
90  * @deprecated This interface is being removed. Use either {@code org.opendaylight.mdsal.binding.api.WriteTransaction}
91  *             or {@code org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction} instead.
92  */
93 @Deprecated
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      * <h3>Example usage:</h3>
139      * <pre>
140      *  private void doWrite(final int tries) {
141      *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
142      *      MyDataObject data = ...;
143      *      InstanceIdentifier&lt;MyDataObject&gt; path = ...;
144      *      writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
145      *      Futures.addCallback(writeTx.commit(), new FutureCallback&lt;CommitInfo&gt;() {
146      *          public void onSuccess(CommitInfo result) {
147      *              // succeeded
148      *          }
149      *          public void onFailure(Throwable t) {
150      *              if(t instanceof OptimisticLockFailedException) {
151      *                  if(( tries - 1) &gt; 0 ) {
152      *                      // do retry
153      *                      doWrite(tries - 1);
154      *                  } else {
155      *                      // out of retries
156      *                  }
157      *              } else {
158      *                  // failed due to another type of TransactionCommitFailedException.
159      *              }
160      *          });
161      * }
162      * ...
163      * doWrite(2);
164      * </pre>
165      *
166      * <h2>Failure scenarios</h2>
167      *
168      * <p>
169      * Transaction may fail because of multiple reasons, such as
170      * <ul>
171      *   <li>
172      *     Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
173      *     case the returned future will fail with an {@link OptimisticLockFailedException}. It is the responsibility
174      *     of the caller to create a new transaction and commit the same modification again in order to update data
175      *     tree.
176      *     <i>
177      *       <b>Warning</b>: In most cases, retrying after an OptimisticLockFailedException will result in a high
178      *       probability of success. However, there are scenarios, albeit unusual, where any number of retries will
179      *       not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) to avoid
180      *       an endless loop.
181      *     </i>
182      *   </li>
183      *   <li>Data change introduced by this transaction did not pass validation by commit handlers or data was
184      *       incorrectly structured. Returned future will fail with a {@link DataValidationFailedException}. User
185      *       should not retry to create new transaction with same data, since it probably will fail again.
186      *   </li>
187      * </ul>
188      *
189      * <h3>Change compatibility</h3>
190      * There are several sets of changes which could be considered incompatible between two transactions which are
191      * derived from same initial state. Rules for conflict detection applies recursively for each subtree level.
192      *
193      * <h4>Change compatibility of leafs, leaf-list items</h4>
194      * Following table shows state changes and failures between two concurrent transactions, which are based on same
195      * initial state, Tx 1 completes successfully before Tx 2 is committed.
196      *
197      * <table summary="Change compatibility of leaf values">
198      * <tr>
199      * <th>Initial state</th>
200      * <th>Tx 1</th>
201      * <th>Tx 2</th>
202      * <th>Result</th>
203      * </tr>
204      * <tr>
205      * <td>Empty</td>
206      * <td>put(A,1)</td>
207      * <td>put(A,2)</td>
208      * <td>Tx 2 will fail, state is A=1</td>
209      * </tr>
210      * <tr>
211      * <td>Empty</td>
212      * <td>put(A,1)</td>
213      * <td>merge(A,2)</td>
214      * <td>A=2</td>
215      * </tr>
216      *
217      * <tr>
218      * <td>Empty</td>
219      * <td>merge(A,1)</td>
220      * <td>put(A,2)</td>
221      * <td>Tx 2 will fail, state is A=1</td>
222      * </tr>
223      * <tr>
224      * <td>Empty</td>
225      * <td>merge(A,1)</td>
226      * <td>merge(A,2)</td>
227      * <td>A=2</td>
228      * </tr>
229      *
230      *
231      * <tr>
232      * <td>A=0</td>
233      * <td>put(A,1)</td>
234      * <td>put(A,2)</td>
235      * <td>Tx 2 will fail, A=1</td>
236      * </tr>
237      * <tr>
238      * <td>A=0</td>
239      * <td>put(A,1)</td>
240      * <td>merge(A,2)</td>
241      * <td>A=2</td>
242      * </tr>
243      * <tr>
244      * <td>A=0</td>
245      * <td>merge(A,1)</td>
246      * <td>put(A,2)</td>
247      * <td>Tx 2 will fail, A=1</td>
248      * </tr>
249      * <tr>
250      * <td>A=0</td>
251      * <td>merge(A,1)</td>
252      * <td>merge(A,2)</td>
253      * <td>A=2</td>
254      * </tr>
255      *
256      * <tr>
257      * <td>A=0</td>
258      * <td>delete(A)</td>
259      * <td>put(A,2)</td>
260      * <td>Tx 2 will fail, A does not exists</td>
261      * </tr>
262      * <tr>
263      * <td>A=0</td>
264      * <td>delete(A)</td>
265      * <td>merge(A,2)</td>
266      * <td>A=2</td>
267      * </tr>
268      * </table>
269      *
270      * <h4>Change compatibility of subtrees</h4>
271      * Following table shows state changes and failures between two concurrent transactions, which are based on same
272      * initial state, Tx 1 completes successfully before Tx 2 is committed.
273      *
274      * <table summary="Change compatibility of containers">
275      * <tr>
276      * <th>Initial state</th>
277      * <th>Tx 1</th>
278      * <th>Tx 2</th>
279      * <th>Result</th>
280      * </tr>
281      *
282      * <tr>
283      * <td>Empty</td>
284      * <td>put(TOP,[])</td>
285      * <td>put(TOP,[])</td>
286      * <td>Tx 2 will fail, state is TOP=[]</td>
287      * </tr>
288      * <tr>
289      * <td>Empty</td>
290      * <td>put(TOP,[])</td>
291      * <td>merge(TOP,[])</td>
292      * <td>TOP=[]</td>
293      * </tr>
294      *
295      * <tr>
296      * <td>Empty</td>
297      * <td>put(TOP,[FOO=1])</td>
298      * <td>put(TOP,[BAR=1])</td>
299      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
300      * </tr>
301      * <tr>
302      * <td>Empty</td>
303      * <td>put(TOP,[FOO=1])</td>
304      * <td>merge(TOP,[BAR=1])</td>
305      * <td>TOP=[FOO=1,BAR=1]</td>
306      * </tr>
307      *
308      * <tr>
309      * <td>Empty</td>
310      * <td>merge(TOP,[FOO=1])</td>
311      * <td>put(TOP,[BAR=1])</td>
312      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
313      * </tr>
314      * <tr>
315      * <td>Empty</td>
316      * <td>merge(TOP,[FOO=1])</td>
317      * <td>merge(TOP,[BAR=1])</td>
318      * <td>TOP=[FOO=1,BAR=1]</td>
319      * </tr>
320      *
321      * <tr>
322      * <td>TOP=[]</td>
323      * <td>put(TOP,[FOO=1])</td>
324      * <td>put(TOP,[BAR=1])</td>
325      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
326      * </tr>
327      * <tr>
328      * <td>TOP=[]</td>
329      * <td>put(TOP,[FOO=1])</td>
330      * <td>merge(TOP,[BAR=1])</td>
331      * <td>state is TOP=[FOO=1,BAR=1]</td>
332      * </tr>
333      * <tr>
334      * <td>TOP=[]</td>
335      * <td>merge(TOP,[FOO=1])</td>
336      * <td>put(TOP,[BAR=1])</td>
337      * <td>Tx 2 will fail, state is TOP=[FOO=1]</td>
338      * </tr>
339      * <tr>
340      * <td>TOP=[]</td>
341      * <td>merge(TOP,[FOO=1])</td>
342      * <td>merge(TOP,[BAR=1])</td>
343      * <td>state is TOP=[FOO=1,BAR=1]</td>
344      * </tr>
345      * <tr>
346      * <td>TOP=[]</td>
347      * <td>delete(TOP)</td>
348      * <td>put(TOP,[BAR=1])</td>
349      * <td>Tx 2 will fail, state is empty store</td>
350      * </tr>
351      * <tr>
352      * <td>TOP=[]</td>
353      * <td>delete(TOP)</td>
354      * <td>merge(TOP,[BAR=1])</td>
355      * <td>state is TOP=[BAR=1]</td>
356      * </tr>
357      *
358      * <tr>
359      * <td>TOP=[]</td>
360      * <td>put(TOP/FOO,1)</td>
361      * <td>put(TOP/BAR,1])</td>
362      * <td>state is TOP=[FOO=1,BAR=1]</td>
363      * </tr>
364      * <tr>
365      * <td>TOP=[]</td>
366      * <td>put(TOP/FOO,1)</td>
367      * <td>merge(TOP/BAR,1)</td>
368      * <td>state is TOP=[FOO=1,BAR=1]</td>
369      * </tr>
370      * <tr>
371      * <td>TOP=[]</td>
372      * <td>merge(TOP/FOO,1)</td>
373      * <td>put(TOP/BAR,1)</td>
374      * <td>state is TOP=[FOO=1,BAR=1]</td>
375      * </tr>
376      * <tr>
377      * <td>TOP=[]</td>
378      * <td>merge(TOP/FOO,1)</td>
379      * <td>merge(TOP/BAR,1)</td>
380      * <td>state is TOP=[FOO=1,BAR=1]</td>
381      * </tr>
382      * <tr>
383      * <td>TOP=[]</td>
384      * <td>delete(TOP)</td>
385      * <td>put(TOP/BAR,1)</td>
386      * <td>Tx 2 will fail, state is empty store</td>
387      * </tr>
388      * <tr>
389      * <td>TOP=[]</td>
390      * <td>delete(TOP)</td>
391      * <td>merge(TOP/BAR,1]</td>
392      * <td>Tx 2 will fail, state is empty store</td>
393      * </tr>
394      *
395      * <tr>
396      * <td>TOP=[FOO=1]</td>
397      * <td>put(TOP/FOO,2)</td>
398      * <td>put(TOP/BAR,1)</td>
399      * <td>state is TOP=[FOO=2,BAR=1]</td>
400      * </tr>
401      * <tr>
402      * <td>TOP=[FOO=1]</td>
403      * <td>put(TOP/FOO,2)</td>
404      * <td>merge(TOP/BAR,1)</td>
405      * <td>state is TOP=[FOO=2,BAR=1]</td>
406      * </tr>
407      * <tr>
408      * <td>TOP=[FOO=1]</td>
409      * <td>merge(TOP/FOO,2)</td>
410      * <td>put(TOP/BAR,1)</td>
411      * <td>state is TOP=[FOO=2,BAR=1]</td>
412      * </tr>
413      * <tr>
414      * <td>TOP=[FOO=1]</td>
415      * <td>merge(TOP/FOO,2)</td>
416      * <td>merge(TOP/BAR,1)</td>
417      * <td>state is TOP=[FOO=2,BAR=1]</td>
418      * </tr>
419      * <tr>
420      * <td>TOP=[FOO=1]</td>
421      * <td>delete(TOP/FOO)</td>
422      * <td>put(TOP/BAR,1)</td>
423      * <td>state is TOP=[BAR=1]</td>
424      * </tr>
425      * <tr>
426      * <td>TOP=[FOO=1]</td>
427      * <td>delete(TOP/FOO)</td>
428      * <td>merge(TOP/BAR,1]</td>
429      * <td>state is TOP=[BAR=1]</td>
430      * </tr>
431      * </table>
432      *
433      *
434      * <h3>Examples of failure scenarios</h3>
435      *
436      * <h4>Conflict of two transactions</h4>
437      * This example illustrates two concurrent transactions, which derived from same initial state
438      * of data tree and proposes conflicting modifications.
439      *
440      * <pre>
441      * txA = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
442      * txB = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
443      * txA.put(CONFIGURATION, PATH, A);    // writes to PATH value A
444      * txB.put(CONFIGURATION, PATH, B)     // writes to PATH value B
445      * ListenableFuture futureA = txA.commit(); // transaction A is sealed and committed
446      * ListenebleFuture futureB = txB.commit(); // transaction B is sealed and committed
447      * </pre>
448      * Commit of transaction A will be processed asynchronously and data tree will be updated to
449      * contain value <code>A</code> for <code>PATH</code>. Returned {@link ListenableFuture} will
450      * successfully complete once state is applied to data tree.
451      * Commit of Transaction B will fail, because previous transaction also modified path in a
452      * concurrent way. The state introduced by transaction B will not be applied. Returned
453      * {@link ListenableFuture} object will fail with {@link OptimisticLockFailedException}
454      * exception, which indicates to client that concurrent transaction prevented the committed
455      * transaction from being applied. <br>
456      *
457      * <p>
458      * A successful commit produces implementation-specific {@link CommitInfo} structure, which is used to communicate
459      * post-condition information to the caller. Such information can contain commit-id, timing information or any
460      * other information the implementation wishes to share.
461      *
462      * @return a FluentFuture containing the result of the commit information. The Future blocks until the commit
463      *         operation is complete. A successful commit returns nothing. On failure, the Future will fail with a
464      *         {@link TransactionCommitFailedException} or an exception derived from TransactionCommitFailedException.
465      * @throws IllegalStateException if the transaction is already committed or was canceled.
466      */
467     @CheckReturnValue
468     @NonNull FluentFuture<? extends @NonNull CommitInfo> commit();
469 }