blob: 1def9f9fa00f21c76e7552ae859ab0b3a97525fd [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 Koshibe45503ce2014-10-14 11:26:45 -07005import java.util.LinkedList;
6import java.util.List;
alshabib339a3d92014-09-26 17:54:32 -07007import java.util.Map;
alshabib339a3d92014-09-26 17:54:32 -07008import java.util.Set;
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -07009
tomb41d1ac2014-09-24 01:51:24 -070010import org.apache.felix.scr.annotations.Activate;
11import org.apache.felix.scr.annotations.Component;
12import org.apache.felix.scr.annotations.Deactivate;
13import org.apache.felix.scr.annotations.Reference;
14import org.apache.felix.scr.annotations.ReferenceCardinality;
15import org.apache.felix.scr.annotations.Service;
16import org.onlab.onos.cluster.ClusterService;
tomb41d1ac2014-09-24 01:51:24 -070017import org.onlab.onos.cluster.NodeId;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070018import org.onlab.onos.mastership.MastershipEvent;
19import org.onlab.onos.mastership.MastershipStore;
20import org.onlab.onos.mastership.MastershipStoreDelegate;
21import org.onlab.onos.mastership.MastershipTerm;
tomb41d1ac2014-09-24 01:51:24 -070022import org.onlab.onos.net.DeviceId;
23import org.onlab.onos.net.MastershipRole;
Yuta HIGUCHIb5df76d2014-09-27 20:54:00 -070024import org.onlab.onos.store.common.AbstractHazelcastStore;
tomb41d1ac2014-09-24 01:51:24 -070025
alshabib339a3d92014-09-26 17:54:32 -070026import com.google.common.collect.ImmutableSet;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070027import com.hazelcast.core.ILock;
alshabib339a3d92014-09-26 17:54:32 -070028import com.hazelcast.core.IMap;
Ayaka Koshibec4047702014-10-07 14:43:52 -070029import com.hazelcast.core.MultiMap;
tomb41d1ac2014-09-24 01:51:24 -070030
31/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070032 * Distributed implementation of the mastership store. The store is
33 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070034 */
35@Component(immediate = true)
36@Service
tom0755a362014-09-24 11:54:43 -070037public class DistributedMastershipStore
Yuta HIGUCHI2e963892014-09-27 13:00:39 -070038extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
alshabib339a3d92014-09-26 17:54:32 -070039implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070040
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070041 //arbitrary lock name
42 private static final String LOCK = "lock";
Ayaka Koshibec4047702014-10-07 14:43:52 -070043 //initial term/TTL value
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070044 private static final Integer INIT = 0;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070045
46 //devices to masters
Ayaka Koshibec4047702014-10-07 14:43:52 -070047 protected IMap<byte[], byte[]> masters;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070048 //devices to terms
Ayaka Koshibec4047702014-10-07 14:43:52 -070049 protected IMap<byte[], Integer> terms;
50
51 //re-election related, disjoint-set structures:
52 //device-nodes multiset of available nodes
53 protected MultiMap<byte[], byte[]> standbys;
54 //device-nodes multiset for nodes that have given up on device
55 protected MultiMap<byte[], byte[]> unusable;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070056
tomb41d1ac2014-09-24 01:51:24 -070057 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 protected ClusterService clusterService;
59
Ayaka Koshibe406d0102014-09-24 16:08:12 -070060 @Override
tomb41d1ac2014-09-24 01:51:24 -070061 @Activate
62 public void activate() {
63 super.activate();
64
Ayaka Koshibec4047702014-10-07 14:43:52 -070065 masters = theInstance.getMap("masters");
66 terms = theInstance.getMap("terms");
67 standbys = theInstance.getMultiMap("backups");
68 unusable = theInstance.getMultiMap("unusable");
tomb41d1ac2014-09-24 01:51:24 -070069
Ayaka Koshibec4047702014-10-07 14:43:52 -070070 masters.addEntryListener(new RemoteMasterShipEventHandler(), true);
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070071
tomb41d1ac2014-09-24 01:51:24 -070072 log.info("Started");
73 }
74
75 @Deactivate
76 public void deactivate() {
77 log.info("Stopped");
78 }
79
80 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -070081 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
82 byte[] did = serialize(deviceId);
83 byte[] nid = serialize(nodeId);
84
85 NodeId current = deserialize(masters.get(did));
86 if (current == null) {
87 if (standbys.containsEntry(did, nid)) {
88 //was previously standby, or set to standby from master
89 return MastershipRole.STANDBY;
90 } else {
91 return MastershipRole.NONE;
92 }
93 } else {
94 if (current.equals(nodeId)) {
95 //*should* be in unusable, not always
96 return MastershipRole.MASTER;
97 } else {
98 //may be in backups or unusable from earlier retirement
99 return MastershipRole.STANDBY;
100 }
101 }
102 }
103
104 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700105 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700106 byte [] did = serialize(deviceId);
107 byte [] nid = serialize(nodeId);
tomb41d1ac2014-09-24 01:51:24 -0700108
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700109 ILock lock = theInstance.getLock(LOCK);
110 lock.lock();
111 try {
112 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700113 switch (role) {
114 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700115 //reinforce mastership
116 evict(nid, did);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700117 return null;
118 case STANDBY:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700119 //make current master standby
120 byte [] current = masters.get(did);
121 if (current != null) {
122 backup(current, did);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700123 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700124 //assign specified node as new master
125 masters.put(did, nid);
126 evict(nid, did);
127 updateTerm(did);
128 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
129 case NONE:
130 masters.put(did, nid);
131 evict(nid, did);
132 updateTerm(did);
133 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700134 default:
135 log.warn("unknown Mastership Role {}", role);
136 return null;
137 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700138 } finally {
139 lock.unlock();
tomb41d1ac2014-09-24 01:51:24 -0700140 }
141 }
142
143 @Override
144 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700145 return deserialize(masters.get(serialize(deviceId)));
tomb41d1ac2014-09-24 01:51:24 -0700146 }
147
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700148
149 @Override
150 public List<NodeId> getNodes(DeviceId deviceId) {
151 byte [] did = serialize(deviceId);
152 List<NodeId> nodes = new LinkedList<>();
153
154 //add current master to head - if there is one
155 ILock lock = theInstance.getLock(LOCK);
156 lock.lock();
157 try {
158 byte [] master = masters.get(did);
159 if (master != null) {
160 nodes.add((NodeId) deserialize(master));
161 }
162
163 for (byte [] el : standbys.get(serialize(deviceId))) {
164 nodes.add((NodeId) deserialize(el));
165 }
166 return nodes;
167 } finally {
168 lock.unlock();
169 }
170 }
171
tomb41d1ac2014-09-24 01:51:24 -0700172 @Override
173 public Set<DeviceId> getDevices(NodeId nodeId) {
174 ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700175
Ayaka Koshibec4047702014-10-07 14:43:52 -0700176 for (Map.Entry<byte[], byte[]> entry : masters.entrySet()) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700177 if (nodeId.equals(deserialize(entry.getValue()))) {
178 builder.add((DeviceId) deserialize(entry.getKey()));
tomb41d1ac2014-09-24 01:51:24 -0700179 }
180 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700181
tomb41d1ac2014-09-24 01:51:24 -0700182 return builder.build();
183 }
184
185 @Override
186 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700187 NodeId local = clusterService.getLocalNode().id();
Ayaka Koshibec4047702014-10-07 14:43:52 -0700188 byte [] did = serialize(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700189 byte [] lnid = serialize(local);
190
191 ILock lock = theInstance.getLock(LOCK);
192 lock.lock();
193 try {
194 MastershipRole role = getRole(local, deviceId);
195 switch (role) {
196 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700197 evict(lnid, did);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700198 break;
199 case STANDBY:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700200 backup(lnid, did);
201 terms.putIfAbsent(did, INIT);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700202 break;
203 case NONE:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700204 //claim mastership
205 masters.put(did, lnid);
206 evict(lnid, did);
207 updateTerm(did);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700208 role = MastershipRole.MASTER;
209 break;
210 default:
211 log.warn("unknown Mastership Role {}", role);
212 }
213 return role;
214 } finally {
215 lock.unlock();
216 }
tomb41d1ac2014-09-24 01:51:24 -0700217 }
218
219 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700220 public MastershipTerm getTermFor(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700221 byte[] did = serialize(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700222 if ((masters.get(did) == null) ||
223 (terms.get(did) == null)) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700224 return null;
225 }
226 return MastershipTerm.of(
Ayaka Koshibec4047702014-10-07 14:43:52 -0700227 (NodeId) deserialize(masters.get(did)), terms.get(did));
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700228 }
229
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700230 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700231 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700232 byte [] did = serialize(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700233 byte [] nid = serialize(nodeId);
234 MastershipEvent event = null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700235
236 ILock lock = theInstance.getLock(LOCK);
237 lock.lock();
238 try {
239 MastershipRole role = getRole(nodeId, deviceId);
240 switch (role) {
241 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700242 event = reelect(nodeId, deviceId);
243 backup(nid, did);
244 break;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700245 case STANDBY:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700246 //fall through to reinforce role
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700247 case NONE:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700248 backup(nid, did);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700249 break;
250 default:
251 log.warn("unknown Mastership Role {}", role);
252 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700253 return event;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700254 } finally {
255 lock.unlock();
256 }
257 }
258
Ayaka Koshibec4047702014-10-07 14:43:52 -0700259 @Override
260 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
261 byte [] did = serialize(deviceId);
262 byte [] nid = serialize(nodeId);
263 MastershipEvent event = null;
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700264
Ayaka Koshibec4047702014-10-07 14:43:52 -0700265 ILock lock = theInstance.getLock(LOCK);
266 lock.lock();
267 try {
268 MastershipRole role = getRole(nodeId, deviceId);
269 switch (role) {
270 case MASTER:
271 event = reelect(nodeId, deviceId);
272 evict(nid, did);
273 break;
274 case STANDBY:
275 //fall through to reinforce relinquishment
276 case NONE:
277 evict(nid, did);
278 break;
279 default:
280 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700281 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700282 return event;
283 } finally {
284 lock.unlock();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700285 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700286 }
287
Ayaka Koshibec4047702014-10-07 14:43:52 -0700288 //helper to fetch a new master candidate for a given device.
289 private MastershipEvent reelect(NodeId current, DeviceId deviceId) {
290 byte [] did = serialize(deviceId);
291 byte [] nid = serialize(current);
292
293 //if this is an queue it'd be neater.
294 byte [] backup = null;
295 for (byte [] n : standbys.get(serialize(deviceId))) {
296 if (!current.equals(deserialize(n))) {
297 backup = n;
298 break;
299 }
300 }
301
302 if (backup == null) {
303 masters.remove(did, nid);
304 return null;
305 } else {
306 masters.put(did, backup);
307 evict(backup, did);
308 Integer term = terms.get(did);
309 terms.put(did, ++term);
310 return new MastershipEvent(
311 MASTER_CHANGED, deviceId, (NodeId) deserialize(backup));
312 }
313 }
314
315 //adds node to pool(s) of backups and moves them from unusable.
316 private void backup(byte [] nodeId, byte [] deviceId) {
317 if (!standbys.containsEntry(deviceId, nodeId)) {
318 standbys.put(deviceId, nodeId);
319 }
320 if (unusable.containsEntry(deviceId, nodeId)) {
321 unusable.remove(deviceId, nodeId);
322 }
323 }
324
325 //adds node to unusable and evicts it from backup pool.
326 private void evict(byte [] nodeId, byte [] deviceId) {
327 if (!unusable.containsEntry(deviceId, nodeId)) {
328 unusable.put(deviceId, nodeId);
329 }
330 if (standbys.containsEntry(deviceId, nodeId)) {
331 standbys.remove(deviceId, nodeId);
332 }
333 }
334
335 //adds or updates term information.
336 private void updateTerm(byte [] deviceId) {
337 Integer term = terms.get(deviceId);
338 if (term == null) {
339 terms.put(deviceId, INIT);
340 } else {
341 terms.put(deviceId, ++term);
342 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700343 }
344
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700345 private class RemoteMasterShipEventHandler extends RemoteEventHandler<DeviceId, NodeId> {
alshabib339a3d92014-09-26 17:54:32 -0700346
347 @Override
348 protected void onAdd(DeviceId deviceId, NodeId nodeId) {
349 notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
350 }
351
352 @Override
353 protected void onRemove(DeviceId deviceId, NodeId nodeId) {
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700354 //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
alshabib339a3d92014-09-26 17:54:32 -0700355 }
356
357 @Override
358 protected void onUpdate(DeviceId deviceId, NodeId oldNodeId, NodeId nodeId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700359 //only addition indicates a change in mastership
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700360 //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
alshabib339a3d92014-09-26 17:54:32 -0700361 }
362 }
363
tomb41d1ac2014-09-24 01:51:24 -0700364}