Ayaka Koshibe
Committed by Yuta HIGUCHI

ConsistentDeviceMastership on top of LeadershipService, and leaders CLI command

modified to filter on topic. This does not support changing candidate ordering
(yet).

Refernce: ONOS-76

Change-Id: I028a6df0acbe3c4e4ff7c228f687f640e48e13be
...@@ -18,7 +18,9 @@ package org.onosproject.cli.net; ...@@ -18,7 +18,9 @@ package org.onosproject.cli.net;
18 import java.util.Comparator; 18 import java.util.Comparator;
19 import java.util.Map; 19 import java.util.Map;
20 import java.util.List; 20 import java.util.List;
21 +import java.util.regex.Pattern;
21 22
23 +import org.apache.karaf.shell.commands.Argument;
22 import org.apache.karaf.shell.commands.Command; 24 import org.apache.karaf.shell.commands.Command;
23 import org.apache.karaf.shell.commands.Option; 25 import org.apache.karaf.shell.commands.Option;
24 import org.onlab.util.Tools; 26 import org.onlab.util.Tools;
...@@ -40,6 +42,12 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -40,6 +42,12 @@ public class LeaderCommand extends AbstractShellCommand {
40 42
41 private static final String FMT = "%-20s | %-15s | %-6s | %-10s |"; 43 private static final String FMT = "%-20s | %-15s | %-6s | %-10s |";
42 private static final String FMT_C = "%-20s | %-15s | %-19s |"; 44 private static final String FMT_C = "%-20s | %-15s | %-19s |";
45 + private boolean allTopics;
46 + private Pattern pattern;
47 +
48 + @Argument(index = 0, name = "topic", description = "A leadership topic. Can be a regex",
49 + required = false, multiValued = false)
50 + String topicPattern = null;
43 51
44 @Option(name = "-c", aliases = "--candidates", 52 @Option(name = "-c", aliases = "--candidates",
45 description = "List candidate Nodes for each topic's leadership race", 53 description = "List candidate Nodes for each topic's leadership race",
...@@ -75,6 +83,7 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -75,6 +83,7 @@ public class LeaderCommand extends AbstractShellCommand {
75 83
76 leaderBoard.values() 84 leaderBoard.values()
77 .stream() 85 .stream()
86 + .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
78 .sorted(leadershipComparator) 87 .sorted(leadershipComparator)
79 .forEach(l -> print(FMT, 88 .forEach(l -> print(FMT,
80 l.topic(), 89 l.topic(),
...@@ -92,6 +101,7 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -92,6 +101,7 @@ public class LeaderCommand extends AbstractShellCommand {
92 leaderBoard 101 leaderBoard
93 .values() 102 .values()
94 .stream() 103 .stream()
104 + .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
95 .sorted(leadershipComparator) 105 .sorted(leadershipComparator)
96 .forEach(l -> { 106 .forEach(l -> {
97 List<NodeId> list = candidates.get(l.topic()).candidates(); 107 List<NodeId> list = candidates.get(l.topic()).candidates();
...@@ -135,6 +145,13 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -135,6 +145,13 @@ public class LeaderCommand extends AbstractShellCommand {
135 LeadershipService leaderService = get(LeadershipService.class); 145 LeadershipService leaderService = get(LeadershipService.class);
136 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard(); 146 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
137 147
148 + if (topicPattern == null) {
149 + allTopics = true;
150 + } else {
151 + allTopics = false;
152 + pattern = Pattern.compile(topicPattern);
153 + }
154 +
138 if (outputJson()) { 155 if (outputJson()) {
139 print("%s", json(leaderBoard)); 156 print("%s", json(leaderBoard));
140 } else { 157 } else {
......
...@@ -362,8 +362,8 @@ public class DistributedLeadershipManager implements LeadershipService { ...@@ -362,8 +362,8 @@ public class DistributedLeadershipManager implements LeadershipService {
362 Leadership newInfo = new Leadership(path, candidates, epoch, electedTime); 362 Leadership newInfo = new Leadership(path, candidates, epoch, electedTime);
363 final MutableBoolean updated = new MutableBoolean(false); 363 final MutableBoolean updated = new MutableBoolean(false);
364 candidateBoard.compute(path, (k, current) -> { 364 candidateBoard.compute(path, (k, current) -> {
365 - if (current != null && current.epoch() == newInfo.epoch()) { 365 + if (current != null && current.epoch() <= newInfo.epoch()) {
366 - log.info("updating candidateboard with {}", newInfo); 366 + log.info("updating candidateboard with removal of {}", newInfo);
367 updated.setTrue(); 367 updated.setTrue();
368 if (candidates.isEmpty()) { 368 if (candidates.isEmpty()) {
369 return null; 369 return null;
...@@ -452,7 +452,7 @@ public class DistributedLeadershipManager implements LeadershipService { ...@@ -452,7 +452,7 @@ public class DistributedLeadershipManager implements LeadershipService {
452 }); 452 });
453 } else if (eventType.equals(LeadershipEvent.Type.LEADER_BOOTED)) { 453 } else if (eventType.equals(LeadershipEvent.Type.LEADER_BOOTED)) {
454 leaderBoard.compute(topic, (k, currentLeadership) -> { 454 leaderBoard.compute(topic, (k, currentLeadership) -> {
455 - if (currentLeadership == null || currentLeadership.epoch() < leadershipUpdate.epoch()) { 455 + if (currentLeadership == null || currentLeadership.epoch() == leadershipUpdate.epoch()) {
456 updateAccepted.setTrue(); 456 updateAccepted.setTrue();
457 return null; 457 return null;
458 } 458 }
...@@ -462,6 +462,9 @@ public class DistributedLeadershipManager implements LeadershipService { ...@@ -462,6 +462,9 @@ public class DistributedLeadershipManager implements LeadershipService {
462 candidateBoard.compute(topic, (k, currentInfo) -> { 462 candidateBoard.compute(topic, (k, currentInfo) -> {
463 if (currentInfo == null || currentInfo.epoch() <= leadershipUpdate.epoch()) { 463 if (currentInfo == null || currentInfo.epoch() <= leadershipUpdate.epoch()) {
464 updateAccepted.setTrue(); 464 updateAccepted.setTrue();
465 + if (leadershipUpdate.candidates().isEmpty()) {
466 + return null;
467 + }
465 return leadershipUpdate; 468 return leadershipUpdate;
466 } 469 }
467 return currentInfo; 470 return currentInfo;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.store.mastership.impl; 16 package org.onosproject.store.mastership.impl;
17 17
18 import static org.onlab.util.Tools.groupedThreads; 18 import static org.onlab.util.Tools.groupedThreads;
19 +import static org.onlab.util.Tools.futureGetOrElse;
19 import static org.onosproject.mastership.MastershipEvent.Type.BACKUPS_CHANGED; 20 import static org.onosproject.mastership.MastershipEvent.Type.BACKUPS_CHANGED;
20 import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED; 21 import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED;
21 import static org.slf4j.LoggerFactory.getLogger; 22 import static org.slf4j.LoggerFactory.getLogger;
...@@ -25,12 +26,8 @@ import java.io.IOException; ...@@ -25,12 +26,8 @@ import java.io.IOException;
25 import java.util.List; 26 import java.util.List;
26 import java.util.Map; 27 import java.util.Map;
27 import java.util.Set; 28 import java.util.Set;
28 -import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.ExecutorService; 29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors; 30 import java.util.concurrent.Executors;
31 -import java.util.concurrent.Future;
32 -import java.util.concurrent.TimeUnit;
33 -import java.util.concurrent.TimeoutException;
34 import java.util.regex.Matcher; 31 import java.util.regex.Matcher;
35 import java.util.regex.Pattern; 32 import java.util.regex.Pattern;
36 import java.util.stream.Collectors; 33 import java.util.stream.Collectors;
...@@ -182,12 +179,12 @@ public class ConsistentDeviceMastershipStore ...@@ -182,12 +179,12 @@ public class ConsistentDeviceMastershipStore
182 return MastershipRole.NONE; 179 return MastershipRole.NONE;
183 } 180 }
184 } 181 }
185 - MastershipRole role = complete(clusterCommunicator.sendAndReceive( 182 + MastershipRole role = futureGetOrElse(clusterCommunicator.sendAndReceive(
186 deviceId, 183 deviceId,
187 ROLE_QUERY_SUBJECT, 184 ROLE_QUERY_SUBJECT,
188 SERIALIZER::encode, 185 SERIALIZER::encode,
189 SERIALIZER::decode, 186 SERIALIZER::decode,
190 - nodeId)); 187 + nodeId), null);
191 return role == null ? MastershipRole.NONE : role; 188 return role == null ? MastershipRole.NONE : role;
192 } 189 }
193 190
...@@ -270,12 +267,12 @@ public class ConsistentDeviceMastershipStore ...@@ -270,12 +267,12 @@ public class ConsistentDeviceMastershipStore
270 if (!nodeId.equals(localNodeId)) { 267 if (!nodeId.equals(localNodeId)) {
271 log.debug("Forwarding request to relinquish " 268 log.debug("Forwarding request to relinquish "
272 + "role for device {} to {}", deviceId, nodeId); 269 + "role for device {} to {}", deviceId, nodeId);
273 - return complete(clusterCommunicator.sendAndReceive( 270 + return futureGetOrElse(clusterCommunicator.sendAndReceive(
274 deviceId, 271 deviceId,
275 ROLE_RELINQUISH_SUBJECT, 272 ROLE_RELINQUISH_SUBJECT,
276 SERIALIZER::encode, 273 SERIALIZER::encode,
277 SERIALIZER::decode, 274 SERIALIZER::decode,
278 - nodeId)); 275 + nodeId), null);
279 } 276 }
280 277
281 // Check if this node is can be managed by this node. 278 // Check if this node is can be managed by this node.
...@@ -374,16 +371,4 @@ public class ConsistentDeviceMastershipStore ...@@ -374,16 +371,4 @@ public class ConsistentDeviceMastershipStore
374 return m.matches(); 371 return m.matches();
375 } 372 }
376 373
377 - private <T> T complete(Future<byte[]> future) {
378 - try {
379 - return SERIALIZER.decode(future.get(PEER_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
380 - } catch (InterruptedException e) {
381 - Thread.currentThread().interrupt();
382 - log.error("Interrupted while waiting for operation to complete.", e);
383 - return null;
384 - } catch (TimeoutException | ExecutionException e) {
385 - log.error("Failed remote operation", e);
386 - return null;
387 - }
388 - }
389 } 374 }
...\ No newline at end of file ...\ No newline at end of file
......