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