blob: a0ac4c7e3b917061298989224d2a81e2f28e6656 [file] [log] [blame]
tomea961ff2014-10-01 12:45:15 -07001package org.onlab.onos.store.trivial.impl;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -07002
3import static org.slf4j.LoggerFactory.getLogger;
4
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -07005import java.util.ArrayList;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -07006import java.util.Collections;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -07007import java.util.HashMap;
Ayaka Koshibe406d0102014-09-24 16:08:12 -07008import java.util.HashSet;
Ayaka Koshibe45503ce2014-10-14 11:26:45 -07009import java.util.List;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070010import java.util.Map;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070011import java.util.Set;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070012import java.util.concurrent.atomic.AtomicInteger;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070013
14import org.apache.felix.scr.annotations.Activate;
15import org.apache.felix.scr.annotations.Component;
16import org.apache.felix.scr.annotations.Deactivate;
17import org.apache.felix.scr.annotations.Service;
18import org.onlab.onos.cluster.ControllerNode;
19import org.onlab.onos.cluster.DefaultControllerNode;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070020import org.onlab.onos.cluster.NodeId;
Ayaka Koshibeabedb092014-10-20 17:01:31 -070021import org.onlab.onos.cluster.RoleInfo;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070022import org.onlab.onos.mastership.MastershipEvent;
23import org.onlab.onos.mastership.MastershipStore;
24import org.onlab.onos.mastership.MastershipStoreDelegate;
25import org.onlab.onos.mastership.MastershipTerm;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070026import org.onlab.onos.net.DeviceId;
27import org.onlab.onos.net.MastershipRole;
tomf80c9722014-09-24 14:49:18 -070028import org.onlab.onos.store.AbstractStore;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070029import org.onlab.packet.IpPrefix;
30import org.slf4j.Logger;
31
Ayaka Koshibefc981cf2014-10-21 12:44:17 -070032import com.google.common.collect.Lists;
33
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070034import static org.onlab.onos.mastership.MastershipEvent.Type.*;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070035
36/**
37 * Manages inventory of controller mastership over devices using
Ayaka Koshibe406d0102014-09-24 16:08:12 -070038 * trivial, non-distributed in-memory structures implementation.
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070039 */
40@Component(immediate = true)
41@Service
tomf80c9722014-09-24 14:49:18 -070042public class SimpleMastershipStore
43 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
44 implements MastershipStore {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070045
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070046 private final Logger log = getLogger(getClass());
47
Ayaka Koshibe406d0102014-09-24 16:08:12 -070048 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070049
Ayaka Koshibe406d0102014-09-24 16:08:12 -070050 private ControllerNode instance =
51 new DefaultControllerNode(new NodeId("local"), LOCALHOST);
52
53 //devices mapped to their masters, to emulate multiple nodes
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070054 protected final Map<DeviceId, NodeId> masterMap = new HashMap<>();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070055 //emulate backups with pile of nodes
56 protected final Set<NodeId> backups = new HashSet<>();
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070057 //terms
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070058 protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070059
60 @Activate
61 public void activate() {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070062 log.info("Started");
63 }
64
65 @Deactivate
66 public void deactivate() {
67 log.info("Stopped");
68 }
69
70 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070071 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070072 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe406d0102014-09-24 16:08:12 -070073
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070074 synchronized (this) {
75 switch (role) {
76 case MASTER:
77 return null;
78 case STANDBY:
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070079 masterMap.put(deviceId, nodeId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070080 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070081 backups.add(nodeId);
82 break;
83 case NONE:
84 masterMap.put(deviceId, nodeId);
85 termMap.put(deviceId, new AtomicInteger());
86 backups.add(nodeId);
87 break;
88 default:
89 log.warn("unknown Mastership Role {}", role);
90 return null;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070091 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -070092 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070093
Ayaka Koshibefc981cf2014-10-21 12:44:17 -070094 return new MastershipEvent(MASTER_CHANGED, deviceId,
95 new RoleInfo(nodeId, Lists.newLinkedList(backups)));
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070096 }
97
98 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070099 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700100 return masterMap.get(deviceId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700101 }
102
103 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700104 public RoleInfo getNodes(DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700105 List<NodeId> nodes = new ArrayList<>();
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700106 nodes.addAll(backups);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700107
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700108 return new RoleInfo(masterMap.get(deviceId), nodes);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700109 }
110
111 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700112 public Set<DeviceId> getDevices(NodeId nodeId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700113 Set<DeviceId> ids = new HashSet<>();
114 for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) {
115 if (d.getValue().equals(nodeId)) {
116 ids.add(d.getKey());
117 }
118 }
119 return Collections.unmodifiableSet(ids);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700120 }
121
122 @Override
tomb41d1ac2014-09-24 01:51:24 -0700123 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700124 //query+possible reelection
125 NodeId node = instance.id();
126 MastershipRole role = getRole(node, deviceId);
127
128 switch (role) {
129 case MASTER:
130 break;
131 case STANDBY:
132 synchronized (this) {
133 //try to "re-elect", since we're really not distributed
134 NodeId rel = reelect(node);
135 if (rel == null) {
136 masterMap.put(deviceId, node);
137 termMap.put(deviceId, new AtomicInteger());
138 role = MastershipRole.MASTER;
139 }
140 backups.add(node);
141 }
142 break;
143 case NONE:
144 //first to get to it, say we are master
145 synchronized (this) {
146 masterMap.put(deviceId, node);
147 termMap.put(deviceId, new AtomicInteger());
148 backups.add(node);
149 role = MastershipRole.MASTER;
150 }
151 break;
152 default:
153 log.warn("unknown Mastership Role {}", role);
154 }
155 return role;
tomb41d1ac2014-09-24 01:51:24 -0700156 }
157
158 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700159 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700160 //just query
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700161 NodeId current = masterMap.get(deviceId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700162 MastershipRole role;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700163
164 if (current == null) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700165 if (backups.contains(nodeId)) {
166 role = MastershipRole.STANDBY;
167 } else {
168 role = MastershipRole.NONE;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700169 }
170 } else {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700171 if (current.equals(nodeId)) {
172 role = MastershipRole.MASTER;
173 } else {
174 role = MastershipRole.STANDBY;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700175 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700176 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700177 return role;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700178 }
179
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700180 @Override
181 public MastershipTerm getTermFor(DeviceId deviceId) {
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700182 if ((masterMap.get(deviceId) == null) ||
183 (termMap.get(deviceId) == null)) {
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700184 return null;
185 }
186 return MastershipTerm.of(
187 masterMap.get(deviceId), termMap.get(deviceId).get());
188 }
189
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700190 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700191 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700192 MastershipRole role = getRole(nodeId, deviceId);
193 synchronized (this) {
194 switch (role) {
195 case MASTER:
196 NodeId backup = reelect(nodeId);
197 if (backup == null) {
198 masterMap.remove(deviceId);
199 } else {
200 masterMap.put(deviceId, backup);
201 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700202 return new MastershipEvent(MASTER_CHANGED, deviceId,
203 new RoleInfo(backup, Lists.newLinkedList(backups)));
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700204 }
205 case STANDBY:
206 case NONE:
207 if (!termMap.containsKey(deviceId)) {
208 termMap.put(deviceId, new AtomicInteger());
209 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700210 backups.add(nodeId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700211 break;
212 default:
213 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700214 }
215 }
216 return null;
217 }
218
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700219 //dumbly selects next-available node that's not the current one
220 //emulate leader election
221 private NodeId reelect(NodeId nodeId) {
222 NodeId backup = null;
223 for (NodeId n : backups) {
224 if (!n.equals(nodeId)) {
225 backup = n;
226 break;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700227 }
228 }
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700229 backups.remove(backup);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700230 return backup;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700231 }
232
Ayaka Koshibec4047702014-10-07 14:43:52 -0700233 @Override
234 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700235 MastershipRole role = getRole(nodeId, deviceId);
236 synchronized (this) {
237 switch (role) {
238 case MASTER:
239 NodeId backup = reelect(nodeId);
240 backups.remove(nodeId);
241 if (backup == null) {
242 masterMap.remove(deviceId);
243 } else {
244 masterMap.put(deviceId, backup);
245 termMap.get(deviceId).incrementAndGet();
246 return new MastershipEvent(MASTER_CHANGED, deviceId,
247 new RoleInfo(backup, Lists.newLinkedList(backups)));
248 }
249 case STANDBY:
250 backups.remove(nodeId);
251 case NONE:
252 default:
253 log.warn("unknown Mastership Role {}", role);
254 }
255 }
256 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700257 }
258
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700259}