Ayaka Koshibe
Committed by Gerrit Code Review

DistributedLeadershipManager tracks topic election candidates in addition to

leaders. Includes update to leaders CLI command to list candidates.

part of: Device Mastership store on top of LeadershipService
Reference: ONOS-76

Conflicts:
	core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DistributedLeadershipManager.java

Change-Id: I587bb9e9ad16a9c8392969dde45001181053e5e6
...@@ -17,12 +17,15 @@ package org.onosproject.cli.net; ...@@ -17,12 +17,15 @@ package org.onosproject.cli.net;
17 17
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 21
21 import org.apache.karaf.shell.commands.Command; 22 import org.apache.karaf.shell.commands.Command;
23 +import org.apache.karaf.shell.commands.Option;
22 import org.onlab.util.Tools; 24 import org.onlab.util.Tools;
23 import org.onosproject.cli.AbstractShellCommand; 25 import org.onosproject.cli.AbstractShellCommand;
24 import org.onosproject.cluster.Leadership; 26 import org.onosproject.cluster.Leadership;
25 import org.onosproject.cluster.LeadershipService; 27 import org.onosproject.cluster.LeadershipService;
28 +import org.onosproject.cluster.NodeId;
26 29
27 import com.fasterxml.jackson.databind.JsonNode; 30 import com.fasterxml.jackson.databind.JsonNode;
28 import com.fasterxml.jackson.databind.ObjectMapper; 31 import com.fasterxml.jackson.databind.ObjectMapper;
...@@ -36,6 +39,12 @@ import com.fasterxml.jackson.databind.node.ArrayNode; ...@@ -36,6 +39,12 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
36 public class LeaderCommand extends AbstractShellCommand { 39 public class LeaderCommand extends AbstractShellCommand {
37 40
38 private static final String FMT = "%-20s | %-15s | %-6s | %-10s |"; 41 private static final String FMT = "%-20s | %-15s | %-6s | %-10s |";
42 + private static final String FMT_C = "%-20s | %-15s | %-19s |";
43 +
44 + @Option(name = "-c", aliases = "--candidates",
45 + description = "List candidate Nodes for each topic's leadership race",
46 + required = false, multiValued = false)
47 + private boolean showCandidates = false;
39 48
40 /** 49 /**
41 * Compares leaders, sorting by toString() output. 50 * Compares leaders, sorting by toString() output.
...@@ -75,6 +84,28 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -75,6 +84,28 @@ public class LeaderCommand extends AbstractShellCommand {
75 print("--------------------------------------------------------------"); 84 print("--------------------------------------------------------------");
76 } 85 }
77 86
87 + private void displayCandidates(Map<String, Leadership> leaderBoard,
88 + Map<String, List<NodeId>> candidates) {
89 + print("--------------------------------------------------------------");
90 + print(FMT_C, "Topic", "Leader", "Candidates");
91 + print("--------------------------------------------------------------");
92 + leaderBoard
93 + .values()
94 + .stream()
95 + .sorted(leadershipComparator)
96 + .forEach(l -> {
97 + List<NodeId> list = candidates.get(l.topic());
98 + print(FMT_C,
99 + l.topic(),
100 + l.leader(),
101 + list.remove(0).toString());
102 + // formatting hacks to get it into a table
103 + list.forEach(n -> print(FMT_C, " ", " ", n));
104 + print(FMT_C, " ", " ", " ");
105 + });
106 + print("--------------------------------------------------------------");
107 + }
108 +
78 /** 109 /**
79 * Returns JSON node representing the leaders. 110 * Returns JSON node representing the leaders.
80 * 111 *
...@@ -91,6 +122,7 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -91,6 +122,7 @@ public class LeaderCommand extends AbstractShellCommand {
91 mapper.createObjectNode() 122 mapper.createObjectNode()
92 .put("topic", l.topic()) 123 .put("topic", l.topic())
93 .put("leader", l.leader().toString()) 124 .put("leader", l.leader().toString())
125 + .put("candidates", l.candidates().toString())
94 .put("epoch", l.epoch()) 126 .put("epoch", l.epoch())
95 .put("electedTime", Tools.timeAgo(l.electedTime())))); 127 .put("electedTime", Tools.timeAgo(l.electedTime()))));
96 128
...@@ -106,7 +138,12 @@ public class LeaderCommand extends AbstractShellCommand { ...@@ -106,7 +138,12 @@ public class LeaderCommand extends AbstractShellCommand {
106 if (outputJson()) { 138 if (outputJson()) {
107 print("%s", json(leaderBoard)); 139 print("%s", json(leaderBoard));
108 } else { 140 } else {
141 + if (showCandidates) {
142 + Map<String, List<NodeId>> candidates = leaderService.getCandidates();
143 + displayCandidates(leaderBoard, candidates);
144 + } else {
109 displayLeaders(leaderBoard); 145 displayLeaders(leaderBoard);
110 } 146 }
111 } 147 }
148 + }
112 } 149 }
......
...@@ -49,11 +49,10 @@ public class LeadershipEvent extends AbstractEvent<LeadershipEvent.Type, Leaders ...@@ -49,11 +49,10 @@ public class LeadershipEvent extends AbstractEvent<LeadershipEvent.Type, Leaders
49 LEADER_BOOTED, 49 LEADER_BOOTED,
50 50
51 /** 51 /**
52 - * Signifies that the list of candidates for leadership for a resource 52 + * Signifies that the list of candidates for leadership for a topic has
53 - * has changed. If the change in the backups list is accompanied by a 53 + * changed.
54 - * change in the leader, the event is subsumed by the leadership change.
55 */ 54 */
56 - LEADER_CANDIDATES_CHANGED 55 + CANDIDATES_CHANGED
57 } 56 }
58 57
59 /** 58 /**
......
...@@ -17,6 +17,7 @@ package org.onosproject.cluster; ...@@ -17,6 +17,7 @@ package org.onosproject.cluster;
17 17
18 import java.util.Map; 18 import java.util.Map;
19 import java.util.Set; 19 import java.util.Set;
20 +import java.util.List;
20 21
21 /** 22 /**
22 * Service for leader election. 23 * Service for leader election.
...@@ -67,6 +68,19 @@ public interface LeadershipService { ...@@ -67,6 +68,19 @@ public interface LeadershipService {
67 Map<String, Leadership> getLeaderBoard(); 68 Map<String, Leadership> getLeaderBoard();
68 69
69 /** 70 /**
71 + * Returns the candidates for all known topics.
72 + * @return A map of topics to lists of NodeIds.
73 + */
74 + Map<String, List<NodeId>> getCandidates();
75 +
76 + /**
77 + * Returns the candidates for a given topic.
78 + * @param path topic
79 + * @return A lists of NodeIds, which may be empty.
80 + */
81 + List<NodeId> getCandidates(String path);
82 +
83 + /**
70 * Registers a event listener to be notified of leadership events. 84 * Registers a event listener to be notified of leadership events.
71 * @param listener listener that will asynchronously notified of leadership events. 85 * @param listener listener that will asynchronously notified of leadership events.
72 */ 86 */
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 package org.onosproject.cluster; 16 package org.onosproject.cluster;
17 17
18 +import java.util.List;
18 import java.util.Map; 19 import java.util.Map;
19 import java.util.Set; 20 import java.util.Set;
20 21
...@@ -62,4 +63,14 @@ public class LeadershipServiceAdapter implements LeadershipService { ...@@ -62,4 +63,14 @@ public class LeadershipServiceAdapter implements LeadershipService {
62 public void removeListener(LeadershipEventListener listener) { 63 public void removeListener(LeadershipEventListener listener) {
63 64
64 } 65 }
66 +
67 + @Override
68 + public Map<String, List<NodeId>> getCandidates() {
69 + return null;
70 + }
71 +
72 + @Override
73 + public List<NodeId> getCandidates(String path) {
74 + return null;
75 + }
65 } 76 }
......
...@@ -46,6 +46,7 @@ import org.slf4j.Logger; ...@@ -46,6 +46,7 @@ import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory; 46 import org.slf4j.LoggerFactory;
47 47
48 import java.util.HashMap; 48 import java.util.HashMap;
49 +import java.util.List;
49 import java.util.Map; 50 import java.util.Map;
50 import java.util.Set; 51 import java.util.Set;
51 import java.util.concurrent.ExecutorService; 52 import java.util.concurrent.ExecutorService;
...@@ -573,4 +574,14 @@ public class HazelcastLeadershipService implements LeadershipService { ...@@ -573,4 +574,14 @@ public class HazelcastLeadershipService implements LeadershipService {
573 eventDispatcher.post(leadershipEvent); 574 eventDispatcher.post(leadershipEvent);
574 } 575 }
575 } 576 }
577 +
578 + @Override
579 + public Map<String, List<NodeId>> getCandidates() {
580 + return null;
581 + }
582 +
583 + @Override
584 + public List<NodeId> getCandidates(String path) {
585 + return null;
586 + }
576 } 587 }
......
...@@ -17,6 +17,7 @@ package org.onosproject.store.trivial.impl; ...@@ -17,6 +17,7 @@ package org.onosproject.store.trivial.impl;
17 17
18 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkArgument;
19 19
20 +import java.util.List;
20 import java.util.Map; 21 import java.util.Map;
21 import java.util.Map.Entry; 22 import java.util.Map.Entry;
22 import java.util.Set; 23 import java.util.Set;
...@@ -108,4 +109,14 @@ public class SimpleLeadershipManager implements LeadershipService { ...@@ -108,4 +109,14 @@ public class SimpleLeadershipManager implements LeadershipService {
108 public void removeListener(LeadershipEventListener listener) { 109 public void removeListener(LeadershipEventListener listener) {
109 listeners.remove(listener); 110 listeners.remove(listener);
110 } 111 }
112 +
113 + @Override
114 + public Map<String, List<NodeId>> getCandidates() {
115 + return null;
116 + }
117 +
118 + @Override
119 + public List<NodeId> getCandidates(String path) {
120 + return null;
121 + }
111 } 122 }
......