blob: e8096eabaf73383c562378f192a4ed9d672ac632 [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
5import java.util.Collections;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -07006import java.util.HashMap;
Ayaka Koshibe406d0102014-09-24 16:08:12 -07007import java.util.HashSet;
8import java.util.Map;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -07009import java.util.Set;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070010import java.util.concurrent.atomic.AtomicInteger;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070011
12import org.apache.felix.scr.annotations.Activate;
13import org.apache.felix.scr.annotations.Component;
14import org.apache.felix.scr.annotations.Deactivate;
15import org.apache.felix.scr.annotations.Service;
16import org.onlab.onos.cluster.ControllerNode;
17import org.onlab.onos.cluster.DefaultControllerNode;
18import org.onlab.onos.cluster.MastershipEvent;
19import org.onlab.onos.cluster.MastershipStore;
tomf80c9722014-09-24 14:49:18 -070020import org.onlab.onos.cluster.MastershipStoreDelegate;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070021import org.onlab.onos.cluster.MastershipTerm;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070022import org.onlab.onos.cluster.NodeId;
23import org.onlab.onos.net.DeviceId;
24import org.onlab.onos.net.MastershipRole;
tomf80c9722014-09-24 14:49:18 -070025import org.onlab.onos.store.AbstractStore;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070026import org.onlab.packet.IpPrefix;
27import org.slf4j.Logger;
28
29import static org.onlab.onos.cluster.MastershipEvent.Type.*;
30
31/**
32 * Manages inventory of controller mastership over devices using
Ayaka Koshibe406d0102014-09-24 16:08:12 -070033 * trivial, non-distributed in-memory structures implementation.
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070034 */
35@Component(immediate = true)
36@Service
tomf80c9722014-09-24 14:49:18 -070037public class SimpleMastershipStore
38 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
39 implements MastershipStore {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070040
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070041 private final Logger log = getLogger(getClass());
42
Ayaka Koshibe406d0102014-09-24 16:08:12 -070043 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070044
Ayaka Koshibe406d0102014-09-24 16:08:12 -070045 private ControllerNode instance =
46 new DefaultControllerNode(new NodeId("local"), LOCALHOST);
47
48 //devices mapped to their masters, to emulate multiple nodes
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070049 protected final Map<DeviceId, NodeId> masterMap = new HashMap<>();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070050 //emulate backups with pile of nodes
51 protected final Set<NodeId> backups = new HashSet<>();
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070052 //terms
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070053 protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070054
55 @Activate
56 public void activate() {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070057 log.info("Started");
58 }
59
60 @Deactivate
61 public void deactivate() {
62 log.info("Stopped");
63 }
64
65 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070066 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070067 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe406d0102014-09-24 16:08:12 -070068
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070069 synchronized (this) {
70 switch (role) {
71 case MASTER:
72 return null;
73 case STANDBY:
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070074 masterMap.put(deviceId, nodeId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070075 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070076 backups.add(nodeId);
77 break;
78 case NONE:
79 masterMap.put(deviceId, nodeId);
80 termMap.put(deviceId, new AtomicInteger());
81 backups.add(nodeId);
82 break;
83 default:
84 log.warn("unknown Mastership Role {}", role);
85 return null;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070086 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -070087 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070088
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070089 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070090 }
91
92 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070093 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070094 return masterMap.get(deviceId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070095 }
96
97 @Override
98 public Set<DeviceId> getDevices(NodeId nodeId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070099 Set<DeviceId> ids = new HashSet<>();
100 for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) {
101 if (d.getValue().equals(nodeId)) {
102 ids.add(d.getKey());
103 }
104 }
105 return Collections.unmodifiableSet(ids);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700106 }
107
108 @Override
tomb41d1ac2014-09-24 01:51:24 -0700109 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700110 //query+possible reelection
111 NodeId node = instance.id();
112 MastershipRole role = getRole(node, deviceId);
113
114 switch (role) {
115 case MASTER:
116 break;
117 case STANDBY:
118 synchronized (this) {
119 //try to "re-elect", since we're really not distributed
120 NodeId rel = reelect(node);
121 if (rel == null) {
122 masterMap.put(deviceId, node);
123 termMap.put(deviceId, new AtomicInteger());
124 role = MastershipRole.MASTER;
125 }
126 backups.add(node);
127 }
128 break;
129 case NONE:
130 //first to get to it, say we are master
131 synchronized (this) {
132 masterMap.put(deviceId, node);
133 termMap.put(deviceId, new AtomicInteger());
134 backups.add(node);
135 role = MastershipRole.MASTER;
136 }
137 break;
138 default:
139 log.warn("unknown Mastership Role {}", role);
140 }
141 return role;
tomb41d1ac2014-09-24 01:51:24 -0700142 }
143
144 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700145 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700146 //just query
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700147 NodeId current = masterMap.get(deviceId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700148 MastershipRole role;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700149
150 if (current == null) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700151 if (backups.contains(nodeId)) {
152 role = MastershipRole.STANDBY;
153 } else {
154 role = MastershipRole.NONE;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700155 }
156 } else {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700157 if (current.equals(nodeId)) {
158 role = MastershipRole.MASTER;
159 } else {
160 role = MastershipRole.STANDBY;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700161 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700162 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700163 return role;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700164 }
165
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700166 @Override
167 public MastershipTerm getTermFor(DeviceId deviceId) {
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700168 if ((masterMap.get(deviceId) == null) ||
169 (termMap.get(deviceId) == null)) {
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700170 return null;
171 }
172 return MastershipTerm.of(
173 masterMap.get(deviceId), termMap.get(deviceId).get());
174 }
175
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700176 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700177 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700178 MastershipRole role = getRole(nodeId, deviceId);
179 synchronized (this) {
180 switch (role) {
181 case MASTER:
182 NodeId backup = reelect(nodeId);
183 if (backup == null) {
184 masterMap.remove(deviceId);
185 } else {
186 masterMap.put(deviceId, backup);
187 termMap.get(deviceId).incrementAndGet();
188 return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
189 }
190 case STANDBY:
191 case NONE:
192 if (!termMap.containsKey(deviceId)) {
193 termMap.put(deviceId, new AtomicInteger());
194 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700195 backups.add(nodeId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700196 break;
197 default:
198 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700199 }
200 }
201 return null;
202 }
203
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700204 //dumbly selects next-available node that's not the current one
205 //emulate leader election
206 private NodeId reelect(NodeId nodeId) {
207 NodeId backup = null;
208 for (NodeId n : backups) {
209 if (!n.equals(nodeId)) {
210 backup = n;
211 break;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700212 }
213 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700214 return backup;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700215 }
216
Ayaka Koshibec4047702014-10-07 14:43:52 -0700217 @Override
218 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
219 return setStandby(nodeId, deviceId);
220 }
221
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700222}