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