blob: 41adfded67021de7fdec23c261962091bf68c786 [file] [log] [blame]
Madan Jampani84b6b402015-02-25 17:49:54 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Madan Jampani84b6b402015-02-25 17:49:54 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.store.mastership.impl;
17
18import static org.onlab.util.Tools.groupedThreads;
Madan Jampani0f6ad142015-05-13 17:10:04 -070019import static org.onosproject.mastership.MastershipEvent.Type.BACKUPS_CHANGED;
Madan Jampani84b6b402015-02-25 17:49:54 -080020import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED;
Andrea Campanella80b296d2018-09-18 10:48:15 +020021import static org.onosproject.mastership.MastershipEvent.Type.RESTORED;
Jon Hall7a8bfc62016-05-26 17:59:04 -070022import static org.onosproject.mastership.MastershipEvent.Type.SUSPENDED;
Madan Jampani84b6b402015-02-25 17:49:54 -080023import static org.slf4j.LoggerFactory.getLogger;
24import static com.google.common.base.Preconditions.checkArgument;
25
Madan Jampani84b6b402015-02-25 17:49:54 -080026import java.util.List;
Jordan Halterman0a2bd452018-06-13 17:24:58 -070027import java.util.Objects;
28import java.util.Optional;
Madan Jampani84b6b402015-02-25 17:49:54 -080029import java.util.Set;
Madan Jampanif7536ab2015-05-07 23:23:23 -070030import java.util.concurrent.CompletableFuture;
Madan Jampani84b6b402015-02-25 17:49:54 -080031import java.util.concurrent.ExecutorService;
32import java.util.concurrent.Executors;
Madan Jampanif7536ab2015-05-07 23:23:23 -070033import java.util.concurrent.ScheduledExecutorService;
34import java.util.concurrent.TimeUnit;
Madan Jampani84b6b402015-02-25 17:49:54 -080035import java.util.regex.Matcher;
36import java.util.regex.Pattern;
37import java.util.stream.Collectors;
38
Jordan Halterman0a2bd452018-06-13 17:24:58 -070039import com.google.common.collect.ImmutableMap;
Madan Jampani84b6b402015-02-25 17:49:54 -080040import org.apache.felix.scr.annotations.Activate;
41import org.apache.felix.scr.annotations.Component;
42import org.apache.felix.scr.annotations.Deactivate;
43import org.apache.felix.scr.annotations.Reference;
44import org.apache.felix.scr.annotations.ReferenceCardinality;
45import org.apache.felix.scr.annotations.Service;
46import org.onlab.util.KryoNamespace;
47import org.onosproject.cluster.ClusterService;
48import org.onosproject.cluster.Leadership;
Madan Jampani620f70d2016-01-30 22:22:47 -080049import org.onosproject.cluster.LeadershipAdminService;
Madan Jampani84b6b402015-02-25 17:49:54 -080050import org.onosproject.cluster.LeadershipEvent;
51import org.onosproject.cluster.LeadershipEventListener;
52import org.onosproject.cluster.LeadershipService;
53import org.onosproject.cluster.NodeId;
54import org.onosproject.cluster.RoleInfo;
55import org.onosproject.mastership.MastershipEvent;
Jordan Halterman0a2bd452018-06-13 17:24:58 -070056import org.onosproject.mastership.MastershipInfo;
Madan Jampani84b6b402015-02-25 17:49:54 -080057import org.onosproject.mastership.MastershipStore;
58import org.onosproject.mastership.MastershipStoreDelegate;
59import org.onosproject.mastership.MastershipTerm;
60import org.onosproject.net.DeviceId;
61import org.onosproject.net.MastershipRole;
62import org.onosproject.store.AbstractStore;
63import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
Madan Jampani84b6b402015-02-25 17:49:54 -080064import org.onosproject.store.cluster.messaging.MessageSubject;
65import org.onosproject.store.serializers.KryoNamespaces;
Jordan Halterman2c83a102017-08-20 17:11:41 -070066import org.onosproject.store.service.Serializer;
Madan Jampani84b6b402015-02-25 17:49:54 -080067import org.slf4j.Logger;
68
Madan Jampani620f70d2016-01-30 22:22:47 -080069import com.google.common.collect.ImmutableList;
Madan Jampani84b6b402015-02-25 17:49:54 -080070
71/**
72 * Implementation of the MastershipStore on top of Leadership Service.
73 */
Sho SHIMIZU5c396e32016-08-12 15:19:12 -070074@Component(immediate = true)
Madan Jampani84b6b402015-02-25 17:49:54 -080075@Service
76public class ConsistentDeviceMastershipStore
77 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
78 implements MastershipStore {
79
80 private final Logger log = getLogger(getClass());
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected LeadershipService leadershipService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Madan Jampani620f70d2016-01-30 22:22:47 -080086 protected LeadershipAdminService leadershipAdminService;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Madan Jampani84b6b402015-02-25 17:49:54 -080089 protected ClusterService clusterService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected ClusterCommunicationService clusterCommunicator;
93
94 private NodeId localNodeId;
Madan Jampani84b6b402015-02-25 17:49:54 -080095
Madan Jampani84b6b402015-02-25 17:49:54 -080096 private static final MessageSubject ROLE_RELINQUISH_SUBJECT =
97 new MessageSubject("mastership-store-device-role-relinquish");
98
99 private static final Pattern DEVICE_MASTERSHIP_TOPIC_PATTERN =
Madan Jampani5756c352015-04-29 00:23:58 -0700100 Pattern.compile("device:(.*)");
Madan Jampani84b6b402015-02-25 17:49:54 -0800101
Madan Jampani71c32ca2016-06-22 08:23:18 -0700102 private ExecutorService eventHandler;
Madan Jampani84b6b402015-02-25 17:49:54 -0800103 private ExecutorService messageHandlingExecutor;
Madan Jampanif7536ab2015-05-07 23:23:23 -0700104 private ScheduledExecutorService transferExecutor;
Madan Jampani84b6b402015-02-25 17:49:54 -0800105 private final LeadershipEventListener leadershipEventListener =
106 new InternalDeviceMastershipEventListener();
107
108 private static final String NODE_ID_NULL = "Node ID cannot be null";
Madan Jampanif7536ab2015-05-07 23:23:23 -0700109 private static final String DEVICE_ID_NULL = "Device ID cannot be null";
110 private static final int WAIT_BEFORE_MASTERSHIP_HANDOFF_MILLIS = 3000;
Madan Jampani84b6b402015-02-25 17:49:54 -0800111
Jordan Halterman2c83a102017-08-20 17:11:41 -0700112 public static final Serializer SERIALIZER = Serializer.using(
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700113 KryoNamespace.newBuilder()
Madan Jampani84b6b402015-02-25 17:49:54 -0800114 .register(KryoNamespaces.API)
115 .register(MastershipRole.class)
116 .register(MastershipEvent.class)
Madan Jampani1af8e132015-04-30 16:41:18 -0700117 .register(MastershipEvent.Type.class)
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700118 .build("MastershipStore"));
Madan Jampani84b6b402015-02-25 17:49:54 -0800119
120 @Activate
121 public void activate() {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700122
123 eventHandler = Executors.newSingleThreadExecutor(
124 groupedThreads("onos/store/device/mastership", "event-handler", log));
125
Madan Jampani84b6b402015-02-25 17:49:54 -0800126 messageHandlingExecutor =
Madan Jampanif7536ab2015-05-07 23:23:23 -0700127 Executors.newSingleThreadExecutor(
HIGUCHI Yuta060da9a2016-03-11 19:16:35 -0800128 groupedThreads("onos/store/device/mastership", "message-handler", log));
Madan Jampanif7536ab2015-05-07 23:23:23 -0700129 transferExecutor =
130 Executors.newSingleThreadScheduledExecutor(
HIGUCHI Yuta060da9a2016-03-11 19:16:35 -0800131 groupedThreads("onos/store/device/mastership", "mastership-transfer-executor", log));
Madan Jampanibbed40422015-05-20 12:00:38 -0700132 clusterCommunicator.addSubscriber(ROLE_RELINQUISH_SUBJECT,
Madan Jampanid46e18f2015-05-04 23:19:33 -0700133 SERIALIZER::decode,
Madan Jampanif7536ab2015-05-07 23:23:23 -0700134 this::relinquishLocalRole,
Madan Jampanid46e18f2015-05-04 23:19:33 -0700135 SERIALIZER::encode,
136 messageHandlingExecutor);
Madan Jampani84b6b402015-02-25 17:49:54 -0800137 localNodeId = clusterService.getLocalNode().id();
138 leadershipService.addListener(leadershipEventListener);
139
Madan Jampaniafeebbd2015-05-19 15:26:01 -0700140 log.info("Started");
Madan Jampani84b6b402015-02-25 17:49:54 -0800141 }
142
143 @Deactivate
144 public void deactivate() {
Madan Jampani84b6b402015-02-25 17:49:54 -0800145 clusterCommunicator.removeSubscriber(ROLE_RELINQUISH_SUBJECT);
Madan Jampani71c32ca2016-06-22 08:23:18 -0700146 leadershipService.removeListener(leadershipEventListener);
Madan Jampani84b6b402015-02-25 17:49:54 -0800147 messageHandlingExecutor.shutdown();
Madan Jampanif7536ab2015-05-07 23:23:23 -0700148 transferExecutor.shutdown();
Madan Jampani71c32ca2016-06-22 08:23:18 -0700149 eventHandler.shutdown();
Madan Jampaniafeebbd2015-05-19 15:26:01 -0700150 log.info("Stopped");
Madan Jampani84b6b402015-02-25 17:49:54 -0800151 }
152
153 @Override
Madan Jampanide003d92015-05-11 17:14:20 -0700154 public CompletableFuture<MastershipRole> requestRole(DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800155 checkArgument(deviceId != null, DEVICE_ID_NULL);
156
157 String leadershipTopic = createDeviceMastershipTopic(deviceId);
Madan Jampani620f70d2016-01-30 22:22:47 -0800158 Leadership leadership = leadershipService.runForLeadership(leadershipTopic);
Jordan Halterman980a8c12017-09-22 18:01:19 -0700159 NodeId leader = leadership == null ? null : leadership.leaderNodeId();
160 List<NodeId> candidates = leadership == null ?
161 ImmutableList.of() : ImmutableList.copyOf(leadership.candidates());
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700162 MastershipRole role = Objects.equals(localNodeId, leader) ?
Jordan Halterman980a8c12017-09-22 18:01:19 -0700163 MastershipRole.MASTER : candidates.contains(localNodeId) ? MastershipRole.STANDBY : MastershipRole.NONE;
164 return CompletableFuture.completedFuture(role);
Madan Jampani84b6b402015-02-25 17:49:54 -0800165 }
166
167 @Override
168 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
169 checkArgument(nodeId != null, NODE_ID_NULL);
170 checkArgument(deviceId != null, DEVICE_ID_NULL);
171
172 String leadershipTopic = createDeviceMastershipTopic(deviceId);
Madan Jampani620f70d2016-01-30 22:22:47 -0800173 Leadership leadership = leadershipService.getLeadership(leadershipTopic);
174 NodeId leader = leadership == null ? null : leadership.leaderNodeId();
175 List<NodeId> candidates = leadership == null ?
176 ImmutableList.of() : ImmutableList.copyOf(leadership.candidates());
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700177 return Objects.equals(nodeId, leader) ?
Madan Jampani620f70d2016-01-30 22:22:47 -0800178 MastershipRole.MASTER : candidates.contains(nodeId) ? MastershipRole.STANDBY : MastershipRole.NONE;
Madan Jampani84b6b402015-02-25 17:49:54 -0800179 }
180
181 @Override
182 public NodeId getMaster(DeviceId deviceId) {
183 checkArgument(deviceId != null, DEVICE_ID_NULL);
184
Madan Jampani620f70d2016-01-30 22:22:47 -0800185 return leadershipService.getLeader(createDeviceMastershipTopic(deviceId));
Madan Jampani84b6b402015-02-25 17:49:54 -0800186 }
187
188 @Override
189 public RoleInfo getNodes(DeviceId deviceId) {
190 checkArgument(deviceId != null, DEVICE_ID_NULL);
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700191 Leadership leadership = leadershipService.getLeadership(createDeviceMastershipTopic(deviceId));
192 return new RoleInfo(leadership.leaderNodeId(), leadership.candidates());
193 }
Madan Jampani84b6b402015-02-25 17:49:54 -0800194
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700195 @Override
196 public MastershipInfo getMastership(DeviceId deviceId) {
197 checkArgument(deviceId != null, DEVICE_ID_NULL);
198 Leadership leadership = leadershipService.getLeadership(createDeviceMastershipTopic(deviceId));
199 return buildMastershipFromLeadership(leadership);
Madan Jampani84b6b402015-02-25 17:49:54 -0800200 }
201
202 @Override
203 public Set<DeviceId> getDevices(NodeId nodeId) {
204 checkArgument(nodeId != null, NODE_ID_NULL);
205
Yuta HIGUCHId9340032017-01-25 09:25:44 -0800206 // FIXME This result contains REMOVED device.
207 // MastershipService cannot listen to DeviceEvent to GC removed topic,
208 // since DeviceManager depend on it.
209 // Reference count, etc. at LeadershipService layer?
Madan Jampani84b6b402015-02-25 17:49:54 -0800210 return leadershipService
211 .ownedTopics(nodeId)
212 .stream()
213 .filter(this::isDeviceMastershipTopic)
214 .map(this::extractDeviceIdFromTopic)
215 .collect(Collectors.toSet());
216 }
217
218 @Override
Madan Jampanif7536ab2015-05-07 23:23:23 -0700219 public CompletableFuture<MastershipEvent> setMaster(NodeId nodeId, DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800220 checkArgument(nodeId != null, NODE_ID_NULL);
221 checkArgument(deviceId != null, DEVICE_ID_NULL);
222
Madan Jampani620f70d2016-01-30 22:22:47 -0800223 String leadershipTopic = createDeviceMastershipTopic(deviceId);
224 if (leadershipAdminService.promoteToTopOfCandidateList(leadershipTopic, nodeId)) {
225 transferExecutor.schedule(() -> leadershipAdminService.transferLeadership(leadershipTopic, nodeId),
226 WAIT_BEFORE_MASTERSHIP_HANDOFF_MILLIS, TimeUnit.MILLISECONDS);
Madan Jampani1af8e132015-04-30 16:41:18 -0700227 }
Madan Jampanif7536ab2015-05-07 23:23:23 -0700228 return CompletableFuture.completedFuture(null);
Madan Jampani84b6b402015-02-25 17:49:54 -0800229 }
230
231 @Override
232 public MastershipTerm getTermFor(DeviceId deviceId) {
233 checkArgument(deviceId != null, DEVICE_ID_NULL);
234
235 String leadershipTopic = createDeviceMastershipTopic(deviceId);
236 Leadership leadership = leadershipService.getLeadership(leadershipTopic);
Madan Jampanidbe8a812016-01-31 21:10:46 -0800237 return leadership != null && leadership.leaderNodeId() != null ?
238 MastershipTerm.of(leadership.leaderNodeId(), leadership.leader().term()) : null;
Madan Jampani84b6b402015-02-25 17:49:54 -0800239 }
240
241 @Override
Madan Jampanif7536ab2015-05-07 23:23:23 -0700242 public CompletableFuture<MastershipEvent> setStandby(NodeId nodeId, DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800243 checkArgument(nodeId != null, NODE_ID_NULL);
244 checkArgument(deviceId != null, DEVICE_ID_NULL);
245
Madan Jampani1af8e132015-04-30 16:41:18 -0700246 NodeId currentMaster = getMaster(deviceId);
247 if (!nodeId.equals(currentMaster)) {
Madan Jampanif7536ab2015-05-07 23:23:23 -0700248 return CompletableFuture.completedFuture(null);
Madan Jampani1af8e132015-04-30 16:41:18 -0700249 }
Madan Jampanid46e18f2015-05-04 23:19:33 -0700250
251 String leadershipTopic = createDeviceMastershipTopic(deviceId);
252 List<NodeId> candidates = leadershipService.getCandidates(leadershipTopic);
253
254 NodeId newMaster = candidates.stream()
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700255 .filter(candidate -> !Objects.equals(nodeId, candidate))
Madan Jampanid46e18f2015-05-04 23:19:33 -0700256 .findFirst()
257 .orElse(null);
258 log.info("Transitioning to role {} for {}. Next master: {}",
259 newMaster != null ? MastershipRole.STANDBY : MastershipRole.NONE, deviceId, newMaster);
260
261 if (newMaster != null) {
262 return setMaster(newMaster, deviceId);
263 }
264 return relinquishRole(nodeId, deviceId);
Madan Jampani84b6b402015-02-25 17:49:54 -0800265 }
266
267 @Override
Madan Jampanif7536ab2015-05-07 23:23:23 -0700268 public CompletableFuture<MastershipEvent> relinquishRole(NodeId nodeId, DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800269 checkArgument(nodeId != null, NODE_ID_NULL);
270 checkArgument(deviceId != null, DEVICE_ID_NULL);
271
Madan Jampanibbed40422015-05-20 12:00:38 -0700272 if (nodeId.equals(localNodeId)) {
273 return relinquishLocalRole(deviceId);
Madan Jampani84b6b402015-02-25 17:49:54 -0800274 }
Madan Jampanibbed40422015-05-20 12:00:38 -0700275
276 log.debug("Forwarding request to relinquish "
277 + "role for device {} to {}", deviceId, nodeId);
278 return clusterCommunicator.sendAndReceive(
279 deviceId,
280 ROLE_RELINQUISH_SUBJECT,
281 SERIALIZER::encode,
282 SERIALIZER::decode,
283 nodeId);
Madan Jampanif7536ab2015-05-07 23:23:23 -0700284 }
285
Madan Jampanibbed40422015-05-20 12:00:38 -0700286 private CompletableFuture<MastershipEvent> relinquishLocalRole(DeviceId deviceId) {
Madan Jampanif7536ab2015-05-07 23:23:23 -0700287 checkArgument(deviceId != null, DEVICE_ID_NULL);
Madan Jampani84b6b402015-02-25 17:49:54 -0800288
Madan Jampani620f70d2016-01-30 22:22:47 -0800289 String leadershipTopic = createDeviceMastershipTopic(deviceId);
290 if (!leadershipService.getCandidates(leadershipTopic).contains(localNodeId)) {
Madan Jampanibbed40422015-05-20 12:00:38 -0700291 return CompletableFuture.completedFuture(null);
Madan Jampani84b6b402015-02-25 17:49:54 -0800292 }
Madan Jampani620f70d2016-01-30 22:22:47 -0800293 MastershipEvent.Type eventType = localNodeId.equals(leadershipService.getLeader(leadershipTopic)) ?
294 MastershipEvent.Type.MASTER_CHANGED : MastershipEvent.Type.BACKUPS_CHANGED;
295 leadershipService.withdraw(leadershipTopic);
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700296 return CompletableFuture.completedFuture(new MastershipEvent(eventType, deviceId, getMastership(deviceId)));
Madan Jampani1af8e132015-04-30 16:41:18 -0700297 }
298
Madan Jampani84b6b402015-02-25 17:49:54 -0800299 @Override
300 public void relinquishAllRole(NodeId nodeId) {
Madan Jampani620f70d2016-01-30 22:22:47 -0800301 // Noop. LeadershipService already takes care of detecting and purging stale locks.
Madan Jampani84b6b402015-02-25 17:49:54 -0800302 }
303
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700304 private MastershipInfo buildMastershipFromLeadership(Leadership leadership) {
305 ImmutableMap.Builder<NodeId, MastershipRole> builder = ImmutableMap.builder();
306 if (leadership.leaderNodeId() != null) {
307 builder.put(leadership.leaderNodeId(), MastershipRole.MASTER);
308 }
309 leadership.candidates().stream()
310 .filter(nodeId -> !Objects.equals(leadership.leaderNodeId(), nodeId))
311 .forEach(nodeId -> builder.put(nodeId, MastershipRole.STANDBY));
312 clusterService.getNodes().stream()
313 .filter(node -> !Objects.equals(leadership.leaderNodeId(), node.id()))
314 .filter(node -> !leadership.candidates().contains(node.id()))
315 .forEach(node -> builder.put(node.id(), MastershipRole.NONE));
316
317 return new MastershipInfo(
318 leadership.leader() != null ? leadership.leader().term() : 0,
319 leadership.leader() != null
320 ? Optional.of(leadership.leader().nodeId())
321 : Optional.empty(),
322 builder.build());
323 }
324
Madan Jampani84b6b402015-02-25 17:49:54 -0800325 private class InternalDeviceMastershipEventListener implements LeadershipEventListener {
Madan Jampani620f70d2016-01-30 22:22:47 -0800326
327 @Override
328 public boolean isRelevant(LeadershipEvent event) {
329 Leadership leadership = event.subject();
330 return isDeviceMastershipTopic(leadership.topic());
331 }
332
Madan Jampani84b6b402015-02-25 17:49:54 -0800333 @Override
334 public void event(LeadershipEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700335 eventHandler.execute(() -> handleEvent(event));
336 }
337
338 private void handleEvent(LeadershipEvent event) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800339 Leadership leadership = event.subject();
Madan Jampani84b6b402015-02-25 17:49:54 -0800340 DeviceId deviceId = extractDeviceIdFromTopic(leadership.topic());
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700341 MastershipInfo mastershipInfo = event.type() != LeadershipEvent.Type.SERVICE_DISRUPTED
342 ? buildMastershipFromLeadership(event.subject())
343 : new MastershipInfo();
344
Thomas Vachuska4b839c72015-05-18 15:43:03 -0700345 switch (event.type()) {
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800346 case LEADER_AND_CANDIDATES_CHANGED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700347 notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, mastershipInfo));
348 notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800349 break;
350 case LEADER_CHANGED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700351 notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800352 break;
353 case CANDIDATES_CHANGED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700354 notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800355 break;
356 case SERVICE_DISRUPTED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700357 notifyDelegate(new MastershipEvent(SUSPENDED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800358 break;
359 case SERVICE_RESTORED:
Andrea Campanella80b296d2018-09-18 10:48:15 +0200360 notifyDelegate(new MastershipEvent(RESTORED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800361 break;
362 default:
363 return;
Madan Jampani84b6b402015-02-25 17:49:54 -0800364 }
365 }
366 }
367
368 private String createDeviceMastershipTopic(DeviceId deviceId) {
Madan Jampani5756c352015-04-29 00:23:58 -0700369 return String.format("device:%s", deviceId.toString());
Madan Jampani84b6b402015-02-25 17:49:54 -0800370 }
371
372 private DeviceId extractDeviceIdFromTopic(String topic) {
373 Matcher m = DEVICE_MASTERSHIP_TOPIC_PATTERN.matcher(topic);
374 if (m.matches()) {
375 return DeviceId.deviceId(m.group(1));
376 } else {
377 throw new IllegalArgumentException("Invalid device mastership topic: " + topic);
378 }
379 }
380
381 private boolean isDeviceMastershipTopic(String topic) {
382 Matcher m = DEVICE_MASTERSHIP_TOPIC_PATTERN.matcher(topic);
383 return m.matches();
384 }
Madan Jampanidbe8a812016-01-31 21:10:46 -0800385}