blob: bc323751f5fb5fe07598ff50547a82adfe0a9db7 [file] [log] [blame]
Yuta HIGUCHI80912e62014-10-12 00:15:47 -07001package org.onlab.onos.store.mastership.impl;
tomb41d1ac2014-09-24 01:51:24 -07002
Yuta HIGUCHI80912e62014-10-12 00:15:47 -07003import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED;
alshabib339a3d92014-09-26 17:54:32 -07004
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -07005import java.util.Collections;
Ayaka Koshibe45503ce2014-10-14 11:26:45 -07006import java.util.LinkedList;
7import java.util.List;
alshabib339a3d92014-09-26 17:54:32 -07008import java.util.Map;
alshabib339a3d92014-09-26 17:54:32 -07009import java.util.Set;
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070010
tomb41d1ac2014-09-24 01:51:24 -070011import org.apache.felix.scr.annotations.Activate;
12import org.apache.felix.scr.annotations.Component;
13import org.apache.felix.scr.annotations.Deactivate;
14import org.apache.felix.scr.annotations.Reference;
15import org.apache.felix.scr.annotations.ReferenceCardinality;
16import org.apache.felix.scr.annotations.Service;
17import org.onlab.onos.cluster.ClusterService;
tomb41d1ac2014-09-24 01:51:24 -070018import org.onlab.onos.cluster.NodeId;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070019import org.onlab.onos.mastership.MastershipEvent;
20import org.onlab.onos.mastership.MastershipStore;
21import org.onlab.onos.mastership.MastershipStoreDelegate;
22import org.onlab.onos.mastership.MastershipTerm;
tomb41d1ac2014-09-24 01:51:24 -070023import org.onlab.onos.net.DeviceId;
24import org.onlab.onos.net.MastershipRole;
Yuta HIGUCHIb5df76d2014-09-27 20:54:00 -070025import org.onlab.onos.store.common.AbstractHazelcastStore;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070026import org.onlab.onos.store.common.SMap;
27import org.onlab.onos.store.serializers.KryoSerializer;
tomb41d1ac2014-09-24 01:51:24 -070028
alshabib339a3d92014-09-26 17:54:32 -070029import com.google.common.collect.ImmutableSet;
30import com.hazelcast.core.IMap;
Ayaka Koshibec4047702014-10-07 14:43:52 -070031import com.hazelcast.core.MultiMap;
tomb41d1ac2014-09-24 01:51:24 -070032
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070033import static org.onlab.onos.net.MastershipRole.*;
34
tomb41d1ac2014-09-24 01:51:24 -070035/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070036 * Distributed implementation of the mastership store. The store is
37 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070038 */
39@Component(immediate = true)
40@Service
tom0755a362014-09-24 11:54:43 -070041public class DistributedMastershipStore
Yuta HIGUCHI2e963892014-09-27 13:00:39 -070042extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
alshabib339a3d92014-09-26 17:54:32 -070043implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070044
Ayaka Koshibec4047702014-10-07 14:43:52 -070045 //initial term/TTL value
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070046 private static final Integer INIT = 0;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070047
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070048 //device to node roles
49 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070050 //devices to terms
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070051 protected SMap<DeviceId, Integer> terms;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070052
tomb41d1ac2014-09-24 01:51:24 -070053 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
54 protected ClusterService clusterService;
55
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070056 @SuppressWarnings({ "unchecked", "rawtypes" })
Ayaka Koshibe406d0102014-09-24 16:08:12 -070057 @Override
tomb41d1ac2014-09-24 01:51:24 -070058 @Activate
59 public void activate() {
60 super.activate();
61
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070062 roleMap = new SMap(theInstance.getMap("nodeRoles"), new KryoSerializer());
63 terms = new SMap(theInstance.getMap("terms"), new KryoSerializer());
64 // roleMap.addEntryListener(new RemoteMasterShipEventHandler(), true);
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070065
tomb41d1ac2014-09-24 01:51:24 -070066 log.info("Started");
67 }
68
69 @Deactivate
70 public void deactivate() {
71 log.info("Stopped");
72 }
73
74 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -070075 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070076 NodeId current = getNode(MASTER, deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -070077 if (current == null) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070078 if (isRole(STANDBY, nodeId, deviceId)) {
Ayaka Koshibec4047702014-10-07 14:43:52 -070079 //was previously standby, or set to standby from master
80 return MastershipRole.STANDBY;
81 } else {
82 return MastershipRole.NONE;
83 }
84 } else {
85 if (current.equals(nodeId)) {
86 //*should* be in unusable, not always
87 return MastershipRole.MASTER;
88 } else {
89 //may be in backups or unusable from earlier retirement
90 return MastershipRole.STANDBY;
91 }
92 }
93 }
94
95 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070096 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -070097
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070098 MastershipRole role = getRole(nodeId, deviceId);
99 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700100 try {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700101 RoleValue rv = getRoleValue(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700102 switch (role) {
103 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700104 //reinforce mastership
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700105 rv.reassign(nodeId, STANDBY, NONE);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700106 return null;
107 case STANDBY:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700108 NodeId current = rv.get(MASTER);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700109 if (current != null) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700110 //backup and replace current master
111 rv.reassign(nodeId, NONE, STANDBY);
112 rv.replace(current, nodeId, MASTER);
113 } else {
114 //no master before so just add.
115 rv.add(MASTER, nodeId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700116 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700117 rv.reassign(nodeId, STANDBY, NONE);
118 updateTerm(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700119 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
120 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700121 rv.add(MASTER, nodeId);
122 rv.reassign(nodeId, STANDBY, NONE);
123 updateTerm(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700124 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700125 default:
126 log.warn("unknown Mastership Role {}", role);
127 return null;
128 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700129 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700130 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700131 }
132 }
133
134 @Override
135 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700136 return getMaster(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700137 }
138
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700139
140 @Override
141 public List<NodeId> getNodes(DeviceId deviceId) {
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700142 List<NodeId> nodes = new LinkedList<>();
143
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700144 //add current master to head - if there is one.
145 roleMap.lock(deviceId);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700146 try {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700147 RoleValue rv = getRoleValue(deviceId);
148 NodeId master = rv.get(MASTER);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700149 if (master != null) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700150 nodes.add(master);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700151 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700152 //We ignore NONE nodes.
153 nodes.addAll(rv.nodesOfRole(STANDBY));
154 return Collections.unmodifiableList(nodes);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700155 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700156 roleMap.unlock(deviceId);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700157 }
158 }
159
tomb41d1ac2014-09-24 01:51:24 -0700160 @Override
161 public Set<DeviceId> getDevices(NodeId nodeId) {
162 ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700163
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700164 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
165 if (nodeId.equals(el.getValue().get(MASTER))) {
166 builder.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700167 }
168 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700169
tomb41d1ac2014-09-24 01:51:24 -0700170 return builder.build();
171 }
172
173 @Override
174 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700175 NodeId local = clusterService.getLocalNode().id();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700176
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700177 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700178 try {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700179 RoleValue rv = getRoleValue(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700180 MastershipRole role = getRole(local, deviceId);
181 switch (role) {
182 case MASTER:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700183 rv.reassign(local, STANDBY, NONE);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700184 break;
185 case STANDBY:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700186 rv.reassign(local, NONE, STANDBY);
187 terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700188 break;
189 case NONE:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700190 //claim mastership
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700191 rv.add(MASTER, local);
192 rv.reassign(local, STANDBY, NONE);
193 updateTerm(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700194 role = MastershipRole.MASTER;
195 break;
196 default:
197 log.warn("unknown Mastership Role {}", role);
198 }
199 return role;
200 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700201 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700202 }
tomb41d1ac2014-09-24 01:51:24 -0700203 }
204
205 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700206 public MastershipTerm getTermFor(DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700207 RoleValue rv = getRoleValue(deviceId);
208 if ((rv.get(MASTER) == null) || (terms.get(deviceId) == null)) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700209 return null;
210 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700211 return MastershipTerm.of(rv.get(MASTER), terms.get(deviceId));
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700212 }
213
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700214 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700215 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700216 MastershipEvent event = null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700217
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700218 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700219 try {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700220 RoleValue rv = getRoleValue(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700221 MastershipRole role = getRole(nodeId, deviceId);
222 switch (role) {
223 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700224 event = reelect(nodeId, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700225 //fall through to reinforce role
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700226 case STANDBY:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700227 //fall through to reinforce role
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700228 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700229 rv.reassign(nodeId, NONE, STANDBY);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700230 break;
231 default:
232 log.warn("unknown Mastership Role {}", role);
233 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700234 return event;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700235 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700236 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700237 }
238 }
239
Ayaka Koshibec4047702014-10-07 14:43:52 -0700240 @Override
241 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700242 MastershipEvent event = null;
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700243
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700244 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700245 try {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700246 RoleValue rv = getRoleValue(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700247 MastershipRole role = getRole(nodeId, deviceId);
248 switch (role) {
249 case MASTER:
250 event = reelect(nodeId, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700251 //fall through to reinforce relinquishment
Ayaka Koshibec4047702014-10-07 14:43:52 -0700252 case STANDBY:
253 //fall through to reinforce relinquishment
254 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700255 rv.reassign(nodeId, STANDBY, NONE);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700256 break;
257 default:
258 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700259 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700260 return event;
261 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700262 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700263 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700264 }
265
Ayaka Koshibec4047702014-10-07 14:43:52 -0700266 //helper to fetch a new master candidate for a given device.
267 private MastershipEvent reelect(NodeId current, DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700268 RoleValue rv = roleMap.get(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700269
270 //if this is an queue it'd be neater.
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700271 NodeId backup = null;
272 for (NodeId n : rv.nodesOfRole(STANDBY)) {
273 if (!current.equals(n)) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700274 backup = n;
275 break;
276 }
277 }
278
279 if (backup == null) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700280 rv.remove(MASTER, current);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700281 return null;
282 } else {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700283 rv.replace(current, backup, MASTER);
284 rv.reassign(backup, STANDBY, NONE);
285 Integer term = terms.get(deviceId);
286 terms.put(deviceId, ++term);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700287 return new MastershipEvent(
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700288 MASTER_CHANGED, deviceId, backup);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700289 }
290 }
291
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700292 //return the RoleValue structure for a device, or create one
293 private RoleValue getRoleValue(DeviceId deviceId) {
294 RoleValue value = roleMap.get(deviceId);
295 if (value == null) {
296 value = new RoleValue();
297 roleMap.put(deviceId, value);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700298 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700299 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700300 }
301
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700302 //get first applicable node out of store-unique structure.
303 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
304 RoleValue value = roleMap.get(deviceId);
305 if (value != null) {
306 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700307 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700308 return null;
309 }
310
311 //check if node is a certain role given a device
312 private boolean isRole(
313 MastershipRole role, NodeId nodeId, DeviceId deviceId) {
314 RoleValue value = roleMap.get(deviceId);
315 if (value != null) {
316 return value.contains(role, nodeId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700317 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700318 return false;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700319 }
320
321 //adds or updates term information.
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700322 private void updateTerm(DeviceId deviceId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700323 Integer term = terms.get(deviceId);
324 if (term == null) {
325 terms.put(deviceId, INIT);
326 } else {
327 terms.put(deviceId, ++term);
328 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700329 }
330
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700331 private class RemoteMasterShipEventHandler extends RemoteEventHandler<DeviceId, NodeId> {
alshabib339a3d92014-09-26 17:54:32 -0700332
333 @Override
334 protected void onAdd(DeviceId deviceId, NodeId nodeId) {
335 notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
336 }
337
338 @Override
339 protected void onRemove(DeviceId deviceId, NodeId nodeId) {
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700340 //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
alshabib339a3d92014-09-26 17:54:32 -0700341 }
342
343 @Override
344 protected void onUpdate(DeviceId deviceId, NodeId oldNodeId, NodeId nodeId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700345 //only addition indicates a change in mastership
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700346 //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
alshabib339a3d92014-09-26 17:54:32 -0700347 }
348 }
349
tomb41d1ac2014-09-24 01:51:24 -0700350}