fixes in mastership reelection for single-node failure
Change-Id: Iedcab52bb156643464a97435fcc39c5db7393976
diff --git a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
index 125745b..ba3e616 100644
--- a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
+++ b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
@@ -4,6 +4,7 @@
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -14,6 +15,7 @@
import org.onlab.onos.cluster.ClusterEvent;
import org.onlab.onos.cluster.ClusterEventListener;
import org.onlab.onos.cluster.ClusterService;
+import org.onlab.onos.cluster.ControllerNode;
import org.onlab.onos.cluster.MastershipAdminService;
import org.onlab.onos.cluster.MastershipEvent;
import org.onlab.onos.cluster.MastershipListener;
@@ -164,21 +166,68 @@
//callback for reacting to cluster events
private class InternalClusterEventListener implements ClusterEventListener {
+ // A notion of a local maximum cluster size, used to tie-break.
+ // Think of a better way to do this.
+ private AtomicInteger clusterSize;
+
+ InternalClusterEventListener() {
+ clusterSize = new AtomicInteger(0);
+ }
+
@Override
public void event(ClusterEvent event) {
switch (event.type()) {
//FIXME: worry about addition when the time comes
case INSTANCE_ADDED:
case INSTANCE_ACTIVATED:
- break;
+ clusterSize.incrementAndGet();
+ log.info("instance {} added/activated", event.subject());
+ break;
case INSTANCE_REMOVED:
case INSTANCE_DEACTIVATED:
+ ControllerNode node = event.subject();
+
+ if (node.equals(clusterService.getLocalNode())) {
+ //If we are in smaller cluster, relinquish and return
+ for (DeviceId device : getDevicesOf(node.id())) {
+ if (!isInMajority()) {
+ //own DeviceManager should catch event and tell switch
+ store.relinquishRole(node.id(), device);
+ }
+ }
+ log.info("broke off from cluster, relinquished devices");
+ break;
+ }
+
+ // if we are the larger one and the removed node(s) are brain dead,
+ // force relinquish on behalf of disabled node.
+ // check network channel to do this?
+ for (DeviceId device : getDevicesOf(node.id())) {
+ //some things to check:
+ // 1. we didn't break off as well while we're at it
+ // 2. others don't pile in and try too - maybe a lock
+ if (isInMajority()) {
+ store.relinquishRole(node.id(), device);
+ }
+ }
+ clusterSize.decrementAndGet();
+ log.info("instance {} removed/deactivated", event.subject());
break;
default:
log.warn("unknown cluster event {}", event);
}
}
+ private boolean isInMajority() {
+ if (clusterService.getNodes().size() > (clusterSize.intValue() / 2)) {
+ return true;
+ }
+ //else {
+ //FIXME: break tie for equal-sized clusters, can we use hz's functions?
+ // }
+ return false;
+ }
+
}
public class InternalDelegate implements MastershipStoreDelegate {