Charles Chan
Committed by Gerrit Code Review

Implement map listener in DistributedMcastStore

Fix the problem that only local delegation is triggered

Change-Id: Ibe7b4a6abb447b9a8e3a0959882ef2da0d21f4be
...@@ -31,14 +31,18 @@ import org.onosproject.net.mcast.McastStoreDelegate; ...@@ -31,14 +31,18 @@ import org.onosproject.net.mcast.McastStoreDelegate;
31 import org.onosproject.store.AbstractStore; 31 import org.onosproject.store.AbstractStore;
32 import org.onosproject.store.serializers.KryoNamespaces; 32 import org.onosproject.store.serializers.KryoNamespaces;
33 import org.onosproject.store.service.ConsistentMap; 33 import org.onosproject.store.service.ConsistentMap;
34 +import org.onosproject.store.service.MapEvent;
35 +import org.onosproject.store.service.MapEventListener;
34 import org.onosproject.store.service.Serializer; 36 import org.onosproject.store.service.Serializer;
35 import org.onosproject.store.service.StorageService; 37 import org.onosproject.store.service.StorageService;
36 import org.slf4j.Logger; 38 import org.slf4j.Logger;
37 39
38 import java.util.Map; 40 import java.util.Map;
39 import java.util.Set; 41 import java.util.Set;
42 +import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.atomic.AtomicReference; 43 import java.util.concurrent.atomic.AtomicReference;
41 44
45 +import static com.google.common.base.Preconditions.checkState;
42 import static org.slf4j.LoggerFactory.getLogger; 46 import static org.slf4j.LoggerFactory.getLogger;
43 47
44 /** 48 /**
...@@ -62,11 +66,16 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD ...@@ -62,11 +66,16 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD
62 66
63 protected ConsistentMap<McastRoute, MulticastData> mcastRib; 67 protected ConsistentMap<McastRoute, MulticastData> mcastRib;
64 protected Map<McastRoute, MulticastData> mcastRoutes; 68 protected Map<McastRoute, MulticastData> mcastRoutes;
69 + private final MapEventListener<McastRoute, MulticastData> mcastMapListener =
70 + new McastMapListener();
65 71
72 + // NOTE: MapEvent cannot provide correct old value of sink since MulticastData
73 + // is a object reference. Use this localSink to track sink.
74 + private Map<McastRoute, Set<ConnectPoint>> localSink =
75 + new ConcurrentHashMap<>();
66 76
67 @Activate 77 @Activate
68 public void activate() { 78 public void activate() {
69 -
70 mcastRib = storageService.<McastRoute, MulticastData>consistentMapBuilder() 79 mcastRib = storageService.<McastRoute, MulticastData>consistentMapBuilder()
71 .withName(MCASTRIB) 80 .withName(MCASTRIB)
72 .withSerializer(Serializer.using(KryoNamespace.newBuilder() 81 .withSerializer(Serializer.using(KryoNamespace.newBuilder()
...@@ -79,10 +88,9 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD ...@@ -79,10 +88,9 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD
79 ).build())) 88 ).build()))
80 //.withRelaxedReadConsistency() 89 //.withRelaxedReadConsistency()
81 .build(); 90 .build();
82 - 91 + mcastRib.addListener(mcastMapListener);
83 mcastRoutes = mcastRib.asJavaMap(); 92 mcastRoutes = mcastRib.asJavaMap();
84 93
85 -
86 log.info("Started"); 94 log.info("Started");
87 } 95 }
88 96
...@@ -95,16 +103,10 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD ...@@ -95,16 +103,10 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD
95 public void storeRoute(McastRoute route, Type operation) { 103 public void storeRoute(McastRoute route, Type operation) {
96 switch (operation) { 104 switch (operation) {
97 case ADD: 105 case ADD:
98 - if (mcastRoutes.putIfAbsent(route, MulticastData.empty()) == null) { 106 + mcastRoutes.putIfAbsent(route, MulticastData.empty());
99 - delegate.notify(new McastEvent(McastEvent.Type.ROUTE_ADDED,
100 - McastRouteInfo.mcastRouteInfo(route)));
101 - }
102 break; 107 break;
103 case REMOVE: 108 case REMOVE:
104 - if (mcastRoutes.remove(route) != null) { 109 + mcastRoutes.remove(route);
105 - delegate.notify(new McastEvent(McastEvent.Type.ROUTE_REMOVED,
106 - McastRouteInfo.mcastRouteInfo(route)));
107 - }
108 break; 110 break;
109 default: 111 default:
110 log.warn("Unknown mcast operation type: {}", operation); 112 log.warn("Unknown mcast operation type: {}", operation);
...@@ -121,15 +123,6 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD ...@@ -121,15 +123,6 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD
121 } 123 }
122 return v; 124 return v;
123 }); 125 });
124 -
125 -
126 - if (data != null) {
127 - delegate.notify(new McastEvent(McastEvent.Type.SOURCE_ADDED,
128 - McastRouteInfo.mcastRouteInfo(route,
129 - data.sinks(),
130 - source)));
131 - }
132 -
133 } 126 }
134 127
135 @Override 128 @Override
...@@ -152,31 +145,6 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD ...@@ -152,31 +145,6 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD
152 } 145 }
153 return v; 146 return v;
154 }); 147 });
155 -
156 -
157 - if (data != null) {
158 - switch (operation) {
159 - case ADD:
160 - delegate.notify(new McastEvent(
161 - McastEvent.Type.SINK_ADDED,
162 - McastRouteInfo.mcastRouteInfo(route,
163 - sink,
164 - data.source())));
165 - break;
166 - case REMOVE:
167 - if (data != null) {
168 - delegate.notify(new McastEvent(
169 - McastEvent.Type.SINK_REMOVED,
170 - McastRouteInfo.mcastRouteInfo(route,
171 - sink,
172 - data.source())));
173 - }
174 - break;
175 - default:
176 - log.warn("Unknown mcast operation type: {}", operation);
177 - }
178 - }
179 -
180 } 148 }
181 149
182 @Override 150 @Override
...@@ -194,4 +162,75 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD ...@@ -194,4 +162,75 @@ public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreD
194 return mcastRoutes.keySet(); 162 return mcastRoutes.keySet();
195 } 163 }
196 164
165 + private class McastMapListener implements MapEventListener<McastRoute, MulticastData> {
166 + @Override
167 + public void event(MapEvent<McastRoute, MulticastData> event) {
168 + McastRoute route = event.key();
169 + MulticastData newValue, oldValue;
170 +
171 + switch (event.type()) {
172 + case INSERT:
173 + checkState(event.newValue() != null, "Map insert event should have newValue");
174 + newValue = event.newValue().value();
175 + if (newValue.source() != null) {
176 + notifyDelegate(new McastEvent(McastEvent.Type.SOURCE_ADDED,
177 + McastRouteInfo.mcastRouteInfo(route,
178 + newValue.sinks(), newValue.source())));
179 + }
180 + if (!newValue.sinks().isEmpty()) {
181 + newValue.sinks().forEach(sink -> {
182 + notifyDelegate(new McastEvent(McastEvent.Type.SINK_ADDED,
183 + McastRouteInfo.mcastRouteInfo(route,
184 + sink, newValue.source())));
185 + });
186 + }
187 + if (newValue.source() == null && newValue.sinks().isEmpty()) {
188 + notifyDelegate(new McastEvent(McastEvent.Type.ROUTE_ADDED,
189 + McastRouteInfo.mcastRouteInfo(route)));
190 + }
191 + localSink.put(route, newValue.sinks());
192 + break;
193 + case REMOVE:
194 + checkState(event.oldValue() != null, "Map remove event should have oldValue");
195 + oldValue = event.oldValue().value();
196 + notifyDelegate(new McastEvent(McastEvent.Type.ROUTE_REMOVED,
197 + McastRouteInfo.mcastRouteInfo(route)));
198 + oldValue.sinks().forEach(sink -> {
199 + notifyDelegate(new McastEvent(
200 + McastEvent.Type.SINK_REMOVED,
201 + McastRouteInfo.mcastRouteInfo(route, sink, oldValue.source())));
202 + });
203 + localSink.remove(route);
204 + break;
205 + case UPDATE:
206 + checkState(event.newValue() != null, "Map update event should have newValue");
207 + checkState(event.oldValue() != null, "Map update event should have oldValue");
208 + newValue = event.newValue().value();
209 + oldValue = event.oldValue().value();
210 + if (newValue.source() != null && oldValue.source() == null) {
211 + notifyDelegate(new McastEvent(McastEvent.Type.SOURCE_ADDED,
212 + McastRouteInfo.mcastRouteInfo(route,
213 + newValue.sinks(), newValue.source())));
214 + }
215 + newValue.sinks().stream()
216 + .filter(sink -> !localSink.get(route).contains(sink))
217 + .forEach(addedSink -> {
218 + notifyDelegate(new McastEvent(McastEvent.Type.SINK_ADDED,
219 + McastRouteInfo.mcastRouteInfo(route,
220 + addedSink, newValue.source())));
221 + });
222 + localSink.get(route).stream()
223 + .filter(sink -> !newValue.sinks().contains(sink))
224 + .forEach(removedSink -> {
225 + notifyDelegate(new McastEvent(McastEvent.Type.SINK_REMOVED,
226 + McastRouteInfo.mcastRouteInfo(route,
227 + removedSink, newValue.source())));
228 + });
229 + localSink.put(route, newValue.sinks());
230 + break;
231 + default:
232 + break;
233 + }
234 + }
235 + }
197 } 236 }
......