Committed by
Gerrit Code Review
LeadershipService and MastershipService/Store APIs return CompletableFutures so …
…that callers can (optionally) chain together dependent operations Change-Id: Ia00fcb7d98fbfce897527f67ea9690abf6fe846a
Showing
20 changed files
with
179 additions
and
125 deletions
| ... | @@ -18,6 +18,7 @@ package org.onosproject.cluster; | ... | @@ -18,6 +18,7 @@ package org.onosproject.cluster; |
| 18 | import java.util.List; | 18 | import java.util.List; |
| 19 | import java.util.Map; | 19 | import java.util.Map; |
| 20 | import java.util.Set; | 20 | import java.util.Set; |
| 21 | +import java.util.concurrent.CompletableFuture; | ||
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| 23 | * Service for leader election. | 24 | * Service for leader election. |
| ... | @@ -55,16 +56,18 @@ public interface LeadershipService { | ... | @@ -55,16 +56,18 @@ public interface LeadershipService { |
| 55 | /** | 56 | /** |
| 56 | * Joins the leadership contest. | 57 | * Joins the leadership contest. |
| 57 | * | 58 | * |
| 58 | - * @param path topic for which this controller node wishes to be a leader. | 59 | + * @param path topic for which this controller node wishes to be a leader |
| 60 | + * @return {@code Leadership} future | ||
| 59 | */ | 61 | */ |
| 60 | - void runForLeadership(String path); | 62 | + CompletableFuture<Leadership> runForLeadership(String path); |
| 61 | 63 | ||
| 62 | /** | 64 | /** |
| 63 | * Withdraws from a leadership contest. | 65 | * Withdraws from a leadership contest. |
| 64 | * | 66 | * |
| 65 | - * @param path topic for which this controller node no longer wishes to be a leader. | 67 | + * @param path topic for which this controller node no longer wishes to be a leader |
| 68 | + * @return future that is successfully completed when withdraw is done | ||
| 66 | */ | 69 | */ |
| 67 | - void withdraw(String path); | 70 | + CompletableFuture<Void> withdraw(String path); |
| 68 | 71 | ||
| 69 | /** | 72 | /** |
| 70 | * If the local nodeId is the leader for specified topic, this method causes it to | 73 | * If the local nodeId is the leader for specified topic, this method causes it to | ... | ... |
| ... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.mastership; | 16 | package org.onosproject.mastership; |
| 17 | 17 | ||
| 18 | +import java.util.concurrent.CompletableFuture; | ||
| 19 | + | ||
| 18 | import org.onosproject.cluster.NodeId; | 20 | import org.onosproject.cluster.NodeId; |
| 19 | import org.onosproject.net.DeviceId; | 21 | import org.onosproject.net.DeviceId; |
| 20 | import org.onosproject.net.MastershipRole; | 22 | import org.onosproject.net.MastershipRole; |
| ... | @@ -30,8 +32,9 @@ public interface MastershipAdminService { | ... | @@ -30,8 +32,9 @@ public interface MastershipAdminService { |
| 30 | * @param instance controller instance identifier | 32 | * @param instance controller instance identifier |
| 31 | * @param deviceId device identifier | 33 | * @param deviceId device identifier |
| 32 | * @param role requested role | 34 | * @param role requested role |
| 35 | + * @return future that is completed when the role is set | ||
| 33 | */ | 36 | */ |
| 34 | - void setRole(NodeId instance, DeviceId deviceId, MastershipRole role); | 37 | + CompletableFuture<Void> setRole(NodeId instance, DeviceId deviceId, MastershipRole role); |
| 35 | 38 | ||
| 36 | /** | 39 | /** |
| 37 | * Balances the mastership to be shared as evenly as possibly by all | 40 | * Balances the mastership to be shared as evenly as possibly by all | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onosproject.mastership; | 16 | package org.onosproject.mastership; |
| 17 | 17 | ||
| 18 | import java.util.Set; | 18 | import java.util.Set; |
| 19 | +import java.util.concurrent.CompletableFuture; | ||
| 19 | 20 | ||
| 20 | import org.onosproject.cluster.NodeId; | 21 | import org.onosproject.cluster.NodeId; |
| 21 | import org.onosproject.cluster.RoleInfo; | 22 | import org.onosproject.cluster.RoleInfo; |
| ... | @@ -46,7 +47,7 @@ public interface MastershipService { | ... | @@ -46,7 +47,7 @@ public interface MastershipService { |
| 46 | * @param deviceId the the identifier of the device | 47 | * @param deviceId the the identifier of the device |
| 47 | * @return the role of this controller instance | 48 | * @return the role of this controller instance |
| 48 | */ | 49 | */ |
| 49 | - MastershipRole requestRoleFor(DeviceId deviceId); | 50 | + CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId); |
| 50 | 51 | ||
| 51 | /** | 52 | /** |
| 52 | * Abandons mastership of the specified device on the local node thus | 53 | * Abandons mastership of the specified device on the local node thus | ... | ... |
| ... | @@ -38,7 +38,7 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD | ... | @@ -38,7 +38,7 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD |
| 38 | * @param deviceId device identifier | 38 | * @param deviceId device identifier |
| 39 | * @return established or newly negotiated mastership role | 39 | * @return established or newly negotiated mastership role |
| 40 | */ | 40 | */ |
| 41 | - MastershipRole requestRole(DeviceId deviceId); | 41 | + CompletableFuture<MastershipRole> requestRole(DeviceId deviceId); |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| 44 | * Returns the role of a device for a specific controller instance. | 44 | * Returns the role of a device for a specific controller instance. | ... | ... |
| ... | @@ -18,6 +18,7 @@ package org.onosproject.cluster; | ... | @@ -18,6 +18,7 @@ package org.onosproject.cluster; |
| 18 | import java.util.List; | 18 | import java.util.List; |
| 19 | import java.util.Map; | 19 | import java.util.Map; |
| 20 | import java.util.Set; | 20 | import java.util.Set; |
| 21 | +import java.util.concurrent.CompletableFuture; | ||
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| 23 | * Test adapter for leadership service. | 24 | * Test adapter for leadership service. |
| ... | @@ -40,13 +41,13 @@ public class LeadershipServiceAdapter implements LeadershipService { | ... | @@ -40,13 +41,13 @@ public class LeadershipServiceAdapter implements LeadershipService { |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | @Override | 43 | @Override |
| 43 | - public void runForLeadership(String path) { | 44 | + public CompletableFuture<Leadership> runForLeadership(String path) { |
| 44 | - | 45 | + return null; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | @Override | 48 | @Override |
| 48 | - public void withdraw(String path) { | 49 | + public CompletableFuture<Void> withdraw(String path) { |
| 49 | - | 50 | + return null; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | @Override | 53 | @Override | ... | ... |
| ... | @@ -21,6 +21,7 @@ import org.onosproject.net.DeviceId; | ... | @@ -21,6 +21,7 @@ import org.onosproject.net.DeviceId; |
| 21 | import org.onosproject.net.MastershipRole; | 21 | import org.onosproject.net.MastershipRole; |
| 22 | 22 | ||
| 23 | import java.util.Set; | 23 | import java.util.Set; |
| 24 | +import java.util.concurrent.CompletableFuture; | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | * Test adapter for mastership service. | 27 | * Test adapter for mastership service. |
| ... | @@ -32,7 +33,7 @@ public class MastershipServiceAdapter implements MastershipService { | ... | @@ -32,7 +33,7 @@ public class MastershipServiceAdapter implements MastershipService { |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | @Override | 35 | @Override |
| 35 | - public MastershipRole requestRoleFor(DeviceId deviceId) { | 36 | + public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) { |
| 36 | return null; | 37 | return null; |
| 37 | } | 38 | } |
| 38 | 39 | ... | ... |
| ... | @@ -17,6 +17,8 @@ package org.onosproject.cluster.impl; | ... | @@ -17,6 +17,8 @@ package org.onosproject.cluster.impl; |
| 17 | 17 | ||
| 18 | import com.codahale.metrics.Timer; | 18 | import com.codahale.metrics.Timer; |
| 19 | import com.codahale.metrics.Timer.Context; | 19 | import com.codahale.metrics.Timer.Context; |
| 20 | +import com.google.common.collect.Lists; | ||
| 21 | +import com.google.common.util.concurrent.Futures; | ||
| 20 | 22 | ||
| 21 | import org.apache.felix.scr.annotations.Activate; | 23 | import org.apache.felix.scr.annotations.Activate; |
| 22 | import org.apache.felix.scr.annotations.Component; | 24 | import org.apache.felix.scr.annotations.Component; |
| ... | @@ -109,7 +111,7 @@ public class MastershipManager | ... | @@ -109,7 +111,7 @@ public class MastershipManager |
| 109 | } | 111 | } |
| 110 | 112 | ||
| 111 | @Override | 113 | @Override |
| 112 | - public void setRole(NodeId nodeId, DeviceId deviceId, MastershipRole role) { | 114 | + public CompletableFuture<Void> setRole(NodeId nodeId, DeviceId deviceId, MastershipRole role) { |
| 113 | checkNotNull(nodeId, NODE_ID_NULL); | 115 | checkNotNull(nodeId, NODE_ID_NULL); |
| 114 | checkNotNull(deviceId, DEVICE_ID_NULL); | 116 | checkNotNull(deviceId, DEVICE_ID_NULL); |
| 115 | checkNotNull(role, ROLE_NULL); | 117 | checkNotNull(role, ROLE_NULL); |
| ... | @@ -128,14 +130,14 @@ public class MastershipManager | ... | @@ -128,14 +130,14 @@ public class MastershipManager |
| 128 | break; | 130 | break; |
| 129 | default: | 131 | default: |
| 130 | log.info("Unknown role; ignoring"); | 132 | log.info("Unknown role; ignoring"); |
| 131 | - return; | 133 | + return CompletableFuture.completedFuture(null); |
| 132 | } | 134 | } |
| 133 | 135 | ||
| 134 | - eventFuture.whenComplete((event, error) -> { | 136 | + return eventFuture.whenComplete((event, error) -> { |
| 135 | if (event != null) { | 137 | if (event != null) { |
| 136 | post(event); | 138 | post(event); |
| 137 | } | 139 | } |
| 138 | - }); | 140 | + }).thenApply(v -> null); |
| 139 | } | 141 | } |
| 140 | 142 | ||
| 141 | @Override | 143 | @Override |
| ... | @@ -155,14 +157,11 @@ public class MastershipManager | ... | @@ -155,14 +157,11 @@ public class MastershipManager |
| 155 | } | 157 | } |
| 156 | 158 | ||
| 157 | @Override | 159 | @Override |
| 158 | - public MastershipRole requestRoleFor(DeviceId deviceId) { | 160 | + public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) { |
| 159 | checkNotNull(deviceId, DEVICE_ID_NULL); | 161 | checkNotNull(deviceId, DEVICE_ID_NULL); |
| 160 | final Context timer = startTimer(requestRoleTimer); | 162 | final Context timer = startTimer(requestRoleTimer); |
| 161 | - try { | 163 | + return store.requestRole(deviceId).whenComplete((result, error) -> stopTimer(timer)); |
| 162 | - return store.requestRole(deviceId); | 164 | + |
| 163 | - } finally { | ||
| 164 | - stopTimer(timer); | ||
| 165 | - } | ||
| 166 | } | 165 | } |
| 167 | 166 | ||
| 168 | @Override | 167 | @Override |
| ... | @@ -222,13 +221,18 @@ public class MastershipManager | ... | @@ -222,13 +221,18 @@ public class MastershipManager |
| 222 | } | 221 | } |
| 223 | 222 | ||
| 224 | // Now re-balance the buckets until they are roughly even. | 223 | // Now re-balance the buckets until they are roughly even. |
| 224 | + List<CompletableFuture<Void>> balanceBucketsFutures = Lists.newLinkedList(); | ||
| 225 | int rounds = controllerDevices.keySet().size(); | 225 | int rounds = controllerDevices.keySet().size(); |
| 226 | for (int i = 0; i < rounds; i++) { | 226 | for (int i = 0; i < rounds; i++) { |
| 227 | // Iterate over the buckets and find the smallest and the largest. | 227 | // Iterate over the buckets and find the smallest and the largest. |
| 228 | ControllerNode smallest = findBucket(true, controllerDevices); | 228 | ControllerNode smallest = findBucket(true, controllerDevices); |
| 229 | ControllerNode largest = findBucket(false, controllerDevices); | 229 | ControllerNode largest = findBucket(false, controllerDevices); |
| 230 | - balanceBuckets(smallest, largest, controllerDevices, deviceCount); | 230 | + balanceBucketsFutures.add(balanceBuckets(smallest, largest, controllerDevices, deviceCount)); |
| 231 | } | 231 | } |
| 232 | + CompletableFuture<Void> balanceRolesFuture = CompletableFuture.allOf( | ||
| 233 | + balanceBucketsFutures.toArray(new CompletableFuture[balanceBucketsFutures.size()])); | ||
| 234 | + | ||
| 235 | + Futures.getUnchecked(balanceRolesFuture); | ||
| 232 | } | 236 | } |
| 233 | 237 | ||
| 234 | private ControllerNode findBucket(boolean min, | 238 | private ControllerNode findBucket(boolean min, |
| ... | @@ -245,7 +249,7 @@ public class MastershipManager | ... | @@ -245,7 +249,7 @@ public class MastershipManager |
| 245 | return xNode; | 249 | return xNode; |
| 246 | } | 250 | } |
| 247 | 251 | ||
| 248 | - private void balanceBuckets(ControllerNode smallest, ControllerNode largest, | 252 | + private CompletableFuture<Void> balanceBuckets(ControllerNode smallest, ControllerNode largest, |
| 249 | Map<ControllerNode, Set<DeviceId>> controllerDevices, | 253 | Map<ControllerNode, Set<DeviceId>> controllerDevices, |
| 250 | int deviceCount) { | 254 | int deviceCount) { |
| 251 | Collection<DeviceId> minBucket = controllerDevices.get(smallest); | 255 | Collection<DeviceId> minBucket = controllerDevices.get(smallest); |
| ... | @@ -255,6 +259,8 @@ public class MastershipManager | ... | @@ -255,6 +259,8 @@ public class MastershipManager |
| 255 | int delta = (maxBucket.size() - minBucket.size()) / 2; | 259 | int delta = (maxBucket.size() - minBucket.size()) / 2; |
| 256 | delta = Math.min(deviceCount / bucketCount, delta); | 260 | delta = Math.min(deviceCount / bucketCount, delta); |
| 257 | 261 | ||
| 262 | + List<CompletableFuture<Void>> setRoleFutures = Lists.newLinkedList(); | ||
| 263 | + | ||
| 258 | if (delta > 0) { | 264 | if (delta > 0) { |
| 259 | log.info("Attempting to move {} nodes from {} to {}...", delta, | 265 | log.info("Attempting to move {} nodes from {} to {}...", delta, |
| 260 | largest.id(), smallest.id()); | 266 | largest.id(), smallest.id()); |
| ... | @@ -264,12 +270,14 @@ public class MastershipManager | ... | @@ -264,12 +270,14 @@ public class MastershipManager |
| 264 | while (it.hasNext() && i < delta) { | 270 | while (it.hasNext() && i < delta) { |
| 265 | DeviceId deviceId = it.next(); | 271 | DeviceId deviceId = it.next(); |
| 266 | log.info("Setting {} as the master for {}", smallest.id(), deviceId); | 272 | log.info("Setting {} as the master for {}", smallest.id(), deviceId); |
| 267 | - setRole(smallest.id(), deviceId, MASTER); | 273 | + setRoleFutures.add(setRole(smallest.id(), deviceId, MASTER)); |
| 268 | controllerDevices.get(smallest).add(deviceId); | 274 | controllerDevices.get(smallest).add(deviceId); |
| 269 | it.remove(); | 275 | it.remove(); |
| 270 | i++; | 276 | i++; |
| 271 | } | 277 | } |
| 272 | } | 278 | } |
| 279 | + | ||
| 280 | + return CompletableFuture.allOf(setRoleFutures.toArray(new CompletableFuture[setRoleFutures.size()])); | ||
| 273 | } | 281 | } |
| 274 | 282 | ||
| 275 | 283 | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onosproject.net.device.impl; | 16 | package org.onosproject.net.device.impl; |
| 17 | 17 | ||
| 18 | import com.google.common.collect.Lists; | 18 | import com.google.common.collect.Lists; |
| 19 | + | ||
| 19 | import org.apache.felix.scr.annotations.Activate; | 20 | import org.apache.felix.scr.annotations.Activate; |
| 20 | import org.apache.felix.scr.annotations.Component; | 21 | import org.apache.felix.scr.annotations.Component; |
| 21 | import org.apache.felix.scr.annotations.Deactivate; | 22 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -57,6 +58,7 @@ import org.slf4j.Logger; | ... | @@ -57,6 +58,7 @@ import org.slf4j.Logger; |
| 57 | 58 | ||
| 58 | import java.util.Collection; | 59 | import java.util.Collection; |
| 59 | import java.util.List; | 60 | import java.util.List; |
| 61 | +import java.util.concurrent.CompletableFuture; | ||
| 60 | import java.util.concurrent.ScheduledExecutorService; | 62 | import java.util.concurrent.ScheduledExecutorService; |
| 61 | import java.util.concurrent.TimeUnit; | 63 | import java.util.concurrent.TimeUnit; |
| 62 | 64 | ||
| ... | @@ -79,7 +81,6 @@ public class DeviceManager | ... | @@ -79,7 +81,6 @@ public class DeviceManager |
| 79 | private static final String PORT_NUMBER_NULL = "Port number cannot be null"; | 81 | private static final String PORT_NUMBER_NULL = "Port number cannot be null"; |
| 80 | private static final String DEVICE_DESCRIPTION_NULL = "Device description cannot be null"; | 82 | private static final String DEVICE_DESCRIPTION_NULL = "Device description cannot be null"; |
| 81 | private static final String PORT_DESCRIPTION_NULL = "Port description cannot be null"; | 83 | private static final String PORT_DESCRIPTION_NULL = "Port description cannot be null"; |
| 82 | - private static final String ROLE_NULL = "Role cannot be null"; | ||
| 83 | 84 | ||
| 84 | private final Logger log = getLogger(getClass()); | 85 | private final Logger log = getLogger(getClass()); |
| 85 | 86 | ||
| ... | @@ -89,6 +90,7 @@ public class DeviceManager | ... | @@ -89,6 +90,7 @@ public class DeviceManager |
| 89 | private final DeviceStoreDelegate delegate = new InternalStoreDelegate(); | 90 | private final DeviceStoreDelegate delegate = new InternalStoreDelegate(); |
| 90 | 91 | ||
| 91 | private final MastershipListener mastershipListener = new InternalMastershipListener(); | 92 | private final MastershipListener mastershipListener = new InternalMastershipListener(); |
| 93 | + private NodeId localNodeId; | ||
| 92 | 94 | ||
| 93 | private ScheduledExecutorService backgroundService; | 95 | private ScheduledExecutorService backgroundService; |
| 94 | 96 | ||
| ... | @@ -113,6 +115,7 @@ public class DeviceManager | ... | @@ -113,6 +115,7 @@ public class DeviceManager |
| 113 | @Activate | 115 | @Activate |
| 114 | public void activate() { | 116 | public void activate() { |
| 115 | backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background")); | 117 | backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background")); |
| 118 | + localNodeId = clusterService.getLocalNode().id(); | ||
| 116 | 119 | ||
| 117 | store.setDelegate(delegate); | 120 | store.setDelegate(delegate); |
| 118 | eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); | 121 | eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); |
| ... | @@ -302,12 +305,10 @@ public class DeviceManager | ... | @@ -302,12 +305,10 @@ public class DeviceManager |
| 302 | checkValidity(); | 305 | checkValidity(); |
| 303 | 306 | ||
| 304 | log.info("Device {} connected", deviceId); | 307 | log.info("Device {} connected", deviceId); |
| 305 | - final NodeId myNodeId = clusterService.getLocalNode().id(); | ||
| 306 | - | ||
| 307 | // check my Role | 308 | // check my Role |
| 308 | mastershipService.requestRoleFor(deviceId); | 309 | mastershipService.requestRoleFor(deviceId); |
| 309 | final MastershipTerm term = termService.getMastershipTerm(deviceId); | 310 | final MastershipTerm term = termService.getMastershipTerm(deviceId); |
| 310 | - if (term == null || !myNodeId.equals(term.master())) { | 311 | + if (term == null || !localNodeId.equals(term.master())) { |
| 311 | log.info("Role of this node is STANDBY for {}", deviceId); | 312 | log.info("Role of this node is STANDBY for {}", deviceId); |
| 312 | // TODO: Do we need to explicitly tell the Provider that | 313 | // TODO: Do we need to explicitly tell the Provider that |
| 313 | // this instance is not the MASTER | 314 | // this instance is not the MASTER |
| ... | @@ -337,7 +338,6 @@ public class DeviceManager | ... | @@ -337,7 +338,6 @@ public class DeviceManager |
| 337 | 338 | ||
| 338 | log.info("Device {} disconnected from this node", deviceId); | 339 | log.info("Device {} disconnected from this node", deviceId); |
| 339 | 340 | ||
| 340 | - DeviceEvent event = null; | ||
| 341 | List<Port> ports = store.getPorts(deviceId); | 341 | List<Port> ports = store.getPorts(deviceId); |
| 342 | List<PortDescription> descs = Lists.newArrayList(); | 342 | List<PortDescription> descs = Lists.newArrayList(); |
| 343 | ports.forEach(port -> | 343 | ports.forEach(port -> |
| ... | @@ -346,7 +346,7 @@ public class DeviceManager | ... | @@ -346,7 +346,7 @@ public class DeviceManager |
| 346 | port.portSpeed()))); | 346 | port.portSpeed()))); |
| 347 | store.updatePorts(this.provider().id(), deviceId, descs); | 347 | store.updatePorts(this.provider().id(), deviceId, descs); |
| 348 | try { | 348 | try { |
| 349 | - event = store.markOffline(deviceId); | 349 | + post(store.markOffline(deviceId)); |
| 350 | } catch (IllegalStateException e) { | 350 | } catch (IllegalStateException e) { |
| 351 | log.warn("Failed to mark {} offline", deviceId); | 351 | log.warn("Failed to mark {} offline", deviceId); |
| 352 | // only the MASTER should be marking off-line in normal cases, | 352 | // only the MASTER should be marking off-line in normal cases, |
| ... | @@ -360,26 +360,21 @@ public class DeviceManager | ... | @@ -360,26 +360,21 @@ public class DeviceManager |
| 360 | 360 | ||
| 361 | // FIXME: Store semantics leaking out as IllegalStateException. | 361 | // FIXME: Store semantics leaking out as IllegalStateException. |
| 362 | // Consider revising store API to handle this scenario. | 362 | // Consider revising store API to handle this scenario. |
| 363 | - | 363 | + CompletableFuture<MastershipRole> roleFuture = mastershipService.requestRoleFor(deviceId); |
| 364 | - MastershipRole role = mastershipService.requestRoleFor(deviceId); | 364 | + roleFuture.whenComplete((role, error) -> { |
| 365 | MastershipTerm term = termService.getMastershipTerm(deviceId); | 365 | MastershipTerm term = termService.getMastershipTerm(deviceId); |
| 366 | - final NodeId myNodeId = clusterService.getLocalNode().id(); | ||
| 367 | // TODO: Move this type of check inside device clock manager, etc. | 366 | // TODO: Move this type of check inside device clock manager, etc. |
| 368 | - if (term != null && myNodeId.equals(term.master())) { | 367 | + if (term != null && localNodeId.equals(term.master())) { |
| 369 | log.info("Retry marking {} offline", deviceId); | 368 | log.info("Retry marking {} offline", deviceId); |
| 370 | deviceClockProviderService.setMastershipTerm(deviceId, term); | 369 | deviceClockProviderService.setMastershipTerm(deviceId, term); |
| 371 | - event = store.markOffline(deviceId); | 370 | + post(store.markOffline(deviceId)); |
| 372 | } else { | 371 | } else { |
| 373 | log.info("Failed again marking {} offline. {}", deviceId, role); | 372 | log.info("Failed again marking {} offline. {}", deviceId, role); |
| 374 | } | 373 | } |
| 374 | + }); | ||
| 375 | } finally { | 375 | } finally { |
| 376 | //relinquish master role and ability to be backup. | 376 | //relinquish master role and ability to be backup. |
| 377 | mastershipService.relinquishMastership(deviceId); | 377 | mastershipService.relinquishMastership(deviceId); |
| 378 | - | ||
| 379 | - if (event != null) { | ||
| 380 | - log.info("Device {} disconnected from cluster", deviceId); | ||
| 381 | - post(event); | ||
| 382 | - } | ||
| 383 | } | 378 | } |
| 384 | } | 379 | } |
| 385 | 380 | ||
| ... | @@ -531,12 +526,11 @@ public class DeviceManager | ... | @@ -531,12 +526,11 @@ public class DeviceManager |
| 531 | private void reassertRole(final DeviceId did, | 526 | private void reassertRole(final DeviceId did, |
| 532 | final MastershipRole nextRole) { | 527 | final MastershipRole nextRole) { |
| 533 | 528 | ||
| 534 | - final NodeId myNodeId = clusterService.getLocalNode().id(); | ||
| 535 | MastershipRole myNextRole = nextRole; | 529 | MastershipRole myNextRole = nextRole; |
| 536 | if (myNextRole == NONE) { | 530 | if (myNextRole == NONE) { |
| 537 | mastershipService.requestRoleFor(did); | 531 | mastershipService.requestRoleFor(did); |
| 538 | MastershipTerm term = termService.getMastershipTerm(did); | 532 | MastershipTerm term = termService.getMastershipTerm(did); |
| 539 | - if (term != null && myNodeId.equals(term.master())) { | 533 | + if (term != null && localNodeId.equals(term.master())) { |
| 540 | myNextRole = MASTER; | 534 | myNextRole = MASTER; |
| 541 | } else { | 535 | } else { |
| 542 | myNextRole = STANDBY; | 536 | myNextRole = STANDBY; |
| ... | @@ -597,21 +591,20 @@ public class DeviceManager | ... | @@ -597,21 +591,20 @@ public class DeviceManager |
| 597 | } | 591 | } |
| 598 | 592 | ||
| 599 | final DeviceId did = event.subject(); | 593 | final DeviceId did = event.subject(); |
| 600 | - final NodeId myNodeId = clusterService.getLocalNode().id(); | ||
| 601 | 594 | ||
| 602 | // myRole suggested by MastershipService | 595 | // myRole suggested by MastershipService |
| 603 | MastershipRole myNextRole; | 596 | MastershipRole myNextRole; |
| 604 | - if (myNodeId.equals(event.roleInfo().master())) { | 597 | + if (localNodeId.equals(event.roleInfo().master())) { |
| 605 | // confirm latest info | 598 | // confirm latest info |
| 606 | MastershipTerm term = termService.getMastershipTerm(did); | 599 | MastershipTerm term = termService.getMastershipTerm(did); |
| 607 | - final boolean iHaveControl = term != null && myNodeId.equals(term.master()); | 600 | + final boolean iHaveControl = term != null && localNodeId.equals(term.master()); |
| 608 | if (iHaveControl) { | 601 | if (iHaveControl) { |
| 609 | deviceClockProviderService.setMastershipTerm(did, term); | 602 | deviceClockProviderService.setMastershipTerm(did, term); |
| 610 | myNextRole = MASTER; | 603 | myNextRole = MASTER; |
| 611 | } else { | 604 | } else { |
| 612 | myNextRole = STANDBY; | 605 | myNextRole = STANDBY; |
| 613 | } | 606 | } |
| 614 | - } else if (event.roleInfo().backups().contains(myNodeId)) { | 607 | + } else if (event.roleInfo().backups().contains(localNodeId)) { |
| 615 | myNextRole = STANDBY; | 608 | myNextRole = STANDBY; |
| 616 | } else { | 609 | } else { |
| 617 | myNextRole = NONE; | 610 | myNextRole = NONE; | ... | ... |
| ... | @@ -34,6 +34,7 @@ import org.onosproject.net.DeviceId; | ... | @@ -34,6 +34,7 @@ import org.onosproject.net.DeviceId; |
| 34 | import org.onosproject.store.trivial.impl.SimpleMastershipStore; | 34 | import org.onosproject.store.trivial.impl.SimpleMastershipStore; |
| 35 | 35 | ||
| 36 | import com.google.common.collect.Sets; | 36 | import com.google.common.collect.Sets; |
| 37 | +import com.google.common.util.concurrent.Futures; | ||
| 37 | 38 | ||
| 38 | import static org.junit.Assert.assertEquals; | 39 | import static org.junit.Assert.assertEquals; |
| 39 | import static org.junit.Assert.assertNull; | 40 | import static org.junit.Assert.assertNull; |
| ... | @@ -77,7 +78,7 @@ public class MastershipManagerTest { | ... | @@ -77,7 +78,7 @@ public class MastershipManagerTest { |
| 77 | public void setRole() { | 78 | public void setRole() { |
| 78 | mgr.setRole(NID_OTHER, DEV_MASTER, MASTER); | 79 | mgr.setRole(NID_OTHER, DEV_MASTER, MASTER); |
| 79 | assertEquals("wrong local role:", NONE, mgr.getLocalRole(DEV_MASTER)); | 80 | assertEquals("wrong local role:", NONE, mgr.getLocalRole(DEV_MASTER)); |
| 80 | - assertEquals("wrong obtained role:", STANDBY, mgr.requestRoleFor(DEV_MASTER)); | 81 | + assertEquals("wrong obtained role:", STANDBY, Futures.getUnchecked(mgr.requestRoleFor(DEV_MASTER))); |
| 81 | 82 | ||
| 82 | //set to master | 83 | //set to master |
| 83 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | 84 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); |
| ... | @@ -112,8 +113,8 @@ public class MastershipManagerTest { | ... | @@ -112,8 +113,8 @@ public class MastershipManagerTest { |
| 112 | mgr.setRole(NID_OTHER, DEV_OTHER, MASTER); | 113 | mgr.setRole(NID_OTHER, DEV_OTHER, MASTER); |
| 113 | 114 | ||
| 114 | //local should be master for one but standby for other | 115 | //local should be master for one but standby for other |
| 115 | - assertEquals("wrong role:", MASTER, mgr.requestRoleFor(DEV_MASTER)); | 116 | + assertEquals("wrong role:", MASTER, Futures.getUnchecked(mgr.requestRoleFor(DEV_MASTER))); |
| 116 | - assertEquals("wrong role:", STANDBY, mgr.requestRoleFor(DEV_OTHER)); | 117 | + assertEquals("wrong role:", STANDBY, Futures.getUnchecked(mgr.requestRoleFor(DEV_OTHER))); |
| 117 | } | 118 | } |
| 118 | 119 | ||
| 119 | @Test | 120 | @Test | ... | ... |
| ... | @@ -19,6 +19,7 @@ import java.util.ArrayList; | ... | @@ -19,6 +19,7 @@ import java.util.ArrayList; |
| 19 | import java.util.Iterator; | 19 | import java.util.Iterator; |
| 20 | import java.util.List; | 20 | import java.util.List; |
| 21 | import java.util.Set; | 21 | import java.util.Set; |
| 22 | +import java.util.concurrent.CompletableFuture; | ||
| 22 | 23 | ||
| 23 | import org.junit.After; | 24 | import org.junit.After; |
| 24 | import org.junit.Before; | 25 | import org.junit.Before; |
| ... | @@ -305,8 +306,8 @@ public class DeviceManagerTest { | ... | @@ -305,8 +306,8 @@ public class DeviceManagerTest { |
| 305 | } | 306 | } |
| 306 | 307 | ||
| 307 | @Override | 308 | @Override |
| 308 | - public MastershipRole requestRoleFor(DeviceId deviceId) { | 309 | + public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) { |
| 309 | - return MastershipRole.MASTER; | 310 | + return CompletableFuture.completedFuture(MastershipRole.MASTER); |
| 310 | } | 311 | } |
| 311 | 312 | ||
| 312 | @Override | 313 | @Override | ... | ... |
| ... | @@ -49,6 +49,7 @@ import java.util.HashMap; | ... | @@ -49,6 +49,7 @@ import java.util.HashMap; |
| 49 | import java.util.List; | 49 | import java.util.List; |
| 50 | import java.util.Map; | 50 | import java.util.Map; |
| 51 | import java.util.Set; | 51 | import java.util.Set; |
| 52 | +import java.util.concurrent.CompletableFuture; | ||
| 52 | import java.util.concurrent.ExecutorService; | 53 | import java.util.concurrent.ExecutorService; |
| 53 | import java.util.concurrent.Executors; | 54 | import java.util.concurrent.Executors; |
| 54 | import java.util.concurrent.Future; | 55 | import java.util.concurrent.Future; |
| ... | @@ -188,7 +189,7 @@ public class HazelcastLeadershipService implements LeadershipService { | ... | @@ -188,7 +189,7 @@ public class HazelcastLeadershipService implements LeadershipService { |
| 188 | } | 189 | } |
| 189 | 190 | ||
| 190 | @Override | 191 | @Override |
| 191 | - public void runForLeadership(String path) { | 192 | + public CompletableFuture<Leadership> runForLeadership(String path) { |
| 192 | checkArgument(path != null); | 193 | checkArgument(path != null); |
| 193 | Topic topic = new Topic(path); | 194 | Topic topic = new Topic(path); |
| 194 | Topic oldTopic = topics.putIfAbsent(path, topic); | 195 | Topic oldTopic = topics.putIfAbsent(path, topic); |
| ... | @@ -198,16 +199,18 @@ public class HazelcastLeadershipService implements LeadershipService { | ... | @@ -198,16 +199,18 @@ public class HazelcastLeadershipService implements LeadershipService { |
| 198 | } else { | 199 | } else { |
| 199 | oldTopic.runForLeadership(); | 200 | oldTopic.runForLeadership(); |
| 200 | } | 201 | } |
| 202 | + return CompletableFuture.completedFuture(getLeadership(path)); | ||
| 201 | } | 203 | } |
| 202 | 204 | ||
| 203 | @Override | 205 | @Override |
| 204 | - public void withdraw(String path) { | 206 | + public CompletableFuture<Void> withdraw(String path) { |
| 205 | checkArgument(path != null); | 207 | checkArgument(path != null); |
| 206 | Topic topic = topics.get(path); | 208 | Topic topic = topics.get(path); |
| 207 | if (topic != null) { | 209 | if (topic != null) { |
| 208 | topics.remove(path, topic); | 210 | topics.remove(path, topic); |
| 209 | topic.stop(); | 211 | topic.stop(); |
| 210 | } | 212 | } |
| 213 | + return CompletableFuture.completedFuture(null); | ||
| 211 | } | 214 | } |
| 212 | 215 | ||
| 213 | @Override | 216 | @Override | ... | ... |
| ... | @@ -37,6 +37,8 @@ import java.util.Map.Entry; | ... | @@ -37,6 +37,8 @@ import java.util.Map.Entry; |
| 37 | import java.util.Objects; | 37 | import java.util.Objects; |
| 38 | import java.util.Set; | 38 | import java.util.Set; |
| 39 | import java.util.List; | 39 | import java.util.List; |
| 40 | +import java.util.concurrent.CancellationException; | ||
| 41 | +import java.util.concurrent.CompletableFuture; | ||
| 40 | import java.util.concurrent.ExecutorService; | 42 | import java.util.concurrent.ExecutorService; |
| 41 | import java.util.concurrent.Executors; | 43 | import java.util.concurrent.Executors; |
| 42 | import java.util.concurrent.ScheduledExecutorService; | 44 | import java.util.concurrent.ScheduledExecutorService; |
| ... | @@ -199,8 +201,14 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -199,8 +201,14 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 199 | } | 201 | } |
| 200 | 202 | ||
| 201 | @Override | 203 | @Override |
| 202 | - public void runForLeadership(String path) { | 204 | + public CompletableFuture<Leadership> runForLeadership(String path) { |
| 203 | log.debug("Running for leadership for topic: {}", path); | 205 | log.debug("Running for leadership for topic: {}", path); |
| 206 | + CompletableFuture<Leadership> resultFuture = new CompletableFuture<>(); | ||
| 207 | + doRunForLeadership(path, resultFuture); | ||
| 208 | + return resultFuture; | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + private void doRunForLeadership(String path, CompletableFuture<Leadership> future) { | ||
| 204 | try { | 212 | try { |
| 205 | Versioned<List<NodeId>> candidates = candidateMap.get(path); | 213 | Versioned<List<NodeId>> candidates = candidateMap.get(path); |
| 206 | if (candidates != null) { | 214 | if (candidates != null) { |
| ... | @@ -216,7 +224,7 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -216,7 +224,7 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 216 | newCandidates.version(), | 224 | newCandidates.version(), |
| 217 | newCandidates.creationTime()))); | 225 | newCandidates.creationTime()))); |
| 218 | } else { | 226 | } else { |
| 219 | - rerunForLeadership(path); | 227 | + rerunForLeadership(path, future); |
| 220 | return; | 228 | return; |
| 221 | } | 229 | } |
| 222 | } | 230 | } |
| ... | @@ -231,28 +239,38 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -231,28 +239,38 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 231 | newCandidates.version(), | 239 | newCandidates.version(), |
| 232 | newCandidates.creationTime()))); | 240 | newCandidates.creationTime()))); |
| 233 | } else { | 241 | } else { |
| 234 | - rerunForLeadership(path); | 242 | + rerunForLeadership(path, future); |
| 235 | return; | 243 | return; |
| 236 | } | 244 | } |
| 237 | } | 245 | } |
| 238 | log.debug("In the leadership race for topic {} with candidates {}", path, candidates); | 246 | log.debug("In the leadership race for topic {} with candidates {}", path, candidates); |
| 239 | activeTopics.add(path); | 247 | activeTopics.add(path); |
| 240 | - tryLeaderLock(path); | 248 | + tryLeaderLock(path, future); |
| 241 | } catch (ConsistentMapException e) { | 249 | } catch (ConsistentMapException e) { |
| 242 | log.debug("Failed to enter topic leader race for {}. Retrying.", path, e); | 250 | log.debug("Failed to enter topic leader race for {}. Retrying.", path, e); |
| 243 | - rerunForLeadership(path); | 251 | + rerunForLeadership(path, future); |
| 244 | } | 252 | } |
| 245 | } | 253 | } |
| 246 | 254 | ||
| 247 | @Override | 255 | @Override |
| 248 | - public void withdraw(String path) { | 256 | + public CompletableFuture<Void> withdraw(String path) { |
| 249 | activeTopics.remove(path); | 257 | activeTopics.remove(path); |
| 258 | + CompletableFuture<Void> resultFuture = new CompletableFuture<>(); | ||
| 259 | + doWithdraw(path, resultFuture); | ||
| 260 | + return resultFuture; | ||
| 261 | + } | ||
| 262 | + | ||
| 250 | 263 | ||
| 264 | + private void doWithdraw(String path, CompletableFuture<Void> future) { | ||
| 265 | + if (activeTopics.contains(path)) { | ||
| 266 | + future.completeExceptionally(new CancellationException(String.format("%s is now a active topic", path))); | ||
| 267 | + } | ||
| 251 | try { | 268 | try { |
| 252 | Versioned<NodeId> leader = leaderMap.get(path); | 269 | Versioned<NodeId> leader = leaderMap.get(path); |
| 253 | if (leader != null && Objects.equals(leader.value(), localNodeId)) { | 270 | if (leader != null && Objects.equals(leader.value(), localNodeId)) { |
| 254 | if (leaderMap.remove(path, leader.version())) { | 271 | if (leaderMap.remove(path, leader.version())) { |
| 255 | log.info("Gave up leadership for {}", path); | 272 | log.info("Gave up leadership for {}", path); |
| 273 | + future.complete(null); | ||
| 256 | publish(new LeadershipEvent( | 274 | publish(new LeadershipEvent( |
| 257 | LeadershipEvent.Type.LEADER_BOOTED, | 275 | LeadershipEvent.Type.LEADER_BOOTED, |
| 258 | new Leadership(path, | 276 | new Leadership(path, |
| ... | @@ -267,10 +285,12 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -267,10 +285,12 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 267 | ? Lists.newArrayList(candidates.value()) | 285 | ? Lists.newArrayList(candidates.value()) |
| 268 | : Lists.newArrayList(); | 286 | : Lists.newArrayList(); |
| 269 | if (!candidateList.remove(localNodeId)) { | 287 | if (!candidateList.remove(localNodeId)) { |
| 288 | + future.complete(null); | ||
| 270 | return; | 289 | return; |
| 271 | } | 290 | } |
| 272 | if (candidateMap.replace(path, candidates.version(), candidateList)) { | 291 | if (candidateMap.replace(path, candidates.version(), candidateList)) { |
| 273 | Versioned<List<NodeId>> newCandidates = candidateMap.get(path); | 292 | Versioned<List<NodeId>> newCandidates = candidateMap.get(path); |
| 293 | + future.complete(null); | ||
| 274 | publish(new LeadershipEvent( | 294 | publish(new LeadershipEvent( |
| 275 | LeadershipEvent.Type.CANDIDATES_CHANGED, | 295 | LeadershipEvent.Type.CANDIDATES_CHANGED, |
| 276 | new Leadership(path, | 296 | new Leadership(path, |
| ... | @@ -279,11 +299,11 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -279,11 +299,11 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 279 | newCandidates.creationTime()))); | 299 | newCandidates.creationTime()))); |
| 280 | } else { | 300 | } else { |
| 281 | log.warn("Failed to withdraw from candidates list. Will retry"); | 301 | log.warn("Failed to withdraw from candidates list. Will retry"); |
| 282 | - retryWithdraw(path); | 302 | + retryWithdraw(path, future); |
| 283 | } | 303 | } |
| 284 | } catch (Exception e) { | 304 | } catch (Exception e) { |
| 285 | log.debug("Failed to verify (and clear) any lock this node might be holding for {}", path, e); | 305 | log.debug("Failed to verify (and clear) any lock this node might be holding for {}", path, e); |
| 286 | - retryWithdraw(path); | 306 | + retryWithdraw(path, future); |
| 287 | } | 307 | } |
| 288 | } | 308 | } |
| 289 | 309 | ||
| ... | @@ -304,7 +324,7 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -304,7 +324,7 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 304 | localNodeId, | 324 | localNodeId, |
| 305 | leader.version(), | 325 | leader.version(), |
| 306 | leader.creationTime()))); | 326 | leader.creationTime()))); |
| 307 | - retryLock(path); | 327 | + retryLock(path, new CompletableFuture<>()); |
| 308 | return true; | 328 | return true; |
| 309 | } | 329 | } |
| 310 | } | 330 | } |
| ... | @@ -350,7 +370,7 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -350,7 +370,7 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 350 | return updated; | 370 | return updated; |
| 351 | } | 371 | } |
| 352 | 372 | ||
| 353 | - private void tryLeaderLock(String path) { | 373 | + private void tryLeaderLock(String path, CompletableFuture<Leadership> future) { |
| 354 | if (!activeTopics.contains(path) || Objects.equals(localNodeId, getLeader(path))) { | 374 | if (!activeTopics.contains(path) || Objects.equals(localNodeId, getLeader(path))) { |
| 355 | return; | 375 | return; |
| 356 | } | 376 | } |
| ... | @@ -362,35 +382,37 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -362,35 +382,37 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 362 | .filter(n -> clusterService.getState(n) == ACTIVE) | 382 | .filter(n -> clusterService.getState(n) == ACTIVE) |
| 363 | .collect(Collectors.toList()); | 383 | .collect(Collectors.toList()); |
| 364 | if (localNodeId.equals(activeNodes.get(LEADER_CANDIDATE_POS))) { | 384 | if (localNodeId.equals(activeNodes.get(LEADER_CANDIDATE_POS))) { |
| 365 | - leaderLockAttempt(path, candidates.value()); | 385 | + leaderLockAttempt(path, candidates.value(), future); |
| 366 | } else { | 386 | } else { |
| 367 | - retryLock(path); | 387 | + retryLock(path, future); |
| 368 | } | 388 | } |
| 369 | } else { | 389 | } else { |
| 370 | throw new IllegalStateException("should not be here"); | 390 | throw new IllegalStateException("should not be here"); |
| 371 | } | 391 | } |
| 372 | } catch (Exception e) { | 392 | } catch (Exception e) { |
| 373 | log.debug("Failed to fetch candidate information for {}", path, e); | 393 | log.debug("Failed to fetch candidate information for {}", path, e); |
| 374 | - retryLock(path); | 394 | + retryLock(path, future); |
| 375 | } | 395 | } |
| 376 | } | 396 | } |
| 377 | 397 | ||
| 378 | - private void leaderLockAttempt(String path, List<NodeId> candidates) { | 398 | + private void leaderLockAttempt(String path, List<NodeId> candidates, CompletableFuture<Leadership> future) { |
| 379 | try { | 399 | try { |
| 380 | Versioned<NodeId> currentLeader = leaderMap.get(path); | 400 | Versioned<NodeId> currentLeader = leaderMap.get(path); |
| 381 | if (currentLeader != null) { | 401 | if (currentLeader != null) { |
| 382 | if (localNodeId.equals(currentLeader.value())) { | 402 | if (localNodeId.equals(currentLeader.value())) { |
| 383 | log.info("Already has leadership for {}", path); | 403 | log.info("Already has leadership for {}", path); |
| 384 | // FIXME: candidates can get out of sync. | 404 | // FIXME: candidates can get out of sync. |
| 385 | - publish(new LeadershipEvent( | 405 | + Leadership leadership = new Leadership(path, |
| 386 | - LeadershipEvent.Type.LEADER_ELECTED, | ||
| 387 | - new Leadership(path, | ||
| 388 | localNodeId, | 406 | localNodeId, |
| 389 | currentLeader.version(), | 407 | currentLeader.version(), |
| 390 | - currentLeader.creationTime()))); | 408 | + currentLeader.creationTime()); |
| 409 | + future.complete(leadership); | ||
| 410 | + publish(new LeadershipEvent( | ||
| 411 | + LeadershipEvent.Type.LEADER_ELECTED, | ||
| 412 | + leadership)); | ||
| 391 | } else { | 413 | } else { |
| 392 | // someone else has leadership. will retry after sometime. | 414 | // someone else has leadership. will retry after sometime. |
| 393 | - retryLock(path); | 415 | + retryLock(path, future); |
| 394 | } | 416 | } |
| 395 | } else { | 417 | } else { |
| 396 | if (leaderMap.putIfAbsent(path, localNodeId) == null) { | 418 | if (leaderMap.putIfAbsent(path, localNodeId) == null) { |
| ... | @@ -398,20 +420,22 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -398,20 +420,22 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 398 | // do a get again to get the version (epoch) | 420 | // do a get again to get the version (epoch) |
| 399 | Versioned<NodeId> newLeader = leaderMap.get(path); | 421 | Versioned<NodeId> newLeader = leaderMap.get(path); |
| 400 | // FIXME: candidates can get out of sync | 422 | // FIXME: candidates can get out of sync |
| 401 | - publish(new LeadershipEvent( | 423 | + Leadership leadership = new Leadership(path, |
| 402 | - LeadershipEvent.Type.LEADER_ELECTED, | ||
| 403 | - new Leadership(path, | ||
| 404 | newLeader.value(), | 424 | newLeader.value(), |
| 405 | newLeader.version(), | 425 | newLeader.version(), |
| 406 | - newLeader.creationTime()))); | 426 | + newLeader.creationTime()); |
| 427 | + future.complete(leadership); | ||
| 428 | + publish(new LeadershipEvent( | ||
| 429 | + LeadershipEvent.Type.LEADER_ELECTED, | ||
| 430 | + leadership)); | ||
| 407 | } else { | 431 | } else { |
| 408 | // someone beat us to it. | 432 | // someone beat us to it. |
| 409 | - retryLock(path); | 433 | + retryLock(path, future); |
| 410 | } | 434 | } |
| 411 | } | 435 | } |
| 412 | } catch (Exception e) { | 436 | } catch (Exception e) { |
| 413 | log.debug("Attempt to acquire leadership lock for topic {} failed", path, e); | 437 | log.debug("Attempt to acquire leadership lock for topic {} failed", path, e); |
| 414 | - retryLock(path); | 438 | + retryLock(path, future); |
| 415 | } | 439 | } |
| 416 | } | 440 | } |
| 417 | 441 | ||
| ... | @@ -463,23 +487,23 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -463,23 +487,23 @@ public class DistributedLeadershipManager implements LeadershipService { |
| 463 | } | 487 | } |
| 464 | } | 488 | } |
| 465 | 489 | ||
| 466 | - private void rerunForLeadership(String path) { | 490 | + private void rerunForLeadership(String path, CompletableFuture<Leadership> future) { |
| 467 | retryLeaderLockExecutor.schedule( | 491 | retryLeaderLockExecutor.schedule( |
| 468 | - () -> runForLeadership(path), | 492 | + () -> doRunForLeadership(path, future), |
| 469 | ELECTION_JOIN_ATTEMPT_INTERVAL_SEC, | 493 | ELECTION_JOIN_ATTEMPT_INTERVAL_SEC, |
| 470 | TimeUnit.SECONDS); | 494 | TimeUnit.SECONDS); |
| 471 | } | 495 | } |
| 472 | 496 | ||
| 473 | - private void retryLock(String path) { | 497 | + private void retryLock(String path, CompletableFuture<Leadership> future) { |
| 474 | retryLeaderLockExecutor.schedule( | 498 | retryLeaderLockExecutor.schedule( |
| 475 | - () -> tryLeaderLock(path), | 499 | + () -> tryLeaderLock(path, future), |
| 476 | DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, | 500 | DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, |
| 477 | TimeUnit.SECONDS); | 501 | TimeUnit.SECONDS); |
| 478 | } | 502 | } |
| 479 | 503 | ||
| 480 | - private void retryWithdraw(String path) { | 504 | + private void retryWithdraw(String path, CompletableFuture<Void> future) { |
| 481 | retryLeaderLockExecutor.schedule( | 505 | retryLeaderLockExecutor.schedule( |
| 482 | - () -> withdraw(path), | 506 | + () -> doWithdraw(path, future), |
| 483 | DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, | 507 | DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, |
| 484 | TimeUnit.SECONDS); | 508 | TimeUnit.SECONDS); |
| 485 | } | 509 | } | ... | ... |
| ... | @@ -163,19 +163,22 @@ public class ConsistentDeviceMastershipStore | ... | @@ -163,19 +163,22 @@ public class ConsistentDeviceMastershipStore |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | @Override | 165 | @Override |
| 166 | - public MastershipRole requestRole(DeviceId deviceId) { | 166 | + public CompletableFuture<MastershipRole> requestRole(DeviceId deviceId) { |
| 167 | checkArgument(deviceId != null, DEVICE_ID_NULL); | 167 | checkArgument(deviceId != null, DEVICE_ID_NULL); |
| 168 | 168 | ||
| 169 | String leadershipTopic = createDeviceMastershipTopic(deviceId); | 169 | String leadershipTopic = createDeviceMastershipTopic(deviceId); |
| 170 | if (connectedDevices.add(deviceId)) { | 170 | if (connectedDevices.add(deviceId)) { |
| 171 | - leadershipService.runForLeadership(leadershipTopic); | 171 | + return leadershipService.runForLeadership(leadershipTopic) |
| 172 | - return MastershipRole.STANDBY; | 172 | + .thenApply(leadership -> { |
| 173 | + return Objects.equal(localNodeId, leadership.leader()) | ||
| 174 | + ? MastershipRole.MASTER : MastershipRole.STANDBY; | ||
| 175 | + }); | ||
| 173 | } else { | 176 | } else { |
| 174 | Leadership leadership = leadershipService.getLeadership(leadershipTopic); | 177 | Leadership leadership = leadershipService.getLeadership(leadershipTopic); |
| 175 | if (leadership != null && leadership.leader().equals(localNodeId)) { | 178 | if (leadership != null && leadership.leader().equals(localNodeId)) { |
| 176 | - return MastershipRole.MASTER; | 179 | + return CompletableFuture.completedFuture(MastershipRole.MASTER); |
| 177 | } else { | 180 | } else { |
| 178 | - return MastershipRole.STANDBY; | 181 | + return CompletableFuture.completedFuture(MastershipRole.STANDBY); |
| 179 | } | 182 | } |
| 180 | } | 183 | } |
| 181 | } | 184 | } | ... | ... |
| ... | @@ -205,7 +205,7 @@ public class DistributedMastershipStore | ... | @@ -205,7 +205,7 @@ public class DistributedMastershipStore |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | @Override | 207 | @Override |
| 208 | - public MastershipRole requestRole(DeviceId deviceId) { | 208 | + public CompletableFuture<MastershipRole> requestRole(DeviceId deviceId) { |
| 209 | 209 | ||
| 210 | // if no master => become master | 210 | // if no master => become master |
| 211 | // if there already exists a master: | 211 | // if there already exists a master: |
| ... | @@ -225,7 +225,7 @@ public class DistributedMastershipStore | ... | @@ -225,7 +225,7 @@ public class DistributedMastershipStore |
| 225 | 225 | ||
| 226 | updateTerm(deviceId); | 226 | updateTerm(deviceId); |
| 227 | roleMap.put(deviceId, rv); | 227 | roleMap.put(deviceId, rv); |
| 228 | - return MASTER; | 228 | + return CompletableFuture.completedFuture(MASTER); |
| 229 | } | 229 | } |
| 230 | final MastershipRole currentRole = rv.getRole(local); | 230 | final MastershipRole currentRole = rv.getRole(local); |
| 231 | switch (currentRole) { | 231 | switch (currentRole) { |
| ... | @@ -239,7 +239,7 @@ public class DistributedMastershipStore | ... | @@ -239,7 +239,7 @@ public class DistributedMastershipStore |
| 239 | roleMap.put(deviceId, rv); | 239 | roleMap.put(deviceId, rv); |
| 240 | // trigger BACKUPS_CHANGED? | 240 | // trigger BACKUPS_CHANGED? |
| 241 | } | 241 | } |
| 242 | - return currentRole; | 242 | + return CompletableFuture.completedFuture(currentRole); |
| 243 | case STANDBY: | 243 | case STANDBY: |
| 244 | // RoleInfo integrity check | 244 | // RoleInfo integrity check |
| 245 | modified = rv.reassign(local, NONE, STANDBY); | 245 | modified = rv.reassign(local, NONE, STANDBY); |
| ... | @@ -250,16 +250,16 @@ public class DistributedMastershipStore | ... | @@ -250,16 +250,16 @@ public class DistributedMastershipStore |
| 250 | roleMap.put(deviceId, rv); | 250 | roleMap.put(deviceId, rv); |
| 251 | // trigger BACKUPS_CHANGED? | 251 | // trigger BACKUPS_CHANGED? |
| 252 | } | 252 | } |
| 253 | - return currentRole; | 253 | + return CompletableFuture.completedFuture(currentRole); |
| 254 | case NONE: | 254 | case NONE: |
| 255 | rv.reassign(local, NONE, STANDBY); | 255 | rv.reassign(local, NONE, STANDBY); |
| 256 | roleMap.put(deviceId, rv); | 256 | roleMap.put(deviceId, rv); |
| 257 | // TODO: notifyDelegate BACKUPS_CHANGED | 257 | // TODO: notifyDelegate BACKUPS_CHANGED |
| 258 | - return STANDBY; | 258 | + return CompletableFuture.completedFuture(STANDBY); |
| 259 | default: | 259 | default: |
| 260 | log.warn("unknown Mastership Role {}", currentRole); | 260 | log.warn("unknown Mastership Role {}", currentRole); |
| 261 | } | 261 | } |
| 262 | - return currentRole; | 262 | + return CompletableFuture.completedFuture(currentRole); |
| 263 | } finally { | 263 | } finally { |
| 264 | roleMap.unlock(deviceId); | 264 | roleMap.unlock(deviceId); |
| 265 | } | 265 | } | ... | ... |
| ... | @@ -35,6 +35,7 @@ import java.util.HashSet; | ... | @@ -35,6 +35,7 @@ import java.util.HashSet; |
| 35 | import java.util.Map; | 35 | import java.util.Map; |
| 36 | import java.util.Objects; | 36 | import java.util.Objects; |
| 37 | import java.util.Set; | 37 | import java.util.Set; |
| 38 | +import java.util.concurrent.CompletableFuture; | ||
| 38 | 39 | ||
| 39 | import static junit.framework.TestCase.assertFalse; | 40 | import static junit.framework.TestCase.assertFalse; |
| 40 | import static org.easymock.EasyMock.anyObject; | 41 | import static org.easymock.EasyMock.anyObject; |
| ... | @@ -74,8 +75,11 @@ public class PartitionManagerTest { | ... | @@ -74,8 +75,11 @@ public class PartitionManagerTest { |
| 74 | 75 | ||
| 75 | leadershipService.addListener(anyObject(LeadershipEventListener.class)); | 76 | leadershipService.addListener(anyObject(LeadershipEventListener.class)); |
| 76 | expectLastCall().andDelegateTo(new TestLeadershipService()); | 77 | expectLastCall().andDelegateTo(new TestLeadershipService()); |
| 77 | - leadershipService.runForLeadership(anyString()); | 78 | + for (int i = 0; i < PartitionManager.NUM_PARTITIONS; i++) { |
| 78 | - expectLastCall().anyTimes(); | 79 | + expect(leadershipService.runForLeadership(ELECTION_PREFIX + i)) |
| 80 | + .andReturn(CompletableFuture.completedFuture(null)) | ||
| 81 | + .times(1); | ||
| 82 | + } | ||
| 79 | 83 | ||
| 80 | partitionManager = new PartitionManager() | 84 | partitionManager = new PartitionManager() |
| 81 | .withScheduledExecutor(new NullScheduledExecutor()); | 85 | .withScheduledExecutor(new NullScheduledExecutor()); |
| ... | @@ -92,6 +96,7 @@ public class PartitionManagerTest { | ... | @@ -92,6 +96,7 @@ public class PartitionManagerTest { |
| 92 | * @param numMine number of partitions that should be owned by the local node | 96 | * @param numMine number of partitions that should be owned by the local node |
| 93 | */ | 97 | */ |
| 94 | private void setUpLeadershipService(int numMine) { | 98 | private void setUpLeadershipService(int numMine) { |
| 99 | + | ||
| 95 | Map<String, Leadership> leaderBoard = new HashMap<>(); | 100 | Map<String, Leadership> leaderBoard = new HashMap<>(); |
| 96 | 101 | ||
| 97 | for (int i = 0; i < numMine; i++) { | 102 | for (int i = 0; i < numMine; i++) { |
| ... | @@ -123,7 +128,9 @@ public class PartitionManagerTest { | ... | @@ -123,7 +128,9 @@ public class PartitionManagerTest { |
| 123 | leadershipService.addListener(anyObject(LeadershipEventListener.class)); | 128 | leadershipService.addListener(anyObject(LeadershipEventListener.class)); |
| 124 | 129 | ||
| 125 | for (int i = 0; i < PartitionManager.NUM_PARTITIONS; i++) { | 130 | for (int i = 0; i < PartitionManager.NUM_PARTITIONS; i++) { |
| 126 | - leadershipService.runForLeadership(ELECTION_PREFIX + i); | 131 | + expect(leadershipService.runForLeadership(ELECTION_PREFIX + i)) |
| 132 | + .andReturn(CompletableFuture.completedFuture(null)) | ||
| 133 | + .times(1); | ||
| 127 | } | 134 | } |
| 128 | 135 | ||
| 129 | replay(leadershipService); | 136 | replay(leadershipService); |
| ... | @@ -172,8 +179,9 @@ public class PartitionManagerTest { | ... | @@ -172,8 +179,9 @@ public class PartitionManagerTest { |
| 172 | // We have all the partitions so we'll need to relinquish some | 179 | // We have all the partitions so we'll need to relinquish some |
| 173 | setUpLeadershipService(PartitionManager.NUM_PARTITIONS); | 180 | setUpLeadershipService(PartitionManager.NUM_PARTITIONS); |
| 174 | 181 | ||
| 175 | - leadershipService.withdraw(anyString()); | 182 | + expect(leadershipService.withdraw(anyString())) |
| 176 | - expectLastCall().times(7); | 183 | + .andReturn(CompletableFuture.completedFuture(null)) |
| 184 | + .times(7); | ||
| 177 | 185 | ||
| 178 | replay(leadershipService); | 186 | replay(leadershipService); |
| 179 | 187 | ... | ... |
| ... | @@ -145,22 +145,22 @@ public class DistributedMastershipStoreTest { | ... | @@ -145,22 +145,22 @@ public class DistributedMastershipStoreTest { |
| 145 | 145 | ||
| 146 | //if already MASTER, nothing should happen | 146 | //if already MASTER, nothing should happen |
| 147 | testStore.put(DID2, N1, true, false, true); | 147 | testStore.put(DID2, N1, true, false, true); |
| 148 | - assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2)); | 148 | + assertEquals("wrong role for MASTER:", MASTER, Futures.getUnchecked(dms.requestRole(DID2))); |
| 149 | 149 | ||
| 150 | //populate maps with DID1, N1 thru NONE case | 150 | //populate maps with DID1, N1 thru NONE case |
| 151 | - assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1)); | 151 | + assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1))); |
| 152 | assertTrue("wrong state for store:", !dms.terms.isEmpty()); | 152 | assertTrue("wrong state for store:", !dms.terms.isEmpty()); |
| 153 | assertEquals("wrong term", | 153 | assertEquals("wrong term", |
| 154 | MastershipTerm.of(N1, 1), dms.getTermFor(DID1)); | 154 | MastershipTerm.of(N1, 1), dms.getTermFor(DID1)); |
| 155 | 155 | ||
| 156 | //CN2 now local. DID2 has N1 as MASTER so N2 is STANDBY | 156 | //CN2 now local. DID2 has N1 as MASTER so N2 is STANDBY |
| 157 | testStore.setCurrent(CN2); | 157 | testStore.setCurrent(CN2); |
| 158 | - assertEquals("wrong role for STANDBY:", STANDBY, dms.requestRole(DID2)); | 158 | + assertEquals("wrong role for STANDBY:", STANDBY, Futures.getUnchecked(dms.requestRole(DID2))); |
| 159 | assertEquals("wrong number of entries:", 2, dms.terms.size()); | 159 | assertEquals("wrong number of entries:", 2, dms.terms.size()); |
| 160 | 160 | ||
| 161 | //change term and requestRole() again; should persist | 161 | //change term and requestRole() again; should persist |
| 162 | testStore.increment(DID2); | 162 | testStore.increment(DID2); |
| 163 | - assertEquals("wrong role for STANDBY:", STANDBY, dms.requestRole(DID2)); | 163 | + assertEquals("wrong role for STANDBY:", STANDBY, Futures.getUnchecked(dms.requestRole(DID2))); |
| 164 | assertEquals("wrong term", MastershipTerm.of(N1, 1), dms.getTermFor(DID2)); | 164 | assertEquals("wrong term", MastershipTerm.of(N1, 1), dms.getTermFor(DID2)); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| ... | @@ -168,7 +168,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -168,7 +168,7 @@ public class DistributedMastershipStoreTest { |
| 168 | public void setMaster() { | 168 | public void setMaster() { |
| 169 | //populate maps with DID1, N1 as MASTER thru NONE case | 169 | //populate maps with DID1, N1 as MASTER thru NONE case |
| 170 | testStore.setCurrent(CN1); | 170 | testStore.setCurrent(CN1); |
| 171 | - assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1)); | 171 | + assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1))); |
| 172 | assertNull("wrong event:", Futures.getUnchecked(dms.setMaster(N1, DID1))); | 172 | assertNull("wrong event:", Futures.getUnchecked(dms.setMaster(N1, DID1))); |
| 173 | 173 | ||
| 174 | //switch over to N2 | 174 | //switch over to N2 |
| ... | @@ -189,7 +189,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -189,7 +189,7 @@ public class DistributedMastershipStoreTest { |
| 189 | public void relinquishRole() { | 189 | public void relinquishRole() { |
| 190 | //populate maps with DID1, N1 as MASTER thru NONE case | 190 | //populate maps with DID1, N1 as MASTER thru NONE case |
| 191 | testStore.setCurrent(CN1); | 191 | testStore.setCurrent(CN1); |
| 192 | - assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1)); | 192 | + assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1))); |
| 193 | //no backup, no new MASTER/event | 193 | //no backup, no new MASTER/event |
| 194 | assertNull("wrong event:", Futures.getUnchecked(dms.relinquishRole(N1, DID1))); | 194 | assertNull("wrong event:", Futures.getUnchecked(dms.relinquishRole(N1, DID1))); |
| 195 | 195 | ||
| ... | @@ -197,7 +197,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -197,7 +197,7 @@ public class DistributedMastershipStoreTest { |
| 197 | 197 | ||
| 198 | //add backup CN2, get it elected MASTER by relinquishing | 198 | //add backup CN2, get it elected MASTER by relinquishing |
| 199 | testStore.setCurrent(CN2); | 199 | testStore.setCurrent(CN2); |
| 200 | - assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1)); | 200 | + assertEquals("wrong role for NONE:", STANDBY, Futures.getUnchecked(dms.requestRole(DID1))); |
| 201 | assertEquals("wrong event:", Type.MASTER_CHANGED, Futures.getUnchecked(dms.relinquishRole(N1, DID1)).type()); | 201 | assertEquals("wrong event:", Type.MASTER_CHANGED, Futures.getUnchecked(dms.relinquishRole(N1, DID1)).type()); |
| 202 | assertEquals("wrong master", N2, dms.getMaster(DID1)); | 202 | assertEquals("wrong master", N2, dms.getMaster(DID1)); |
| 203 | 203 | ||
| ... | @@ -209,9 +209,9 @@ public class DistributedMastershipStoreTest { | ... | @@ -209,9 +209,9 @@ public class DistributedMastershipStoreTest { |
| 209 | dms.roleMap.get(DID1).nodesOfRole(NONE).size()); | 209 | dms.roleMap.get(DID1).nodesOfRole(NONE).size()); |
| 210 | 210 | ||
| 211 | //bring nodes back | 211 | //bring nodes back |
| 212 | - assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1)); | 212 | + assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1))); |
| 213 | testStore.setCurrent(CN1); | 213 | testStore.setCurrent(CN1); |
| 214 | - assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1)); | 214 | + assertEquals("wrong role for NONE:", STANDBY, Futures.getUnchecked(dms.requestRole(DID1))); |
| 215 | assertEquals("wrong number of backup nodes", 1, | 215 | assertEquals("wrong number of backup nodes", 1, |
| 216 | dms.roleMap.get(DID1).nodesOfRole(STANDBY).size()); | 216 | dms.roleMap.get(DID1).nodesOfRole(STANDBY).size()); |
| 217 | 217 | ... | ... |
| ... | @@ -21,6 +21,7 @@ import java.util.List; | ... | @@ -21,6 +21,7 @@ import java.util.List; |
| 21 | import java.util.Map; | 21 | import java.util.Map; |
| 22 | import java.util.Map.Entry; | 22 | import java.util.Map.Entry; |
| 23 | import java.util.Set; | 23 | import java.util.Set; |
| 24 | +import java.util.concurrent.CompletableFuture; | ||
| 24 | import java.util.concurrent.ConcurrentHashMap; | 25 | import java.util.concurrent.ConcurrentHashMap; |
| 25 | import java.util.concurrent.CopyOnWriteArraySet; | 26 | import java.util.concurrent.CopyOnWriteArraySet; |
| 26 | import java.util.stream.Collectors; | 27 | import java.util.stream.Collectors; |
| ... | @@ -76,21 +77,23 @@ public class SimpleLeadershipManager implements LeadershipService { | ... | @@ -76,21 +77,23 @@ public class SimpleLeadershipManager implements LeadershipService { |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | @Override | 79 | @Override |
| 79 | - public void runForLeadership(String path) { | 80 | + public CompletableFuture<Leadership> runForLeadership(String path) { |
| 80 | elections.put(path, true); | 81 | elections.put(path, true); |
| 81 | for (LeadershipEventListener listener : listeners) { | 82 | for (LeadershipEventListener listener : listeners) { |
| 82 | listener.event(new LeadershipEvent(Type.LEADER_ELECTED, | 83 | listener.event(new LeadershipEvent(Type.LEADER_ELECTED, |
| 83 | new Leadership(path, clusterService.getLocalNode().id(), 0, 0))); | 84 | new Leadership(path, clusterService.getLocalNode().id(), 0, 0))); |
| 84 | } | 85 | } |
| 86 | + return CompletableFuture.completedFuture(new Leadership(path, clusterService.getLocalNode().id(), 0, 0)); | ||
| 85 | } | 87 | } |
| 86 | 88 | ||
| 87 | @Override | 89 | @Override |
| 88 | - public void withdraw(String path) { | 90 | + public CompletableFuture<Void> withdraw(String path) { |
| 89 | elections.remove(path); | 91 | elections.remove(path); |
| 90 | for (LeadershipEventListener listener : listeners) { | 92 | for (LeadershipEventListener listener : listeners) { |
| 91 | listener.event(new LeadershipEvent(Type.LEADER_BOOTED, | 93 | listener.event(new LeadershipEvent(Type.LEADER_BOOTED, |
| 92 | new Leadership(path, clusterService.getLocalNode().id(), 0, 0))); | 94 | new Leadership(path, clusterService.getLocalNode().id(), 0, 0))); |
| 93 | } | 95 | } |
| 96 | + return CompletableFuture.completedFuture(null); | ||
| 94 | } | 97 | } |
| 95 | 98 | ||
| 96 | @Override | 99 | @Override | ... | ... |
| ... | @@ -191,14 +191,14 @@ public class SimpleMastershipStore | ... | @@ -191,14 +191,14 @@ public class SimpleMastershipStore |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | @Override | 193 | @Override |
| 194 | - public synchronized MastershipRole requestRole(DeviceId deviceId) { | 194 | + public synchronized CompletableFuture<MastershipRole> requestRole(DeviceId deviceId) { |
| 195 | //query+possible reelection | 195 | //query+possible reelection |
| 196 | NodeId node = clusterService.getLocalNode().id(); | 196 | NodeId node = clusterService.getLocalNode().id(); |
| 197 | MastershipRole role = getRole(node, deviceId); | 197 | MastershipRole role = getRole(node, deviceId); |
| 198 | 198 | ||
| 199 | switch (role) { | 199 | switch (role) { |
| 200 | case MASTER: | 200 | case MASTER: |
| 201 | - return MastershipRole.MASTER; | 201 | + return CompletableFuture.completedFuture(MastershipRole.MASTER); |
| 202 | case STANDBY: | 202 | case STANDBY: |
| 203 | if (getMaster(deviceId) == null) { | 203 | if (getMaster(deviceId) == null) { |
| 204 | // no master => become master | 204 | // no master => become master |
| ... | @@ -208,9 +208,9 @@ public class SimpleMastershipStore | ... | @@ -208,9 +208,9 @@ public class SimpleMastershipStore |
| 208 | removeFromBackups(deviceId, node); | 208 | removeFromBackups(deviceId, node); |
| 209 | notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, | 209 | notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, |
| 210 | getNodes(deviceId))); | 210 | getNodes(deviceId))); |
| 211 | - return MastershipRole.MASTER; | 211 | + return CompletableFuture.completedFuture(MastershipRole.MASTER); |
| 212 | } | 212 | } |
| 213 | - return MastershipRole.STANDBY; | 213 | + return CompletableFuture.completedFuture(MastershipRole.STANDBY); |
| 214 | case NONE: | 214 | case NONE: |
| 215 | if (getMaster(deviceId) == null) { | 215 | if (getMaster(deviceId) == null) { |
| 216 | // no master => become master | 216 | // no master => become master |
| ... | @@ -218,18 +218,18 @@ public class SimpleMastershipStore | ... | @@ -218,18 +218,18 @@ public class SimpleMastershipStore |
| 218 | incrementTerm(deviceId); | 218 | incrementTerm(deviceId); |
| 219 | notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, | 219 | notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, |
| 220 | getNodes(deviceId))); | 220 | getNodes(deviceId))); |
| 221 | - return MastershipRole.MASTER; | 221 | + return CompletableFuture.completedFuture(MastershipRole.MASTER); |
| 222 | } | 222 | } |
| 223 | // add to backup list | 223 | // add to backup list |
| 224 | if (addToBackup(deviceId, node)) { | 224 | if (addToBackup(deviceId, node)) { |
| 225 | notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, | 225 | notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, |
| 226 | getNodes(deviceId))); | 226 | getNodes(deviceId))); |
| 227 | } | 227 | } |
| 228 | - return MastershipRole.STANDBY; | 228 | + return CompletableFuture.completedFuture(MastershipRole.STANDBY); |
| 229 | default: | 229 | default: |
| 230 | log.warn("unknown Mastership Role {}", role); | 230 | log.warn("unknown Mastership Role {}", role); |
| 231 | } | 231 | } |
| 232 | - return role; | 232 | + return CompletableFuture.completedFuture(role); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | // add to backup if not there already, silently ignores null node | 235 | // add to backup if not there already, silently ignores null node | ... | ... |
| ... | @@ -130,19 +130,19 @@ public class SimpleMastershipStoreTest { | ... | @@ -130,19 +130,19 @@ public class SimpleMastershipStoreTest { |
| 130 | public void requestRole() { | 130 | public void requestRole() { |
| 131 | //NONE - become MASTER | 131 | //NONE - become MASTER |
| 132 | put(DID1, N1, false, false); | 132 | put(DID1, N1, false, false); |
| 133 | - assertEquals("wrong role", MASTER, sms.requestRole(DID1)); | 133 | + assertEquals("wrong role", MASTER, Futures.getUnchecked(sms.requestRole(DID1))); |
| 134 | 134 | ||
| 135 | //was STANDBY - become MASTER | 135 | //was STANDBY - become MASTER |
| 136 | put(DID2, N1, false, true); | 136 | put(DID2, N1, false, true); |
| 137 | - assertEquals("wrong role", MASTER, sms.requestRole(DID2)); | 137 | + assertEquals("wrong role", MASTER, Futures.getUnchecked(sms.requestRole(DID2))); |
| 138 | 138 | ||
| 139 | //other MASTER - stay STANDBY | 139 | //other MASTER - stay STANDBY |
| 140 | put(DID3, N2, true, false); | 140 | put(DID3, N2, true, false); |
| 141 | - assertEquals("wrong role", STANDBY, sms.requestRole(DID3)); | 141 | + assertEquals("wrong role", STANDBY, Futures.getUnchecked(sms.requestRole(DID3))); |
| 142 | 142 | ||
| 143 | //local (N1) is MASTER - stay MASTER | 143 | //local (N1) is MASTER - stay MASTER |
| 144 | put(DID4, N1, true, true); | 144 | put(DID4, N1, true, true); |
| 145 | - assertEquals("wrong role", MASTER, sms.requestRole(DID4)); | 145 | + assertEquals("wrong role", MASTER, Futures.getUnchecked(sms.requestRole(DID4))); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | @Test | 148 | @Test | ... | ... |
| ... | @@ -30,6 +30,7 @@ import java.util.HashMap; | ... | @@ -30,6 +30,7 @@ import java.util.HashMap; |
| 30 | import java.util.List; | 30 | import java.util.List; |
| 31 | import java.util.Map; | 31 | import java.util.Map; |
| 32 | import java.util.Set; | 32 | import java.util.Set; |
| 33 | +import java.util.concurrent.CompletableFuture; | ||
| 33 | 34 | ||
| 34 | import org.junit.After; | 35 | import org.junit.After; |
| 35 | import org.junit.Before; | 36 | import org.junit.Before; |
| ... | @@ -496,8 +497,8 @@ public class LLDPLinkProviderTest { | ... | @@ -496,8 +497,8 @@ public class LLDPLinkProviderTest { |
| 496 | } | 497 | } |
| 497 | 498 | ||
| 498 | @Override | 499 | @Override |
| 499 | - public MastershipRole requestRoleFor(DeviceId deviceId) { | 500 | + public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) { |
| 500 | - return null; | 501 | + return CompletableFuture.completedFuture(null); |
| 501 | } | 502 | } |
| 502 | 503 | ||
| 503 | @Override | 504 | @Override | ... | ... |
-
Please register or login to post a comment