blob: b0b42a713bb1ea8fe5544125ff9da527c908299a [file] [log] [blame]
Madan Jampani38a88212015-09-15 11:21:27 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Madan Jampani38a88212015-09-15 11:21:27 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.store.host.impl;
17
alshabib8a4a6002015-11-25 14:31:16 -080018import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Sets;
Madan Jampanic7f49f92015-12-10 11:35:06 -080020
Madan Jampani38a88212015-09-15 11:21:27 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.MacAddress;
29import org.onlab.packet.VlanId;
30import org.onlab.util.KryoNamespace;
31import org.onosproject.net.Annotations;
32import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.DefaultAnnotations;
34import org.onosproject.net.DefaultHost;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.Host;
37import org.onosproject.net.HostId;
Brian O'Connorf107bd72015-09-21 15:31:03 -070038import org.onosproject.net.HostLocation;
Madan Jampani38a88212015-09-15 11:21:27 -070039import org.onosproject.net.host.HostDescription;
40import org.onosproject.net.host.HostEvent;
41import org.onosproject.net.host.HostStore;
42import org.onosproject.net.host.HostStoreDelegate;
Madan Jampani38a88212015-09-15 11:21:27 -070043import org.onosproject.net.provider.ProviderId;
44import org.onosproject.store.AbstractStore;
45import org.onosproject.store.serializers.KryoNamespaces;
alshabib8a4a6002015-11-25 14:31:16 -080046import org.onosproject.store.service.ConsistentMap;
47import org.onosproject.store.service.MapEvent;
48import org.onosproject.store.service.MapEventListener;
49import org.onosproject.store.service.Serializer;
Madan Jampani38a88212015-09-15 11:21:27 -070050import org.onosproject.store.service.StorageService;
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +053051import org.onosproject.store.service.DistributedPrimitive.Status;
piera3dcca92019-04-11 11:35:55 +020052import org.onosproject.store.service.Versioned;
Madan Jampani38a88212015-09-15 11:21:27 -070053import org.slf4j.Logger;
54
alshabib8a4a6002015-11-25 14:31:16 -080055import java.util.Collection;
piera3dcca92019-04-11 11:35:55 +020056import java.util.Collections;
alshabib8a4a6002015-11-25 14:31:16 -080057import java.util.HashSet;
58import java.util.Map;
59import java.util.Objects;
60import java.util.Set;
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +053061import java.util.concurrent.ConcurrentHashMap;
62import java.util.concurrent.ScheduledExecutorService;
63import java.util.function.Consumer;
alshabib8a4a6002015-11-25 14:31:16 -080064import java.util.function.Predicate;
65import java.util.stream.Collectors;
66
alshabib8a4a6002015-11-25 14:31:16 -080067import static com.google.common.base.Preconditions.checkState;
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +053068import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
69import static org.onlab.util.Tools.groupedThreads;
alshabib8a4a6002015-11-25 14:31:16 -080070import static org.onosproject.net.DefaultAnnotations.merge;
71import static org.onosproject.net.host.HostEvent.Type.*;
72import static org.slf4j.LoggerFactory.getLogger;
Madan Jampani38a88212015-09-15 11:21:27 -070073
74/**
75 * Manages the inventory of hosts using a {@code EventuallyConsistentMap}.
76 */
77@Component(immediate = true)
78@Service
alshabib8a4a6002015-11-25 14:31:16 -080079public class DistributedHostStore
Madan Jampani38a88212015-09-15 11:21:27 -070080 extends AbstractStore<HostEvent, HostStoreDelegate>
81 implements HostStore {
82
83 private final Logger log = getLogger(getClass());
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected StorageService storageService;
87
Madan Jampanic6371882016-06-03 21:30:17 -070088 private ConsistentMap<HostId, DefaultHost> hostsConsistentMap;
alshabib8a4a6002015-11-25 14:31:16 -080089 private Map<HostId, DefaultHost> hosts;
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +053090 private Map<IpAddress, Set<Host>> hostsByIp;
Harshada Chaundkar08bddcc2019-07-02 15:13:24 +000091 MapEventListener<HostId, DefaultHost> hostLocationTracker =
Madan Jampani38a88212015-09-15 11:21:27 -070092 new HostLocationTracker();
93
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +053094 private ScheduledExecutorService executor;
95
96 private Consumer<Status> statusChangeListener;
97
Madan Jampani38a88212015-09-15 11:21:27 -070098 @Activate
99 public void activate() {
100 KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder()
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000101 .register(KryoNamespaces.API);
Madan Jampanic6371882016-06-03 21:30:17 -0700102 hostsConsistentMap = storageService.<HostId, DefaultHost>consistentMapBuilder()
Madan Jampani38a88212015-09-15 11:21:27 -0700103 .withName("onos-hosts")
alshabib8a4a6002015-11-25 14:31:16 -0800104 .withRelaxedReadConsistency()
105 .withSerializer(Serializer.using(hostSerializer.build()))
Madan Jampani38a88212015-09-15 11:21:27 -0700106 .build();
Charles Chan35a32322017-08-14 11:42:11 -0700107 hostsConsistentMap.addListener(hostLocationTracker);
Madan Jampanic6371882016-06-03 21:30:17 -0700108 hosts = hostsConsistentMap.asJavaMap();
alshabib8a4a6002015-11-25 14:31:16 -0800109
Charles Chan1ac47bd2018-04-19 15:11:23 -0700110 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/hosts", "status-listener", log));
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530111 statusChangeListener = status -> {
112 if (status == Status.ACTIVE) {
113 executor.execute(this::loadHostsByIp);
114 }
115 };
116 hostsConsistentMap.addStatusChangeListener(statusChangeListener);
117 loadHostsByIp();
Madan Jampani38a88212015-09-15 11:21:27 -0700118 log.info("Started");
119 }
120
121 @Deactivate
122 public void deactivate() {
Madan Jampanic6371882016-06-03 21:30:17 -0700123 hostsConsistentMap.removeListener(hostLocationTracker);
Charles Chan1ac47bd2018-04-19 15:11:23 -0700124 executor.shutdown();
Charles Chan35a32322017-08-14 11:42:11 -0700125
Madan Jampani38a88212015-09-15 11:21:27 -0700126 log.info("Stopped");
127 }
128
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530129 private void loadHostsByIp() {
130 hostsByIp = new ConcurrentHashMap<IpAddress, Set<Host>>();
131 hostsConsistentMap.asJavaMap().values().forEach(host -> {
132 host.ipAddresses().forEach(ip -> {
133 Set<Host> existingHosts = hostsByIp.get(ip);
134 if (existingHosts == null) {
135 hostsByIp.put(ip, addHosts(host));
136 } else {
137 existingHosts.add(host);
138 }
139 });
140 });
141 }
142
Brian O'Connordab09742015-12-07 20:06:29 -0800143 private boolean shouldUpdate(DefaultHost existingHost,
144 ProviderId providerId,
Brian O'Connordab09742015-12-07 20:06:29 -0800145 HostDescription hostDescription,
146 boolean replaceIPs) {
147 if (existingHost == null) {
148 return true;
149 }
150
Charles Chan69ebcbb2017-04-27 14:33:21 -0700151 // Avoid overriding configured host with learnt host
152 if (existingHost.configured() && !hostDescription.configured()) {
Charles Chan29ecdee2017-02-22 18:46:56 -0800153 return false;
154 }
155
Brian O'Connordab09742015-12-07 20:06:29 -0800156 if (!Objects.equals(existingHost.providerId(), providerId) ||
157 !Objects.equals(existingHost.mac(), hostDescription.hwAddress()) ||
158 !Objects.equals(existingHost.vlan(), hostDescription.vlan()) ||
Jonghwan Hyun2c95acf2018-03-14 16:47:34 -0700159 !Objects.equals(existingHost.innerVlan(), hostDescription.innerVlan()) ||
160 !Objects.equals(existingHost.tpid(), hostDescription.tpid()) ||
Charles Chancd06c692017-04-27 20:46:06 -0700161 !Objects.equals(existingHost.locations(), hostDescription.locations())) {
Brian O'Connordab09742015-12-07 20:06:29 -0800162 return true;
163 }
164
165 if (replaceIPs) {
166 if (!Objects.equals(hostDescription.ipAddress(),
167 existingHost.ipAddresses())) {
168 return true;
169 }
170 } else {
171 if (!existingHost.ipAddresses().containsAll(hostDescription.ipAddress())) {
172 return true;
173 }
174 }
175
176 // check to see if any of the annotations provided by hostDescription
177 // differ from those in the existing host
178 return hostDescription.annotations().keys().stream()
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530179 .anyMatch(k -> !Objects.equals(hostDescription.annotations().value(k),
180 existingHost.annotations().value(k)));
Brian O'Connordab09742015-12-07 20:06:29 -0800181
182
183 }
184
Charles Chan009c3082015-11-10 14:18:04 -0800185 // TODO No longer need to return HostEvent
Madan Jampani38a88212015-09-15 11:21:27 -0700186 @Override
187 public HostEvent createOrUpdateHost(ProviderId providerId,
Brian O'Connorf107bd72015-09-21 15:31:03 -0700188 HostId hostId,
189 HostDescription hostDescription,
190 boolean replaceIPs) {
Madan Jampanic6371882016-06-03 21:30:17 -0700191 hostsConsistentMap.computeIf(hostId,
Charles Chan69ebcbb2017-04-27 14:33:21 -0700192 existingHost -> shouldUpdate(existingHost, providerId,
Brian O'Connordab09742015-12-07 20:06:29 -0800193 hostDescription, replaceIPs),
194 (id, existingHost) -> {
Brian O'Connorf107bd72015-09-21 15:31:03 -0700195
Madan Jampanic7f49f92015-12-10 11:35:06 -0800196 final Set<IpAddress> addresses;
197 if (existingHost == null || replaceIPs) {
198 addresses = ImmutableSet.copyOf(hostDescription.ipAddress());
199 } else {
200 addresses = Sets.newHashSet(existingHost.ipAddresses());
201 addresses.addAll(hostDescription.ipAddress());
202 }
Brian O'Connorf107bd72015-09-21 15:31:03 -0700203
Madan Jampanic7f49f92015-12-10 11:35:06 -0800204 final Annotations annotations;
205 if (existingHost != null) {
206 annotations = merge((DefaultAnnotations) existingHost.annotations(),
207 hostDescription.annotations());
208 } else {
209 annotations = hostDescription.annotations();
210 }
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000211
Madan Jampanic7f49f92015-12-10 11:35:06 -0800212 return new DefaultHost(providerId,
213 hostId,
214 hostDescription.hwAddress(),
215 hostDescription.vlan(),
Charles Chancd06c692017-04-27 20:46:06 -0700216 hostDescription.locations(),
Madan Jampanic7f49f92015-12-10 11:35:06 -0800217 addresses,
Jonghwan Hyun2c95acf2018-03-14 16:47:34 -0700218 hostDescription.innerVlan(),
219 hostDescription.tpid(),
Charles Chanb1e99242017-07-07 14:11:09 -0700220 hostDescription.configured(),
Madan Jampanic7f49f92015-12-10 11:35:06 -0800221 annotations);
222 });
Charles Chan009c3082015-11-10 14:18:04 -0800223 return null;
Madan Jampani38a88212015-09-15 11:21:27 -0700224 }
225
Charles Chan009c3082015-11-10 14:18:04 -0800226 // TODO No longer need to return HostEvent
Madan Jampani38a88212015-09-15 11:21:27 -0700227 @Override
228 public HostEvent removeHost(HostId hostId) {
Charles Chan009c3082015-11-10 14:18:04 -0800229 hosts.remove(hostId);
230 return null;
Madan Jampani38a88212015-09-15 11:21:27 -0700231 }
232
Charles Chan009c3082015-11-10 14:18:04 -0800233 // TODO No longer need to return HostEvent
Madan Jampani38a88212015-09-15 11:21:27 -0700234 @Override
samanwita palc40e5ed2015-09-24 11:01:51 -0700235 public HostEvent removeIp(HostId hostId, IpAddress ipAddress) {
Charles Chan009c3082015-11-10 14:18:04 -0800236 hosts.compute(hostId, (id, existingHost) -> {
samanwita palc40e5ed2015-09-24 11:01:51 -0700237 if (existingHost != null) {
238 checkState(Objects.equals(hostId.mac(), existingHost.mac()),
239 "Existing and new MAC addresses differ.");
240 checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()),
241 "Existing and new VLANs differ.");
242
samanwita pale7c08de2015-09-24 21:59:49 -0700243 Set<IpAddress> addresses = existingHost.ipAddresses();
samanwita palc40e5ed2015-09-24 11:01:51 -0700244 if (addresses != null && addresses.contains(ipAddress)) {
samanwita pale7c08de2015-09-24 21:59:49 -0700245 addresses = new HashSet<>(existingHost.ipAddresses());
samanwita palc40e5ed2015-09-24 11:01:51 -0700246 addresses.remove(ipAddress);
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530247 removeIpFromHostsByIp(existingHost, ipAddress);
samanwita palc40e5ed2015-09-24 11:01:51 -0700248 return new DefaultHost(existingHost.providerId(),
249 hostId,
250 existingHost.mac(),
251 existingHost.vlan(),
Charles Chancd06c692017-04-27 20:46:06 -0700252 existingHost.locations(),
samanwita palc40e5ed2015-09-24 11:01:51 -0700253 ImmutableSet.copyOf(addresses),
Charles Chan9c400672019-12-12 16:58:08 -0800254 existingHost.innerVlan(),
255 existingHost.tpid(),
Charles Chancd06c692017-04-27 20:46:06 -0700256 existingHost.configured(),
Charles Chan9c400672019-12-12 16:58:08 -0800257 existingHost.suspended(),
samanwita palc40e5ed2015-09-24 11:01:51 -0700258 existingHost.annotations());
259 } else {
260 return existingHost;
261 }
262 }
263 return null;
264 });
Charles Chan009c3082015-11-10 14:18:04 -0800265 return null;
samanwita palc40e5ed2015-09-24 11:01:51 -0700266 }
267
268 @Override
Charles Chan47933752017-11-30 15:37:50 -0800269 public void appendLocation(HostId hostId, HostLocation location) {
270 log.debug("Appending location {} to host {}", location, hostId);
271 hosts.compute(hostId, (id, existingHost) -> {
272 if (existingHost != null) {
273 checkState(Objects.equals(hostId.mac(), existingHost.mac()),
274 "Existing and new MAC addresses differ.");
275 checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()),
276 "Existing and new VLANs differ.");
277
Charles Chane05ee6d2018-04-25 18:51:46 -0400278 // Move within the same switch
279 // Simply replace old location that is on the same device
280 Set<HostLocation> newLocations = Sets.newHashSet(location);
281 existingHost.locations().stream().filter(loc -> !loc.deviceId().equals(location.deviceId()))
282 .forEach(newLocations::add);
Charles Chan47933752017-11-30 15:37:50 -0800283
284 return new DefaultHost(existingHost.providerId(),
Charles Chan9c400672019-12-12 16:58:08 -0800285 hostId, existingHost.mac(), existingHost.vlan(),
286 newLocations, existingHost.ipAddresses(),
287 existingHost.innerVlan(), existingHost.tpid(),
288 existingHost.configured(), existingHost.suspended(), existingHost.annotations());
Charles Chan47933752017-11-30 15:37:50 -0800289 }
290 return null;
291 });
292 }
293
294 @Override
Charles Chan888e20a2017-05-01 15:44:23 -0700295 public void removeLocation(HostId hostId, HostLocation location) {
Charles Chan47933752017-11-30 15:37:50 -0800296 log.debug("Removing location {} from host {}", location, hostId);
Charles Chan888e20a2017-05-01 15:44:23 -0700297 hosts.compute(hostId, (id, existingHost) -> {
298 if (existingHost != null) {
299 checkState(Objects.equals(hostId.mac(), existingHost.mac()),
300 "Existing and new MAC addresses differ.");
301 checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()),
302 "Existing and new VLANs differ.");
303
304 Set<HostLocation> locations = new HashSet<>(existingHost.locations());
305 locations.remove(location);
306
307 // Remove entire host if we are removing the last location
308 return locations.isEmpty() ? null :
309 new DefaultHost(existingHost.providerId(),
310 hostId, existingHost.mac(), existingHost.vlan(),
311 locations, existingHost.ipAddresses(),
Charles Chan9c400672019-12-12 16:58:08 -0800312 existingHost.innerVlan(), existingHost.tpid(),
313 existingHost.configured(), existingHost.suspended(), existingHost.annotations());
Charles Chan888e20a2017-05-01 15:44:23 -0700314 }
315 return null;
316 });
317 }
318
319 @Override
Madan Jampani38a88212015-09-15 11:21:27 -0700320 public int getHostCount() {
321 return hosts.size();
322 }
323
324 @Override
325 public Iterable<Host> getHosts() {
326 return ImmutableSet.copyOf(hosts.values());
327 }
328
329 @Override
330 public Host getHost(HostId hostId) {
331 return hosts.get(hostId);
332 }
333
334 @Override
335 public Set<Host> getHosts(VlanId vlanId) {
336 return filter(hosts.values(), host -> Objects.equals(host.vlan(), vlanId));
337 }
338
339 @Override
340 public Set<Host> getHosts(MacAddress mac) {
341 return filter(hosts.values(), host -> Objects.equals(host.mac(), mac));
342 }
343
344 @Override
345 public Set<Host> getHosts(IpAddress ip) {
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530346 Set<Host> hosts = hostsByIp.get(ip);
347 return hosts != null ? ImmutableSet.copyOf(hosts) : ImmutableSet.of();
Madan Jampani38a88212015-09-15 11:21:27 -0700348 }
349
350 @Override
351 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Charles Chan009c3082015-11-10 14:18:04 -0800352 Set<Host> filtered = hosts.entrySet().stream()
Charles Chancd06c692017-04-27 20:46:06 -0700353 .filter(entry -> entry.getValue().locations().contains(connectPoint))
Charles Chan009c3082015-11-10 14:18:04 -0800354 .map(Map.Entry::getValue)
355 .collect(Collectors.toSet());
356 return ImmutableSet.copyOf(filtered);
Madan Jampani38a88212015-09-15 11:21:27 -0700357 }
358
359 @Override
360 public Set<Host> getConnectedHosts(DeviceId deviceId) {
Charles Chan009c3082015-11-10 14:18:04 -0800361 Set<Host> filtered = hosts.entrySet().stream()
Charles Chancd06c692017-04-27 20:46:06 -0700362 .filter(entry -> entry.getValue().locations().stream()
363 .map(HostLocation::deviceId).anyMatch(dpid -> dpid.equals(deviceId)))
Charles Chan009c3082015-11-10 14:18:04 -0800364 .map(Map.Entry::getValue)
365 .collect(Collectors.toSet());
HIGUCHI Yutafe2122c2015-09-30 13:46:22 -0700366 return ImmutableSet.copyOf(filtered);
Madan Jampani38a88212015-09-15 11:21:27 -0700367 }
368
jobinca9960a2019-05-09 06:55:47 -0400369 @Override
370 public void suspend(HostId hostId) {
371 hosts.compute(hostId, (id, existingHost) -> {
372 if (existingHost != null) {
373 if (!existingHost.suspended()) {
374 return new DefaultHost(existingHost.providerId(),
375 hostId,
376 existingHost.mac(),
377 existingHost.vlan(),
378 existingHost.locations(),
379 existingHost.ipAddresses(),
380 existingHost.innerVlan(),
381 existingHost.tpid(),
382 existingHost.configured(),
383 true,
384 existingHost.annotations());
385 }
386
387 }
388 return null;
389 });
390 }
391
392 @Override
393 public void unsuspend(HostId hostId) {
394 hosts.compute(hostId, (id, existingHost) -> {
395 if (existingHost != null) {
396 if (existingHost.suspended()) {
397 return new DefaultHost(existingHost.providerId(),
398 hostId,
399 existingHost.mac(),
400 existingHost.vlan(),
401 existingHost.locations(),
402 existingHost.ipAddresses(),
403 existingHost.innerVlan(),
404 existingHost.tpid(),
405 existingHost.configured(),
406 false,
407 existingHost.annotations());
408
409 }
410 }
411 return null;
412 });
413 }
414
Madan Jampani38a88212015-09-15 11:21:27 -0700415 private Set<Host> filter(Collection<DefaultHost> collection, Predicate<DefaultHost> predicate) {
416 return collection.stream().filter(predicate).collect(Collectors.toSet());
417 }
418
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530419 private Set<Host> addHosts(Host host) {
420 Set<Host> hosts = Sets.newConcurrentHashSet();
421 hosts.add(host);
422 return hosts;
423 }
424
425 private Set<Host> updateHosts(Set<Host> existingHosts, Host host) {
piera3dcca92019-04-11 11:35:55 +0200426 existingHosts.removeIf(existingHost -> existingHost.id().equals(host.id()));
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530427 existingHosts.add(host);
428 return existingHosts;
429 }
430
431 private Set<Host> removeHosts(Set<Host> existingHosts, Host host) {
Harshada Chaundkar08bddcc2019-07-02 15:13:24 +0000432
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530433 if (existingHosts != null) {
piera3dcca92019-04-11 11:35:55 +0200434 existingHosts.removeIf(existingHost -> existingHost.id().equals(host.id()));
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530435 }
436
Ray Milkey74e59132018-01-17 15:24:52 -0800437 if (existingHosts == null || existingHosts.isEmpty()) {
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530438 return null;
439 }
440 return existingHosts;
441 }
442
piera3dcca92019-04-11 11:35:55 +0200443 private void updateHostsByIp(DefaultHost host, DefaultHost prevHost) {
Harshada Chaundkar08bddcc2019-07-02 15:13:24 +0000444 // Let's update first the current ips
445 host.ipAddresses().forEach(
piera3dcca92019-04-11 11:35:55 +0200446 ip -> hostsByIp.compute(ip, (k, v) -> v == null ? addHosts(host) : updateHosts(v, host)));
Harshada Chaundkar08bddcc2019-07-02 15:13:24 +0000447
piera3dcca92019-04-11 11:35:55 +0200448 // Let's remove then each old ip
Harshada Chaundkar08bddcc2019-07-02 15:13:24 +0000449 Set<IpAddress> oldIps = prevHost != null ? prevHost.ipAddresses() : Collections.emptySet();
piera3dcca92019-04-11 11:35:55 +0200450 Sets.difference(oldIps, host.ipAddresses()).forEach(
451 ip -> hostsByIp.computeIfPresent(ip, (k, v) -> removeHosts(v, host)));
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530452 }
453
454 private void removeHostsByIp(DefaultHost host) {
piera3dcca92019-04-11 11:35:55 +0200455 host.ipAddresses().forEach(ip -> hostsByIp.computeIfPresent(ip, (k, v) -> removeHosts(v, host)));
Deepa Vaddireddy0a71c8b2017-01-19 21:20:45 +0530456 }
457
458 private void removeIpFromHostsByIp(DefaultHost host, IpAddress ip) {
459 hostsByIp.computeIfPresent(ip, (k, v) -> removeHosts(v, host));
460 }
461
alshabib8a4a6002015-11-25 14:31:16 -0800462 private class HostLocationTracker implements MapEventListener<HostId, DefaultHost> {
Madan Jampani38a88212015-09-15 11:21:27 -0700463 @Override
alshabib8a4a6002015-11-25 14:31:16 -0800464 public void event(MapEvent<HostId, DefaultHost> event) {
piera3dcca92019-04-11 11:35:55 +0200465 DefaultHost host = Versioned.valueOrNull(event.newValue());
466 DefaultHost prevHost = Versioned.valueOrNull(event.oldValue());
alshabib1400ce92015-12-16 15:05:47 -0800467 switch (event.type()) {
468 case INSERT:
piera3dcca92019-04-11 11:35:55 +0200469 updateHostsByIp(host, prevHost);
Charles Chan009c3082015-11-10 14:18:04 -0800470 notifyDelegate(new HostEvent(HOST_ADDED, host));
alshabib1400ce92015-12-16 15:05:47 -0800471 break;
472 case UPDATE:
piera3dcca92019-04-11 11:35:55 +0200473 updateHostsByIp(host, prevHost);
jobinca9960a2019-05-09 06:55:47 -0400474 if (host.suspended() && !prevHost.suspended()) {
475 notifyDelegate(new HostEvent(HOST_SUSPENDED, host, prevHost));
476 } else if (!host.suspended() && prevHost.suspended()) {
477 notifyDelegate(new HostEvent(HOST_UNSUSPENDED, host, prevHost));
478 } else if (!Objects.equals(prevHost.locations(), host.locations())) {
alshabib1400ce92015-12-16 15:05:47 -0800479 notifyDelegate(new HostEvent(HOST_MOVED, host, prevHost));
480 } else if (!Objects.equals(prevHost, host)) {
481 notifyDelegate(new HostEvent(HOST_UPDATED, host, prevHost));
482 }
483 break;
484 case REMOVE:
piera3dcca92019-04-11 11:35:55 +0200485 removeHostsByIp(prevHost);
486 notifyDelegate(new HostEvent(HOST_REMOVED, prevHost));
alshabib1400ce92015-12-16 15:05:47 -0800487 break;
488 default:
489 log.warn("Unknown map event type: {}", event.type());
Madan Jampani38a88212015-09-15 11:21:27 -0700490 }
491 }
492 }
493}