HIGUCHI Yuta

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
...@@ -246,6 +246,18 @@ public class GossipLinkStore ...@@ -246,6 +246,18 @@ public class GossipLinkStore
246 @Override 246 @Override
247 public Set<Link> getEgressLinks(ConnectPoint src) { 247 public Set<Link> getEgressLinks(ConnectPoint src) {
248 Set<Link> egress = new HashSet<>(); 248 Set<Link> egress = new HashSet<>();
249 + //
250 + // Change `srcLinks` to ConcurrentMap<DeviceId, (Concurrent)Set>
251 + // to remove this synchronized block, if we hit performance issue.
252 + // SetMultiMap#get returns wrapped collection to provide modifiable-view.
253 + // And the wrapped collection is not concurrent access safe.
254 + //
255 + // Our use case here does not require returned collection to be modifiable,
256 + // so the wrapped collection forces us to lock the whole multiset,
257 + // for benefit we don't need.
258 + //
259 + // Same applies to `dstLinks`
260 + synchronized (srcLinks) {
249 for (LinkKey linkKey : srcLinks.get(src.deviceId())) { 261 for (LinkKey linkKey : srcLinks.get(src.deviceId())) {
250 if (linkKey.src().equals(src)) { 262 if (linkKey.src().equals(src)) {
251 Link link = links.get(linkKey); 263 Link link = links.get(linkKey);
...@@ -256,12 +268,14 @@ public class GossipLinkStore ...@@ -256,12 +268,14 @@ public class GossipLinkStore
256 } 268 }
257 } 269 }
258 } 270 }
271 + }
259 return egress; 272 return egress;
260 } 273 }
261 274
262 @Override 275 @Override
263 public Set<Link> getIngressLinks(ConnectPoint dst) { 276 public Set<Link> getIngressLinks(ConnectPoint dst) {
264 Set<Link> ingress = new HashSet<>(); 277 Set<Link> ingress = new HashSet<>();
278 + synchronized (dstLinks) {
265 for (LinkKey linkKey : dstLinks.get(dst.deviceId())) { 279 for (LinkKey linkKey : dstLinks.get(dst.deviceId())) {
266 if (linkKey.dst().equals(dst)) { 280 if (linkKey.dst().equals(dst)) {
267 Link link = links.get(linkKey); 281 Link link = links.get(linkKey);
...@@ -272,6 +286,7 @@ public class GossipLinkStore ...@@ -272,6 +286,7 @@ public class GossipLinkStore
272 } 286 }
273 } 287 }
274 } 288 }
289 + }
275 return ingress; 290 return ingress;
276 } 291 }
277 292
......
...@@ -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
......