BUG-4084: Li: Log unsuccessful submiting of write transactiion
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / TransactionChainManager.java
1 /**
2  * Copyright (c) 2015 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
9 package org.opendaylight.openflowplugin.impl.device;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
27 import org.opendaylight.yangtools.concepts.Registration;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * openflowplugin-impl
36  * org.opendaylight.openflowplugin.impl.device
37  * <p/>
38  * Package protected class for controlling {@link WriteTransaction} life cycle. It is
39  * a {@link TransactionChainListener} and provide package protected methods for writeToTransaction
40  * method (wrapped {@link WriteTransaction#put(LogicalDatastoreType, InstanceIdentifier, DataObject)})
41  * and submitTransaction method (wrapped {@link WriteTransaction#submit()})
42  *
43  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
44  *         </p>
45  *         Created: Apr 2, 2015
46  */
47 class TransactionChainManager implements TransactionChainListener, AutoCloseable {
48
49     private static final Logger LOG = LoggerFactory.getLogger(TransactionChainManager.class);
50
51     private final Object txLock = new Object();
52
53     private final DataBroker dataBroker;
54     private WriteTransaction wTx;
55     private BindingTransactionChain txChainFactory;
56     private boolean submitIsEnabled;
57
58     public TransactionChainManagerStatus getTransactionChainManagerStatus() {
59         return transactionChainManagerStatus;
60     }
61
62     private TransactionChainManagerStatus transactionChainManagerStatus;
63     private ReadyForNewTransactionChainHandler readyForNewTransactionChainHandler;
64     private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
65     private Registration managerRegistration;
66
67     TransactionChainManager(@Nonnull final DataBroker dataBroker,
68                             @Nonnull final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
69                             @Nonnull final Registration managerRegistration) {
70         this.dataBroker = Preconditions.checkNotNull(dataBroker);
71         this.nodeII = Preconditions.checkNotNull(nodeII);
72         this.managerRegistration = Preconditions.checkNotNull(managerRegistration);
73         this.transactionChainManagerStatus = TransactionChainManagerStatus.WORKING;
74         createTxChain(dataBroker);
75         LOG.debug("created txChainManager");
76     }
77
78     private void createTxChain(final DataBroker dataBroker) {
79         txChainFactory = dataBroker.createTransactionChain(TransactionChainManager.this);
80     }
81
82     void initialSubmitWriteTransaction() {
83         enableSubmit();
84         submitWriteTransaction();
85     }
86
87     public synchronized boolean attemptToRegisterHandler(final ReadyForNewTransactionChainHandler readyForNewTransactionChainHandler) {
88         if (TransactionChainManagerStatus.SHUTTING_DOWN.equals(this.transactionChainManagerStatus)
89                 && null == this.readyForNewTransactionChainHandler) {
90             this.readyForNewTransactionChainHandler = readyForNewTransactionChainHandler;
91             if (managerRegistration == null) {
92                 this.readyForNewTransactionChainHandler.onReadyForNewTransactionChain();
93             }
94             return true;
95         } else {
96             return false;
97         }
98     }
99
100     boolean submitWriteTransaction() {
101         if (!submitIsEnabled) {
102             LOG.trace("transaction not committed - submit block issued");
103             return false;
104         }
105         synchronized (txLock) {
106             if (wTx == null) {
107                 LOG.trace("nothing to commit - submit returns true");
108                 return true;
109             }
110             final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit();
111             Futures.addCallback(submitFuture, new FutureCallback<Void>() {
112                 @Override
113                 public void onSuccess(Void result) {
114                     //no action required
115                 }
116
117                 @Override
118                 public void onFailure(Throwable t) {
119                     if (t instanceof TransactionCommitFailedException) {
120                         LOG.error("Transaction commit failed. {}", t);
121                     } else {
122                         LOG.error("Exception during transaction submitting. {}", t);
123                     }
124                 }
125             });
126             wTx = null;
127         }
128         return true;
129     }
130
131     <T extends DataObject> void addDeleteOperationTotTxChain(final LogicalDatastoreType store,
132                                                              final InstanceIdentifier<T> path) {
133         final WriteTransaction writeTx = getTransactionSafely();
134         writeTx.delete(store, path);
135     }
136
137     <T extends DataObject> void writeToTransaction(final LogicalDatastoreType store,
138                                                    final InstanceIdentifier<T> path, final T data) {
139         final WriteTransaction writeTx = getTransactionSafely();
140         writeTx.put(store, path, data);
141     }
142
143     @Override
144     public void onTransactionChainFailed(final TransactionChain<?, ?> chain,
145                                          final AsyncTransaction<?, ?> transaction, final Throwable cause) {
146         LOG.warn("txChain failed -> recreating", cause);
147         recreateTxChain();
148     }
149
150     @Override
151     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
152         // NOOP - only yet, here is probably place for notification to get new WriteTransaction
153     }
154
155     private void recreateTxChain() {
156         txChainFactory.close();
157         createTxChain(dataBroker);
158         synchronized (txLock) {
159             wTx = null;
160         }
161     }
162
163     private WriteTransaction getTransactionSafely() {
164         if (wTx == null && !TransactionChainManagerStatus.SHUTTING_DOWN.equals(transactionChainManagerStatus)) {
165             synchronized (txLock) {
166                 if (wTx == null) {
167                     wTx = txChainFactory.newWriteOnlyTransaction();
168                 }
169             }
170         }
171         return wTx;
172     }
173
174     @VisibleForTesting
175     void enableSubmit() {
176         submitIsEnabled = true;
177     }
178
179     @Override
180     public void close() {
181         LOG.debug("Removing node {} from operational DS.", nodeII);
182         synchronized (txLock) {
183             final WriteTransaction writeTx = getTransactionSafely();
184             this.transactionChainManagerStatus = TransactionChainManagerStatus.SHUTTING_DOWN;
185             writeTx.delete(LogicalDatastoreType.OPERATIONAL, nodeII);
186             LOG.debug("Delete node {} from operational DS put to write transaction.", nodeII);
187             CheckedFuture<Void, TransactionCommitFailedException> submitsFuture = writeTx.submit();
188             LOG.debug("Delete node {} from operational DS write transaction submitted.", nodeII);
189             Futures.addCallback(submitsFuture, new FutureCallback<Void>() {
190                 @Override
191                 public void onSuccess(final Void aVoid) {
192                     LOG.debug("Removing node {} from operational DS successful .", nodeII);
193                     notifyReadyForNewTransactionChainAndCloseFactory();
194                 }
195
196                 @Override
197                 public void onFailure(final Throwable throwable) {
198                     LOG.info("Attempt to close transaction chain factory failed.", throwable);
199                     notifyReadyForNewTransactionChainAndCloseFactory();
200                 }
201             });
202             wTx = null;
203         }
204     }
205
206     private void notifyReadyForNewTransactionChainAndCloseFactory() {
207         synchronized (this) {
208             try {
209                 LOG.debug("Closing registration in manager.");
210                 managerRegistration.close();
211             } catch (Exception e) {
212                 LOG.warn("Failed to close transaction chain manager's registration.", e);
213             }
214             managerRegistration = null;
215             if (null != readyForNewTransactionChainHandler) {
216                 readyForNewTransactionChainHandler.onReadyForNewTransactionChain();
217             }
218         }
219         txChainFactory.close();
220         LOG.debug("Transaction chain factory closed.");
221     }
222
223     public enum TransactionChainManagerStatus {
224         WORKING, SHUTTING_DOWN;
225     }
226
227 }