import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
-import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
private final Object txLock = new Object();
private final DataBroker dataBroker;
private final String nodeId;
- private LifecycleService lifecycleService;
@GuardedBy("txLock")
private WriteTransaction wTx;
@GuardedBy("txLock")
private ListenableFuture<Void> lastSubmittedFuture;
- private boolean initCommit;
+ private volatile boolean initCommit;
@GuardedBy("txLock")
private TransactionChainManagerStatus transactionChainManagerStatus = TransactionChainManagerStatus.SLEEPING;
TransactionChainManager(@Nonnull final DataBroker dataBroker,
@Nonnull final DeviceInfo deviceInfo) {
this.dataBroker = dataBroker;
- this.nodeId = deviceInfo.getNodeInstanceIdentifier().getKey().getId().getValue();
- this.transactionChainManagerStatus = TransactionChainManagerStatus.SLEEPING;
+ this.nodeId = deviceInfo.getLOGValue();
this.lastSubmittedFuture = Futures.immediateFuture(null);
}
@GuardedBy("txLock")
private void createTxChain() {
- Optional.ofNullable(txChainFactory).ifPresent(TransactionChain::close);
+ BindingTransactionChain txChainFactoryTemp = txChainFactory;
txChainFactory = dataBroker.createTransactionChain(TransactionChainManager.this);
+ Optional.ofNullable(txChainFactoryTemp).ifPresent(TransactionChain::close);
}
- public void setLifecycleService(final LifecycleService lifecycleService) {
- this.lifecycleService = lifecycleService;
- }
-
- void initialSubmitWriteTransaction() {
+ boolean initialSubmitWriteTransaction() {
enableSubmit();
- submitWriteTransaction();
+ return submitWriteTransaction();
}
/**
*/
void activateTransactionManager() {
if (LOG.isDebugEnabled()) {
- LOG.debug("activateTransactionManager for node {} transaction submit is set to {}", this.nodeId, submitIsEnabled);
+ LOG.debug("activateTransactionManager for node {} transaction submit is set to {}",
+ this.nodeId, submitIsEnabled);
}
synchronized (txLock) {
- if (TransactionChainManagerStatus.SLEEPING.equals(transactionChainManagerStatus)) {
- Preconditions.checkState(txChainFactory == null, "TxChainFactory survive last close.");
- Preconditions.checkState(wTx == null, "We have some unexpected WriteTransaction.");
+ if (TransactionChainManagerStatus.SLEEPING == transactionChainManagerStatus) {
+ Preconditions.checkState(txChainFactory == null,
+ "TxChainFactory survive last close.");
+ Preconditions.checkState(wTx == null,
+ "We have some unexpected WriteTransaction.");
this.transactionChainManagerStatus = TransactionChainManagerStatus.WORKING;
this.submitIsEnabled = false;
this.initCommit = true;
}
final ListenableFuture<Void> future;
synchronized (txLock) {
- if (TransactionChainManagerStatus.WORKING.equals(transactionChainManagerStatus)) {
+ if (TransactionChainManagerStatus.WORKING == transactionChainManagerStatus) {
transactionChainManagerStatus = TransactionChainManagerStatus.SLEEPING;
future = txChainShuttingDown();
- Preconditions.checkState(wTx == null, "We have some unexpected WriteTransaction.");
+ Preconditions.checkState(wTx == null,
+ "We have some unexpected WriteTransaction.");
Futures.addCallback(future, new FutureCallback<Void>() {
@Override
public void onSuccess(final Void result) {
}
});
} else {
- // TODO : ignoring redundant deactivate invocation
+ // ignoring redundant deactivate invocation
future = Futures.immediateCheckedFuture(null);
}
}
}
return true;
}
- Preconditions.checkState(TransactionChainManagerStatus.WORKING.equals(transactionChainManagerStatus),
- "we have here Uncompleted Transaction for node {} and we are not MASTER", this.nodeId);
+ Preconditions.checkState(TransactionChainManagerStatus.WORKING == transactionChainManagerStatus,
+ "we have here Uncompleted Transaction for node {} and we are not MASTER",
+ this.nodeId);
final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit();
+ lastSubmittedFuture = submitFuture;
+ wTx = null;
+
+ if (initCommit) {
+ try {
+ submitFuture.get(5L, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException ex) {
+ LOG.error("Exception during INITIAL transaction submitting. ", ex);
+ return false;
+ }
+ initCommit = false;
+ return true;
+ }
+
Futures.addCallback(submitFuture, new FutureCallback<Void>() {
@Override
public void onSuccess(final Void result) {
- if (initCommit) {
- initCommit = false;
- }
+ //NOOP
}
@Override
LOG.error("Exception during transaction submitting. ", t);
}
}
- if (initCommit) {
- wTx = null;
- Optional.ofNullable(lifecycleService).ifPresent(LifecycleService::closeConnection);
- }
}
});
- lastSubmittedFuture = submitFuture;
- wTx = null;
}
return true;
}
<T extends DataObject> void addDeleteOperationTotTxChain(final LogicalDatastoreType store,
final InstanceIdentifier<T> path){
- final WriteTransaction writeTx = getTransactionSafely();
- if (Objects.nonNull(writeTx)) {
- writeTx.delete(store, path);
- } else {
- if (LOG.isDebugEnabled()) {
+ synchronized (txLock) {
+ ensureTransaction();
+ if (wTx == null) {
LOG.debug("WriteTx is null for node {}. Delete {} was not realized.", this.nodeId, path);
+ throw new TransactionChainClosedException(CANNOT_WRITE_INTO_TRANSACTION);
}
- throw new TransactionChainClosedException(CANNOT_WRITE_INTO_TRANSACTION);
+
+ wTx.delete(store, path);
}
}
final InstanceIdentifier<T> path,
final T data,
final boolean createParents){
- final WriteTransaction writeTx = getTransactionSafely();
- if (Objects.nonNull(writeTx)) {
- writeTx.put(store, path, data, createParents);
- } else {
- if (LOG.isDebugEnabled()) {
+ synchronized (txLock) {
+ ensureTransaction();
+ if (wTx == null) {
LOG.debug("WriteTx is null for node {}. Write data for {} was not realized.", this.nodeId, path);
+ throw new TransactionChainClosedException(CANNOT_WRITE_INTO_TRANSACTION);
}
- throw new TransactionChainClosedException(CANNOT_WRITE_INTO_TRANSACTION);
+
+ wTx.put(store, path, data, createParents);
}
}
@Override
public void onTransactionChainFailed(final TransactionChain<?, ?> chain,
final AsyncTransaction<?, ?> transaction, final Throwable cause) {
- if (transactionChainManagerStatus.equals(TransactionChainManagerStatus.WORKING)) {
- LOG.warn("txChain failed -> recreating due to {}", cause);
- recreateTxChain();
+ synchronized (txLock) {
+ if (TransactionChainManagerStatus.WORKING == transactionChainManagerStatus) {
+ LOG.warn("Transaction chain failed, recreating chain due to ", cause);
+ createTxChain();
+ wTx = null;
+ }
}
}
// NOOP
}
- private void recreateTxChain() {
- synchronized (txLock) {
- createTxChain();
- wTx = null;
+ @GuardedBy("txLock")
+ private void ensureTransaction() {
+ if (wTx == null && TransactionChainManagerStatus.WORKING == transactionChainManagerStatus
+ && txChainFactory != null) {
+ wTx = txChainFactory.newWriteOnlyTransaction();
}
}
- @Nullable
- private WriteTransaction getTransactionSafely() {
- synchronized (txLock) {
- if (wTx == null && TransactionChainManagerStatus.WORKING.equals(transactionChainManagerStatus)) {
- Optional.ofNullable(txChainFactory).ifPresent(bindingTransactionChain -> wTx = txChainFactory.newWriteOnlyTransaction());
- }
- }
- return wTx;
- }
-
@VisibleForTesting
void enableSubmit() {
synchronized (txLock) {
if (LOG.isDebugEnabled()) {
LOG.debug("TxManager is going SHUTTING_DOWN for node {}", this.nodeId);
}
- ListenableFuture<Void> future;
synchronized (txLock) {
this.transactionChainManagerStatus = TransactionChainManagerStatus.SHUTTING_DOWN;
- future = txChainShuttingDown();
+ return txChainShuttingDown();
}
- return future;
}
@GuardedBy("txLock")
private ListenableFuture<Void> txChainShuttingDown() {
+ boolean wasSubmitEnabled = submitIsEnabled;
submitIsEnabled = false;
ListenableFuture<Void> future;
- if (txChainFactory == null) {
+
+ if (!wasSubmitEnabled || txChainFactory == null) {
// stay with actual thread
future = Futures.immediateCheckedFuture(null);
+
+ if (wTx != null) {
+ wTx.cancel();
+ wTx = null;
+ }
} else if (wTx == null) {
// hijack md-sal thread
future = lastSubmittedFuture;
future = wTx.submit();
wTx = null;
}
+
return future;
}