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;
import java.util.Comparator;
import java.util.Map;
import java.util.List;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onlab.util.Tools;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cluster.Leadership;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -36,6 +39,12 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
public class LeaderCommand extends AbstractShellCommand {
private static final String FMT = "%-20s | %-15s | %-6s | %-10s |";
private static final String FMT_C = "%-20s | %-15s | %-19s |";
@Option(name = "-c", aliases = "--candidates",
description = "List candidate Nodes for each topic's leadership race",
required = false, multiValued = false)
private boolean showCandidates = false;
/**
* Compares leaders, sorting by toString() output.
......@@ -75,6 +84,28 @@ public class LeaderCommand extends AbstractShellCommand {
print("--------------------------------------------------------------");
}
private void displayCandidates(Map<String, Leadership> leaderBoard,
Map<String, List<NodeId>> candidates) {
print("--------------------------------------------------------------");
print(FMT_C, "Topic", "Leader", "Candidates");
print("--------------------------------------------------------------");
leaderBoard
.values()
.stream()
.sorted(leadershipComparator)
.forEach(l -> {
List<NodeId> list = candidates.get(l.topic());
print(FMT_C,
l.topic(),
l.leader(),
list.remove(0).toString());
// formatting hacks to get it into a table
list.forEach(n -> print(FMT_C, " ", " ", n));
print(FMT_C, " ", " ", " ");
});
print("--------------------------------------------------------------");
}
/**
* Returns JSON node representing the leaders.
*
......@@ -91,6 +122,7 @@ public class LeaderCommand extends AbstractShellCommand {
mapper.createObjectNode()
.put("topic", l.topic())
.put("leader", l.leader().toString())
.put("candidates", l.candidates().toString())
.put("epoch", l.epoch())
.put("electedTime", Tools.timeAgo(l.electedTime()))));
......@@ -106,7 +138,12 @@ public class LeaderCommand extends AbstractShellCommand {
if (outputJson()) {
print("%s", json(leaderBoard));
} else {
displayLeaders(leaderBoard);
if (showCandidates) {
Map<String, List<NodeId>> candidates = leaderService.getCandidates();
displayCandidates(leaderBoard, candidates);
} else {
displayLeaders(leaderBoard);
}
}
}
}
......
......@@ -49,11 +49,10 @@ public class LeadershipEvent extends AbstractEvent<LeadershipEvent.Type, Leaders
LEADER_BOOTED,
/**
* Signifies that the list of candidates for leadership for a resource
* has changed. If the change in the backups list is accompanied by a
* change in the leader, the event is subsumed by the leadership change.
* Signifies that the list of candidates for leadership for a topic has
* changed.
*/
LEADER_CANDIDATES_CHANGED
CANDIDATES_CHANGED
}
/**
......
......@@ -17,6 +17,7 @@ package org.onosproject.cluster;
import java.util.Map;
import java.util.Set;
import java.util.List;
/**
* Service for leader election.
......@@ -67,6 +68,19 @@ public interface LeadershipService {
Map<String, Leadership> getLeaderBoard();
/**
* Returns the candidates for all known topics.
* @return A map of topics to lists of NodeIds.
*/
Map<String, List<NodeId>> getCandidates();
/**
* Returns the candidates for a given topic.
* @param path topic
* @return A lists of NodeIds, which may be empty.
*/
List<NodeId> getCandidates(String path);
/**
* Registers a event listener to be notified of leadership events.
* @param listener listener that will asynchronously notified of leadership events.
*/
......
......@@ -15,6 +15,7 @@
*/
package org.onosproject.cluster;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -62,4 +63,14 @@ public class LeadershipServiceAdapter implements LeadershipService {
public void removeListener(LeadershipEventListener listener) {
}
@Override
public Map<String, List<NodeId>> getCandidates() {
return null;
}
@Override
public List<NodeId> getCandidates(String path) {
return null;
}
}
......
......@@ -46,6 +46,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
......@@ -573,4 +574,14 @@ public class HazelcastLeadershipService implements LeadershipService {
eventDispatcher.post(leadershipEvent);
}
}
@Override
public Map<String, List<NodeId>> getCandidates() {
return null;
}
@Override
public List<NodeId> getCandidates(String path) {
return null;
}
}
......
......@@ -17,6 +17,7 @@ package org.onosproject.store.trivial.impl;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
......@@ -108,4 +109,14 @@ public class SimpleLeadershipManager implements LeadershipService {
public void removeListener(LeadershipEventListener listener) {
listeners.remove(listener);
}
@Override
public Map<String, List<NodeId>> getCandidates() {
return null;
}
@Override
public List<NodeId> getCandidates(String path) {
return null;
}
}
......