blob: f4b035c0f7bd43e365dd520abd5df279e5c4aaa0 [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;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070021import org.onlab.onos.mastership.MastershipEvent;
22import org.onlab.onos.mastership.MastershipStore;
23import org.onlab.onos.mastership.MastershipStoreDelegate;
24import org.onlab.onos.mastership.MastershipTerm;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070025import org.onlab.onos.net.DeviceId;
26import org.onlab.onos.net.MastershipRole;
tomf80c9722014-09-24 14:49:18 -070027import org.onlab.onos.store.AbstractStore;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070028import org.onlab.packet.IpPrefix;
29import org.slf4j.Logger;
30
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070031import static org.onlab.onos.mastership.MastershipEvent.Type.*;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070032
33/**
34 * Manages inventory of controller mastership over devices using
Ayaka Koshibe406d0102014-09-24 16:08:12 -070035 * trivial, non-distributed in-memory structures implementation.
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070036 */
37@Component(immediate = true)
38@Service
tomf80c9722014-09-24 14:49:18 -070039public class SimpleMastershipStore
40 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
41 implements MastershipStore {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070042
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070043 private final Logger log = getLogger(getClass());
44
Ayaka Koshibe406d0102014-09-24 16:08:12 -070045 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070046
Ayaka Koshibe406d0102014-09-24 16:08:12 -070047 private ControllerNode instance =
48 new DefaultControllerNode(new NodeId("local"), LOCALHOST);
49
50 //devices mapped to their masters, to emulate multiple nodes
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070051 protected final Map<DeviceId, NodeId> masterMap = new HashMap<>();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070052 //emulate backups with pile of nodes
53 protected final Set<NodeId> backups = new HashSet<>();
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070054 //terms
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070055 protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070056
57 @Activate
58 public void activate() {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070059 log.info("Started");
60 }
61
62 @Deactivate
63 public void deactivate() {
64 log.info("Stopped");
65 }
66
67 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070068 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070069 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe406d0102014-09-24 16:08:12 -070070
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070071 synchronized (this) {
72 switch (role) {
73 case MASTER:
74 return null;
75 case STANDBY:
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070076 masterMap.put(deviceId, nodeId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070077 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070078 backups.add(nodeId);
79 break;
80 case NONE:
81 masterMap.put(deviceId, nodeId);
82 termMap.put(deviceId, new AtomicInteger());
83 backups.add(nodeId);
84 break;
85 default:
86 log.warn("unknown Mastership Role {}", role);
87 return null;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070088 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -070089 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070090
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070091 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070092 }
93
94 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070095 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070096 return masterMap.get(deviceId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070097 }
98
99 @Override
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700100 public List<NodeId> getNodes(DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700101 List<NodeId> nodes = new ArrayList<>();
102
103 nodes.addAll(backups);
104 if (!nodes.contains(masterMap.get(deviceId))) {
105 nodes.add(masterMap.get(deviceId));
106 }
107
108 return Collections.unmodifiableList(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();
202 return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
203 }
204 case STANDBY:
205 case NONE:
206 if (!termMap.containsKey(deviceId)) {
207 termMap.put(deviceId, new AtomicInteger());
208 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700209 backups.add(nodeId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700210 break;
211 default:
212 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700213 }
214 }
215 return null;
216 }
217
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700218 //dumbly selects next-available node that's not the current one
219 //emulate leader election
220 private NodeId reelect(NodeId nodeId) {
221 NodeId backup = null;
222 for (NodeId n : backups) {
223 if (!n.equals(nodeId)) {
224 backup = n;
225 break;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700226 }
227 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700228 return backup;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700229 }
230
Ayaka Koshibec4047702014-10-07 14:43:52 -0700231 @Override
232 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
233 return setStandby(nodeId, deviceId);
234 }
235
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700236}