blob: 59614daf5ebbf02cb40c6d238a70210c553822d3 [file] [log] [blame]
Ayaka Koshibe16609692014-09-23 12:46:15 -07001package org.onlab.onos.cluster.impl;
2
alshabib339a3d92014-09-26 17:54:32 -07003import static com.google.common.base.Preconditions.checkNotNull;
4import static org.slf4j.LoggerFactory.getLogger;
5
6import java.util.Set;
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -07007import java.util.concurrent.atomic.AtomicInteger;
alshabib339a3d92014-09-26 17:54:32 -07008
Ayaka Koshibe16609692014-09-23 12:46:15 -07009import org.apache.felix.scr.annotations.Activate;
tom4a5d1712014-09-23 17:49:39 -070010import org.apache.felix.scr.annotations.Component;
Ayaka Koshibe16609692014-09-23 12:46:15 -070011import org.apache.felix.scr.annotations.Deactivate;
12import org.apache.felix.scr.annotations.Reference;
13import org.apache.felix.scr.annotations.ReferenceCardinality;
tom4a5d1712014-09-23 17:49:39 -070014import org.apache.felix.scr.annotations.Service;
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070015import org.onlab.onos.cluster.ClusterEvent;
16import org.onlab.onos.cluster.ClusterEventListener;
tom4a5d1712014-09-23 17:49:39 -070017import org.onlab.onos.cluster.ClusterService;
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -070018import org.onlab.onos.cluster.ControllerNode;
Ayaka Koshibe16609692014-09-23 12:46:15 -070019import org.onlab.onos.cluster.NodeId;
20import org.onlab.onos.event.AbstractListenerRegistry;
21import org.onlab.onos.event.EventDeliveryService;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070022import org.onlab.onos.mastership.MastershipAdminService;
23import org.onlab.onos.mastership.MastershipEvent;
24import org.onlab.onos.mastership.MastershipListener;
25import org.onlab.onos.mastership.MastershipService;
26import org.onlab.onos.mastership.MastershipStore;
27import org.onlab.onos.mastership.MastershipStoreDelegate;
28import org.onlab.onos.mastership.MastershipTerm;
29import org.onlab.onos.mastership.MastershipTermService;
Ayaka Koshibe16609692014-09-23 12:46:15 -070030import org.onlab.onos.net.DeviceId;
31import org.onlab.onos.net.MastershipRole;
Ayaka Koshibe16609692014-09-23 12:46:15 -070032import org.slf4j.Logger;
33
tom4a5d1712014-09-23 17:49:39 -070034@Component(immediate = true)
35@Service
Ayaka Koshibe3eed2b02014-09-23 13:28:05 -070036public class MastershipManager
alshabib339a3d92014-09-26 17:54:32 -070037implements MastershipService, MastershipAdminService {
Ayaka Koshibe16609692014-09-23 12:46:15 -070038
39 private static final String NODE_ID_NULL = "Node ID cannot be null";
40 private static final String DEVICE_ID_NULL = "Device ID cannot be null";
41 private static final String ROLE_NULL = "Mastership role cannot be null";
42
43 private final Logger log = getLogger(getClass());
44
45 protected final AbstractListenerRegistry<MastershipEvent, MastershipListener>
alshabib339a3d92014-09-26 17:54:32 -070046 listenerRegistry = new AbstractListenerRegistry<>();
47
48 private final MastershipStoreDelegate delegate = new InternalDelegate();
Ayaka Koshibe16609692014-09-23 12:46:15 -070049
50 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
51 protected MastershipStore store;
52
53 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
54 protected EventDeliveryService eventDispatcher;
55
56 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom4a5d1712014-09-23 17:49:39 -070057 protected ClusterService clusterService;
Ayaka Koshibe16609692014-09-23 12:46:15 -070058
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070059 private ClusterEventListener clusterListener = new InternalClusterEventListener();
60
Ayaka Koshibe16609692014-09-23 12:46:15 -070061 @Activate
62 public void activate() {
63 eventDispatcher.addSink(MastershipEvent.class, listenerRegistry);
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070064 clusterService.addListener(clusterListener);
alshabib339a3d92014-09-26 17:54:32 -070065 store.setDelegate(delegate);
Ayaka Koshibe16609692014-09-23 12:46:15 -070066 log.info("Started");
67 }
68
69 @Deactivate
70 public void deactivate() {
71 eventDispatcher.removeSink(MastershipEvent.class);
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070072 clusterService.removeListener(clusterListener);
alshabib339a3d92014-09-26 17:54:32 -070073 store.unsetDelegate(delegate);
Ayaka Koshibe16609692014-09-23 12:46:15 -070074 log.info("Stopped");
75 }
76
Ayaka Koshibe16609692014-09-23 12:46:15 -070077 @Override
78 public void setRole(NodeId nodeId, DeviceId deviceId, MastershipRole role) {
79 checkNotNull(nodeId, NODE_ID_NULL);
80 checkNotNull(deviceId, DEVICE_ID_NULL);
81 checkNotNull(role, ROLE_NULL);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070082
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070083 MastershipEvent event = null;
84 if (role.equals(MastershipRole.MASTER)) {
85 event = store.setMaster(nodeId, deviceId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070086 } else {
Ayaka Koshibec4047702014-10-07 14:43:52 -070087 event = store.setStandby(nodeId, deviceId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070088 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070089
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070090 if (event != null) {
91 post(event);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070092 }
Ayaka Koshibe16609692014-09-23 12:46:15 -070093 }
94
95 @Override
tomb41d1ac2014-09-24 01:51:24 -070096 public MastershipRole getLocalRole(DeviceId deviceId) {
97 checkNotNull(deviceId, DEVICE_ID_NULL);
98 return store.getRole(clusterService.getLocalNode().id(), deviceId);
99 }
100
101 @Override
102 public void relinquishMastership(DeviceId deviceId) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700103 MastershipEvent event = null;
Ayaka Koshibe1c292d72014-10-08 17:46:07 -0700104 event = store.relinquishRole(
105 clusterService.getLocalNode().id(), deviceId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700106
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700107 if (event != null) {
108 post(event);
109 }
tomb41d1ac2014-09-24 01:51:24 -0700110 }
111
112 @Override
113 public MastershipRole requestRoleFor(DeviceId deviceId) {
114 checkNotNull(deviceId, DEVICE_ID_NULL);
115 return store.requestRole(deviceId);
116 }
117
118 @Override
Ayaka Koshibe16609692014-09-23 12:46:15 -0700119 public NodeId getMasterFor(DeviceId deviceId) {
120 checkNotNull(deviceId, DEVICE_ID_NULL);
121 return store.getMaster(deviceId);
122 }
123
124 @Override
125 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
126 checkNotNull(nodeId, NODE_ID_NULL);
127 return store.getDevices(nodeId);
128 }
129
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700130
131 @Override
132 public MastershipTermService requestTermService() {
133 return new InternalMastershipTermService();
134 }
135
Ayaka Koshibe16609692014-09-23 12:46:15 -0700136 @Override
Ayaka Koshibe16609692014-09-23 12:46:15 -0700137 public void addListener(MastershipListener listener) {
138 checkNotNull(listener);
139 listenerRegistry.addListener(listener);
140 }
141
142 @Override
143 public void removeListener(MastershipListener listener) {
144 checkNotNull(listener);
145 listenerRegistry.removeListener(listener);
146 }
147
tomb41d1ac2014-09-24 01:51:24 -0700148 // FIXME: provide wiring to allow events to be triggered by changes within the store
Ayaka Koshibe16609692014-09-23 12:46:15 -0700149
150 // Posts the specified event to the local event dispatcher.
151 private void post(MastershipEvent event) {
152 if (event != null && eventDispatcher != null) {
153 eventDispatcher.post(event);
154 }
155 }
Ayaka Koshibe3eed2b02014-09-23 13:28:05 -0700156
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700157 private class InternalMastershipTermService implements MastershipTermService {
158
159 @Override
160 public MastershipTerm getMastershipTerm(DeviceId deviceId) {
161 return store.getTermFor(deviceId);
162 }
163
164 }
165
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700166 //callback for reacting to cluster events
167 private class InternalClusterEventListener implements ClusterEventListener {
168
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -0700169 // A notion of a local maximum cluster size, used to tie-break.
170 // Think of a better way to do this.
171 private AtomicInteger clusterSize;
172
173 InternalClusterEventListener() {
174 clusterSize = new AtomicInteger(0);
175 }
176
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700177 @Override
178 public void event(ClusterEvent event) {
179 switch (event.type()) {
180 //FIXME: worry about addition when the time comes
181 case INSTANCE_ADDED:
182 case INSTANCE_ACTIVATED:
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -0700183 clusterSize.incrementAndGet();
184 log.info("instance {} added/activated", event.subject());
185 break;
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700186 case INSTANCE_REMOVED:
187 case INSTANCE_DEACTIVATED:
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -0700188 ControllerNode node = event.subject();
189
190 if (node.equals(clusterService.getLocalNode())) {
191 //If we are in smaller cluster, relinquish and return
192 for (DeviceId device : getDevicesOf(node.id())) {
193 if (!isInMajority()) {
194 //own DeviceManager should catch event and tell switch
195 store.relinquishRole(node.id(), device);
196 }
197 }
198 log.info("broke off from cluster, relinquished devices");
199 break;
200 }
201
202 // if we are the larger one and the removed node(s) are brain dead,
203 // force relinquish on behalf of disabled node.
204 // check network channel to do this?
205 for (DeviceId device : getDevicesOf(node.id())) {
206 //some things to check:
207 // 1. we didn't break off as well while we're at it
208 // 2. others don't pile in and try too - maybe a lock
209 if (isInMajority()) {
210 store.relinquishRole(node.id(), device);
211 }
212 }
213 clusterSize.decrementAndGet();
214 log.info("instance {} removed/deactivated", event.subject());
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700215 break;
216 default:
217 log.warn("unknown cluster event {}", event);
218 }
219 }
220
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -0700221 private boolean isInMajority() {
222 if (clusterService.getNodes().size() > (clusterSize.intValue() / 2)) {
223 return true;
224 }
225 //else {
226 //FIXME: break tie for equal-sized clusters, can we use hz's functions?
227 // }
228 return false;
229 }
230
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700231 }
Ayaka Koshibe65efaef2014-09-29 18:21:56 -0700232
alshabib339a3d92014-09-26 17:54:32 -0700233 public class InternalDelegate implements MastershipStoreDelegate {
234
235 @Override
236 public void notify(MastershipEvent event) {
237 log.info("dispatching mastership event {}", event);
238 eventDispatcher.post(event);
239 }
240
241 }
242
Ayaka Koshibe16609692014-09-23 12:46:15 -0700243}