blob: 0f3639306f0cf8730d74082fce373f7bfb8db956 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
tomea961ff2014-10-01 12:45:15 -070016package org.onlab.onos.store.trivial.impl;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070017
18import static org.slf4j.LoggerFactory.getLogger;
19
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070020import java.util.ArrayList;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070021import java.util.Collections;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070022import java.util.HashMap;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070023import java.util.HashSet;
Ayaka Koshibe45503ce2014-10-14 11:26:45 -070024import java.util.List;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070025import java.util.Map;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070026import java.util.Set;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070027import java.util.concurrent.atomic.AtomicInteger;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070028
29import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
32import org.apache.felix.scr.annotations.Service;
33import org.onlab.onos.cluster.ControllerNode;
34import org.onlab.onos.cluster.DefaultControllerNode;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070035import org.onlab.onos.cluster.NodeId;
Ayaka Koshibeabedb092014-10-20 17:01:31 -070036import org.onlab.onos.cluster.RoleInfo;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070037import org.onlab.onos.mastership.MastershipEvent;
38import org.onlab.onos.mastership.MastershipStore;
39import org.onlab.onos.mastership.MastershipStoreDelegate;
40import org.onlab.onos.mastership.MastershipTerm;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070041import org.onlab.onos.net.DeviceId;
42import org.onlab.onos.net.MastershipRole;
tomf80c9722014-09-24 14:49:18 -070043import org.onlab.onos.store.AbstractStore;
Pavlin Radoslavov444b5192014-10-28 10:45:19 -070044import org.onlab.packet.IpAddress;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070045import org.slf4j.Logger;
46
Ayaka Koshibefc981cf2014-10-21 12:44:17 -070047import com.google.common.collect.Lists;
48
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070049import static org.onlab.onos.mastership.MastershipEvent.Type.*;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070050
51/**
52 * Manages inventory of controller mastership over devices using
Ayaka Koshibe406d0102014-09-24 16:08:12 -070053 * trivial, non-distributed in-memory structures implementation.
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070054 */
55@Component(immediate = true)
56@Service
tomf80c9722014-09-24 14:49:18 -070057public class SimpleMastershipStore
58 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
59 implements MastershipStore {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070060
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070061 private final Logger log = getLogger(getClass());
62
Pavlin Radoslavov444b5192014-10-28 10:45:19 -070063 public static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070064
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070065 private static final int NOTHING = 0;
66 private static final int INIT = 1;
67
Ayaka Koshibe406d0102014-09-24 16:08:12 -070068 private ControllerNode instance =
69 new DefaultControllerNode(new NodeId("local"), LOCALHOST);
70
71 //devices mapped to their masters, to emulate multiple nodes
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070072 protected final Map<DeviceId, NodeId> masterMap = new HashMap<>();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070073 //emulate backups with pile of nodes
74 protected final Set<NodeId> backups = new HashSet<>();
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070075 //terms
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070076 protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070077
78 @Activate
79 public void activate() {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070080 log.info("Started");
81 }
82
83 @Deactivate
84 public void deactivate() {
85 log.info("Stopped");
86 }
87
88 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070089 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070090 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe406d0102014-09-24 16:08:12 -070091
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070092 synchronized (this) {
93 switch (role) {
94 case MASTER:
95 return null;
96 case STANDBY:
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070097 masterMap.put(deviceId, nodeId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070098 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070099 backups.add(nodeId);
100 break;
101 case NONE:
102 masterMap.put(deviceId, nodeId);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700103 termMap.put(deviceId, new AtomicInteger(INIT));
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700104 backups.add(nodeId);
105 break;
106 default:
107 log.warn("unknown Mastership Role {}", role);
108 return null;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700109 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700110 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700111
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700112 return new MastershipEvent(MASTER_CHANGED, deviceId,
113 new RoleInfo(nodeId, Lists.newLinkedList(backups)));
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700114 }
115
116 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700117 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700118 return masterMap.get(deviceId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700119 }
120
121 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700122 public RoleInfo getNodes(DeviceId deviceId) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700123 List<NodeId> nodes = new ArrayList<>();
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700124 nodes.addAll(backups);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700125
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700126 return new RoleInfo(masterMap.get(deviceId), nodes);
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700127 }
128
129 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700130 public Set<DeviceId> getDevices(NodeId nodeId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700131 Set<DeviceId> ids = new HashSet<>();
132 for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) {
133 if (d.getValue().equals(nodeId)) {
134 ids.add(d.getKey());
135 }
136 }
137 return Collections.unmodifiableSet(ids);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700138 }
139
140 @Override
tomb41d1ac2014-09-24 01:51:24 -0700141 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700142 //query+possible reelection
143 NodeId node = instance.id();
144 MastershipRole role = getRole(node, deviceId);
145
146 switch (role) {
147 case MASTER:
148 break;
149 case STANDBY:
150 synchronized (this) {
151 //try to "re-elect", since we're really not distributed
152 NodeId rel = reelect(node);
153 if (rel == null) {
154 masterMap.put(deviceId, node);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700155 termMap.put(deviceId, new AtomicInteger(INIT));
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700156 role = MastershipRole.MASTER;
157 }
158 backups.add(node);
159 }
160 break;
161 case NONE:
162 //first to get to it, say we are master
163 synchronized (this) {
164 masterMap.put(deviceId, node);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700165 termMap.put(deviceId, new AtomicInteger(INIT));
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700166 backups.add(node);
167 role = MastershipRole.MASTER;
168 }
169 break;
170 default:
171 log.warn("unknown Mastership Role {}", role);
172 }
173 return role;
tomb41d1ac2014-09-24 01:51:24 -0700174 }
175
176 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700177 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700178 //just query
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700179 NodeId current = masterMap.get(deviceId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700180 MastershipRole role;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700181
182 if (current == null) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700183 if (backups.contains(nodeId)) {
184 role = MastershipRole.STANDBY;
185 } else {
186 role = MastershipRole.NONE;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700187 }
188 } else {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700189 if (current.equals(nodeId)) {
190 role = MastershipRole.MASTER;
191 } else {
192 role = MastershipRole.STANDBY;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700193 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700194 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700195 return role;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700196 }
197
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700198 @Override
199 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700200 if ((termMap.get(deviceId) == null)) {
201 return MastershipTerm.of(masterMap.get(deviceId), NOTHING);
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700202 }
203 return MastershipTerm.of(
204 masterMap.get(deviceId), termMap.get(deviceId).get());
205 }
206
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700207 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700208 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700209 MastershipRole role = getRole(nodeId, deviceId);
210 synchronized (this) {
211 switch (role) {
212 case MASTER:
213 NodeId backup = reelect(nodeId);
214 if (backup == null) {
215 masterMap.remove(deviceId);
216 } else {
217 masterMap.put(deviceId, backup);
218 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700219 return new MastershipEvent(MASTER_CHANGED, deviceId,
220 new RoleInfo(backup, Lists.newLinkedList(backups)));
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700221 }
222 case STANDBY:
223 case NONE:
224 if (!termMap.containsKey(deviceId)) {
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700225 termMap.put(deviceId, new AtomicInteger(INIT));
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700226 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700227 backups.add(nodeId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700228 break;
229 default:
230 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700231 }
232 }
233 return null;
234 }
235
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700236 //dumbly selects next-available node that's not the current one
237 //emulate leader election
238 private NodeId reelect(NodeId nodeId) {
239 NodeId backup = null;
240 for (NodeId n : backups) {
241 if (!n.equals(nodeId)) {
242 backup = n;
243 break;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700244 }
245 }
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700246 backups.remove(backup);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700247 return backup;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700248 }
249
Ayaka Koshibec4047702014-10-07 14:43:52 -0700250 @Override
251 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700252 MastershipRole role = getRole(nodeId, deviceId);
253 synchronized (this) {
254 switch (role) {
255 case MASTER:
256 NodeId backup = reelect(nodeId);
257 backups.remove(nodeId);
258 if (backup == null) {
259 masterMap.remove(deviceId);
260 } else {
261 masterMap.put(deviceId, backup);
262 termMap.get(deviceId).incrementAndGet();
263 return new MastershipEvent(MASTER_CHANGED, deviceId,
264 new RoleInfo(backup, Lists.newLinkedList(backups)));
265 }
266 case STANDBY:
267 backups.remove(nodeId);
268 case NONE:
269 default:
270 log.warn("unknown Mastership Role {}", role);
271 }
272 }
273 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700274 }
275
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700276}