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