HIGUCHI Yuta
Committed by Yuta Higuchi

Workaround for ConcurrentModificationException

- Workaround fix for ONOS-1193
- If locking the whole link collection damages the performance,
  apply the fix suggested on GossipLinkStore comment.

Change-Id: Idd4d2e5b8e3a50843fe7abd10a615cfbd9a16478
(cherry picked from commit 4d973eba)
...@@ -238,6 +238,18 @@ public class GossipLinkStore ...@@ -238,6 +238,18 @@ public class GossipLinkStore
238 @Override 238 @Override
239 public Set<Link> getEgressLinks(ConnectPoint src) { 239 public Set<Link> getEgressLinks(ConnectPoint src) {
240 Set<Link> egress = new HashSet<>(); 240 Set<Link> egress = new HashSet<>();
241 + //
242 + // Change `srcLinks` to ConcurrentMap<DeviceId, (Concurrent)Set>
243 + // to remove this synchronized block, if we hit performance issue.
244 + // SetMultiMap#get returns wrapped collection to provide modifiable-view.
245 + // And the wrapped collection is not concurrent access safe.
246 + //
247 + // Our use case here does not require returned collection to be modifiable,
248 + // so the wrapped collection forces us to lock the whole multiset,
249 + // for benefit we don't need.
250 + //
251 + // Same applies to `dstLinks`
252 + synchronized (srcLinks) {
241 for (LinkKey linkKey : srcLinks.get(src.deviceId())) { 253 for (LinkKey linkKey : srcLinks.get(src.deviceId())) {
242 if (linkKey.src().equals(src)) { 254 if (linkKey.src().equals(src)) {
243 Link link = links.get(linkKey); 255 Link link = links.get(linkKey);
...@@ -248,12 +260,14 @@ public class GossipLinkStore ...@@ -248,12 +260,14 @@ public class GossipLinkStore
248 } 260 }
249 } 261 }
250 } 262 }
263 + }
251 return egress; 264 return egress;
252 } 265 }
253 266
254 @Override 267 @Override
255 public Set<Link> getIngressLinks(ConnectPoint dst) { 268 public Set<Link> getIngressLinks(ConnectPoint dst) {
256 Set<Link> ingress = new HashSet<>(); 269 Set<Link> ingress = new HashSet<>();
270 + synchronized (dstLinks) {
257 for (LinkKey linkKey : dstLinks.get(dst.deviceId())) { 271 for (LinkKey linkKey : dstLinks.get(dst.deviceId())) {
258 if (linkKey.dst().equals(dst)) { 272 if (linkKey.dst().equals(dst)) {
259 Link link = links.get(linkKey); 273 Link link = links.get(linkKey);
...@@ -264,6 +278,7 @@ public class GossipLinkStore ...@@ -264,6 +278,7 @@ public class GossipLinkStore
264 } 278 }
265 } 279 }
266 } 280 }
281 + }
267 return ingress; 282 return ingress;
268 } 283 }
269 284
......
...@@ -146,22 +146,26 @@ public class SimpleLinkStore ...@@ -146,22 +146,26 @@ public class SimpleLinkStore
146 @Override 146 @Override
147 public Set<Link> getEgressLinks(ConnectPoint src) { 147 public Set<Link> getEgressLinks(ConnectPoint src) {
148 Set<Link> egress = new HashSet<>(); 148 Set<Link> egress = new HashSet<>();
149 + synchronized (srcLinks) {
149 for (LinkKey linkKey : srcLinks.get(src.deviceId())) { 150 for (LinkKey linkKey : srcLinks.get(src.deviceId())) {
150 if (linkKey.src().equals(src)) { 151 if (linkKey.src().equals(src)) {
151 egress.add(links.get(linkKey)); 152 egress.add(links.get(linkKey));
152 } 153 }
153 } 154 }
155 + }
154 return egress; 156 return egress;
155 } 157 }
156 158
157 @Override 159 @Override
158 public Set<Link> getIngressLinks(ConnectPoint dst) { 160 public Set<Link> getIngressLinks(ConnectPoint dst) {
159 Set<Link> ingress = new HashSet<>(); 161 Set<Link> ingress = new HashSet<>();
162 + synchronized (dstLinks) {
160 for (LinkKey linkKey : dstLinks.get(dst.deviceId())) { 163 for (LinkKey linkKey : dstLinks.get(dst.deviceId())) {
161 if (linkKey.dst().equals(dst)) { 164 if (linkKey.dst().equals(dst)) {
162 ingress.add(links.get(linkKey)); 165 ingress.add(links.get(linkKey));
163 } 166 }
164 } 167 }
168 + }
165 return ingress; 169 return ingress;
166 } 170 }
167 171
......