Yuta HIGUCHI

GossipDeviceStore: switch inner Map to non-Concurrent

Change-Id: I3f3a36f2249c1ba36175ad81fa374f7d8ab89af1
...@@ -86,14 +86,11 @@ public class GossipDeviceStore ...@@ -86,14 +86,11 @@ public class GossipDeviceStore
86 86
87 private final Logger log = getLogger(getClass()); 87 private final Logger log = getLogger(getClass());
88 88
89 - public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; 89 + private static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
90 90
91 - // TODO: Check if inner Map can be replaced with plain Map.
92 // innerMap is used to lock a Device, thus instance should never be replaced. 91 // innerMap is used to lock a Device, thus instance should never be replaced.
93 -
94 // collection of Description given from various providers 92 // collection of Description given from various providers
95 - private final ConcurrentMap<DeviceId, 93 + private final ConcurrentMap<DeviceId, Map<ProviderId, DeviceDescriptions>>
96 - ConcurrentMap<ProviderId, DeviceDescriptions>>
97 deviceDescs = Maps.newConcurrentMap(); 94 deviceDescs = Maps.newConcurrentMap();
98 95
99 // cache of Device and Ports generated by compositing descriptions from providers 96 // cache of Device and Ports generated by compositing descriptions from providers
...@@ -208,9 +205,9 @@ public class GossipDeviceStore ...@@ -208,9 +205,9 @@ public class GossipDeviceStore
208 final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp); 205 final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp);
209 final DeviceEvent event; 206 final DeviceEvent event;
210 final Timestamped<DeviceDescription> mergedDesc; 207 final Timestamped<DeviceDescription> mergedDesc;
211 - synchronized (getDeviceDescriptions(deviceId)) { 208 + synchronized (getOrCreateDeviceDescriptionsMap(deviceId)) {
212 event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc); 209 event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc);
213 - mergedDesc = getDeviceDescriptions(deviceId).get(providerId).getDeviceDesc(); 210 + mergedDesc = getOrCreateDeviceDescriptionsMap(deviceId).get(providerId).getDeviceDesc();
214 } 211 }
215 if (event != null) { 212 if (event != null) {
216 log.info("Notifying peers of a device update topology event for providerId: {} and deviceId: {}", 213 log.info("Notifying peers of a device update topology event for providerId: {} and deviceId: {}",
...@@ -230,8 +227,8 @@ public class GossipDeviceStore ...@@ -230,8 +227,8 @@ public class GossipDeviceStore
230 Timestamped<DeviceDescription> deltaDesc) { 227 Timestamped<DeviceDescription> deltaDesc) {
231 228
232 // Collection of DeviceDescriptions for a Device 229 // Collection of DeviceDescriptions for a Device
233 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs 230 + Map<ProviderId, DeviceDescriptions> providerDescs
234 - = getDeviceDescriptions(deviceId); 231 + = getOrCreateDeviceDescriptionsMap(deviceId);
235 232
236 synchronized (providerDescs) { 233 synchronized (providerDescs) {
237 // locking per device 234 // locking per device
...@@ -241,9 +238,7 @@ public class GossipDeviceStore ...@@ -241,9 +238,7 @@ public class GossipDeviceStore
241 return null; 238 return null;
242 } 239 }
243 240
244 - DeviceDescriptions descs 241 + DeviceDescriptions descs = getOrCreateProviderDeviceDescriptions(providerDescs, providerId, deltaDesc);
245 - = createIfAbsentUnchecked(providerDescs, providerId,
246 - new InitDeviceDescs(deltaDesc));
247 242
248 final Device oldDevice = devices.get(deviceId); 243 final Device oldDevice = devices.get(deviceId);
249 final Device newDevice; 244 final Device newDevice;
...@@ -338,7 +333,7 @@ public class GossipDeviceStore ...@@ -338,7 +333,7 @@ public class GossipDeviceStore
338 private DeviceEvent markOfflineInternal(DeviceId deviceId, Timestamp timestamp) { 333 private DeviceEvent markOfflineInternal(DeviceId deviceId, Timestamp timestamp) {
339 334
340 Map<ProviderId, DeviceDescriptions> providerDescs 335 Map<ProviderId, DeviceDescriptions> providerDescs
341 - = getDeviceDescriptions(deviceId); 336 + = getOrCreateDeviceDescriptionsMap(deviceId);
342 337
343 // locking device 338 // locking device
344 synchronized (providerDescs) { 339 synchronized (providerDescs) {
...@@ -401,9 +396,9 @@ public class GossipDeviceStore ...@@ -401,9 +396,9 @@ public class GossipDeviceStore
401 final List<DeviceEvent> events; 396 final List<DeviceEvent> events;
402 final Timestamped<List<PortDescription>> merged; 397 final Timestamped<List<PortDescription>> merged;
403 398
404 - synchronized (getDeviceDescriptions(deviceId)) { 399 + synchronized (getOrCreateDeviceDescriptionsMap(deviceId)) {
405 events = updatePortsInternal(providerId, deviceId, timestampedInput); 400 events = updatePortsInternal(providerId, deviceId, timestampedInput);
406 - final DeviceDescriptions descs = getDeviceDescriptions(deviceId).get(providerId); 401 + final DeviceDescriptions descs = getOrCreateDeviceDescriptionsMap(deviceId).get(providerId);
407 List<PortDescription> mergedList = 402 List<PortDescription> mergedList =
408 FluentIterable.from(portDescriptions) 403 FluentIterable.from(portDescriptions)
409 .transform(new Function<PortDescription, PortDescription>() { 404 .transform(new Function<PortDescription, PortDescription>() {
...@@ -435,7 +430,7 @@ public class GossipDeviceStore ...@@ -435,7 +430,7 @@ public class GossipDeviceStore
435 Device device = devices.get(deviceId); 430 Device device = devices.get(deviceId);
436 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); 431 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
437 432
438 - ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); 433 + Map<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
439 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); 434 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
440 435
441 List<DeviceEvent> events = new ArrayList<>(); 436 List<DeviceEvent> events = new ArrayList<>();
...@@ -539,10 +534,34 @@ public class GossipDeviceStore ...@@ -539,10 +534,34 @@ public class GossipDeviceStore
539 NewConcurrentHashMap.<PortNumber, Port>ifNeeded()); 534 NewConcurrentHashMap.<PortNumber, Port>ifNeeded());
540 } 535 }
541 536
542 - private ConcurrentMap<ProviderId, DeviceDescriptions> getDeviceDescriptions( 537 + private Map<ProviderId, DeviceDescriptions> getOrCreateDeviceDescriptionsMap(
543 DeviceId deviceId) { 538 DeviceId deviceId) {
544 - return createIfAbsentUnchecked(deviceDescs, deviceId, 539 + Map<ProviderId, DeviceDescriptions> r;
545 - NewConcurrentHashMap.<ProviderId, DeviceDescriptions>ifNeeded()); 540 + r = deviceDescs.get(deviceId);
541 + if (r == null) {
542 + r = new HashMap<ProviderId, DeviceDescriptions>();
543 + final Map<ProviderId, DeviceDescriptions> concurrentlyAdded;
544 + concurrentlyAdded = deviceDescs.putIfAbsent(deviceId, r);
545 + if (concurrentlyAdded != null) {
546 + r = concurrentlyAdded;
547 + }
548 + }
549 + return r;
550 + }
551 +
552 + // Guarded by deviceDescs value (=Device lock)
553 + private DeviceDescriptions getOrCreateProviderDeviceDescriptions(
554 + Map<ProviderId, DeviceDescriptions> device,
555 + ProviderId providerId, Timestamped<DeviceDescription> deltaDesc) {
556 +
557 + synchronized (device) {
558 + DeviceDescriptions r = device.get(providerId);
559 + if (r == null) {
560 + r = new DeviceDescriptions(deltaDesc);
561 + device.put(providerId, r);
562 + }
563 + return r;
564 + }
546 } 565 }
547 566
548 @Override 567 @Override
...@@ -555,9 +574,9 @@ public class GossipDeviceStore ...@@ -555,9 +574,9 @@ public class GossipDeviceStore
555 = new Timestamped<>(portDescription, newTimestamp); 574 = new Timestamped<>(portDescription, newTimestamp);
556 final DeviceEvent event; 575 final DeviceEvent event;
557 final Timestamped<PortDescription> mergedDesc; 576 final Timestamped<PortDescription> mergedDesc;
558 - synchronized (getDeviceDescriptions(deviceId)) { 577 + synchronized (getOrCreateDeviceDescriptionsMap(deviceId)) {
559 event = updatePortStatusInternal(providerId, deviceId, deltaDesc); 578 event = updatePortStatusInternal(providerId, deviceId, deltaDesc);
560 - mergedDesc = getDeviceDescriptions(deviceId).get(providerId) 579 + mergedDesc = getOrCreateDeviceDescriptionsMap(deviceId).get(providerId)
561 .getPortDesc(portDescription.portNumber()); 580 .getPortDesc(portDescription.portNumber());
562 } 581 }
563 if (event != null) { 582 if (event != null) {
...@@ -579,7 +598,7 @@ public class GossipDeviceStore ...@@ -579,7 +598,7 @@ public class GossipDeviceStore
579 Device device = devices.get(deviceId); 598 Device device = devices.get(deviceId);
580 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); 599 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
581 600
582 - ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); 601 + Map<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
583 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); 602 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
584 603
585 synchronized (descsMap) { 604 synchronized (descsMap) {
...@@ -591,7 +610,7 @@ public class GossipDeviceStore ...@@ -591,7 +610,7 @@ public class GossipDeviceStore
591 610
592 DeviceDescriptions descs = descsMap.get(providerId); 611 DeviceDescriptions descs = descsMap.get(providerId);
593 // assuming all providers must to give DeviceDescription 612 // assuming all providers must to give DeviceDescription
594 - checkArgument(descs != null, 613 + verify(descs != null,
595 "Device description for Device ID %s from Provider %s was not found", 614 "Device description for Device ID %s from Provider %s was not found",
596 deviceId, providerId); 615 deviceId, providerId);
597 616
...@@ -661,7 +680,7 @@ public class GossipDeviceStore ...@@ -661,7 +680,7 @@ public class GossipDeviceStore
661 private DeviceEvent removeDeviceInternal(DeviceId deviceId, 680 private DeviceEvent removeDeviceInternal(DeviceId deviceId,
662 Timestamp timestamp) { 681 Timestamp timestamp) {
663 682
664 - Map<ProviderId, DeviceDescriptions> descs = getDeviceDescriptions(deviceId); 683 + Map<ProviderId, DeviceDescriptions> descs = getOrCreateDeviceDescriptionsMap(deviceId);
665 synchronized (descs) { 684 synchronized (descs) {
666 // accept removal request if given timestamp is newer than 685 // accept removal request if given timestamp is newer than
667 // the latest Timestamp from Primary provider 686 // the latest Timestamp from Primary provider
...@@ -751,14 +770,14 @@ public class GossipDeviceStore ...@@ -751,14 +770,14 @@ public class GossipDeviceStore
751 * 770 *
752 * @param device device the port is on 771 * @param device device the port is on
753 * @param number port number 772 * @param number port number
754 - * @param providerDescs Collection of Descriptions from multiple providers 773 + * @param descsMap Collection of Descriptions from multiple providers
755 * @return Port instance 774 * @return Port instance
756 */ 775 */
757 private Port composePort(Device device, PortNumber number, 776 private Port composePort(Device device, PortNumber number,
758 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { 777 + Map<ProviderId, DeviceDescriptions> descsMap) {
759 778
760 - ProviderId primary = pickPrimaryPID(providerDescs); 779 + ProviderId primary = pickPrimaryPID(descsMap);
761 - DeviceDescriptions primDescs = providerDescs.get(primary); 780 + DeviceDescriptions primDescs = descsMap.get(primary);
762 // if no primary, assume not enabled 781 // if no primary, assume not enabled
763 // TODO: revisit this default port enabled/disabled behavior 782 // TODO: revisit this default port enabled/disabled behavior
764 boolean isEnabled = false; 783 boolean isEnabled = false;
...@@ -770,7 +789,7 @@ public class GossipDeviceStore ...@@ -770,7 +789,7 @@ public class GossipDeviceStore
770 annotations = merge(annotations, portDesc.value().annotations()); 789 annotations = merge(annotations, portDesc.value().annotations());
771 } 790 }
772 791
773 - for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { 792 + for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
774 if (e.getKey().equals(primary)) { 793 if (e.getKey().equals(primary)) {
775 continue; 794 continue;
776 } 795 }
...@@ -893,41 +912,48 @@ public class GossipDeviceStore ...@@ -893,41 +912,48 @@ public class GossipDeviceStore
893 private DeviceAntiEntropyAdvertisement createAdvertisement() { 912 private DeviceAntiEntropyAdvertisement createAdvertisement() {
894 final NodeId self = clusterService.getLocalNode().id(); 913 final NodeId self = clusterService.getLocalNode().id();
895 914
896 - Map<DeviceFragmentId, Timestamp> devices = new HashMap<>(deviceDescs.size()); 915 + final int numDevices = deviceDescs.size();
897 - final int portsPerDevice = 8; // random guess to minimize reallocation 916 + Map<DeviceFragmentId, Timestamp> adDevices = new HashMap<>(numDevices);
898 - Map<PortFragmentId, Timestamp> ports = new HashMap<>(devices.size() * portsPerDevice); 917 + final int portsPerDevice = 8; // random factor to minimize reallocation
899 - Map<DeviceId, Timestamp> offline = new HashMap<>(devices.size()); 918 + Map<PortFragmentId, Timestamp> adPorts = new HashMap<>(numDevices * portsPerDevice);
919 + Map<DeviceId, Timestamp> adOffline = new HashMap<>(numDevices);
900 920
901 - for (Entry<DeviceId, ConcurrentMap<ProviderId, DeviceDescriptions>> 921 + for (Entry<DeviceId, Map<ProviderId, DeviceDescriptions>>
902 provs : deviceDescs.entrySet()) { 922 provs : deviceDescs.entrySet()) {
903 923
924 + // for each Device...
904 final DeviceId deviceId = provs.getKey(); 925 final DeviceId deviceId = provs.getKey();
905 - final ConcurrentMap<ProviderId, DeviceDescriptions> devDescs = provs.getValue(); 926 + final Map<ProviderId, DeviceDescriptions> devDescs = provs.getValue();
906 synchronized (devDescs) { 927 synchronized (devDescs) {
907 928
908 - offline.put(deviceId, this.offline.get(deviceId)); 929 + // send device offline timestamp
930 + Timestamp lOffline = this.offline.get(deviceId);
931 + if (lOffline != null) {
932 + adOffline.put(deviceId, lOffline);
933 + }
909 934
910 for (Entry<ProviderId, DeviceDescriptions> 935 for (Entry<ProviderId, DeviceDescriptions>
911 prov : devDescs.entrySet()) { 936 prov : devDescs.entrySet()) {
912 937
938 + // for each Provider Descriptions...
913 final ProviderId provId = prov.getKey(); 939 final ProviderId provId = prov.getKey();
914 final DeviceDescriptions descs = prov.getValue(); 940 final DeviceDescriptions descs = prov.getValue();
915 941
916 - devices.put(new DeviceFragmentId(deviceId, provId), 942 + adDevices.put(new DeviceFragmentId(deviceId, provId),
917 descs.getDeviceDesc().timestamp()); 943 descs.getDeviceDesc().timestamp());
918 944
919 for (Entry<PortNumber, Timestamped<PortDescription>> 945 for (Entry<PortNumber, Timestamped<PortDescription>>
920 portDesc : descs.getPortDescs().entrySet()) { 946 portDesc : descs.getPortDescs().entrySet()) {
921 947
922 final PortNumber number = portDesc.getKey(); 948 final PortNumber number = portDesc.getKey();
923 - ports.put(new PortFragmentId(deviceId, provId, number), 949 + adPorts.put(new PortFragmentId(deviceId, provId, number),
924 portDesc.getValue().timestamp()); 950 portDesc.getValue().timestamp());
925 } 951 }
926 } 952 }
927 } 953 }
928 } 954 }
929 955
930 - return new DeviceAntiEntropyAdvertisement(self, devices, ports, offline); 956 + return new DeviceAntiEntropyAdvertisement(self, adDevices, adPorts, adOffline);
931 } 957 }
932 958
933 /** 959 /**
...@@ -950,7 +976,7 @@ public class GossipDeviceStore ...@@ -950,7 +976,7 @@ public class GossipDeviceStore
950 Collection<DeviceFragmentId> reqDevices = new ArrayList<>(); 976 Collection<DeviceFragmentId> reqDevices = new ArrayList<>();
951 Collection<PortFragmentId> reqPorts = new ArrayList<>(); 977 Collection<PortFragmentId> reqPorts = new ArrayList<>();
952 978
953 - for (Entry<DeviceId, ConcurrentMap<ProviderId, DeviceDescriptions>> de : deviceDescs.entrySet()) { 979 + for (Entry<DeviceId, Map<ProviderId, DeviceDescriptions>> de : deviceDescs.entrySet()) {
954 final DeviceId deviceId = de.getKey(); 980 final DeviceId deviceId = de.getKey();
955 final Map<ProviderId, DeviceDescriptions> lDevice = de.getValue(); 981 final Map<ProviderId, DeviceDescriptions> lDevice = de.getValue();
956 982
......