blob: fe34959c79abc09c1ae881d24d15adc8675c78ca [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
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070032import static org.onlab.onos.mastership.MastershipEvent.Type.*;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070033
34/**
35 * Manages inventory of controller mastership over devices using
Ayaka Koshibe406d0102014-09-24 16:08:12 -070036 * trivial, non-distributed in-memory structures implementation.
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070037 */
38@Component(immediate = true)
39@Service
tomf80c9722014-09-24 14:49:18 -070040public class SimpleMastershipStore
41 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
42 implements MastershipStore {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070043
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070044 private final Logger log = getLogger(getClass());
45
Ayaka Koshibe406d0102014-09-24 16:08:12 -070046 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070047
Ayaka Koshibe406d0102014-09-24 16:08:12 -070048 private ControllerNode instance =
49 new DefaultControllerNode(new NodeId("local"), LOCALHOST);
50
51 //devices mapped to their masters, to emulate multiple nodes
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070052 protected final Map<DeviceId, NodeId> masterMap = new HashMap<>();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070053 //emulate backups with pile of nodes
54 protected final Set<NodeId> backups = new HashSet<>();
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070055 //terms
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070056 protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070057
58 @Activate
59 public void activate() {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070060 log.info("Started");
61 }
62
63 @Deactivate
64 public void deactivate() {
65 log.info("Stopped");
66 }
67
68 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070069 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070070 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe406d0102014-09-24 16:08:12 -070071
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070072 synchronized (this) {
73 switch (role) {
74 case MASTER:
75 return null;
76 case STANDBY:
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070077 masterMap.put(deviceId, nodeId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070078 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070079 backups.add(nodeId);
80 break;
81 case NONE:
82 masterMap.put(deviceId, nodeId);
83 termMap.put(deviceId, new AtomicInteger());
84 backups.add(nodeId);
85 break;
86 default:
87 log.warn("unknown Mastership Role {}", role);
88 return null;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070089 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -070090 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070091
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070092 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070093 }
94
95 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070096 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070097 return masterMap.get(deviceId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070098 }
99
100 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700101 public RoleInfo getNodes(DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700102 List<NodeId> nodes = new ArrayList<>();
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700103 nodes.addAll(backups);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700104
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700105 return new RoleInfo(masterMap.get(deviceId), nodes);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700106 }
107
108 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700109 public Set<DeviceId> getDevices(NodeId nodeId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700110 Set<DeviceId> ids = new HashSet<>();
111 for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) {
112 if (d.getValue().equals(nodeId)) {
113 ids.add(d.getKey());
114 }
115 }
116 return Collections.unmodifiableSet(ids);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700117 }
118
119 @Override
tomb41d1ac2014-09-24 01:51:24 -0700120 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700121 //query+possible reelection
122 NodeId node = instance.id();
123 MastershipRole role = getRole(node, deviceId);
124
125 switch (role) {
126 case MASTER:
127 break;
128 case STANDBY:
129 synchronized (this) {
130 //try to "re-elect", since we're really not distributed
131 NodeId rel = reelect(node);
132 if (rel == null) {
133 masterMap.put(deviceId, node);
134 termMap.put(deviceId, new AtomicInteger());
135 role = MastershipRole.MASTER;
136 }
137 backups.add(node);
138 }
139 break;
140 case NONE:
141 //first to get to it, say we are master
142 synchronized (this) {
143 masterMap.put(deviceId, node);
144 termMap.put(deviceId, new AtomicInteger());
145 backups.add(node);
146 role = MastershipRole.MASTER;
147 }
148 break;
149 default:
150 log.warn("unknown Mastership Role {}", role);
151 }
152 return role;
tomb41d1ac2014-09-24 01:51:24 -0700153 }
154
155 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700156 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700157 //just query
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700158 NodeId current = masterMap.get(deviceId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700159 MastershipRole role;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700160
161 if (current == null) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700162 if (backups.contains(nodeId)) {
163 role = MastershipRole.STANDBY;
164 } else {
165 role = MastershipRole.NONE;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700166 }
167 } else {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700168 if (current.equals(nodeId)) {
169 role = MastershipRole.MASTER;
170 } else {
171 role = MastershipRole.STANDBY;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700172 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700173 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700174 return role;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700175 }
176
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700177 @Override
178 public MastershipTerm getTermFor(DeviceId deviceId) {
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700179 if ((masterMap.get(deviceId) == null) ||
180 (termMap.get(deviceId) == null)) {
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700181 return null;
182 }
183 return MastershipTerm.of(
184 masterMap.get(deviceId), termMap.get(deviceId).get());
185 }
186
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700187 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700188 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700189 MastershipRole role = getRole(nodeId, deviceId);
190 synchronized (this) {
191 switch (role) {
192 case MASTER:
193 NodeId backup = reelect(nodeId);
194 if (backup == null) {
195 masterMap.remove(deviceId);
196 } else {
197 masterMap.put(deviceId, backup);
198 termMap.get(deviceId).incrementAndGet();
199 return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
200 }
201 case STANDBY:
202 case NONE:
203 if (!termMap.containsKey(deviceId)) {
204 termMap.put(deviceId, new AtomicInteger());
205 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700206 backups.add(nodeId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700207 break;
208 default:
209 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700210 }
211 }
212 return null;
213 }
214
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700215 //dumbly selects next-available node that's not the current one
216 //emulate leader election
217 private NodeId reelect(NodeId nodeId) {
218 NodeId backup = null;
219 for (NodeId n : backups) {
220 if (!n.equals(nodeId)) {
221 backup = n;
222 break;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700223 }
224 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700225 return backup;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700226 }
227
Ayaka Koshibec4047702014-10-07 14:43:52 -0700228 @Override
229 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
230 return setStandby(nodeId, deviceId);
231 }
232
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700233}