blob: 826665dafc879b87dd4a0de3718a360de3dfd736 [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;
Jon Hall7a8bfc62016-05-26 17:59:04 -070021import static org.onosproject.mastership.MastershipEvent.Type.SUSPENDED;
Madan Jampani84b6b402015-02-25 17:49:54 -080022import static org.slf4j.LoggerFactory.getLogger;
23import static com.google.common.base.Preconditions.checkArgument;
24
Madan Jampani84b6b402015-02-25 17:49:54 -080025import java.util.List;
Jordan Halterman0a2bd452018-06-13 17:24:58 -070026import java.util.Objects;
27import java.util.Optional;
Madan Jampani84b6b402015-02-25 17:49:54 -080028import java.util.Set;
Madan Jampanif7536ab2015-05-07 23:23:23 -070029import java.util.concurrent.CompletableFuture;
Madan Jampani84b6b402015-02-25 17:49:54 -080030import java.util.concurrent.ExecutorService;
31import java.util.concurrent.Executors;
Madan Jampanif7536ab2015-05-07 23:23:23 -070032import java.util.concurrent.ScheduledExecutorService;
33import java.util.concurrent.TimeUnit;
Madan Jampani84b6b402015-02-25 17:49:54 -080034import java.util.regex.Matcher;
35import java.util.regex.Pattern;
36import java.util.stream.Collectors;
37
Jordan Halterman0a2bd452018-06-13 17:24:58 -070038import com.google.common.collect.ImmutableMap;
Madan Jampani84b6b402015-02-25 17:49:54 -080039import org.apache.felix.scr.annotations.Activate;
40import org.apache.felix.scr.annotations.Component;
41import org.apache.felix.scr.annotations.Deactivate;
42import org.apache.felix.scr.annotations.Reference;
43import org.apache.felix.scr.annotations.ReferenceCardinality;
44import org.apache.felix.scr.annotations.Service;
45import org.onlab.util.KryoNamespace;
46import org.onosproject.cluster.ClusterService;
47import org.onosproject.cluster.Leadership;
Madan Jampani620f70d2016-01-30 22:22:47 -080048import org.onosproject.cluster.LeadershipAdminService;
Madan Jampani84b6b402015-02-25 17:49:54 -080049import org.onosproject.cluster.LeadershipEvent;
50import org.onosproject.cluster.LeadershipEventListener;
51import org.onosproject.cluster.LeadershipService;
52import org.onosproject.cluster.NodeId;
53import org.onosproject.cluster.RoleInfo;
54import org.onosproject.mastership.MastershipEvent;
Jordan Halterman0a2bd452018-06-13 17:24:58 -070055import org.onosproject.mastership.MastershipInfo;
Madan Jampani84b6b402015-02-25 17:49:54 -080056import org.onosproject.mastership.MastershipStore;
57import org.onosproject.mastership.MastershipStoreDelegate;
58import org.onosproject.mastership.MastershipTerm;
59import org.onosproject.net.DeviceId;
60import org.onosproject.net.MastershipRole;
61import org.onosproject.store.AbstractStore;
62import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
Madan Jampani84b6b402015-02-25 17:49:54 -080063import org.onosproject.store.cluster.messaging.MessageSubject;
64import org.onosproject.store.serializers.KryoNamespaces;
Jordan Halterman2c83a102017-08-20 17:11:41 -070065import org.onosproject.store.service.Serializer;
Madan Jampani84b6b402015-02-25 17:49:54 -080066import org.slf4j.Logger;
67
Madan Jampani620f70d2016-01-30 22:22:47 -080068import com.google.common.collect.ImmutableList;
Madan Jampani84b6b402015-02-25 17:49:54 -080069
70/**
71 * Implementation of the MastershipStore on top of Leadership Service.
72 */
Sho SHIMIZU5c396e32016-08-12 15:19:12 -070073@Component(immediate = true)
Madan Jampani84b6b402015-02-25 17:49:54 -080074@Service
75public class ConsistentDeviceMastershipStore
76 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
77 implements MastershipStore {
78
79 private final Logger log = getLogger(getClass());
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected LeadershipService leadershipService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Madan Jampani620f70d2016-01-30 22:22:47 -080085 protected LeadershipAdminService leadershipAdminService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Madan Jampani84b6b402015-02-25 17:49:54 -080088 protected ClusterService clusterService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected ClusterCommunicationService clusterCommunicator;
92
93 private NodeId localNodeId;
Madan Jampani84b6b402015-02-25 17:49:54 -080094
Madan Jampani84b6b402015-02-25 17:49:54 -080095 private static final MessageSubject ROLE_RELINQUISH_SUBJECT =
96 new MessageSubject("mastership-store-device-role-relinquish");
97
98 private static final Pattern DEVICE_MASTERSHIP_TOPIC_PATTERN =
Madan Jampani5756c352015-04-29 00:23:58 -070099 Pattern.compile("device:(.*)");
Madan Jampani84b6b402015-02-25 17:49:54 -0800100
Madan Jampani71c32ca2016-06-22 08:23:18 -0700101 private ExecutorService eventHandler;
Madan Jampani84b6b402015-02-25 17:49:54 -0800102 private ExecutorService messageHandlingExecutor;
Madan Jampanif7536ab2015-05-07 23:23:23 -0700103 private ScheduledExecutorService transferExecutor;
Madan Jampani84b6b402015-02-25 17:49:54 -0800104 private final LeadershipEventListener leadershipEventListener =
105 new InternalDeviceMastershipEventListener();
106
107 private static final String NODE_ID_NULL = "Node ID cannot be null";
Madan Jampanif7536ab2015-05-07 23:23:23 -0700108 private static final String DEVICE_ID_NULL = "Device ID cannot be null";
109 private static final int WAIT_BEFORE_MASTERSHIP_HANDOFF_MILLIS = 3000;
Madan Jampani84b6b402015-02-25 17:49:54 -0800110
Jordan Halterman2c83a102017-08-20 17:11:41 -0700111 public static final Serializer SERIALIZER = Serializer.using(
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700112 KryoNamespace.newBuilder()
Madan Jampani84b6b402015-02-25 17:49:54 -0800113 .register(KryoNamespaces.API)
114 .register(MastershipRole.class)
115 .register(MastershipEvent.class)
Madan Jampani1af8e132015-04-30 16:41:18 -0700116 .register(MastershipEvent.Type.class)
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700117 .build("MastershipStore"));
Madan Jampani84b6b402015-02-25 17:49:54 -0800118
119 @Activate
120 public void activate() {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700121
122 eventHandler = Executors.newSingleThreadExecutor(
123 groupedThreads("onos/store/device/mastership", "event-handler", log));
124
Madan Jampani84b6b402015-02-25 17:49:54 -0800125 messageHandlingExecutor =
Madan Jampanif7536ab2015-05-07 23:23:23 -0700126 Executors.newSingleThreadExecutor(
HIGUCHI Yuta060da9a2016-03-11 19:16:35 -0800127 groupedThreads("onos/store/device/mastership", "message-handler", log));
Madan Jampanif7536ab2015-05-07 23:23:23 -0700128 transferExecutor =
129 Executors.newSingleThreadScheduledExecutor(
HIGUCHI Yuta060da9a2016-03-11 19:16:35 -0800130 groupedThreads("onos/store/device/mastership", "mastership-transfer-executor", log));
Madan Jampanibbed40422015-05-20 12:00:38 -0700131 clusterCommunicator.addSubscriber(ROLE_RELINQUISH_SUBJECT,
Madan Jampanid46e18f2015-05-04 23:19:33 -0700132 SERIALIZER::decode,
Madan Jampanif7536ab2015-05-07 23:23:23 -0700133 this::relinquishLocalRole,
Madan Jampanid46e18f2015-05-04 23:19:33 -0700134 SERIALIZER::encode,
135 messageHandlingExecutor);
Madan Jampani84b6b402015-02-25 17:49:54 -0800136 localNodeId = clusterService.getLocalNode().id();
137 leadershipService.addListener(leadershipEventListener);
138
Madan Jampaniafeebbd2015-05-19 15:26:01 -0700139 log.info("Started");
Madan Jampani84b6b402015-02-25 17:49:54 -0800140 }
141
142 @Deactivate
143 public void deactivate() {
Madan Jampani84b6b402015-02-25 17:49:54 -0800144 clusterCommunicator.removeSubscriber(ROLE_RELINQUISH_SUBJECT);
Madan Jampani71c32ca2016-06-22 08:23:18 -0700145 leadershipService.removeListener(leadershipEventListener);
Madan Jampani84b6b402015-02-25 17:49:54 -0800146 messageHandlingExecutor.shutdown();
Madan Jampanif7536ab2015-05-07 23:23:23 -0700147 transferExecutor.shutdown();
Madan Jampani71c32ca2016-06-22 08:23:18 -0700148 eventHandler.shutdown();
Madan Jampaniafeebbd2015-05-19 15:26:01 -0700149 log.info("Stopped");
Madan Jampani84b6b402015-02-25 17:49:54 -0800150 }
151
152 @Override
Madan Jampanide003d92015-05-11 17:14:20 -0700153 public CompletableFuture<MastershipRole> requestRole(DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800154 checkArgument(deviceId != null, DEVICE_ID_NULL);
155
156 String leadershipTopic = createDeviceMastershipTopic(deviceId);
Madan Jampani620f70d2016-01-30 22:22:47 -0800157 Leadership leadership = leadershipService.runForLeadership(leadershipTopic);
Jordan Halterman980a8c12017-09-22 18:01:19 -0700158 NodeId leader = leadership == null ? null : leadership.leaderNodeId();
159 List<NodeId> candidates = leadership == null ?
160 ImmutableList.of() : ImmutableList.copyOf(leadership.candidates());
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700161 MastershipRole role = Objects.equals(localNodeId, leader) ?
Jordan Halterman980a8c12017-09-22 18:01:19 -0700162 MastershipRole.MASTER : candidates.contains(localNodeId) ? MastershipRole.STANDBY : MastershipRole.NONE;
163 return CompletableFuture.completedFuture(role);
Madan Jampani84b6b402015-02-25 17:49:54 -0800164 }
165
166 @Override
167 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
168 checkArgument(nodeId != null, NODE_ID_NULL);
169 checkArgument(deviceId != null, DEVICE_ID_NULL);
170
171 String leadershipTopic = createDeviceMastershipTopic(deviceId);
Madan Jampani620f70d2016-01-30 22:22:47 -0800172 Leadership leadership = leadershipService.getLeadership(leadershipTopic);
173 NodeId leader = leadership == null ? null : leadership.leaderNodeId();
174 List<NodeId> candidates = leadership == null ?
175 ImmutableList.of() : ImmutableList.copyOf(leadership.candidates());
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700176 return Objects.equals(nodeId, leader) ?
Madan Jampani620f70d2016-01-30 22:22:47 -0800177 MastershipRole.MASTER : candidates.contains(nodeId) ? MastershipRole.STANDBY : MastershipRole.NONE;
Madan Jampani84b6b402015-02-25 17:49:54 -0800178 }
179
180 @Override
181 public NodeId getMaster(DeviceId deviceId) {
182 checkArgument(deviceId != null, DEVICE_ID_NULL);
183
Madan Jampani620f70d2016-01-30 22:22:47 -0800184 return leadershipService.getLeader(createDeviceMastershipTopic(deviceId));
Madan Jampani84b6b402015-02-25 17:49:54 -0800185 }
186
187 @Override
188 public RoleInfo getNodes(DeviceId deviceId) {
189 checkArgument(deviceId != null, DEVICE_ID_NULL);
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700190 Leadership leadership = leadershipService.getLeadership(createDeviceMastershipTopic(deviceId));
191 return new RoleInfo(leadership.leaderNodeId(), leadership.candidates());
192 }
Madan Jampani84b6b402015-02-25 17:49:54 -0800193
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700194 @Override
195 public MastershipInfo getMastership(DeviceId deviceId) {
196 checkArgument(deviceId != null, DEVICE_ID_NULL);
197 Leadership leadership = leadershipService.getLeadership(createDeviceMastershipTopic(deviceId));
198 return buildMastershipFromLeadership(leadership);
Madan Jampani84b6b402015-02-25 17:49:54 -0800199 }
200
201 @Override
202 public Set<DeviceId> getDevices(NodeId nodeId) {
203 checkArgument(nodeId != null, NODE_ID_NULL);
204
Yuta HIGUCHId9340032017-01-25 09:25:44 -0800205 // FIXME This result contains REMOVED device.
206 // MastershipService cannot listen to DeviceEvent to GC removed topic,
207 // since DeviceManager depend on it.
208 // Reference count, etc. at LeadershipService layer?
Madan Jampani84b6b402015-02-25 17:49:54 -0800209 return leadershipService
210 .ownedTopics(nodeId)
211 .stream()
212 .filter(this::isDeviceMastershipTopic)
213 .map(this::extractDeviceIdFromTopic)
214 .collect(Collectors.toSet());
215 }
216
217 @Override
Madan Jampanif7536ab2015-05-07 23:23:23 -0700218 public CompletableFuture<MastershipEvent> setMaster(NodeId nodeId, DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800219 checkArgument(nodeId != null, NODE_ID_NULL);
220 checkArgument(deviceId != null, DEVICE_ID_NULL);
221
Madan Jampani620f70d2016-01-30 22:22:47 -0800222 String leadershipTopic = createDeviceMastershipTopic(deviceId);
223 if (leadershipAdminService.promoteToTopOfCandidateList(leadershipTopic, nodeId)) {
224 transferExecutor.schedule(() -> leadershipAdminService.transferLeadership(leadershipTopic, nodeId),
225 WAIT_BEFORE_MASTERSHIP_HANDOFF_MILLIS, TimeUnit.MILLISECONDS);
Madan Jampani1af8e132015-04-30 16:41:18 -0700226 }
Madan Jampanif7536ab2015-05-07 23:23:23 -0700227 return CompletableFuture.completedFuture(null);
Madan Jampani84b6b402015-02-25 17:49:54 -0800228 }
229
230 @Override
231 public MastershipTerm getTermFor(DeviceId deviceId) {
232 checkArgument(deviceId != null, DEVICE_ID_NULL);
233
234 String leadershipTopic = createDeviceMastershipTopic(deviceId);
235 Leadership leadership = leadershipService.getLeadership(leadershipTopic);
Madan Jampanidbe8a812016-01-31 21:10:46 -0800236 return leadership != null && leadership.leaderNodeId() != null ?
237 MastershipTerm.of(leadership.leaderNodeId(), leadership.leader().term()) : null;
Madan Jampani84b6b402015-02-25 17:49:54 -0800238 }
239
240 @Override
Madan Jampanif7536ab2015-05-07 23:23:23 -0700241 public CompletableFuture<MastershipEvent> setStandby(NodeId nodeId, DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800242 checkArgument(nodeId != null, NODE_ID_NULL);
243 checkArgument(deviceId != null, DEVICE_ID_NULL);
244
Madan Jampani1af8e132015-04-30 16:41:18 -0700245 NodeId currentMaster = getMaster(deviceId);
246 if (!nodeId.equals(currentMaster)) {
Madan Jampanif7536ab2015-05-07 23:23:23 -0700247 return CompletableFuture.completedFuture(null);
Madan Jampani1af8e132015-04-30 16:41:18 -0700248 }
Madan Jampanid46e18f2015-05-04 23:19:33 -0700249
250 String leadershipTopic = createDeviceMastershipTopic(deviceId);
251 List<NodeId> candidates = leadershipService.getCandidates(leadershipTopic);
252
253 NodeId newMaster = candidates.stream()
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700254 .filter(candidate -> !Objects.equals(nodeId, candidate))
Madan Jampanid46e18f2015-05-04 23:19:33 -0700255 .findFirst()
256 .orElse(null);
257 log.info("Transitioning to role {} for {}. Next master: {}",
258 newMaster != null ? MastershipRole.STANDBY : MastershipRole.NONE, deviceId, newMaster);
259
260 if (newMaster != null) {
261 return setMaster(newMaster, deviceId);
262 }
263 return relinquishRole(nodeId, deviceId);
Madan Jampani84b6b402015-02-25 17:49:54 -0800264 }
265
266 @Override
Madan Jampanif7536ab2015-05-07 23:23:23 -0700267 public CompletableFuture<MastershipEvent> relinquishRole(NodeId nodeId, DeviceId deviceId) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800268 checkArgument(nodeId != null, NODE_ID_NULL);
269 checkArgument(deviceId != null, DEVICE_ID_NULL);
270
Madan Jampanibbed40422015-05-20 12:00:38 -0700271 if (nodeId.equals(localNodeId)) {
272 return relinquishLocalRole(deviceId);
Madan Jampani84b6b402015-02-25 17:49:54 -0800273 }
Madan Jampanibbed40422015-05-20 12:00:38 -0700274
275 log.debug("Forwarding request to relinquish "
276 + "role for device {} to {}", deviceId, nodeId);
277 return clusterCommunicator.sendAndReceive(
278 deviceId,
279 ROLE_RELINQUISH_SUBJECT,
280 SERIALIZER::encode,
281 SERIALIZER::decode,
282 nodeId);
Madan Jampanif7536ab2015-05-07 23:23:23 -0700283 }
284
Madan Jampanibbed40422015-05-20 12:00:38 -0700285 private CompletableFuture<MastershipEvent> relinquishLocalRole(DeviceId deviceId) {
Madan Jampanif7536ab2015-05-07 23:23:23 -0700286 checkArgument(deviceId != null, DEVICE_ID_NULL);
Madan Jampani84b6b402015-02-25 17:49:54 -0800287
Madan Jampani620f70d2016-01-30 22:22:47 -0800288 String leadershipTopic = createDeviceMastershipTopic(deviceId);
289 if (!leadershipService.getCandidates(leadershipTopic).contains(localNodeId)) {
Madan Jampanibbed40422015-05-20 12:00:38 -0700290 return CompletableFuture.completedFuture(null);
Madan Jampani84b6b402015-02-25 17:49:54 -0800291 }
Madan Jampani620f70d2016-01-30 22:22:47 -0800292 MastershipEvent.Type eventType = localNodeId.equals(leadershipService.getLeader(leadershipTopic)) ?
293 MastershipEvent.Type.MASTER_CHANGED : MastershipEvent.Type.BACKUPS_CHANGED;
294 leadershipService.withdraw(leadershipTopic);
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700295 return CompletableFuture.completedFuture(new MastershipEvent(eventType, deviceId, getMastership(deviceId)));
Madan Jampani1af8e132015-04-30 16:41:18 -0700296 }
297
Madan Jampani84b6b402015-02-25 17:49:54 -0800298 @Override
299 public void relinquishAllRole(NodeId nodeId) {
Madan Jampani620f70d2016-01-30 22:22:47 -0800300 // Noop. LeadershipService already takes care of detecting and purging stale locks.
Madan Jampani84b6b402015-02-25 17:49:54 -0800301 }
302
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700303 private MastershipInfo buildMastershipFromLeadership(Leadership leadership) {
304 ImmutableMap.Builder<NodeId, MastershipRole> builder = ImmutableMap.builder();
305 if (leadership.leaderNodeId() != null) {
306 builder.put(leadership.leaderNodeId(), MastershipRole.MASTER);
307 }
308 leadership.candidates().stream()
309 .filter(nodeId -> !Objects.equals(leadership.leaderNodeId(), nodeId))
310 .forEach(nodeId -> builder.put(nodeId, MastershipRole.STANDBY));
311 clusterService.getNodes().stream()
312 .filter(node -> !Objects.equals(leadership.leaderNodeId(), node.id()))
313 .filter(node -> !leadership.candidates().contains(node.id()))
314 .forEach(node -> builder.put(node.id(), MastershipRole.NONE));
315
316 return new MastershipInfo(
317 leadership.leader() != null ? leadership.leader().term() : 0,
318 leadership.leader() != null
319 ? Optional.of(leadership.leader().nodeId())
320 : Optional.empty(),
321 builder.build());
322 }
323
Madan Jampani84b6b402015-02-25 17:49:54 -0800324 private class InternalDeviceMastershipEventListener implements LeadershipEventListener {
Madan Jampani620f70d2016-01-30 22:22:47 -0800325
326 @Override
327 public boolean isRelevant(LeadershipEvent event) {
328 Leadership leadership = event.subject();
329 return isDeviceMastershipTopic(leadership.topic());
330 }
331
Madan Jampani84b6b402015-02-25 17:49:54 -0800332 @Override
333 public void event(LeadershipEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700334 eventHandler.execute(() -> handleEvent(event));
335 }
336
337 private void handleEvent(LeadershipEvent event) {
Madan Jampani84b6b402015-02-25 17:49:54 -0800338 Leadership leadership = event.subject();
Madan Jampani84b6b402015-02-25 17:49:54 -0800339 DeviceId deviceId = extractDeviceIdFromTopic(leadership.topic());
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700340 MastershipInfo mastershipInfo = event.type() != LeadershipEvent.Type.SERVICE_DISRUPTED
341 ? buildMastershipFromLeadership(event.subject())
342 : new MastershipInfo();
343
Thomas Vachuska4b839c72015-05-18 15:43:03 -0700344 switch (event.type()) {
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800345 case LEADER_AND_CANDIDATES_CHANGED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700346 notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, mastershipInfo));
347 notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800348 break;
349 case LEADER_CHANGED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700350 notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800351 break;
352 case CANDIDATES_CHANGED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700353 notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800354 break;
355 case SERVICE_DISRUPTED:
Jordan Halterman0a2bd452018-06-13 17:24:58 -0700356 notifyDelegate(new MastershipEvent(SUSPENDED, deviceId, mastershipInfo));
Jordan Haltermana1ccbc32017-12-15 17:07:52 -0800357 break;
358 case SERVICE_RESTORED:
359 // Do nothing, wait for updates from peers
360 break;
361 default:
362 return;
Madan Jampani84b6b402015-02-25 17:49:54 -0800363 }
364 }
365 }
366
367 private String createDeviceMastershipTopic(DeviceId deviceId) {
Madan Jampani5756c352015-04-29 00:23:58 -0700368 return String.format("device:%s", deviceId.toString());
Madan Jampani84b6b402015-02-25 17:49:54 -0800369 }
370
371 private DeviceId extractDeviceIdFromTopic(String topic) {
372 Matcher m = DEVICE_MASTERSHIP_TOPIC_PATTERN.matcher(topic);
373 if (m.matches()) {
374 return DeviceId.deviceId(m.group(1));
375 } else {
376 throw new IllegalArgumentException("Invalid device mastership topic: " + topic);
377 }
378 }
379
380 private boolean isDeviceMastershipTopic(String topic) {
381 Matcher m = DEVICE_MASTERSHIP_TOPIC_PATTERN.matcher(topic);
382 return m.matches();
383 }
Madan Jampanidbe8a812016-01-31 21:10:46 -0800384}