Class ForwardingWriteTransaction
- java.lang.Object
-
- com.google.common.collect.ForwardingObject
-
- org.opendaylight.mdsal.binding.spi.ForwardingTransaction
-
- org.opendaylight.mdsal.binding.spi.ForwardingWriteTransaction
-
- All Implemented Interfaces:
Transaction
,WriteOperations
,WriteTransaction
,Identifiable<Object>
public class ForwardingWriteTransaction extends ForwardingTransaction implements WriteTransaction
UtilityWriteTransaction
implementation which forwards all interface method invocation to a delegate instance.
-
-
Constructor Summary
Constructors Constructor Description ForwardingWriteTransaction(WriteTransaction delegate)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description boolean
cancel()
Cancels the transaction.FluentFuture<? extends CommitInfo>
commit()
Commits this transaction to be asynchronously applied to update the logical data tree.protected WriteTransaction
delegate()
void
delete(LogicalDatastoreType store, InstanceIdentifier<?> path)
Removes a piece of data from specified path.<T extends DataObject>
voidmerge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Merges a piece of data with the existing data at a specified path.<T extends DataObject>
voidmergeParentStructureMerge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Merges a piece of data with the existing data at a specified path.<T extends DataObject>
voidmergeParentStructurePut(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Stores a piece of data at the specified path.<T extends DataObject>
voidput(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Stores a piece of data at the specified path.-
Methods inherited from class org.opendaylight.mdsal.binding.spi.ForwardingTransaction
getIdentifier
-
Methods inherited from class com.google.common.collect.ForwardingObject
toString
-
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
-
Methods inherited from interface org.opendaylight.yangtools.concepts.Identifiable
getIdentifier
-
-
-
-
Constructor Detail
-
ForwardingWriteTransaction
public ForwardingWriteTransaction(WriteTransaction delegate)
-
-
Method Detail
-
delegate
protected WriteTransaction delegate()
- Specified by:
delegate
in classForwardingTransaction
-
put
public <T extends DataObject> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Description copied from interface:WriteOperations
Stores a piece of data at the specified path. This acts as an add / replace operation, which is to say that whole subtree will be replaced by the specified data.If you need to make sure that a parent object exists but you do not want modify its pre-existing state by using put, consider using
WriteOperations.merge(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.yangtools.yang.binding.InstanceIdentifier<T>, T)
instead.- Specified by:
put
in interfaceWriteOperations
- Parameters:
store
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be written to the specified path
-
mergeParentStructurePut
public <T extends DataObject> void mergeParentStructurePut(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Description copied from interface:WriteOperations
Stores a piece of data at the specified path. This acts as an add / replace operation, which is to say that whole subtree will be replaced by the specified data. UnlikeWriteOperations.put(LogicalDatastoreType, InstanceIdentifier, DataObject)
, this method will attempt to create semantically-significant parent nodes, like list entries and presence containers, as indicated bypath
.If you need to make sure that a parent object exists but you do not want modify its pre-existing state by using put, consider using
WriteOperations.merge(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.yangtools.yang.binding.InstanceIdentifier<T>, T)
instead.WARNING: Using this method may introduce garbage in data store, or recreate nodes, which were deleted by a previous transaction. It also has a significantly higher cost than
WriteOperations.put(LogicalDatastoreType, InstanceIdentifier, DataObject)
and should only be used when absolutely necessary.- Specified by:
mergeParentStructurePut
in interfaceWriteOperations
- Parameters:
store
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be written to the specified path
-
merge
public <T extends DataObject> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Description copied from interface:WriteOperations
Merges a piece of data with the existing data at a specified path. Any pre-existing data which is not explicitly overwritten will be preserved. This means that if you store a container, its child lists will be merged.If you require an explicit replace operation, use
WriteOperations.put(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.yangtools.yang.binding.InstanceIdentifier<T>, T)
instead.- Specified by:
merge
in interfaceWriteOperations
- Parameters:
store
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be merged to the specified path
-
mergeParentStructureMerge
public <T extends DataObject> void mergeParentStructureMerge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
Description copied from interface:WriteOperations
Merges a piece of data with the existing data at a specified path. Any pre-existing data which is not explicitly overwritten will be preserved. This means that if you store a container, its child lists will be merged. UnlikeWriteOperations.merge(LogicalDatastoreType, InstanceIdentifier, DataObject)
, this method will attempt to create semantically-significant parent nodes, like list entries and presence containers, as indicated bypath
.If you require an explicit replace operation, use
WriteOperations.put(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.yangtools.yang.binding.InstanceIdentifier<T>, T)
instead.WARNING: Using this method may introduce garbage in data store, or recreate nodes, which were deleted by a previous transaction. It is not necessary in most scenarios and has a significantly higher cost than
WriteOperations.merge(LogicalDatastoreType, InstanceIdentifier, DataObject)
. It should only be used when absolutely necessary.- Specified by:
mergeParentStructureMerge
in interfaceWriteOperations
- Parameters:
store
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be merged to the specified path
-
delete
public void delete(LogicalDatastoreType store, InstanceIdentifier<?> path)
Description copied from interface:WriteOperations
Removes a piece of data from specified path. This operation does not fail if the specified path does not exist.- Specified by:
delete
in interfaceWriteOperations
- Parameters:
store
- Logical data store which should be modifiedpath
- Data object path
-
cancel
public boolean cancel()
Description copied from interface:WriteTransaction
Cancels the transaction. Transactions can only be cancelled if it was not yet committed. Invoking cancel() on failed or already canceled will have no effect, and transaction is considered cancelled. Invoking cancel() on finished transaction (future returned byWriteTransaction.commit()
already successfully completed) will always fail (return false).- Specified by:
cancel
in interfaceWriteTransaction
- Returns:
false
if the task could not be cancelled, typically because it has already completed normally;true
otherwise
-
commit
public FluentFuture<? extends CommitInfo> commit()
Description copied from interface:WriteTransaction
Commits this transaction to be asynchronously applied to update the logical data tree. The returnedFluentFuture
conveys the result of applying the data changes.This call logically seals the transaction, which prevents the client from further changing the data tree using this transaction. Any subsequent calls to
put(LogicalDatastoreType, Path, Object)
,merge(LogicalDatastoreType, Path, Object)
,delete(LogicalDatastoreType, Path)
will fail withIllegalStateException
. The transaction is marked as committed and enqueued into the data store back-end for processing.Whether or not the commit is successful is determined by versioning of the data tree and validation of registered commit participants if the transaction changes the data tree.
The effects of a successful commit of data depends on listeners and commit participants that are registered with the data broker.
Example usage:
private void doWrite(final int tries) { WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction(); MyDataObject data = ...; InstanceIdentifier<MyDataObject> path = ...; writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); Futures.addCallback(writeTx.commit(), new FutureCallback<CommitInfo>() { public void onSuccess(CommitInfo result) { // succeeded } public void onFailure(Throwable t) { if (t instanceof OptimisticLockFailedException) { if(( tries - 1) > 0 ) { // do retry doWrite(tries - 1); } else { // out of retries } } else { // failed due to another type of TransactionCommitFailedException. } }); } ... doWrite(2);
Failure scenarios
Transaction may fail because of multiple reasons, such as
-
Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
case the returned future will fail with an
OptimisticLockFailedException
. It is the responsibility of the caller to create a new transaction and commit the same modification again in order to update data tree. Warning: In most cases, retrying after an OptimisticLockFailedException will result in a high probability of success. However, there are scenarios, albeit unusual, where any number of retries will not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) to avoid an endless loop. - Data change introduced by this transaction did not pass validation by commit handlers or data was
incorrectly structured. Returned future will fail with a
DataValidationFailedException
. User should not retry to create new transaction with same data, since it probably will fail again.
Change compatibility
There are several sets of changes which could be considered incompatible between two transactions which are derived from same initial state. Rules for conflict detection applies recursively for each subtree level.Change compatibility of leafs, leaf-list items
Following table shows state changes and failures between two concurrent transactions, which are based on same initial state, Tx 1 completes successfully before Tx 2 is committed.Change compatibility of leaf values Initial state Tx 1 Tx 2 Result Empty put(A,1) put(A,2) Tx 2 will fail, state is A=1 Empty put(A,1) merge(A,2) A=2 Empty merge(A,1) put(A,2) Tx 2 will fail, state is A=1 Empty merge(A,1) merge(A,2) A=2 A=0 put(A,1) put(A,2) Tx 2 will fail, A=1 A=0 put(A,1) merge(A,2) A=2 A=0 merge(A,1) put(A,2) Tx 2 will fail, A=1 A=0 merge(A,1) merge(A,2) A=2 A=0 delete(A) put(A,2) Tx 2 will fail, A does not exists A=0 delete(A) merge(A,2) A=2 Change compatibility of subtrees
Following table shows state changes and failures between two concurrent transactions, which are based on same initial state, Tx 1 completes successfully before Tx 2 is committed.Change compatibility of containers Initial state Tx 1 Tx 2 Result Empty put(TOP,[]) put(TOP,[]) Tx 2 will fail, state is TOP=[] Empty put(TOP,[]) merge(TOP,[]) TOP=[] Empty put(TOP,[FOO=1]) put(TOP,[BAR=1]) Tx 2 will fail, state is TOP=[FOO=1] Empty put(TOP,[FOO=1]) merge(TOP,[BAR=1]) TOP=[FOO=1,BAR=1] Empty merge(TOP,[FOO=1]) put(TOP,[BAR=1]) Tx 2 will fail, state is TOP=[FOO=1] Empty merge(TOP,[FOO=1]) merge(TOP,[BAR=1]) TOP=[FOO=1,BAR=1] TOP=[] put(TOP,[FOO=1]) put(TOP,[BAR=1]) Tx 2 will fail, state is TOP=[FOO=1] TOP=[] put(TOP,[FOO=1]) merge(TOP,[BAR=1]) state is TOP=[FOO=1,BAR=1] TOP=[] merge(TOP,[FOO=1]) put(TOP,[BAR=1]) Tx 2 will fail, state is TOP=[FOO=1] TOP=[] merge(TOP,[FOO=1]) merge(TOP,[BAR=1]) state is TOP=[FOO=1,BAR=1] TOP=[] delete(TOP) put(TOP,[BAR=1]) Tx 2 will fail, state is empty store TOP=[] delete(TOP) merge(TOP,[BAR=1]) state is TOP=[BAR=1] TOP=[] put(TOP/FOO,1) put(TOP/BAR,1]) state is TOP=[FOO=1,BAR=1] TOP=[] put(TOP/FOO,1) merge(TOP/BAR,1) state is TOP=[FOO=1,BAR=1] TOP=[] merge(TOP/FOO,1) put(TOP/BAR,1) state is TOP=[FOO=1,BAR=1] TOP=[] merge(TOP/FOO,1) merge(TOP/BAR,1) state is TOP=[FOO=1,BAR=1] TOP=[] delete(TOP) put(TOP/BAR,1) Tx 2 will fail, state is empty store TOP=[] delete(TOP) merge(TOP/BAR,1] Tx 2 will fail, state is empty store TOP=[FOO=1] put(TOP/FOO,2) put(TOP/BAR,1) state is TOP=[FOO=2,BAR=1] TOP=[FOO=1] put(TOP/FOO,2) merge(TOP/BAR,1) state is TOP=[FOO=2,BAR=1] TOP=[FOO=1] merge(TOP/FOO,2) put(TOP/BAR,1) state is TOP=[FOO=2,BAR=1] TOP=[FOO=1] merge(TOP/FOO,2) merge(TOP/BAR,1) state is TOP=[FOO=2,BAR=1] TOP=[FOO=1] delete(TOP/FOO) put(TOP/BAR,1) state is TOP=[BAR=1] TOP=[FOO=1] delete(TOP/FOO) merge(TOP/BAR,1] state is TOP=[BAR=1] Examples of failure scenarios
Conflict of two transactions
This example illustrates two concurrent transactions, which derived from same initial state of data tree and proposes conflicting modifications.txA = broker.newWriteTransaction(); // allocates new transaction, data tree is empty txB = broker.newWriteTransaction(); // allocates new transaction, data tree is empty txA.put(CONFIGURATION, PATH, A); // writes to PATH value A txB.put(CONFIGURATION, PATH, B) // writes to PATH value B ListenableFuture futureA = txA.commit(); // transaction A is sealed and committed ListenebleFuture futureB = txB.commit(); // transaction B is sealed and committed
Commit of transaction A will be processed asynchronously and data tree will be updated to contain valueA
forPATH
. ReturnedFluentFuture
will successfully complete once state is applied to data tree. Commit of Transaction B will fail, because previous transaction also modified path in a concurrent way. The state introduced by transaction B will not be applied. ReturnedFluentFuture
object will fail withOptimisticLockFailedException
exception, which indicates to client that concurrent transaction prevented the committed transaction from being applied.
A successful commit produces implementation-specific
CommitInfo
structure, which is used to communicate post-condition information to the caller. Such information can contain commit-id, timing information or any other information the implementation wishes to share.- Specified by:
commit
in interfaceWriteTransaction
- Returns:
- a FluentFuture containing the result of the commit information. The Future blocks until the commit
operation is complete. A successful commit returns nothing. On failure, the Future will fail with a
TransactionCommitFailedException
or an exception derived from TransactionCommitFailedException.
-
Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
case the returned future will fail with an
-
-