fixes for mastership handoff race conditions
Change-Id: Ifed733df1bdc3b144b6a341a9322838ea2aacd72
Showing
9 changed files
with
148 additions
and
26 deletions
... | @@ -104,7 +104,6 @@ implements MastershipService, MastershipAdminService { | ... | @@ -104,7 +104,6 @@ implements MastershipService, MastershipAdminService { |
104 | MastershipEvent event = null; | 104 | MastershipEvent event = null; |
105 | event = store.relinquishRole( | 105 | event = store.relinquishRole( |
106 | clusterService.getLocalNode().id(), deviceId); | 106 | clusterService.getLocalNode().id(), deviceId); |
107 | - | ||
108 | if (event != null) { | 107 | if (event != null) { |
109 | post(event); | 108 | post(event); |
110 | } | 109 | } |
... | @@ -229,7 +228,8 @@ implements MastershipService, MastershipAdminService { | ... | @@ -229,7 +228,8 @@ implements MastershipService, MastershipAdminService { |
229 | return true; | 228 | return true; |
230 | } | 229 | } |
231 | //else { | 230 | //else { |
232 | - //FIXME: break tie for equal-sized clusters, can we use hz's functions? | 231 | + //FIXME: break tie for equal-sized clusters, |
232 | + // maybe by number of connected switches | ||
233 | // } | 233 | // } |
234 | return false; | 234 | return false; |
235 | } | 235 | } | ... | ... |
... | @@ -161,6 +161,9 @@ public class DeviceManager | ... | @@ -161,6 +161,9 @@ public class DeviceManager |
161 | @Override | 161 | @Override |
162 | public void removeDevice(DeviceId deviceId) { | 162 | public void removeDevice(DeviceId deviceId) { |
163 | checkNotNull(deviceId, DEVICE_ID_NULL); | 163 | checkNotNull(deviceId, DEVICE_ID_NULL); |
164 | + // XXX is this intended to apply to the full global topology? | ||
165 | + // if so, we probably don't want the fact that we aren't | ||
166 | + // MASTER to get in the way, as it would do now. | ||
164 | DeviceEvent event = store.removeDevice(deviceId); | 167 | DeviceEvent event = store.removeDevice(deviceId); |
165 | if (event != null) { | 168 | if (event != null) { |
166 | log.info("Device {} administratively removed", deviceId); | 169 | log.info("Device {} administratively removed", deviceId); |
... | @@ -203,19 +206,21 @@ public class DeviceManager | ... | @@ -203,19 +206,21 @@ public class DeviceManager |
203 | log.info("Device {} connected", deviceId); | 206 | log.info("Device {} connected", deviceId); |
204 | // check my Role | 207 | // check my Role |
205 | MastershipRole role = mastershipService.requestRoleFor(deviceId); | 208 | MastershipRole role = mastershipService.requestRoleFor(deviceId); |
206 | - | 209 | + log.info("## - our role for {} is {} [master is {}]", deviceId, role, |
210 | + mastershipService.getMasterFor(deviceId)); | ||
207 | if (role != MastershipRole.MASTER) { | 211 | if (role != MastershipRole.MASTER) { |
208 | // TODO: Do we need to explicitly tell the Provider that | 212 | // TODO: Do we need to explicitly tell the Provider that |
209 | // this instance is no longer the MASTER? probably not | 213 | // this instance is no longer the MASTER? probably not |
210 | return; | 214 | return; |
211 | } | 215 | } |
212 | - | ||
213 | MastershipTerm term = mastershipService.requestTermService() | 216 | MastershipTerm term = mastershipService.requestTermService() |
214 | .getMastershipTerm(deviceId); | 217 | .getMastershipTerm(deviceId); |
218 | + | ||
215 | if (!term.master().equals(clusterService.getLocalNode().id())) { | 219 | if (!term.master().equals(clusterService.getLocalNode().id())) { |
216 | // lost mastership after requestRole told this instance was MASTER. | 220 | // lost mastership after requestRole told this instance was MASTER. |
217 | return; | 221 | return; |
218 | } | 222 | } |
223 | + | ||
219 | // tell clock provider if this instance is the master | 224 | // tell clock provider if this instance is the master |
220 | deviceClockProviderService.setMastershipTerm(deviceId, term); | 225 | deviceClockProviderService.setMastershipTerm(deviceId, term); |
221 | 226 | ||
... | @@ -256,13 +261,25 @@ public class DeviceManager | ... | @@ -256,13 +261,25 @@ public class DeviceManager |
256 | // but if I was the last STANDBY connection, etc. and no one else | 261 | // but if I was the last STANDBY connection, etc. and no one else |
257 | // was there to mark the device offline, this instance may need to | 262 | // was there to mark the device offline, this instance may need to |
258 | // temporarily request for Master Role and mark offline. | 263 | // temporarily request for Master Role and mark offline. |
264 | + log.info("## for {} role is {}", deviceId, mastershipService.getLocalRole(deviceId)); | ||
259 | if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { | 265 | if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { |
260 | log.debug("Device {} disconnected, but I am not the master", deviceId); | 266 | log.debug("Device {} disconnected, but I am not the master", deviceId); |
261 | //let go of ability to be backup | 267 | //let go of ability to be backup |
262 | mastershipService.relinquishMastership(deviceId); | 268 | mastershipService.relinquishMastership(deviceId); |
263 | return; | 269 | return; |
264 | } | 270 | } |
265 | - DeviceEvent event = store.markOffline(deviceId); | 271 | + |
272 | + DeviceEvent event = null; | ||
273 | + try { | ||
274 | + event = store.markOffline(deviceId); | ||
275 | + } catch (IllegalStateException e) { | ||
276 | + //there are times when this node will correctly have mastership, BUT | ||
277 | + //that isn't reflected in the ClockManager before the device disconnects. | ||
278 | + //we want to let go of the device anyways, so make sure this happens. | ||
279 | + MastershipTerm term = termService.getMastershipTerm(deviceId); | ||
280 | + deviceClockProviderService.setMastershipTerm(deviceId, term); | ||
281 | + event = store.markOffline(deviceId); | ||
282 | + } finally { | ||
266 | //relinquish master role and ability to be backup. | 283 | //relinquish master role and ability to be backup. |
267 | mastershipService.relinquishMastership(deviceId); | 284 | mastershipService.relinquishMastership(deviceId); |
268 | 285 | ||
... | @@ -271,6 +288,7 @@ public class DeviceManager | ... | @@ -271,6 +288,7 @@ public class DeviceManager |
271 | post(event); | 288 | post(event); |
272 | } | 289 | } |
273 | } | 290 | } |
291 | + } | ||
274 | 292 | ||
275 | @Override | 293 | @Override |
276 | public void updatePorts(DeviceId deviceId, | 294 | public void updatePorts(DeviceId deviceId, |
... | @@ -279,7 +297,15 @@ public class DeviceManager | ... | @@ -279,7 +297,15 @@ public class DeviceManager |
279 | checkNotNull(portDescriptions, | 297 | checkNotNull(portDescriptions, |
280 | "Port descriptions list cannot be null"); | 298 | "Port descriptions list cannot be null"); |
281 | checkValidity(); | 299 | checkValidity(); |
300 | + //XXX what's this doing here? | ||
282 | this.provider().id(); | 301 | this.provider().id(); |
302 | + | ||
303 | + if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { | ||
304 | + // TODO If we become master, then we'll trigger something to update this | ||
305 | + // info to fix any inconsistencies that may result during the handoff. | ||
306 | + return; | ||
307 | + } | ||
308 | + | ||
283 | List<DeviceEvent> events = store.updatePorts(this.provider().id(), | 309 | List<DeviceEvent> events = store.updatePorts(this.provider().id(), |
284 | deviceId, portDescriptions); | 310 | deviceId, portDescriptions); |
285 | for (DeviceEvent event : events) { | 311 | for (DeviceEvent event : events) { |
... | @@ -293,6 +319,12 @@ public class DeviceManager | ... | @@ -293,6 +319,12 @@ public class DeviceManager |
293 | checkNotNull(deviceId, DEVICE_ID_NULL); | 319 | checkNotNull(deviceId, DEVICE_ID_NULL); |
294 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); | 320 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); |
295 | checkValidity(); | 321 | checkValidity(); |
322 | + | ||
323 | + if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { | ||
324 | + // TODO If we become master, then we'll trigger something to update this | ||
325 | + // info to fix any inconsistencies that may result during the handoff. | ||
326 | + return; | ||
327 | + } | ||
296 | DeviceEvent event = store.updatePortStatus(this.provider().id(), | 328 | DeviceEvent event = store.updatePortStatus(this.provider().id(), |
297 | deviceId, portDescription); | 329 | deviceId, portDescription); |
298 | if (event != null) { | 330 | if (event != null) { |
... | @@ -328,27 +360,37 @@ public class DeviceManager | ... | @@ -328,27 +360,37 @@ public class DeviceManager |
328 | final DeviceId did = event.subject(); | 360 | final DeviceId did = event.subject(); |
329 | final NodeId myNodeId = clusterService.getLocalNode().id(); | 361 | final NodeId myNodeId = clusterService.getLocalNode().id(); |
330 | 362 | ||
363 | + log.info("## got Mastershipevent for dev {}", did); | ||
331 | if (myNodeId.equals(event.master())) { | 364 | if (myNodeId.equals(event.master())) { |
332 | MastershipTerm term = termService.getMastershipTerm(did); | 365 | MastershipTerm term = termService.getMastershipTerm(did); |
333 | 366 | ||
334 | - if (term.master().equals(myNodeId)) { | 367 | + if (!myNodeId.equals(term.master())) { |
368 | + // something went wrong in consistency, let go | ||
369 | + mastershipService.relinquishMastership(did); | ||
370 | + applyRole(did, MastershipRole.STANDBY); | ||
371 | + return; | ||
372 | + } | ||
373 | + | ||
374 | + log.info("## setting term for CPS as new master for {}", did); | ||
335 | // only set the new term if I am the master | 375 | // only set the new term if I am the master |
336 | deviceClockProviderService.setMastershipTerm(did, term); | 376 | deviceClockProviderService.setMastershipTerm(did, term); |
337 | - } | ||
338 | 377 | ||
339 | // FIXME: we should check that the device is connected on our end. | 378 | // FIXME: we should check that the device is connected on our end. |
340 | // currently, this is not straight forward as the actual switch | 379 | // currently, this is not straight forward as the actual switch |
341 | - // implementation is hidden from the registry. | 380 | + // implementation is hidden from the registry. Maybe we can ask the |
342 | - if (!isAvailable(did)) { | 381 | + // provider. |
343 | - //flag the device as online. Is there a better way to do this? | 382 | + // if the device is null here, we are the first master to claim the |
383 | + // device. No worries, the DeviceManager will create one soon. | ||
344 | Device device = getDevice(did); | 384 | Device device = getDevice(did); |
385 | + if ((device != null) && !isAvailable(did)) { | ||
386 | + //flag the device as online. Is there a better way to do this? | ||
345 | store.createOrUpdateDevice(device.providerId(), did, | 387 | store.createOrUpdateDevice(device.providerId(), did, |
346 | new DefaultDeviceDescription( | 388 | new DefaultDeviceDescription( |
347 | did.uri(), device.type(), device.manufacturer(), | 389 | did.uri(), device.type(), device.manufacturer(), |
348 | device.hwVersion(), device.swVersion(), | 390 | device.hwVersion(), device.swVersion(), |
349 | device.serialNumber())); | 391 | device.serialNumber())); |
350 | } | 392 | } |
351 | - | 393 | + //TODO re-collect device information to fix potential staleness |
352 | applyRole(did, MastershipRole.MASTER); | 394 | applyRole(did, MastershipRole.MASTER); |
353 | } else { | 395 | } else { |
354 | applyRole(did, MastershipRole.STANDBY); | 396 | applyRole(did, MastershipRole.STANDBY); | ... | ... |
... | @@ -16,6 +16,7 @@ import org.onlab.onos.event.EventDeliveryService; | ... | @@ -16,6 +16,7 @@ import org.onlab.onos.event.EventDeliveryService; |
16 | import org.onlab.onos.net.ConnectPoint; | 16 | import org.onlab.onos.net.ConnectPoint; |
17 | import org.onlab.onos.net.DeviceId; | 17 | import org.onlab.onos.net.DeviceId; |
18 | import org.onlab.onos.net.Link; | 18 | import org.onlab.onos.net.Link; |
19 | +import org.onlab.onos.net.MastershipRole; | ||
19 | import org.onlab.onos.net.device.DeviceEvent; | 20 | import org.onlab.onos.net.device.DeviceEvent; |
20 | import org.onlab.onos.net.device.DeviceListener; | 21 | import org.onlab.onos.net.device.DeviceListener; |
21 | import org.onlab.onos.net.device.DeviceService; | 22 | import org.onlab.onos.net.device.DeviceService; |
... | @@ -139,11 +140,17 @@ public class LinkManager | ... | @@ -139,11 +140,17 @@ public class LinkManager |
139 | 140 | ||
140 | @Override | 141 | @Override |
141 | public void removeLinks(ConnectPoint connectPoint) { | 142 | public void removeLinks(ConnectPoint connectPoint) { |
143 | + if (deviceService.getRole(connectPoint.deviceId()) != MastershipRole.MASTER) { | ||
144 | + return; | ||
145 | + } | ||
142 | removeLinks(getLinks(connectPoint)); | 146 | removeLinks(getLinks(connectPoint)); |
143 | } | 147 | } |
144 | 148 | ||
145 | @Override | 149 | @Override |
146 | public void removeLinks(DeviceId deviceId) { | 150 | public void removeLinks(DeviceId deviceId) { |
151 | + if (deviceService.getRole(deviceId) != MastershipRole.MASTER) { | ||
152 | + return; | ||
153 | + } | ||
147 | removeLinks(getDeviceLinks(deviceId)); | 154 | removeLinks(getDeviceLinks(deviceId)); |
148 | } | 155 | } |
149 | 156 | ||
... | @@ -189,6 +196,15 @@ public class LinkManager | ... | @@ -189,6 +196,15 @@ public class LinkManager |
189 | public void linkDetected(LinkDescription linkDescription) { | 196 | public void linkDetected(LinkDescription linkDescription) { |
190 | checkNotNull(linkDescription, LINK_DESC_NULL); | 197 | checkNotNull(linkDescription, LINK_DESC_NULL); |
191 | checkValidity(); | 198 | checkValidity(); |
199 | + | ||
200 | + ConnectPoint src = linkDescription.src(); | ||
201 | + ConnectPoint dst = linkDescription.dst(); | ||
202 | + // if we aren't master for the device associated with the ConnectPoint | ||
203 | + // we probably shouldn't be doing this. | ||
204 | + if ((deviceService.getRole(src.deviceId()) != MastershipRole.MASTER) || | ||
205 | + (deviceService.getRole(dst.deviceId()) != MastershipRole.MASTER)) { | ||
206 | + return; | ||
207 | + } | ||
192 | LinkEvent event = store.createOrUpdateLink(provider().id(), | 208 | LinkEvent event = store.createOrUpdateLink(provider().id(), |
193 | linkDescription); | 209 | linkDescription); |
194 | if (event != null) { | 210 | if (event != null) { |
... | @@ -201,6 +217,15 @@ public class LinkManager | ... | @@ -201,6 +217,15 @@ public class LinkManager |
201 | public void linkVanished(LinkDescription linkDescription) { | 217 | public void linkVanished(LinkDescription linkDescription) { |
202 | checkNotNull(linkDescription, LINK_DESC_NULL); | 218 | checkNotNull(linkDescription, LINK_DESC_NULL); |
203 | checkValidity(); | 219 | checkValidity(); |
220 | + | ||
221 | + ConnectPoint src = linkDescription.src(); | ||
222 | + ConnectPoint dst = linkDescription.dst(); | ||
223 | + // if we aren't master for the device associated with the ConnectPoint | ||
224 | + // we probably shouldn't be doing this. | ||
225 | + if ((deviceService.getRole(src.deviceId()) != MastershipRole.MASTER) || | ||
226 | + (deviceService.getRole(dst.deviceId()) != MastershipRole.MASTER)) { | ||
227 | + return; | ||
228 | + } | ||
204 | LinkEvent event = store.removeLink(linkDescription.src(), | 229 | LinkEvent event = store.removeLink(linkDescription.src(), |
205 | linkDescription.dst()); | 230 | linkDescription.dst()); |
206 | if (event != null) { | 231 | if (event != null) { |
... | @@ -213,6 +238,11 @@ public class LinkManager | ... | @@ -213,6 +238,11 @@ public class LinkManager |
213 | public void linksVanished(ConnectPoint connectPoint) { | 238 | public void linksVanished(ConnectPoint connectPoint) { |
214 | checkNotNull(connectPoint, "Connect point cannot be null"); | 239 | checkNotNull(connectPoint, "Connect point cannot be null"); |
215 | checkValidity(); | 240 | checkValidity(); |
241 | + // if we aren't master for the device associated with the ConnectPoint | ||
242 | + // we probably shouldn't be doing this. | ||
243 | + if (deviceService.getRole(connectPoint.deviceId()) != MastershipRole.MASTER) { | ||
244 | + return; | ||
245 | + } | ||
216 | log.info("Links for connection point {} vanished", connectPoint); | 246 | log.info("Links for connection point {} vanished", connectPoint); |
217 | removeLinks(getLinks(connectPoint)); | 247 | removeLinks(getLinks(connectPoint)); |
218 | } | 248 | } |
... | @@ -221,6 +251,11 @@ public class LinkManager | ... | @@ -221,6 +251,11 @@ public class LinkManager |
221 | public void linksVanished(DeviceId deviceId) { | 251 | public void linksVanished(DeviceId deviceId) { |
222 | checkNotNull(deviceId, DEVICE_ID_NULL); | 252 | checkNotNull(deviceId, DEVICE_ID_NULL); |
223 | checkValidity(); | 253 | checkValidity(); |
254 | + // if we aren't master for the device associated with the ConnectPoint | ||
255 | + // we probably shouldn't be doing this. | ||
256 | + if (deviceService.getRole(deviceId) != MastershipRole.MASTER) { | ||
257 | + return; | ||
258 | + } | ||
224 | log.info("Links for device {} vanished", deviceId); | 259 | log.info("Links for device {} vanished", deviceId); |
225 | removeLinks(getDeviceLinks(deviceId)); | 260 | removeLinks(getDeviceLinks(deviceId)); |
226 | } | 261 | } | ... | ... |
... | @@ -59,6 +59,7 @@ public class LinkManagerTest { | ... | @@ -59,6 +59,7 @@ public class LinkManagerTest { |
59 | protected LinkProviderService providerService; | 59 | protected LinkProviderService providerService; |
60 | protected TestProvider provider; | 60 | protected TestProvider provider; |
61 | protected TestListener listener = new TestListener(); | 61 | protected TestListener listener = new TestListener(); |
62 | + protected DeviceManager devmgr = new TestDeviceManager(); | ||
62 | 63 | ||
63 | @Before | 64 | @Before |
64 | public void setUp() { | 65 | public void setUp() { |
... | @@ -68,7 +69,7 @@ public class LinkManagerTest { | ... | @@ -68,7 +69,7 @@ public class LinkManagerTest { |
68 | registry = mgr; | 69 | registry = mgr; |
69 | mgr.store = new SimpleLinkStore(); | 70 | mgr.store = new SimpleLinkStore(); |
70 | mgr.eventDispatcher = new TestEventDispatcher(); | 71 | mgr.eventDispatcher = new TestEventDispatcher(); |
71 | - mgr.deviceService = new DeviceManager(); | 72 | + mgr.deviceService = devmgr; |
72 | mgr.activate(); | 73 | mgr.activate(); |
73 | 74 | ||
74 | service.addListener(listener); | 75 | service.addListener(listener); |
... | @@ -259,4 +260,11 @@ public class LinkManagerTest { | ... | @@ -259,4 +260,11 @@ public class LinkManagerTest { |
259 | } | 260 | } |
260 | } | 261 | } |
261 | 262 | ||
263 | + private static class TestDeviceManager extends DeviceManager { | ||
264 | + @Override | ||
265 | + public MastershipRole getRole(DeviceId deviceId) { | ||
266 | + return MastershipRole.MASTER; | ||
267 | + } | ||
268 | + } | ||
269 | + | ||
262 | } | 270 | } | ... | ... |
... | @@ -44,6 +44,8 @@ public class DeviceClockManager implements DeviceClockService, DeviceClockProvid | ... | @@ -44,6 +44,8 @@ public class DeviceClockManager implements DeviceClockService, DeviceClockProvid |
44 | @Override | 44 | @Override |
45 | public Timestamp getTimestamp(DeviceId deviceId) { | 45 | public Timestamp getTimestamp(DeviceId deviceId) { |
46 | MastershipTerm term = deviceMastershipTerms.get(deviceId); | 46 | MastershipTerm term = deviceMastershipTerms.get(deviceId); |
47 | + log.info("term info for {} is: {}", deviceId, term); | ||
48 | + | ||
47 | if (term == null) { | 49 | if (term == null) { |
48 | throw new IllegalStateException("Requesting timestamp for a deviceId without mastership"); | 50 | throw new IllegalStateException("Requesting timestamp for a deviceId without mastership"); |
49 | } | 51 | } |
... | @@ -52,6 +54,7 @@ public class DeviceClockManager implements DeviceClockService, DeviceClockProvid | ... | @@ -52,6 +54,7 @@ public class DeviceClockManager implements DeviceClockService, DeviceClockProvid |
52 | 54 | ||
53 | @Override | 55 | @Override |
54 | public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { | 56 | public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { |
57 | + log.info("adding term info {} {}", deviceId, term.master()); | ||
55 | deviceMastershipTerms.put(deviceId, term); | 58 | deviceMastershipTerms.put(deviceId, term); |
56 | } | 59 | } |
57 | } | 60 | } | ... | ... |
... | @@ -390,6 +390,7 @@ public class GossipDeviceStore | ... | @@ -390,6 +390,7 @@ public class GossipDeviceStore |
390 | List<PortDescription> portDescriptions) { | 390 | List<PortDescription> portDescriptions) { |
391 | 391 | ||
392 | final Timestamp newTimestamp = deviceClockService.getTimestamp(deviceId); | 392 | final Timestamp newTimestamp = deviceClockService.getTimestamp(deviceId); |
393 | + log.info("timestamp for {} {}", deviceId, newTimestamp); | ||
393 | 394 | ||
394 | final Timestamped<List<PortDescription>> timestampedInput | 395 | final Timestamped<List<PortDescription>> timestampedInput |
395 | = new Timestamped<>(portDescriptions, newTimestamp); | 396 | = new Timestamped<>(portDescriptions, newTimestamp); | ... | ... |
... | @@ -360,7 +360,14 @@ public class GossipLinkStore | ... | @@ -360,7 +360,14 @@ public class GossipLinkStore |
360 | final LinkKey key = linkKey(src, dst); | 360 | final LinkKey key = linkKey(src, dst); |
361 | 361 | ||
362 | DeviceId dstDeviceId = dst.deviceId(); | 362 | DeviceId dstDeviceId = dst.deviceId(); |
363 | - Timestamp timestamp = deviceClockService.getTimestamp(dstDeviceId); | 363 | + Timestamp timestamp = null; |
364 | + try { | ||
365 | + timestamp = deviceClockService.getTimestamp(dstDeviceId); | ||
366 | + } catch (IllegalStateException e) { | ||
367 | + //there are times when this is called before mastership | ||
368 | + // handoff correctly completes. | ||
369 | + return null; | ||
370 | + } | ||
364 | 371 | ||
365 | LinkEvent event = removeLinkInternal(key, timestamp); | 372 | LinkEvent event = removeLinkInternal(key, timestamp); |
366 | 373 | ... | ... |
... | @@ -29,7 +29,10 @@ import org.onlab.onos.store.serializers.KryoSerializer; | ... | @@ -29,7 +29,10 @@ import org.onlab.onos.store.serializers.KryoSerializer; |
29 | import org.onlab.util.KryoPool; | 29 | import org.onlab.util.KryoPool; |
30 | 30 | ||
31 | import com.google.common.collect.ImmutableSet; | 31 | import com.google.common.collect.ImmutableSet; |
32 | +import com.hazelcast.core.EntryEvent; | ||
33 | +import com.hazelcast.core.EntryListener; | ||
32 | import com.hazelcast.core.IAtomicLong; | 34 | import com.hazelcast.core.IAtomicLong; |
35 | +import com.hazelcast.core.MapEvent; | ||
33 | 36 | ||
34 | import static org.onlab.onos.net.MastershipRole.*; | 37 | import static org.onlab.onos.net.MastershipRole.*; |
35 | 38 | ||
... | @@ -78,7 +81,7 @@ implements MastershipStore { | ... | @@ -78,7 +81,7 @@ implements MastershipStore { |
78 | roleMap = new SMap(theInstance.getMap("nodeRoles"), this.serializer); | 81 | roleMap = new SMap(theInstance.getMap("nodeRoles"), this.serializer); |
79 | terms = new SMap(theInstance.getMap("terms"), this.serializer); | 82 | terms = new SMap(theInstance.getMap("terms"), this.serializer); |
80 | clusterSize = theInstance.getAtomicLong("clustersize"); | 83 | clusterSize = theInstance.getAtomicLong("clustersize"); |
81 | - // roleMap.addEntryListener(new RemoteMasterShipEventHandler(), true); | 84 | + roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true); |
82 | 85 | ||
83 | log.info("Started"); | 86 | log.info("Started"); |
84 | } | 87 | } |
... | @@ -207,6 +210,7 @@ implements MastershipStore { | ... | @@ -207,6 +210,7 @@ implements MastershipStore { |
207 | rv.reassign(local, NONE, STANDBY); | 210 | rv.reassign(local, NONE, STANDBY); |
208 | roleMap.put(deviceId, rv); | 211 | roleMap.put(deviceId, rv); |
209 | terms.putIfAbsent(deviceId, INIT); | 212 | terms.putIfAbsent(deviceId, INIT); |
213 | + | ||
210 | break; | 214 | break; |
211 | case NONE: | 215 | case NONE: |
212 | //claim mastership | 216 | //claim mastership |
... | @@ -289,7 +293,8 @@ implements MastershipStore { | ... | @@ -289,7 +293,8 @@ implements MastershipStore { |
289 | } | 293 | } |
290 | 294 | ||
291 | //helper to fetch a new master candidate for a given device. | 295 | //helper to fetch a new master candidate for a given device. |
292 | - private MastershipEvent reelect(NodeId current, DeviceId deviceId, RoleValue rv) { | 296 | + private MastershipEvent reelect( |
297 | + NodeId current, DeviceId deviceId, RoleValue rv) { | ||
293 | 298 | ||
294 | //if this is an queue it'd be neater. | 299 | //if this is an queue it'd be neater. |
295 | NodeId backup = null; | 300 | NodeId backup = null; |
... | @@ -301,17 +306,18 @@ implements MastershipStore { | ... | @@ -301,17 +306,18 @@ implements MastershipStore { |
301 | } | 306 | } |
302 | 307 | ||
303 | if (backup == null) { | 308 | if (backup == null) { |
309 | + log.info("{} giving up and going to NONE for {}", current, deviceId); | ||
304 | rv.remove(MASTER, current); | 310 | rv.remove(MASTER, current); |
305 | roleMap.put(deviceId, rv); | 311 | roleMap.put(deviceId, rv); |
306 | return null; | 312 | return null; |
307 | } else { | 313 | } else { |
314 | + log.info("{} trying to pass mastership for {} to {}", current, deviceId, backup); | ||
308 | rv.replace(current, backup, MASTER); | 315 | rv.replace(current, backup, MASTER); |
309 | rv.reassign(backup, STANDBY, NONE); | 316 | rv.reassign(backup, STANDBY, NONE); |
310 | roleMap.put(deviceId, rv); | 317 | roleMap.put(deviceId, rv); |
311 | Integer term = terms.get(deviceId); | 318 | Integer term = terms.get(deviceId); |
312 | terms.put(deviceId, ++term); | 319 | terms.put(deviceId, ++term); |
313 | - return new MastershipEvent( | 320 | + return new MastershipEvent(MASTER_CHANGED, deviceId, backup); |
314 | - MASTER_CHANGED, deviceId, backup); | ||
315 | } | 321 | } |
316 | } | 322 | } |
317 | 323 | ||
... | @@ -346,30 +352,51 @@ implements MastershipStore { | ... | @@ -346,30 +352,51 @@ implements MastershipStore { |
346 | 352 | ||
347 | //adds or updates term information. | 353 | //adds or updates term information. |
348 | private void updateTerm(DeviceId deviceId) { | 354 | private void updateTerm(DeviceId deviceId) { |
355 | + terms.lock(deviceId); | ||
356 | + try { | ||
349 | Integer term = terms.get(deviceId); | 357 | Integer term = terms.get(deviceId); |
350 | if (term == null) { | 358 | if (term == null) { |
351 | terms.put(deviceId, INIT); | 359 | terms.put(deviceId, INIT); |
352 | } else { | 360 | } else { |
353 | terms.put(deviceId, ++term); | 361 | terms.put(deviceId, ++term); |
354 | } | 362 | } |
363 | + } finally { | ||
364 | + terms.unlock(deviceId); | ||
365 | + } | ||
366 | + } | ||
367 | + | ||
368 | + private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> { | ||
369 | + | ||
370 | + @Override | ||
371 | + public void entryAdded(EntryEvent<DeviceId, RoleValue> event) { | ||
372 | + } | ||
373 | + | ||
374 | + @Override | ||
375 | + public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) { | ||
355 | } | 376 | } |
356 | 377 | ||
357 | - private class RemoteMasterShipEventHandler extends RemoteEventHandler<DeviceId, NodeId> { | 378 | + @Override |
379 | + public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) { | ||
380 | + NodeId myId = clusterService.getLocalNode().id(); | ||
381 | + NodeId node = event.getValue().get(MASTER); | ||
382 | + if (myId.equals(node)) { | ||
383 | + // XXX or do we just let it get sent and caught by ourself? | ||
384 | + return; | ||
385 | + } | ||
386 | + notifyDelegate(new MastershipEvent( | ||
387 | + MASTER_CHANGED, event.getKey(), event.getValue().get(MASTER))); | ||
388 | + } | ||
358 | 389 | ||
359 | @Override | 390 | @Override |
360 | - protected void onAdd(DeviceId deviceId, NodeId nodeId) { | 391 | + public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) { |
361 | - notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId)); | ||
362 | } | 392 | } |
363 | 393 | ||
364 | @Override | 394 | @Override |
365 | - protected void onRemove(DeviceId deviceId, NodeId nodeId) { | 395 | + public void mapEvicted(MapEvent event) { |
366 | - //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId)); | ||
367 | } | 396 | } |
368 | 397 | ||
369 | @Override | 398 | @Override |
370 | - protected void onUpdate(DeviceId deviceId, NodeId oldNodeId, NodeId nodeId) { | 399 | + public void mapCleared(MapEvent event) { |
371 | - //only addition indicates a change in mastership | ||
372 | - //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId)); | ||
373 | } | 400 | } |
374 | } | 401 | } |
375 | 402 | ... | ... |
... | @@ -94,7 +94,6 @@ public final class KryoPoolUtil { | ... | @@ -94,7 +94,6 @@ public final class KryoPoolUtil { |
94 | .register(ConnectPoint.class, new ConnectPointSerializer()) | 94 | .register(ConnectPoint.class, new ConnectPointSerializer()) |
95 | .register(DefaultLink.class, new DefaultLinkSerializer()) | 95 | .register(DefaultLink.class, new DefaultLinkSerializer()) |
96 | .register(MastershipTerm.class, new MastershipTermSerializer()) | 96 | .register(MastershipTerm.class, new MastershipTermSerializer()) |
97 | - .register(MastershipRole.class, new MastershipRoleSerializer()) | ||
98 | .register(HostLocation.class, new HostLocationSerializer()) | 97 | .register(HostLocation.class, new HostLocationSerializer()) |
99 | 98 | ||
100 | .build(); | 99 | .build(); | ... | ... |
-
Please register or login to post a comment