Fix duplicate host event
Change-Id: I632a1482e7b1b768ce7a0243cc8b6b398b9825b7
Showing
4 changed files
with
55 additions
and
84 deletions
... | @@ -88,10 +88,14 @@ public class SimpleHostStore | ... | @@ -88,10 +88,14 @@ public class SimpleHostStore |
88 | boolean replaceIps) { | 88 | boolean replaceIps) { |
89 | //TODO We need a way to detect conflicting changes and abort update. | 89 | //TODO We need a way to detect conflicting changes and abort update. |
90 | StoredHost host = hosts.get(hostId); | 90 | StoredHost host = hosts.get(hostId); |
91 | + HostEvent hostEvent; | ||
91 | if (host == null) { | 92 | if (host == null) { |
92 | - return createHost(providerId, hostId, hostDescription); | 93 | + hostEvent = createHost(providerId, hostId, hostDescription); |
94 | + } else { | ||
95 | + hostEvent = updateHost(providerId, host, hostDescription, replaceIps); | ||
93 | } | 96 | } |
94 | - return updateHost(providerId, host, hostDescription, replaceIps); | 97 | + notifyDelegate(hostEvent); |
98 | + return hostEvent; | ||
95 | } | 99 | } |
96 | 100 | ||
97 | // creates a new host and sends HOST_ADDED | 101 | // creates a new host and sends HOST_ADDED |
... | @@ -153,7 +157,9 @@ public class SimpleHostStore | ... | @@ -153,7 +157,9 @@ public class SimpleHostStore |
153 | Host host = hosts.remove(hostId); | 157 | Host host = hosts.remove(hostId); |
154 | if (host != null) { | 158 | if (host != null) { |
155 | locations.remove((host.location()), host); | 159 | locations.remove((host.location()), host); |
156 | - return new HostEvent(HOST_REMOVED, host); | 160 | + HostEvent hostEvent = new HostEvent(HOST_REMOVED, host); |
161 | + notifyDelegate(hostEvent); | ||
162 | + return hostEvent; | ||
157 | } | 163 | } |
158 | return null; | 164 | return null; |
159 | } | 165 | } | ... | ... |
... | @@ -192,10 +192,7 @@ public class HostManager | ... | @@ -192,10 +192,7 @@ public class HostManager |
192 | @Override | 192 | @Override |
193 | public void removeHost(HostId hostId) { | 193 | public void removeHost(HostId hostId) { |
194 | checkNotNull(hostId, HOST_ID_NULL); | 194 | checkNotNull(hostId, HOST_ID_NULL); |
195 | - HostEvent event = store.removeHost(hostId); | 195 | + store.removeHost(hostId); |
196 | - if (event != null) { | ||
197 | - post(event); | ||
198 | - } | ||
199 | } | 196 | } |
200 | 197 | ||
201 | // Personalized host provider service issued to the supplied provider. | 198 | // Personalized host provider service issued to the supplied provider. |
... | @@ -211,11 +208,8 @@ public class HostManager | ... | @@ -211,11 +208,8 @@ public class HostManager |
211 | checkNotNull(hostId, HOST_ID_NULL); | 208 | checkNotNull(hostId, HOST_ID_NULL); |
212 | checkValidity(); | 209 | checkValidity(); |
213 | hostDescription = validateHost(hostDescription, hostId); | 210 | hostDescription = validateHost(hostDescription, hostId); |
214 | - HostEvent event = store.createOrUpdateHost(provider().id(), hostId, | 211 | + store.createOrUpdateHost(provider().id(), hostId, |
215 | hostDescription, replaceIps); | 212 | hostDescription, replaceIps); |
216 | - if (event != null) { | ||
217 | - post(event); | ||
218 | - } | ||
219 | } | 213 | } |
220 | 214 | ||
221 | // returns a HostDescription made from the union of the BasicHostConfig | 215 | // returns a HostDescription made from the union of the BasicHostConfig |
... | @@ -231,20 +225,14 @@ public class HostManager | ... | @@ -231,20 +225,14 @@ public class HostManager |
231 | public void hostVanished(HostId hostId) { | 225 | public void hostVanished(HostId hostId) { |
232 | checkNotNull(hostId, HOST_ID_NULL); | 226 | checkNotNull(hostId, HOST_ID_NULL); |
233 | checkValidity(); | 227 | checkValidity(); |
234 | - HostEvent event = store.removeHost(hostId); | 228 | + store.removeHost(hostId); |
235 | - if (event != null) { | ||
236 | - post(event); | ||
237 | - } | ||
238 | } | 229 | } |
239 | 230 | ||
240 | @Override | 231 | @Override |
241 | public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { | 232 | public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { |
242 | checkNotNull(hostId, HOST_ID_NULL); | 233 | checkNotNull(hostId, HOST_ID_NULL); |
243 | checkValidity(); | 234 | checkValidity(); |
244 | - HostEvent event = store.removeIp(hostId, ipAddress); | 235 | + store.removeIp(hostId, ipAddress); |
245 | - if (event != null) { | ||
246 | - post(event); | ||
247 | - } | ||
248 | } | 236 | } |
249 | } | 237 | } |
250 | 238 | ... | ... |
... | @@ -20,6 +20,7 @@ import com.google.common.collect.Sets; | ... | @@ -20,6 +20,7 @@ import com.google.common.collect.Sets; |
20 | import org.junit.After; | 20 | import org.junit.After; |
21 | import org.junit.Before; | 21 | import org.junit.Before; |
22 | import org.junit.Test; | 22 | import org.junit.Test; |
23 | +import org.onlab.junit.TestTools; | ||
23 | import org.onlab.packet.IpAddress; | 24 | import org.onlab.packet.IpAddress; |
24 | import org.onlab.packet.MacAddress; | 25 | import org.onlab.packet.MacAddress; |
25 | import org.onlab.packet.VlanId; | 26 | import org.onlab.packet.VlanId; |
... | @@ -129,13 +130,15 @@ public class HostManagerTest { | ... | @@ -129,13 +130,15 @@ public class HostManagerTest { |
129 | } | 130 | } |
130 | 131 | ||
131 | private void validateEvents(Enum... types) { | 132 | private void validateEvents(Enum... types) { |
132 | - int i = 0; | 133 | + TestTools.assertAfter(100, () -> { |
133 | - assertEquals("wrong events received", types.length, listener.events.size()); | 134 | + int i = 0; |
134 | - for (Event event : listener.events) { | 135 | + assertEquals("wrong events received", types.length, listener.events.size()); |
135 | - assertEquals("incorrect event type", types[i], event.type()); | 136 | + for (Event event : listener.events) { |
136 | - i++; | 137 | + assertEquals("incorrect event type", types[i], event.type()); |
137 | - } | 138 | + i++; |
138 | - listener.events.clear(); | 139 | + } |
140 | + listener.events.clear(); | ||
141 | + }); | ||
139 | } | 142 | } |
140 | 143 | ||
141 | @Test | 144 | @Test | ... | ... |
... | @@ -28,9 +28,10 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -28,9 +28,10 @@ import static org.slf4j.LoggerFactory.getLogger; |
28 | 28 | ||
29 | import java.util.Collection; | 29 | import java.util.Collection; |
30 | import java.util.HashSet; | 30 | import java.util.HashSet; |
31 | +import java.util.Map; | ||
31 | import java.util.Objects; | 32 | import java.util.Objects; |
32 | import java.util.Set; | 33 | import java.util.Set; |
33 | -import java.util.concurrent.atomic.AtomicReference; | 34 | +import java.util.concurrent.ConcurrentHashMap; |
34 | import java.util.function.Predicate; | 35 | import java.util.function.Predicate; |
35 | import java.util.stream.Collectors; | 36 | import java.util.stream.Collectors; |
36 | 37 | ||
... | @@ -56,7 +57,6 @@ import org.onosproject.net.host.HostDescription; | ... | @@ -56,7 +57,6 @@ import org.onosproject.net.host.HostDescription; |
56 | import org.onosproject.net.host.HostEvent; | 57 | import org.onosproject.net.host.HostEvent; |
57 | import org.onosproject.net.host.HostStore; | 58 | import org.onosproject.net.host.HostStore; |
58 | import org.onosproject.net.host.HostStoreDelegate; | 59 | import org.onosproject.net.host.HostStoreDelegate; |
59 | -import org.onosproject.net.host.HostEvent.Type; | ||
60 | import org.onosproject.net.provider.ProviderId; | 60 | import org.onosproject.net.provider.ProviderId; |
61 | import org.onosproject.store.AbstractStore; | 61 | import org.onosproject.store.AbstractStore; |
62 | import org.onosproject.store.serializers.KryoNamespaces; | 62 | import org.onosproject.store.serializers.KryoNamespaces; |
... | @@ -67,10 +67,7 @@ import org.onosproject.store.service.LogicalClockService; | ... | @@ -67,10 +67,7 @@ import org.onosproject.store.service.LogicalClockService; |
67 | import org.onosproject.store.service.StorageService; | 67 | import org.onosproject.store.service.StorageService; |
68 | import org.slf4j.Logger; | 68 | import org.slf4j.Logger; |
69 | 69 | ||
70 | -import com.google.common.collect.HashMultimap; | ||
71 | import com.google.common.collect.ImmutableSet; | 70 | import com.google.common.collect.ImmutableSet; |
72 | -import com.google.common.collect.Multimaps; | ||
73 | -import com.google.common.collect.SetMultimap; | ||
74 | import com.google.common.collect.Sets; | 71 | import com.google.common.collect.Sets; |
75 | 72 | ||
76 | /** | 73 | /** |
... | @@ -90,13 +87,11 @@ public class ECHostStore | ... | @@ -90,13 +87,11 @@ public class ECHostStore |
90 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 87 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
91 | protected LogicalClockService clockService; | 88 | protected LogicalClockService clockService; |
92 | 89 | ||
93 | - // Hosts tracked by their location | ||
94 | - private final SetMultimap<ConnectPoint, Host> locations = | ||
95 | - Multimaps.synchronizedSetMultimap( | ||
96 | - HashMultimap.<ConnectPoint, Host>create()); | ||
97 | - | ||
98 | private EventuallyConsistentMap<HostId, DefaultHost> hosts; | 90 | private EventuallyConsistentMap<HostId, DefaultHost> hosts; |
99 | 91 | ||
92 | + private final ConcurrentHashMap<HostId, ConnectPoint> locations = | ||
93 | + new ConcurrentHashMap<>(); | ||
94 | + | ||
100 | private EventuallyConsistentMapListener<HostId, DefaultHost> hostLocationTracker = | 95 | private EventuallyConsistentMapListener<HostId, DefaultHost> hostLocationTracker = |
101 | new HostLocationTracker(); | 96 | new HostLocationTracker(); |
102 | 97 | ||
... | @@ -125,6 +120,7 @@ public class ECHostStore | ... | @@ -125,6 +120,7 @@ public class ECHostStore |
125 | log.info("Stopped"); | 120 | log.info("Stopped"); |
126 | } | 121 | } |
127 | 122 | ||
123 | + // TODO No longer need to return HostEvent | ||
128 | @Override | 124 | @Override |
129 | public HostEvent createOrUpdateHost(ProviderId providerId, | 125 | public HostEvent createOrUpdateHost(ProviderId providerId, |
130 | HostId hostId, | 126 | HostId hostId, |
... | @@ -133,18 +129,7 @@ public class ECHostStore | ... | @@ -133,18 +129,7 @@ public class ECHostStore |
133 | // TODO: We need a way to detect conflicting changes and abort update. | 129 | // TODO: We need a way to detect conflicting changes and abort update. |
134 | // (BOC) Compute might do this for us. | 130 | // (BOC) Compute might do this for us. |
135 | 131 | ||
136 | - final AtomicReference<Type> eventType = new AtomicReference<>(); | 132 | + hosts.compute(hostId, (id, existingHost) -> { |
137 | - final AtomicReference<DefaultHost> oldHost = new AtomicReference<>(); | ||
138 | - DefaultHost host = hosts.compute(hostId, (id, existingHost) -> { | ||
139 | - if (existingHost != null) { | ||
140 | - oldHost.set(existingHost); | ||
141 | - checkState(Objects.equals(hostDescription.hwAddress(), existingHost.mac()), | ||
142 | - "Existing and new MAC addresses differ."); | ||
143 | - checkState(Objects.equals(hostDescription.vlan(), existingHost.vlan()), | ||
144 | - "Existing and new VLANs differ."); | ||
145 | - } | ||
146 | - | ||
147 | - // TODO do we ever want the existing location? | ||
148 | HostLocation location = hostDescription.location(); | 133 | HostLocation location = hostDescription.location(); |
149 | 134 | ||
150 | final Set<IpAddress> addresses; | 135 | final Set<IpAddress> addresses; |
... | @@ -163,15 +148,6 @@ public class ECHostStore | ... | @@ -163,15 +148,6 @@ public class ECHostStore |
163 | annotations = hostDescription.annotations(); | 148 | annotations = hostDescription.annotations(); |
164 | } | 149 | } |
165 | 150 | ||
166 | - if (existingHost == null) { | ||
167 | - eventType.set(HOST_ADDED); | ||
168 | - } else if (!Objects.equals(existingHost.location(), hostDescription.location())) { | ||
169 | - eventType.set(HOST_MOVED); | ||
170 | - } else if (!existingHost.ipAddresses().containsAll(hostDescription.ipAddress()) || | ||
171 | - !hostDescription.annotations().keys().isEmpty()) { | ||
172 | - eventType.set(HOST_UPDATED); | ||
173 | - } // else, eventType == null; this means we don't send an event | ||
174 | - | ||
175 | return new DefaultHost(providerId, | 151 | return new DefaultHost(providerId, |
176 | hostId, | 152 | hostId, |
177 | hostDescription.hwAddress(), | 153 | hostDescription.hwAddress(), |
... | @@ -181,24 +157,20 @@ public class ECHostStore | ... | @@ -181,24 +157,20 @@ public class ECHostStore |
181 | annotations); | 157 | annotations); |
182 | }); | 158 | }); |
183 | 159 | ||
184 | - if (oldHost.get() != null) { | 160 | + return null; |
185 | - DefaultHost old = oldHost.get(); | ||
186 | - locations.remove(old.location(), old); | ||
187 | - } | ||
188 | - locations.put(host.location(), host); | ||
189 | - | ||
190 | - return eventType.get() != null ? new HostEvent(eventType.get(), host) : null; | ||
191 | } | 161 | } |
192 | 162 | ||
163 | + // TODO No longer need to return HostEvent | ||
193 | @Override | 164 | @Override |
194 | public HostEvent removeHost(HostId hostId) { | 165 | public HostEvent removeHost(HostId hostId) { |
195 | - Host host = hosts.remove(hostId); | 166 | + hosts.remove(hostId); |
196 | - return host != null ? new HostEvent(HOST_REMOVED, host) : null; | 167 | + return null; |
197 | } | 168 | } |
198 | 169 | ||
170 | + // TODO No longer need to return HostEvent | ||
199 | @Override | 171 | @Override |
200 | public HostEvent removeIp(HostId hostId, IpAddress ipAddress) { | 172 | public HostEvent removeIp(HostId hostId, IpAddress ipAddress) { |
201 | - DefaultHost host = hosts.compute(hostId, (id, existingHost) -> { | 173 | + hosts.compute(hostId, (id, existingHost) -> { |
202 | if (existingHost != null) { | 174 | if (existingHost != null) { |
203 | checkState(Objects.equals(hostId.mac(), existingHost.mac()), | 175 | checkState(Objects.equals(hostId.mac(), existingHost.mac()), |
204 | "Existing and new MAC addresses differ."); | 176 | "Existing and new MAC addresses differ."); |
... | @@ -222,7 +194,7 @@ public class ECHostStore | ... | @@ -222,7 +194,7 @@ public class ECHostStore |
222 | } | 194 | } |
223 | return null; | 195 | return null; |
224 | }); | 196 | }); |
225 | - return host != null ? new HostEvent(HOST_UPDATED, host) : null; | 197 | + return null; |
226 | } | 198 | } |
227 | 199 | ||
228 | @Override | 200 | @Override |
... | @@ -257,22 +229,19 @@ public class ECHostStore | ... | @@ -257,22 +229,19 @@ public class ECHostStore |
257 | 229 | ||
258 | @Override | 230 | @Override |
259 | public Set<Host> getConnectedHosts(ConnectPoint connectPoint) { | 231 | public Set<Host> getConnectedHosts(ConnectPoint connectPoint) { |
260 | - synchronized (locations) { | 232 | + Set<Host> filtered = hosts.entrySet().stream() |
261 | - return ImmutableSet.copyOf(locations.get(connectPoint)); | 233 | + .filter(entry -> entry.getValue().location().equals(connectPoint)) |
262 | - } | 234 | + .map(Map.Entry::getValue) |
235 | + .collect(Collectors.toSet()); | ||
236 | + return ImmutableSet.copyOf(filtered); | ||
263 | } | 237 | } |
264 | 238 | ||
265 | @Override | 239 | @Override |
266 | public Set<Host> getConnectedHosts(DeviceId deviceId) { | 240 | public Set<Host> getConnectedHosts(DeviceId deviceId) { |
267 | - Set<Host> filtered; | 241 | + Set<Host> filtered = hosts.entrySet().stream() |
268 | - synchronized (locations) { | 242 | + .filter(entry -> entry.getValue().location().deviceId().equals(deviceId)) |
269 | - filtered = locations | 243 | + .map(Map.Entry::getValue) |
270 | - .entries() | 244 | + .collect(Collectors.toSet()); |
271 | - .stream() | ||
272 | - .filter(entry -> entry.getKey().deviceId().equals(deviceId)) | ||
273 | - .map(entry -> entry.getValue()) | ||
274 | - .collect(Collectors.toSet()); | ||
275 | - } | ||
276 | return ImmutableSet.copyOf(filtered); | 245 | return ImmutableSet.copyOf(filtered); |
277 | } | 246 | } |
278 | 247 | ||
... | @@ -285,13 +254,18 @@ public class ECHostStore | ... | @@ -285,13 +254,18 @@ public class ECHostStore |
285 | public void event(EventuallyConsistentMapEvent<HostId, DefaultHost> event) { | 254 | public void event(EventuallyConsistentMapEvent<HostId, DefaultHost> event) { |
286 | DefaultHost host = checkNotNull(event.value()); | 255 | DefaultHost host = checkNotNull(event.value()); |
287 | if (event.type() == PUT) { | 256 | if (event.type() == PUT) { |
288 | - boolean isNew = locations.put(host.location(), host); | 257 | + ConnectPoint prevLocation = locations.put(host.id(), host.location()); |
289 | - notifyDelegate(new HostEvent(isNew ? HOST_ADDED : HOST_UPDATED, host)); | 258 | + if (prevLocation == null) { |
259 | + notifyDelegate(new HostEvent(HOST_ADDED, host)); | ||
260 | + } else if (!Objects.equals(prevLocation, host.location())) { | ||
261 | + notifyDelegate(new HostEvent(HOST_MOVED, host)); | ||
262 | + } else { | ||
263 | + notifyDelegate(new HostEvent(HOST_UPDATED, host)); | ||
264 | + } | ||
290 | } else if (event.type() == REMOVE) { | 265 | } else if (event.type() == REMOVE) { |
291 | - if (locations.remove(host.location(), host)) { | 266 | + if (locations.remove(host.id()) != null) { |
292 | notifyDelegate(new HostEvent(HOST_REMOVED, host)); | 267 | notifyDelegate(new HostEvent(HOST_REMOVED, host)); |
293 | } | 268 | } |
294 | - | ||
295 | } | 269 | } |
296 | } | 270 | } |
297 | } | 271 | } | ... | ... |
-
Please register or login to post a comment