fixes in mastership reelection for single-node failure
Change-Id: Iedcab52bb156643464a97435fcc39c5db7393976
Showing
3 changed files
with
69 additions
and
9 deletions
... | @@ -4,6 +4,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -4,6 +4,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
5 | 5 | ||
6 | import java.util.Set; | 6 | import java.util.Set; |
7 | +import java.util.concurrent.atomic.AtomicInteger; | ||
7 | 8 | ||
8 | import org.apache.felix.scr.annotations.Activate; | 9 | import org.apache.felix.scr.annotations.Activate; |
9 | import org.apache.felix.scr.annotations.Component; | 10 | import org.apache.felix.scr.annotations.Component; |
... | @@ -14,6 +15,7 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -14,6 +15,7 @@ import org.apache.felix.scr.annotations.Service; |
14 | import org.onlab.onos.cluster.ClusterEvent; | 15 | import org.onlab.onos.cluster.ClusterEvent; |
15 | import org.onlab.onos.cluster.ClusterEventListener; | 16 | import org.onlab.onos.cluster.ClusterEventListener; |
16 | import org.onlab.onos.cluster.ClusterService; | 17 | import org.onlab.onos.cluster.ClusterService; |
18 | +import org.onlab.onos.cluster.ControllerNode; | ||
17 | import org.onlab.onos.cluster.MastershipAdminService; | 19 | import org.onlab.onos.cluster.MastershipAdminService; |
18 | import org.onlab.onos.cluster.MastershipEvent; | 20 | import org.onlab.onos.cluster.MastershipEvent; |
19 | import org.onlab.onos.cluster.MastershipListener; | 21 | import org.onlab.onos.cluster.MastershipListener; |
... | @@ -164,21 +166,68 @@ implements MastershipService, MastershipAdminService { | ... | @@ -164,21 +166,68 @@ implements MastershipService, MastershipAdminService { |
164 | //callback for reacting to cluster events | 166 | //callback for reacting to cluster events |
165 | private class InternalClusterEventListener implements ClusterEventListener { | 167 | private class InternalClusterEventListener implements ClusterEventListener { |
166 | 168 | ||
169 | + // A notion of a local maximum cluster size, used to tie-break. | ||
170 | + // Think of a better way to do this. | ||
171 | + private AtomicInteger clusterSize; | ||
172 | + | ||
173 | + InternalClusterEventListener() { | ||
174 | + clusterSize = new AtomicInteger(0); | ||
175 | + } | ||
176 | + | ||
167 | @Override | 177 | @Override |
168 | public void event(ClusterEvent event) { | 178 | public void event(ClusterEvent event) { |
169 | switch (event.type()) { | 179 | switch (event.type()) { |
170 | //FIXME: worry about addition when the time comes | 180 | //FIXME: worry about addition when the time comes |
171 | case INSTANCE_ADDED: | 181 | case INSTANCE_ADDED: |
172 | case INSTANCE_ACTIVATED: | 182 | case INSTANCE_ACTIVATED: |
183 | + clusterSize.incrementAndGet(); | ||
184 | + log.info("instance {} added/activated", event.subject()); | ||
173 | break; | 185 | break; |
174 | case INSTANCE_REMOVED: | 186 | case INSTANCE_REMOVED: |
175 | case INSTANCE_DEACTIVATED: | 187 | case INSTANCE_DEACTIVATED: |
188 | + ControllerNode node = event.subject(); | ||
189 | + | ||
190 | + if (node.equals(clusterService.getLocalNode())) { | ||
191 | + //If we are in smaller cluster, relinquish and return | ||
192 | + for (DeviceId device : getDevicesOf(node.id())) { | ||
193 | + if (!isInMajority()) { | ||
194 | + //own DeviceManager should catch event and tell switch | ||
195 | + store.relinquishRole(node.id(), device); | ||
196 | + } | ||
197 | + } | ||
198 | + log.info("broke off from cluster, relinquished devices"); | ||
199 | + break; | ||
200 | + } | ||
201 | + | ||
202 | + // if we are the larger one and the removed node(s) are brain dead, | ||
203 | + // force relinquish on behalf of disabled node. | ||
204 | + // check network channel to do this? | ||
205 | + for (DeviceId device : getDevicesOf(node.id())) { | ||
206 | + //some things to check: | ||
207 | + // 1. we didn't break off as well while we're at it | ||
208 | + // 2. others don't pile in and try too - maybe a lock | ||
209 | + if (isInMajority()) { | ||
210 | + store.relinquishRole(node.id(), device); | ||
211 | + } | ||
212 | + } | ||
213 | + clusterSize.decrementAndGet(); | ||
214 | + log.info("instance {} removed/deactivated", event.subject()); | ||
176 | break; | 215 | break; |
177 | default: | 216 | default: |
178 | log.warn("unknown cluster event {}", event); | 217 | log.warn("unknown cluster event {}", event); |
179 | } | 218 | } |
180 | } | 219 | } |
181 | 220 | ||
221 | + private boolean isInMajority() { | ||
222 | + if (clusterService.getNodes().size() > (clusterSize.intValue() / 2)) { | ||
223 | + return true; | ||
224 | + } | ||
225 | + //else { | ||
226 | + //FIXME: break tie for equal-sized clusters, can we use hz's functions? | ||
227 | + // } | ||
228 | + return false; | ||
229 | + } | ||
230 | + | ||
182 | } | 231 | } |
183 | 232 | ||
184 | public class InternalDelegate implements MastershipStoreDelegate { | 233 | public class InternalDelegate implements MastershipStoreDelegate { | ... | ... |
... | @@ -26,6 +26,7 @@ import org.onlab.onos.net.DeviceId; | ... | @@ -26,6 +26,7 @@ import org.onlab.onos.net.DeviceId; |
26 | import org.onlab.onos.net.MastershipRole; | 26 | import org.onlab.onos.net.MastershipRole; |
27 | import org.onlab.onos.net.Port; | 27 | import org.onlab.onos.net.Port; |
28 | import org.onlab.onos.net.PortNumber; | 28 | import org.onlab.onos.net.PortNumber; |
29 | +import org.onlab.onos.net.device.DefaultDeviceDescription; | ||
29 | import org.onlab.onos.net.device.DeviceAdminService; | 30 | import org.onlab.onos.net.device.DeviceAdminService; |
30 | import org.onlab.onos.net.device.DeviceDescription; | 31 | import org.onlab.onos.net.device.DeviceDescription; |
31 | import org.onlab.onos.net.device.DeviceEvent; | 32 | import org.onlab.onos.net.device.DeviceEvent; |
... | @@ -257,12 +258,12 @@ public class DeviceManager | ... | @@ -257,12 +258,12 @@ public class DeviceManager |
257 | // temporarily request for Master Role and mark offline. | 258 | // temporarily request for Master Role and mark offline. |
258 | if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { | 259 | if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { |
259 | log.debug("Device {} disconnected, but I am not the master", deviceId); | 260 | log.debug("Device {} disconnected, but I am not the master", deviceId); |
260 | - //let go of any role anyways | 261 | + //let go of ability to be backup |
261 | mastershipService.relinquishMastership(deviceId); | 262 | mastershipService.relinquishMastership(deviceId); |
262 | return; | 263 | return; |
263 | } | 264 | } |
264 | DeviceEvent event = store.markOffline(deviceId); | 265 | DeviceEvent event = store.markOffline(deviceId); |
265 | - //we're no longer capable of being master or a candidate. | 266 | + //relinquish master role and ability to be backup. |
266 | mastershipService.relinquishMastership(deviceId); | 267 | mastershipService.relinquishMastership(deviceId); |
267 | 268 | ||
268 | if (event != null) { | 269 | if (event != null) { |
... | @@ -325,7 +326,6 @@ public class DeviceManager | ... | @@ -325,7 +326,6 @@ public class DeviceManager |
325 | @Override | 326 | @Override |
326 | public void event(MastershipEvent event) { | 327 | public void event(MastershipEvent event) { |
327 | final DeviceId did = event.subject(); | 328 | final DeviceId did = event.subject(); |
328 | - if (isAvailable(did)) { | ||
329 | final NodeId myNodeId = clusterService.getLocalNode().id(); | 329 | final NodeId myNodeId = clusterService.getLocalNode().id(); |
330 | 330 | ||
331 | if (myNodeId.equals(event.master())) { | 331 | if (myNodeId.equals(event.master())) { |
... | @@ -335,13 +335,22 @@ public class DeviceManager | ... | @@ -335,13 +335,22 @@ public class DeviceManager |
335 | // only set the new term if I am the master | 335 | // only set the new term if I am the master |
336 | clockProviderService.setMastershipTerm(did, term); | 336 | clockProviderService.setMastershipTerm(did, term); |
337 | } | 337 | } |
338 | - applyRole(did, MastershipRole.MASTER); | 338 | + |
339 | - } else { | 339 | + // FIXME: we should check that the device is connected on our end. |
340 | - applyRole(did, MastershipRole.STANDBY); | 340 | + // currently, this is not straight forward as the actual switch |
341 | + // implementation is hidden from the registry. | ||
342 | + if (!isAvailable(did)) { | ||
343 | + //flag the device as online. Is there a better way to do this? | ||
344 | + Device device = getDevice(did); | ||
345 | + store.createOrUpdateDevice(device.providerId(), did, | ||
346 | + new DefaultDeviceDescription( | ||
347 | + did.uri(), device.type(), device.manufacturer(), | ||
348 | + device.hwVersion(), device.swVersion(), | ||
349 | + device.serialNumber())); | ||
341 | } | 350 | } |
351 | + | ||
352 | + applyRole(did, MastershipRole.MASTER); | ||
342 | } else { | 353 | } else { |
343 | - //device dead to node, give up | ||
344 | - mastershipService.relinquishMastership(did); | ||
345 | applyRole(did, MastershipRole.STANDBY); | 354 | applyRole(did, MastershipRole.STANDBY); |
346 | } | 355 | } |
347 | } | 356 | } | ... | ... |
... | @@ -18,6 +18,8 @@ import org.onlab.onos.net.DeviceId; | ... | @@ -18,6 +18,8 @@ import org.onlab.onos.net.DeviceId; |
18 | import org.onlab.onos.store.trivial.impl.SimpleMastershipStore; | 18 | import org.onlab.onos.store.trivial.impl.SimpleMastershipStore; |
19 | import org.onlab.packet.IpPrefix; | 19 | import org.onlab.packet.IpPrefix; |
20 | 20 | ||
21 | +import com.google.common.collect.Sets; | ||
22 | + | ||
21 | import static org.junit.Assert.assertEquals; | 23 | import static org.junit.Assert.assertEquals; |
22 | import static org.junit.Assert.assertNull; | 24 | import static org.junit.Assert.assertNull; |
23 | import static org.onlab.onos.net.MastershipRole.*; | 25 | import static org.onlab.onos.net.MastershipRole.*; |
... | @@ -143,7 +145,7 @@ public class MastershipManagerTest { | ... | @@ -143,7 +145,7 @@ public class MastershipManagerTest { |
143 | 145 | ||
144 | @Override | 146 | @Override |
145 | public Set<ControllerNode> getNodes() { | 147 | public Set<ControllerNode> getNodes() { |
146 | - return null; | 148 | + return Sets.newHashSet(); |
147 | } | 149 | } |
148 | 150 | ||
149 | @Override | 151 | @Override | ... | ... |
-
Please register or login to post a comment