Madan Jampani
Committed by Gerrit Code Review

ONOS-3565: Retry host store updates that fail due to concurrent modification

Change-Id: Id2af2795b0c9f9b1c8d0c4985781ff24e576c7e3
...@@ -24,6 +24,10 @@ public class ConsistentMapException extends StorageException { ...@@ -24,6 +24,10 @@ public class ConsistentMapException extends StorageException {
24 public ConsistentMapException() { 24 public ConsistentMapException() {
25 } 25 }
26 26
27 + public ConsistentMapException(String message) {
28 + super(message);
29 + }
30 +
27 public ConsistentMapException(Throwable t) { 31 public ConsistentMapException(Throwable t) {
28 super(t); 32 super(t);
29 } 33 }
...@@ -38,6 +42,13 @@ public class ConsistentMapException extends StorageException { ...@@ -38,6 +42,13 @@ public class ConsistentMapException extends StorageException {
38 * ConsistentMap update conflicts with an in flight transaction. 42 * ConsistentMap update conflicts with an in flight transaction.
39 */ 43 */
40 public static class ConcurrentModification extends ConsistentMapException { 44 public static class ConcurrentModification extends ConsistentMapException {
45 + public ConcurrentModification() {
46 + super();
47 + }
48 +
49 + public ConcurrentModification(String message) {
50 + super(message);
51 + }
41 } 52 }
42 53
43 /** 54 /**
......
...@@ -24,6 +24,10 @@ public class StorageException extends RuntimeException { ...@@ -24,6 +24,10 @@ public class StorageException extends RuntimeException {
24 public StorageException() { 24 public StorageException() {
25 } 25 }
26 26
27 + public StorageException(String message) {
28 + super(message);
29 + }
30 +
27 public StorageException(Throwable t) { 31 public StorageException(Throwable t) {
28 super(t); 32 super(t);
29 } 33 }
......
...@@ -27,6 +27,7 @@ import org.onlab.util.Tools; ...@@ -27,6 +27,7 @@ import org.onlab.util.Tools;
27 import org.onosproject.core.ApplicationId; 27 import org.onosproject.core.ApplicationId;
28 import org.onosproject.store.service.AsyncConsistentMap; 28 import org.onosproject.store.service.AsyncConsistentMap;
29 import org.onosproject.store.service.ConsistentMapException; 29 import org.onosproject.store.service.ConsistentMapException;
30 +import org.onosproject.store.service.ConsistentMapException.ConcurrentModification;
30 import org.onosproject.store.service.MapEvent; 31 import org.onosproject.store.service.MapEvent;
31 import org.onosproject.store.service.MapEventListener; 32 import org.onosproject.store.service.MapEventListener;
32 import org.onosproject.store.service.Serializer; 33 import org.onosproject.store.service.Serializer;
...@@ -293,7 +294,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V ...@@ -293,7 +294,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V
293 if (v.updated()) { 294 if (v.updated()) {
294 return v.newValue(); 295 return v.newValue();
295 } else { 296 } else {
296 - throw new ConsistentMapException.ConcurrentModification(); 297 + throw new ConcurrentModification("Concurrent update to " + name + " detected");
297 } 298 }
298 }); 299 });
299 }); 300 });
......
...@@ -17,6 +17,7 @@ package org.onosproject.store.host.impl; ...@@ -17,6 +17,7 @@ package org.onosproject.store.host.impl;
17 17
18 import com.google.common.collect.ImmutableSet; 18 import com.google.common.collect.ImmutableSet;
19 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
20 +
20 import org.apache.felix.scr.annotations.Activate; 21 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 22 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 23 import org.apache.felix.scr.annotations.Deactivate;
...@@ -27,6 +28,7 @@ import org.onlab.packet.IpAddress; ...@@ -27,6 +28,7 @@ import org.onlab.packet.IpAddress;
27 import org.onlab.packet.MacAddress; 28 import org.onlab.packet.MacAddress;
28 import org.onlab.packet.VlanId; 29 import org.onlab.packet.VlanId;
29 import org.onlab.util.KryoNamespace; 30 import org.onlab.util.KryoNamespace;
31 +import org.onlab.util.Tools;
30 import org.onosproject.net.Annotations; 32 import org.onosproject.net.Annotations;
31 import org.onosproject.net.ConnectPoint; 33 import org.onosproject.net.ConnectPoint;
32 import org.onosproject.net.DefaultAnnotations; 34 import org.onosproject.net.DefaultAnnotations;
...@@ -43,10 +45,12 @@ import org.onosproject.net.provider.ProviderId; ...@@ -43,10 +45,12 @@ import org.onosproject.net.provider.ProviderId;
43 import org.onosproject.store.AbstractStore; 45 import org.onosproject.store.AbstractStore;
44 import org.onosproject.store.serializers.KryoNamespaces; 46 import org.onosproject.store.serializers.KryoNamespaces;
45 import org.onosproject.store.service.ConsistentMap; 47 import org.onosproject.store.service.ConsistentMap;
48 +import org.onosproject.store.service.ConsistentMapException;
46 import org.onosproject.store.service.MapEvent; 49 import org.onosproject.store.service.MapEvent;
47 import org.onosproject.store.service.MapEventListener; 50 import org.onosproject.store.service.MapEventListener;
48 import org.onosproject.store.service.Serializer; 51 import org.onosproject.store.service.Serializer;
49 import org.onosproject.store.service.StorageService; 52 import org.onosproject.store.service.StorageService;
53 +import org.onosproject.store.service.Versioned;
50 import org.slf4j.Logger; 54 import org.slf4j.Logger;
51 55
52 import java.util.Collection; 56 import java.util.Collection;
...@@ -56,6 +60,7 @@ import java.util.Objects; ...@@ -56,6 +60,7 @@ import java.util.Objects;
56 import java.util.Set; 60 import java.util.Set;
57 import java.util.concurrent.ConcurrentHashMap; 61 import java.util.concurrent.ConcurrentHashMap;
58 import java.util.function.Predicate; 62 import java.util.function.Predicate;
63 +import java.util.function.Supplier;
59 import java.util.stream.Collectors; 64 import java.util.stream.Collectors;
60 65
61 import static com.google.common.base.Preconditions.checkNotNull; 66 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -155,37 +160,42 @@ public class DistributedHostStore ...@@ -155,37 +160,42 @@ public class DistributedHostStore
155 HostId hostId, 160 HostId hostId,
156 HostDescription hostDescription, 161 HostDescription hostDescription,
157 boolean replaceIPs) { 162 boolean replaceIPs) {
158 - // TODO: We need a way to detect conflicting changes and abort update. 163 + Supplier<Versioned<DefaultHost>> supplier =
159 - host.computeIf(hostId, 164 + () -> host.computeIf(hostId,
160 existingHost -> shouldUpdate(existingHost, providerId, hostId, 165 existingHost -> shouldUpdate(existingHost, providerId, hostId,
161 hostDescription, replaceIPs), 166 hostDescription, replaceIPs),
162 (id, existingHost) -> { 167 (id, existingHost) -> {
163 - HostLocation location = hostDescription.location(); 168 + HostLocation location = hostDescription.location();
164 - 169 +
165 - final Set<IpAddress> addresses; 170 + final Set<IpAddress> addresses;
166 - if (existingHost == null || replaceIPs) { 171 + if (existingHost == null || replaceIPs) {
167 - addresses = ImmutableSet.copyOf(hostDescription.ipAddress()); 172 + addresses = ImmutableSet.copyOf(hostDescription.ipAddress());
168 - } else { 173 + } else {
169 - addresses = Sets.newHashSet(existingHost.ipAddresses()); 174 + addresses = Sets.newHashSet(existingHost.ipAddresses());
170 - addresses.addAll(hostDescription.ipAddress()); 175 + addresses.addAll(hostDescription.ipAddress());
171 - } 176 + }
172 - 177 +
173 - final Annotations annotations; 178 + final Annotations annotations;
174 - if (existingHost != null) { 179 + if (existingHost != null) {
175 - annotations = merge((DefaultAnnotations) existingHost.annotations(), 180 + annotations = merge((DefaultAnnotations) existingHost.annotations(),
176 - hostDescription.annotations()); 181 + hostDescription.annotations());
177 - } else { 182 + } else {
178 - annotations = hostDescription.annotations(); 183 + annotations = hostDescription.annotations();
179 - } 184 + }
180 - 185 +
181 - return new DefaultHost(providerId, 186 + return new DefaultHost(providerId,
182 - hostId, 187 + hostId,
183 - hostDescription.hwAddress(), 188 + hostDescription.hwAddress(),
184 - hostDescription.vlan(), 189 + hostDescription.vlan(),
185 - location, 190 + location,
186 - addresses, 191 + addresses,
187 - annotations); 192 + annotations);
188 - }); 193 + });
194 +
195 + Tools.retryable(supplier,
196 + ConsistentMapException.ConcurrentModification.class,
197 + Integer.MAX_VALUE,
198 + 50).get();
189 199
190 return null; 200 return null;
191 } 201 }
......
...@@ -86,6 +86,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -86,6 +86,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
86 .build(); 86 .build();
87 87
88 childMap.put(ResourcePath.ROOT, ImmutableList.of()); 88 childMap.put(ResourcePath.ROOT, ImmutableList.of());
89 + log.info("Started");
89 } 90 }
90 91
91 @Override 92 @Override
......