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