* and we are able to set a scheduler for an automatic transaction submitting by time (0,5sec).
*/
void submitTransaction() {
- txChainManager.enableCounter();
+ txChainManager.enableSubmit();
txChainManager.submitTransaction();
}
//TODO : this is the point, where we can discover that add flow operation failed and where we should
//TODO : remove this flow from deviceFlowRegistry
final Error error = (Error) ofHeader;
- final String message = "Operation on device failed";
+ final String message = "Operation on device failed with xid "+ofHeader.getXid()+".";
rpcResult = RpcResultBuilder
.<OfHeader>failed()
.withError(RpcError.ErrorType.APPLICATION, message, new DeviceDataException(message, error))
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
private WriteTransaction wTx;
private Timeout submitTaskTime;
private long nrOfActualTx;
- private boolean counterIsEnabled;
+ private boolean submitIsEnabled;
TransactionChainManager(@Nonnull final DataBroker dataBroker,
@Nonnull final HashedWheelTimer hashedWheelTimer,
public void commitOperationsGatheredInOneTransaction(){
- enableCounter();
+ enableSubmit();
submitTransaction();
}
public void startGatheringOperationsToOneTransaction(){
- counterIsEnabled = false;
+ submitIsEnabled = false;
}
synchronized <T extends DataObject> void writeToTransaction(final LogicalDatastoreType store,
final InstanceIdentifier<T> path, final T data) {
- if (wTx == null) {
- wTx = txChainFactory.newWriteOnlyTransaction();
- }
- wTx.put(store, path, data);
- if (counterIsEnabled) {
+ try {
+ WriteTransaction writeTx = getTransactionSafely();
+ writeTx.put(store, path, data);
countTxInAndCommit();
+ } catch (Exception e) {
+ LOG.warn("failed to put into writeOnlyTransaction: {}", e.getMessage());
+ LOG.trace("failed to put into writeOnlyTransaction.. ", e);
}
}
- synchronized <T extends DataObject> void addDeleteOperationTotTxChain(final LogicalDatastoreType store,
- final InstanceIdentifier<T> path) {
+ private WriteTransaction getTransactionSafely() {
if (wTx == null) {
wTx = txChainFactory.newWriteOnlyTransaction();
}
- wTx.delete(store, path);
- if (counterIsEnabled) {
+ return wTx;
+ }
+
+ synchronized <T extends DataObject> void addDeleteOperationTotTxChain(final LogicalDatastoreType store,
+ final InstanceIdentifier<T> path) {
+ try {
+ WriteTransaction writeTx = getTransactionSafely();
+ writeTx.delete(store, path);
countTxInAndCommit();
+ } catch (Exception e) {
+ LOG.warn("failed to put into writeOnlyTransaction [{}]: {}", e.getMessage());
+ LOG.trace("failed to put into writeOnlyTransaction.. ", e);
}
}
}
}
+ synchronized void submitScheduledTransaction(Timeout timeout) {
+ if (timeout.isCancelled()) {
+ // zombie timer executed
+ return;
+ }
+
+ if (submitIsEnabled) {
+ submitTransaction();
+ } else {
+ LOG.info("transaction submit task will not be scheduled - submit block issued.");
+ }
+ }
+
synchronized void submitTransaction() {
- if (counterIsEnabled) {
- if (wTx != null) {
+ if (submitIsEnabled) {
+ if (wTx != null && nrOfActualTx > 0) {
LOG.trace("submitting transaction, counter: {}", nrOfActualTx);
- wTx.submit();
+ CheckedFuture<Void, TransactionCommitFailedException> submitResult = wTx.submit();
+ hookTimeExpenseCounter(submitResult, String.valueOf(wTx.getIdentifier()) + "::" + nrOfActualTx);
wTx = null;
nrOfActualTx = 0L;
}
- if (submitTaskTime != null && !submitTaskTime.isExpired()) {
+ if (submitTaskTime != null) {
+ // if possible then cancel current timer (even if being executed via timer)
submitTaskTime.cancel();
}
submitTaskTime = hashedWheelTimer.newTimeout(new TimerTask() {
@Override
public void run(final Timeout timeout) throws Exception {
- submitTransaction();
+ submitScheduledTransaction(timeout);
}
}, timerValue, TimeUnit.MILLISECONDS);
+
} else {
- LOG.info("Task will not be scheduled - submit block issued.");
+ LOG.trace("transaction not committed - submit block issued");
}
}
- synchronized void enableCounter() {
- counterIsEnabled = true;
+ private void hookTimeExpenseCounter(CheckedFuture<Void, TransactionCommitFailedException> submitResult, final String name) {
+ final long submitFiredTime = System.currentTimeMillis();
+ LOG.debug("submit of {} fired", name);
+ Futures.addCallback(submitResult, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ LOG.debug("submit of {} finished in {} ms", name, System.currentTimeMillis() - submitFiredTime);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.warn("transaction submit failed: {}", t.getMessage());
+ }
+ });
+ }
+
+ synchronized void enableSubmit() {
+ submitIsEnabled = true;
}
@Override
@Override
public short getTableId() {
- return 0;
+ return tableId;
}
@Override
public int getPriority() {
- return 0;
+ return priority;
}
@Override
public BigInteger getCookie() {
- return null;
+ return cookie;
}
}
}
*/
package org.opendaylight.openflowplugin.impl.services;
+import java.util.ArrayList;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.TableFeaturesReplyConvertor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.MultipartReplyBody;
import java.math.BigInteger;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.TransactionId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.UpdateTableOutputBuilder;
@Override
public Future<RpcResult<UpdateTableOutput>> updateTable(final UpdateTableInput input) {
- class FunctionImpl implements Function<DataCrate<List<MultipartReply>>,ListenableFuture<RpcResult<List<MultipartReply>>>> {
+ class FunctionImpl implements
+ Function<DataCrate<List<MultipartReply>>, ListenableFuture<RpcResult<List<MultipartReply>>>> {
@Override
public ListenableFuture<RpcResult<List<MultipartReply>>> apply(final DataCrate<List<MultipartReply>> data) {
- messageSpy.spyMessage(input.getImplementedInterface(), MessageSpy.STATISTIC_GROUP.TO_SWITCH_SUBMITTED_SUCCESS);
+ messageSpy.spyMessage(input.getImplementedInterface(),
+ MessageSpy.STATISTIC_GROUP.TO_SWITCH_SUBMITTED_SUCCESS);
final SettableFuture<RpcResult<List<MultipartReply>>> result = SettableFuture.create();
-
final MultipartRequestTableFeaturesCaseBuilder caseBuilder = new MultipartRequestTableFeaturesCaseBuilder();
final MultipartRequestTableFeaturesBuilder requestBuilder = new MultipartRequestTableFeaturesBuilder();
final List<TableFeatures> ofTableFeatureList = TableFeaturesConvertor.toTableFeaturesRequest(input
}
}
- final ListenableFuture<RpcResult<List<MultipartReply>>> multipartFuture = handleServiceCall( PRIMARY_CONNECTION, new FunctionImpl());
+ final ListenableFuture<RpcResult<List<MultipartReply>>> multipartFuture = handleServiceCall(PRIMARY_CONNECTION,
+ new FunctionImpl());
final SettableFuture<RpcResult<UpdateTableOutput>> finalFuture = SettableFuture.create();
class CallBackImpl implements FutureCallback<RpcResult<List<MultipartReply>>> {
final List<MultipartReply> multipartReplies = result.getResult();
if (multipartReplies.isEmpty()) {
LOGGER.debug("Multipart reply to table features request shouldn't be empty list.");
- finalFuture.set(RpcResultBuilder.<UpdateTableOutput>failed().withError(ErrorType.RPC, "Multipart reply list is empty.").build());
+ finalFuture.set(RpcResultBuilder.<UpdateTableOutput> failed()
+ .withError(ErrorType.RPC, "Multipart reply list is empty.").build());
} else {
final Long xid = multipartReplies.get(0).getXid();
- LOGGER.debug("OnSuccess, rpc result successful, multipart response for rpc update-table with xid {} obtained.",xid);
+ LOGGER.debug(
+ "OnSuccess, rpc result successful, multipart response for rpc update-table with xid {} obtained.",
+ xid);
final UpdateTableOutputBuilder updateTableOutputBuilder = new UpdateTableOutputBuilder();
updateTableOutputBuilder.setTransactionId(new TransactionId(BigInteger.valueOf(xid)));
finalFuture.set(RpcResultBuilder.success(updateTableOutputBuilder.build()).build());
+ writeResponseToOperationalDatastore(multipartReplies);
}
- //TODO: output could contain more interesting things then only xid.
- //(According to rfc output for table-update it is only xid)
-// for (MultipartReply multipartReply : result.getResult()) {
-// if (multipartReply.getType().equals(MultipartType.OFPMPTABLEFEATURES)) {
-// }
-// }
} else {
LOGGER.debug("OnSuccess, rpc result unsuccessful, multipart response for rpc update-table was unsuccessful.");
- finalFuture.set(RpcResultBuilder.<UpdateTableOutput>failed().withRpcErrors(result.getErrors()).build());
+ finalFuture.set(RpcResultBuilder.<UpdateTableOutput> failed().withRpcErrors(result.getErrors())
+ .build());
}
}
@Override
public void onFailure(Throwable t) {
LOGGER.debug("Failure multipart response for table features request. Exception: {}", t);
- finalFuture.set(RpcResultBuilder.<UpdateTableOutput>failed().withError(ErrorType.RPC, "Future error", t).build());
+ finalFuture.set(RpcResultBuilder.<UpdateTableOutput> failed()
+ .withError(ErrorType.RPC, "Future error", t).build());
+ }
+
+ /**
+ * @param multipartReplies
+ */
+ private void writeResponseToOperationalDatastore(final List<MultipartReply> multipartReplies) {
+
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures> salTableFeatures = convertToSalTableFeatures(multipartReplies);
+
+ final NodeId nodeId = deviceContext.getPrimaryConnectionContext().getNodeId();
+ final InstanceIdentifier<FlowCapableNode> flowCapableNodeII = InstanceIdentifier.create(Nodes.class)
+ .child(Node.class, new NodeKey(nodeId)).augmentation(FlowCapableNode.class);
+ for (org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures tableFeatureData : salTableFeatures) {
+ final Short tableId = tableFeatureData.getTableId();
+ KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures, TableFeaturesKey> tableFeaturesII = flowCapableNodeII
+ .child(Table.class, new TableKey(tableId))
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures.class,
+ new TableFeaturesKey(tableId));
+ deviceContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, tableFeaturesII,
+ tableFeatureData);
+ }
+
}
+
+ private List<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures> convertToSalTableFeatures(
+ final List<MultipartReply> multipartReplies) {
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures> salTableFeaturesAll = new ArrayList<>();
+ for (MultipartReply multipartReply : multipartReplies) {
+ if (multipartReply.getType().equals(MultipartType.OFPMPTABLEFEATURES)) {
+ MultipartReplyBody multipartReplyBody = multipartReply.getMultipartReplyBody();
+ if (multipartReplyBody instanceof MultipartReplyTableFeaturesCase) {
+ MultipartReplyTableFeaturesCase tableFeaturesCase = ((MultipartReplyTableFeaturesCase) multipartReplyBody);
+ MultipartReplyTableFeatures salTableFeatures = tableFeaturesCase
+ .getMultipartReplyTableFeatures();
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures> salTableFeaturesPartial = TableFeaturesReplyConvertor
+ .toTableFeaturesReply(salTableFeatures);
+ salTableFeaturesAll.addAll(salTableFeaturesPartial);
+ LOGGER.debug("TableFeature {} for xid {}.", salTableFeatures, multipartReply.getXid());
+ }
+ }
+ }
+ return salTableFeaturesAll;
+ }
+
}
Futures.addCallback(multipartFuture, new CallBackImpl());
return finalFuture;
}
-
private MultipartRequestInputBuilder createMultipartHeader(final MultipartType multipart, final Long xid) {
final MultipartRequestInputBuilder mprInput = new MultipartRequestInputBuilder();
mprInput.setType(multipart);
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
-import com.sun.org.apache.xpath.internal.operations.Bool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.opendaylight.openflowplugin.impl.rpc.RequestContextImpl;
import org.opendaylight.openflowplugin.impl.services.RequestContextUtil;
import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
- private void pollFlowStatistics() {
- final KeyedInstanceIdentifier<Node, NodeKey> nodeII = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(deviceContext.getPrimaryConnectionContext().getNodeId()));
- final NodeRef nodeRef = new NodeRef(nodeII);
- final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder builder =
- new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
- builder.setNode(nodeRef);
- //TODO : process data from result
- }
-
@Override
public ListenableFuture<Boolean> gatherDynamicData() {
-
final SettableFuture settableResultingFuture = SettableFuture.create();
- ListenableFuture<Boolean> resultingFuture = settableResultingFuture ;
+ ListenableFuture<Boolean> resultingFuture = settableResultingFuture;
+
if (ConnectionContext.CONNECTION_STATE.WORKING.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
final DeviceState devState = deviceContext.getDeviceState();
}
settableResultingFuture.set(new Boolean(atLeastOneSuccess));
}
+
@Override
public void onFailure(final Throwable throwable) {
settableResultingFuture.setException(throwable);
private ConcurrentHashMap<DeviceContext, StatisticsContext> contexts = new ConcurrentHashMap();
+ private final TimeCounter timeCounter = new TimeCounter();
+
+ private static final long basicTimerDelay = 3000;
+ private static long currentTimerDelay = basicTimerDelay;
+ private static long maximumTimerDelay = 900000; //wait max 15 minutes for next statistics
+
@Override
public void setDeviceInitializationPhaseHandler(final DeviceInitializationPhaseHandler handler) {
deviceInitPhaseHandler = handler;
}
private void pollStatistics() {
- for (final StatisticsContext statisticsContext : contexts.values()) {
- ListenableFuture deviceStatisticsCollectionFuture = statisticsContext.gatherDynamicData();
- Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback() {
- @Override
- public void onSuccess(final Object o) {
- //nothing to do here
- }
+ try {
+ timeCounter.markStart();
+ for (final StatisticsContext statisticsContext : contexts.values()) {
+ ListenableFuture deviceStatisticsCollectionFuture = statisticsContext.gatherDynamicData();
+ Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback() {
+ @Override
+ public void onSuccess(final Object o) {
+ timeCounter.addTimeMark();
+ }
- @Override
- public void onFailure(final Throwable throwable) {
- LOG.info("Statistics gathering for single node was not successful.");
- }
- });
+ @Override
+ public void onFailure(final Throwable throwable) {
+ timeCounter.addTimeMark();
+ LOG.info("Statistics gathering for single node was not successful: {}", throwable.getMessage());
+ LOG.debug("Statistics gathering for single node was not successful.. ", throwable);
+ }
+ });
+ }
+ } finally {
+ calculateTimerDelay();
+ if (null != hashedWheelTimer) {
+ hashedWheelTimer.newTimeout(new TimerTask() {
+ @Override
+ public void run(final Timeout timeout) throws Exception {
+ pollStatistics();
+ }
+ }, currentTimerDelay, TimeUnit.MILLISECONDS);
+ }
}
- if (null != hashedWheelTimer) {
- hashedWheelTimer.newTimeout(new TimerTask() {
- @Override
- public void run(final Timeout timeout) throws Exception {
- pollStatistics();
- }
- }, 3000, TimeUnit.MILLISECONDS);
+ }
+
+ private void calculateTimerDelay() {
+ long averageStatisticsGatheringTime = timeCounter.getAverageTimeBetweenMarks();
+ int numberOfDevices = contexts.size();
+ if ((averageStatisticsGatheringTime * numberOfDevices) > currentTimerDelay) {
+ currentTimerDelay *= 2;
+ if (currentTimerDelay > maximumTimerDelay) {
+ currentTimerDelay = maximumTimerDelay;
+ }
+ } else {
+ if (currentTimerDelay > basicTimerDelay) {
+ currentTimerDelay /= 2;
+ }
}
}
}
}
}
+
+ private final class TimeCounter {
+ private long beginningOfTime;
+ private long delta;
+ private int marksCount = 0;
+
+ public void markStart() {
+ beginningOfTime = System.currentTimeMillis();
+ delta = 0;
+ marksCount = 0;
+ }
+
+ public void addTimeMark() {
+ delta += System.currentTimeMillis() - beginningOfTime;
+ marksCount++;
+ }
+
+ public long getAverageTimeBetweenMarks() {
+ long average = 0;
+ if (marksCount > 0) {
+ average = delta / marksCount;
+ }
+ return average;
+ }
+
+ }
}
matchV10Builder.setNwTos(zeroShort);
matchV10Builder.setTpDst(zeroInteger);
matchV10Builder.setTpSrc(zeroInteger);
- FlowWildcardsV10 flowWildcardsV10 = new FlowWildcardsV10(false, false, false, false, false, false, false, false, false, false);
+ FlowWildcardsV10 flowWildcardsV10 = new FlowWildcardsV10(true, true, true, true, true, true, true, true, true, true);
matchV10Builder.setWildcards(flowWildcardsV10);
return matchV10Builder;
}
package org.opendaylight.openflowplugin.impl.device;
+import com.google.common.util.concurrent.Futures;
import io.netty.util.HashedWheelTimer;
import org.junit.After;
import org.junit.Before;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
nodeId = new NodeId("h2g2:42");
path = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+
+ Mockito.when(writeTx.submit()).thenReturn(Futures.<Void, TransactionCommitFailedException>immediateCheckedFuture(null));
}
@After
@Test
public void testSubmitTransaction() throws Exception {
final Node data = new NodeBuilder().setId(nodeId).build();
- txChainManager.enableCounter();
+ txChainManager.enableSubmit();
txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
txChainManager.submitTransaction();
Mockito.verify(txChain).newWriteOnlyTransaction();
Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
Mockito.verify(writeTx).submit();
+ Mockito.verify(writeTx).getIdentifier();
}
/**
- * test of {@link TransactionChainManager#enableCounter()}: no submit - counter is not active
+ * test of {@link TransactionChainManager#enableSubmit()}: no submit - counter is not active
* @throws Exception
*/
@Test
}
/**
- * test of {@link TransactionChainManager#enableCounter()}: submit - after counter activated
+ * test of {@link TransactionChainManager#enableSubmit()}: submit - after counter activated
* @throws Exception
*/
@Test
public void testEnableCounter2() throws Exception {
- txChainManager.enableCounter();
+ txChainManager.enableSubmit();
final Node data = new NodeBuilder().setId(nodeId).build();
txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
Mockito.verify(txChain, Mockito.times(2)).newWriteOnlyTransaction();
Mockito.verify(writeTx, Mockito.times(4)).put(LogicalDatastoreType.CONFIGURATION, path, data);
Mockito.verify(writeTx, Mockito.times(2)).submit();
+ Mockito.verify(writeTx, Mockito.times(2)).getIdentifier();
}
@Test
public void testOnTransactionChainFailed() throws Exception {
+ txChainManager.onTransactionChainFailed(transactionChain, Mockito.mock(AsyncTransaction.class), Mockito.mock(Throwable.class));
+
+ Mockito.verify(txChain).close();
+ Mockito.verify(dataBroker, Mockito.times(2)).createTransactionChain(txChainManager);
+ }
+
+ @Test
+ public void testOnTransactionChainSuccessful() throws Exception {
txChainManager.onTransactionChainSuccessful(transactionChain);
// NOOP
+ Mockito.verifyZeroInteractions(transactionChain);
}
@Test
- public void testOnTransactionChainSuccessful() throws Exception {
- txChainManager.onTransactionChainFailed(transactionChain, Mockito.mock(AsyncTransaction.class), Mockito.mock(Throwable.class));
+ public void testAddDeleteOperationTotTxChain() throws Exception {
+ txChainManager.addDeleteOperationTotTxChain(LogicalDatastoreType.CONFIGURATION, path);
- Mockito.verify(txChain).close();
- Mockito.verify(dataBroker, Mockito.times(2)).createTransactionChain(txChainManager);
+ Mockito.verify(txChain).newWriteOnlyTransaction();
+ Mockito.verify(writeTx).delete(LogicalDatastoreType.CONFIGURATION, path);
}
}
\ No newline at end of file
HashSet<FlowHash> flowHashs = new HashSet();
for (FlowAndStatisticsMapList item : flowStats.getFlowAndStatisticsMapList()) {
- FlowHash flowHash = FlowHashFactory.create(item, deviceContext);
- flowHashs.add(flowHash);
- flowHashs.add(flowHash);
+ flowHashs.add(FlowHashFactory.create(item, deviceContext));
+ flowHashs.add(FlowHashFactory.create(item, deviceContext));
}
assertEquals(3, flowHashs.size());
}