2 * Copyright (c) 2015, 2017 China Telecom Beijing Research Institute and others. All rights reserved.
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
8 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.HashMap;
13 import java.util.List;
15 import java.util.Objects;
16 import java.util.concurrent.atomic.AtomicInteger;
17 import org.apache.commons.lang3.tuple.Pair;
18 import org.opendaylight.mdsal.binding.api.DataObjectModification;
19 import org.opendaylight.mdsal.binding.api.DataTreeModification;
20 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
21 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.Identifiable;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 public class TransactCommandAggregator implements TransactCommand {
33 private static final Logger LOG = LoggerFactory.getLogger(TransactCommandAggregator.class);
35 private final List<TransactCommand> commands = new ArrayList<>();
36 private final AtomicInteger retryCount = new AtomicInteger(HwvtepSouthboundConstants.CHAIN_RETRY_COUNT);
37 private final HwvtepOperationalState operationalState;
38 /* stores the modified and deleted data for each child type of each node id
39 Map<nodeid , Pair < updated, deleted >
40 each updated/ deleted contains Map < child type, List<ChildData>>
41 child type is the child of hwvtep Global augmentation
43 private final Map<InstanceIdentifier<Node>,
44 Pair<Map<Class<? extends Identifiable>, List<Identifiable>>,
45 Map<Class<? extends Identifiable>, List<Identifiable>>>> modifiedData = new HashMap<>();
48 public TransactCommandAggregator(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
49 this.operationalState = state;
50 onDataTreeChanged(changes);
51 commands.add(new PhysicalSwitchUpdateCommand(state,changes));
52 commands.add(new PhysicalSwitchRemoveCommand(state,changes));
53 commands.add(new LogicalSwitchUpdateCommand(state,changes));
54 commands.add(new LogicalSwitchRemoveCommand(state,changes));
55 commands.add(new PhysicalPortUpdateCommand(state,changes));
56 commands.add(new PhysicalPortRemoveCommand(state,changes));
57 commands.add(new McastMacsRemoteUpdateCommand(state,changes));
58 commands.add(new McastMacsRemoteRemoveCommand(state,changes));
59 commands.add(new McastMacsLocalUpdateCommand(state,changes));
60 commands.add(new McastMacsLocalRemoveCommand(state,changes));
61 commands.add(new UcastMacsRemoteUpdateCommand(state,changes));
62 commands.add(new UcastMacsRemoteRemoveCommand(state,changes));
63 commands.add(new UcastMacsLocalUpdateCommand(state,changes));
64 commands.add(new UcastMacsLocalRemoveCommand(state,changes));
65 commands.add(new TunnelUpdateCommand(state,changes));
66 commands.add(new TunnelRemoveCommand(state,changes));
67 commands.add(new LogicalRouterUpdateCommand(state,changes));
68 commands.add(new LogicalRouterRemoveCommand(state,changes));
72 public void execute(TransactionBuilder transaction) {
73 for (TransactCommand command:commands) {
75 command.execute(transaction);
76 } catch (NullPointerException e) {
77 LOG.error("Execution of command {} failed with the following exception."
78 + " Continuing the execution of remaining commands", command, e);
84 public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data,
85 InstanceIdentifier key,
86 Object... extraData) {
90 public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data,
91 InstanceIdentifier key,
92 Object... extraData) {
95 private void onDataTreeChanged(final Collection<DataTreeModification<Node>> changes) {
96 boolean readOperationalNodes = false;
97 for (DataTreeModification<Node> change : changes) {
98 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
99 final DataObjectModification<Node> mod = change.getRootNode();
100 final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData = new HashMap<>();
101 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData = new HashMap<>();
102 extractDataChanged(key, mod, updatedData, deletedData);
103 modifiedData.put(key, Pair.of(updatedData, deletedData));
104 operationalState.setModifiedData(modifiedData);
105 if (!isMacOnlyUpdate(updatedData, deletedData)) {
106 readOperationalNodes = true;
109 if (readOperationalNodes) {
110 operationalState.readOperationalNodes();
114 private static boolean isMacOnlyUpdate(final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
115 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
116 return updatedData.containsKey(RemoteUcastMacs.class) && updatedData.size() == 1
117 || deletedData.containsKey(RemoteUcastMacs.class) && deletedData.size() == 1;
120 private static void extractDataChanged(final InstanceIdentifier<Node> key,
121 final DataObjectModification<Node> mod,
122 final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
123 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
125 extractDataChanged(mod.getModifiedChildren(), updatedData, deletedData);
126 DataObjectModification<HwvtepGlobalAugmentation> aug = mod.getModifiedAugmentation(
127 HwvtepGlobalAugmentation.class);
129 extractDataChanged(aug.getModifiedChildren(), updatedData, deletedData);
131 DataObjectModification<PhysicalSwitchAugmentation> psAug = mod.getModifiedAugmentation(
132 PhysicalSwitchAugmentation.class);
134 extractDataChanged(psAug.getModifiedChildren(), updatedData, deletedData);
138 private static void extractDataChanged(
139 final Collection<? extends DataObjectModification<? extends DataObject>> children,
140 final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
141 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
142 if (children == null) {
145 for (DataObjectModification<? extends DataObject> child : children) {
146 Class<? extends Identifiable> childClass = (Class<? extends Identifiable>) child.getDataType();
147 switch (child.getModificationType()) {
149 case SUBTREE_MODIFIED:
150 DataObject dataAfter = child.getDataAfter();
151 if (!(dataAfter instanceof Identifiable)) {
154 DataObject before = child.getDataBefore();
155 if (Objects.equals(dataAfter, before)) {
157 in cluster reboot scenarios,
158 application rewrites the data tx.put( logicalswitchiid, logicalswitch )
159 that time it fires the update again ignoring such updates here
163 Identifiable identifiable = (Identifiable) dataAfter;
164 addToUpdatedData(updatedData, childClass, identifiable);
167 DataObject dataBefore = child.getDataBefore();
168 if (!(dataBefore instanceof Identifiable)) {
171 addToUpdatedData(deletedData, childClass, (Identifiable)dataBefore);
179 private static void addToUpdatedData(Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
180 Class<? extends Identifiable> childClass, Identifiable identifiable) {
181 updatedData.computeIfAbsent(childClass, (cls) -> new ArrayList<>());
182 updatedData.get(childClass).add(identifiable);
186 public void onFailure(TransactionBuilder deviceTransaction) {
187 commands.forEach(cmd -> cmd.onFailure(deviceTransaction));
188 operationalState.clearIntransitKeys();
192 public void onSuccess(TransactionBuilder deviceTransaction) {
193 commands.forEach(cmd -> cmd.onSuccess(deviceTransaction));
197 public boolean retry() {
198 return retryCount.decrementAndGet() > 0;