@Beta public interface WriteTransaction extends Transaction
Initial state of write transaction is a stable snapshot of the current data tree. The state is captured when the transaction is created and its state and underlying data tree are not affected by other concurrently running transactions.
Write transactions are isolated from other concurrent write transactions. All writes are local to the transaction and represent only a proposal of state change for the data tree and it is not visible to any other concurrently running transaction.
Applications make changes to the local data tree in the transaction by via the put, merge, and delete operations.
Performing the following put operations:
1) container { list [ a ] } 2) container { list [ b ] }will result in the following data being present:
container { list [ b ] }
Performing the following merge operations:
1) container { list [ a ] } 2) container { list [ b ] }will result in the following data being present:
container { list [ a, b ] }This also means that storing the container will preserve any augmentations which have been attached to it.
After applying changes to the local data tree, applications publish the changes proposed in the transaction
by calling commit()
on the transaction. This seals the transaction (preventing any further writes using this
transaction) and commits it to be processed and applied to global conceptual data tree.
The transaction commit may fail due to a concurrent transaction modifying and committing data in an incompatible way.
See commit()
for more concrete commit failure examples.
Implementation Note: This interface is not intended to be implemented by users of MD-SAL, but only to be consumed by them.
Modifier and Type | Field and Description |
---|---|
static boolean |
CREATE_MISSING_PARENTS
Flag value indicating that missing parents should be created.
|
static boolean |
FAIL_ON_MISSING_PARENTS
Flag value indicating that missing parents should cause an error.
|
Modifier and Type | Method and Description |
---|---|
boolean |
cancel()
Cancels the transaction.
|
@NonNull com.google.common.util.concurrent.FluentFuture<? extends CommitInfo> |
commit()
Commits this transaction to be asynchronously applied to update the logical data tree.
|
void |
delete(LogicalDatastoreType store,
InstanceIdentifier<?> path)
Removes a piece of data from specified path.
|
<T extends TreeNode> |
merge(LogicalDatastoreType store,
InstanceIdentifier<T> path,
T data)
Merges a piece of data with the existing data at a specified path.
|
<T extends TreeNode> |
merge(LogicalDatastoreType store,
InstanceIdentifier<T> path,
T data,
boolean createMissingParents)
Merges a piece of data with the existing data at a specified path.
|
<T extends TreeNode> |
put(LogicalDatastoreType store,
InstanceIdentifier<T> path,
T data)
Stores a piece of data at the specified path.
|
<T extends TreeNode> |
put(LogicalDatastoreType store,
InstanceIdentifier<T> path,
T data,
boolean createMissingParents)
Stores a piece of data at the specified path.
|
static final boolean CREATE_MISSING_PARENTS
static final boolean FAIL_ON_MISSING_PARENTS
boolean cancel()
commit()
already successfully completed)
will always fail (return false).@CheckReturnValue @NonNull com.google.common.util.concurrent.FluentFuture<? extends CommitInfo> commit()
FluentFuture
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
with IllegalStateException
. 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.
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);
Transaction may fail because of multiple reasons, such as
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.
DataValidationFailedException
. User
should not retry to create new transaction with same data, since it probably will fail again.
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 |
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] |
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 committedCommit of transaction A will be processed asynchronously and data tree will be updated to contain value
A
for PATH
. Returned FluentFuture
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. Returned
FluentFuture
object will fail with OptimisticLockFailedException
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.
TransactionCommitFailedException
or an exception derived from TransactionCommitFailedException.IllegalStateException
- if the transaction is already committed or was canceled.<T extends TreeNode> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
This method does not automatically create missing parent nodes. It is equivalent to invoking
put(LogicalDatastoreType, InstanceIdentifier, TreeNode, boolean)
with createMissingParents
set to false.
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 merge(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier<T>, T)
instead.
T
- data tree typestore
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be written to the specified pathIllegalStateException
- if the transaction has already been submitted<T extends TreeNode> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data, boolean createMissingParents)
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 merge(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier<T>, T)
instead.
Note: Using createMissingParents
with value true, may
introduce garbage in data store, or recreate nodes, which were deleted by
previous transaction.
T
- data tree typestore
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be written to the specified pathcreateMissingParents
- if CREATE_MISSING_PARENTS
, any missing parent nodes will be automatically
created using a merge operation.IllegalStateException
- if the transaction has already been submitted<T extends TreeNode> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
This method does not automatically create missing parent nodes. It is equivalent to invoking
merge(LogicalDatastoreType, InstanceIdentifier, TreeNode, boolean)
with createMissingParents
set to false.
If you require an explicit replace operation, use put(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier<T>, T)
instead.
T
- data tree typestore
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be merged to the specified pathIllegalStateException
- if the transaction has already been submitted<T extends TreeNode> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data, boolean createMissingParents)
If you require an explicit replace operation, use put(org.opendaylight.mdsal.common.api.LogicalDatastoreType, org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier<T>, T)
instead.
T
- data tree typestore
- the logical data store which should be modifiedpath
- the data object pathdata
- the data object to be merged to the specified pathcreateMissingParents
- if CREATE_MISSING_PARENTS
, any missing parent nodes will be automatically
created using a merge operation.IllegalStateException
- if the transaction has already been submittedvoid delete(LogicalDatastoreType store, InstanceIdentifier<?> path)
store
- Logical data store which should be modifiedpath
- Data object pathIllegalStateException
- if the transaction was committed or canceled.Copyright © 2019 OpenDaylight. All rights reserved.