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