blob: 0e0b2407916f5b9841335f4091cc414432e31429 [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 */
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070016package org.onlab.onos.store.mastership.impl;
tomb41d1ac2014-09-24 01:51:24 -070017
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070018import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED;
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -070019import static org.apache.commons.lang3.concurrent.ConcurrentUtils.putIfAbsent;
alshabib339a3d92014-09-26 17:54:32 -070020
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -070021import java.util.HashSet;
alshabib339a3d92014-09-26 17:54:32 -070022import java.util.Map;
alshabib339a3d92014-09-26 17:54:32 -070023import java.util.Set;
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070024
tomb41d1ac2014-09-24 01:51:24 -070025import org.apache.felix.scr.annotations.Activate;
26import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.apache.felix.scr.annotations.Service;
31import org.onlab.onos.cluster.ClusterService;
tomb41d1ac2014-09-24 01:51:24 -070032import org.onlab.onos.cluster.NodeId;
Ayaka Koshibeabedb092014-10-20 17:01:31 -070033import org.onlab.onos.cluster.RoleInfo;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070034import org.onlab.onos.mastership.MastershipEvent;
35import org.onlab.onos.mastership.MastershipStore;
36import org.onlab.onos.mastership.MastershipStoreDelegate;
37import org.onlab.onos.mastership.MastershipTerm;
tomb41d1ac2014-09-24 01:51:24 -070038import org.onlab.onos.net.DeviceId;
39import org.onlab.onos.net.MastershipRole;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070040import org.onlab.onos.store.hz.AbstractHazelcastStore;
41import org.onlab.onos.store.hz.SMap;
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070042import org.onlab.onos.store.serializers.KryoNamespaces;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070043import org.onlab.onos.store.serializers.KryoSerializer;
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070044import org.onlab.util.KryoNamespace;
tomb41d1ac2014-09-24 01:51:24 -070045
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070046import com.hazelcast.core.EntryEvent;
47import com.hazelcast.core.EntryListener;
Ayaka Koshibee8e45352014-10-16 00:37:19 -070048import com.hazelcast.core.IAtomicLong;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070049import com.hazelcast.core.MapEvent;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070050
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070051import static org.onlab.onos.net.MastershipRole.*;
52
tomb41d1ac2014-09-24 01:51:24 -070053/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070054 * Distributed implementation of the mastership store. The store is
55 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070056 */
57@Component(immediate = true)
58@Service
tom0755a362014-09-24 11:54:43 -070059public class DistributedMastershipStore
Yuta HIGUCHI2e963892014-09-27 13:00:39 -070060extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
alshabib339a3d92014-09-26 17:54:32 -070061implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070062
Ayaka Koshibec4047702014-10-07 14:43:52 -070063 //initial term/TTL value
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070064 private static final Integer INIT = 0;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070065
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070066 //device to node roles
67 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070068 //devices to terms
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070069 protected SMap<DeviceId, Integer> terms;
Ayaka Koshibee8e45352014-10-16 00:37:19 -070070 //last-known cluster size, used for tie-breaking when partitioning occurs
71 protected IAtomicLong clusterSize;
72
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070073
tomb41d1ac2014-09-24 01:51:24 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected ClusterService clusterService;
76
Ayaka Koshibe406d0102014-09-24 16:08:12 -070077 @Override
tomb41d1ac2014-09-24 01:51:24 -070078 @Activate
79 public void activate() {
80 super.activate();
81
Ayaka Koshibee8e45352014-10-16 00:37:19 -070082 this.serializer = new KryoSerializer() {
83 @Override
84 protected void setupKryoPool() {
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070085 serializerPool = KryoNamespace.newBuilder()
86 .register(KryoNamespaces.API)
Ayaka Koshibee8e45352014-10-16 00:37:19 -070087
88 .register(RoleValue.class, new RoleValueSerializer())
89 .build()
90 .populate(1);
91 }
92 };
93
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070094 roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap("nodeRoles"), this.serializer);
Ayaka Koshibe67af1f42014-10-20 15:26:37 -070095 roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070096 terms = new SMap<>(theInstance.<byte[], byte[]>getMap("terms"), this.serializer);
Ayaka Koshibee8e45352014-10-16 00:37:19 -070097 clusterSize = theInstance.getAtomicLong("clustersize");
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070098
tomb41d1ac2014-09-24 01:51:24 -070099 log.info("Started");
100 }
101
102 @Deactivate
103 public void deactivate() {
104 log.info("Stopped");
105 }
106
107 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700108 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700109 final RoleValue roleInfo = roleMap.get(deviceId);
110 if (roleInfo != null) {
111 return roleInfo.getRole(nodeId);
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700112 }
113 return NONE;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700114 }
115
116 @Override
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700117 public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -0700118
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700119 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700120 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700121 final RoleValue rv = getRoleValue(deviceId);
122 final MastershipRole currentRole = rv.getRole(newMaster);
123 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700124 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700125 //reinforce mastership
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700126 // RoleInfo integrity check
127 boolean modified = rv.reassign(newMaster, STANDBY, NONE);
128 if (modified) {
129 roleMap.put(deviceId, rv);
130 // should never reach here.
131 log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
132 // trigger BACKUPS_CHANGED?
133 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700134 return null;
135 case STANDBY:
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700136 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700137 final NodeId currentMaster = rv.get(MASTER);
138 if (currentMaster != null) {
139 // place current master in STANDBY
140 rv.reassign(currentMaster, NONE, STANDBY);
141 rv.replace(currentMaster, newMaster, MASTER);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700142 } else {
143 //no master before so just add.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700144 rv.add(MASTER, newMaster);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700145 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700146 // remove newMaster from STANDBY
147 rv.reassign(newMaster, STANDBY, NONE);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700148 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700149 roleMap.put(deviceId, rv);
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700150 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700151 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700152 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700153 return null;
154 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700155 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700156 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700157 }
158 }
159
160 @Override
161 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700162 return getNode(MASTER, deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700163 }
164
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700165
166 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700167 public RoleInfo getNodes(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700168 RoleValue rv = roleMap.get(deviceId);
169 if (rv != null) {
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700170 return rv.roleInfo();
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700171 } else {
172 return new RoleInfo();
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700173 }
174 }
175
tomb41d1ac2014-09-24 01:51:24 -0700176 @Override
177 public Set<DeviceId> getDevices(NodeId nodeId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700178 Set<DeviceId> devices = new HashSet<>();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700179
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700180 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
181 if (nodeId.equals(el.getValue().get(MASTER))) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700182 devices.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700183 }
184 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700185
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700186 return devices;
tomb41d1ac2014-09-24 01:51:24 -0700187 }
188
189 @Override
190 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700191
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700192 // if no master => become master
193 // if there already exists a master:
194 // if I was the master return MASTER
195 // else put myself in STANDBY and return STANDBY
196
197 final NodeId local = clusterService.getLocalNode().id();
198 boolean modified = false;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700199 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700200 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700201 final RoleValue rv = getRoleValue(deviceId);
202 if (rv.get(MASTER) == null) {
203 // there's no master become one
204 // move out from STANDBY
205 rv.reassign(local, STANDBY, NONE);
206 rv.add(MASTER, local);
207
208 updateTerm(deviceId);
209 roleMap.put(deviceId, rv);
210 return MASTER;
211 }
212 final MastershipRole currentRole = rv.getRole(local);
213 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700214 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700215 // RoleInfo integrity check
216 modified = rv.reassign(local, STANDBY, NONE);
217 if (modified) {
218 log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId);
219 // should never reach here,
220 // but heal if we happened to be there
221 roleMap.put(deviceId, rv);
222 // trigger BACKUPS_CHANGED?
223 }
224 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700225 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700226 // RoleInfo integrity check
227 modified = rv.reassign(local, NONE, STANDBY);
228 if (modified) {
229 log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
230 // should never reach here,
231 // but heal if we happened to be there
232 roleMap.put(deviceId, rv);
233 // trigger BACKUPS_CHANGED?
234 }
235 return currentRole;
236 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700237 rv.reassign(local, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700238 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700239 // TODO: notifyDelegate BACKUPS_CHANGED
240 return STANDBY;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700241 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700242 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700243 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700244 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700245 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700246 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700247 }
tomb41d1ac2014-09-24 01:51:24 -0700248 }
249
250 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700251 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700252 // term information and role must be read atomically
253 // acquiring write lock for the device
254 roleMap.lock(deviceId);
255 try {
256 RoleValue rv = getRoleValue(deviceId);
257 final Integer term = terms.get(deviceId);
258 final NodeId master = rv.get(MASTER);
259 if ((master == null) || (term == null)) {
260 return null;
261 }
262 return MastershipTerm.of(master, term);
263 } finally {
264 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700265 }
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700266 }
267
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700268 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700269 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700270 // if nodeId was MASTER, rotate STANDBY
271 // if nodeId was STANDBY no-op
272 // if nodeId was NONE, add to STANDBY
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700273
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700274 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700275 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700276 final RoleValue rv = getRoleValue(deviceId);
277 final MastershipRole currentRole = getRole(nodeId, deviceId);
278 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700279 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700280 NodeId newMaster = reelect(nodeId, deviceId, rv);
281 rv.reassign(nodeId, NONE, STANDBY);
282 if (newMaster != null) {
283 updateTerm(deviceId);
284 roleMap.put(deviceId, rv);
285 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
286 } else {
287 // no master candidate
288 roleMap.put(deviceId, rv);
289 // FIXME: Should there be new event type?
290 // or should we issue null Master event?
291 return null;
292 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700293 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700294 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700295 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700296 rv.reassign(nodeId, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700297 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700298 // TODO: BACKUPS_CHANGED?
299 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700300 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700301 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700302 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700303 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700304 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700305 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700306 }
307 }
308
Ayaka Koshibec4047702014-10-07 14:43:52 -0700309 @Override
310 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700311 // relinquishRole is basically set to None
312
313 // If nodeId was master reelect next and remove nodeId
314 // else remove from STANDBY
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700315
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700316 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700317 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700318 final RoleValue rv = getRoleValue(deviceId);
319 final MastershipRole currentRole = rv.getRole(nodeId);
320 switch (currentRole) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700321 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700322 NodeId newMaster = reelect(nodeId, deviceId, rv);
323 if (newMaster != null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700324 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700325 roleMap.put(deviceId, rv);
326 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
327 } else {
328 // no master candidate
329 roleMap.put(deviceId, rv);
330 // Should there be new event type?
331 return null;
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700332 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700333 case STANDBY:
334 //fall through to reinforce relinquishment
335 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700336 boolean modified = rv.reassign(nodeId, STANDBY, NONE);
337 if (modified) {
338 roleMap.put(deviceId, rv);
339 // TODO: BACKUPS_CHANGED?
340 return null;
341 }
342 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700343 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700344 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700345 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700346 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700347 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700348 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700349 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700350 }
351
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700352 // TODO: Consider moving this to RoleValue method
Ayaka Koshibec4047702014-10-07 14:43:52 -0700353 //helper to fetch a new master candidate for a given device.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700354 private NodeId reelect(
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700355 NodeId current, DeviceId deviceId, RoleValue rv) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700356
357 //if this is an queue it'd be neater.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700358 NodeId candidate = null;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700359 for (NodeId n : rv.nodesOfRole(STANDBY)) {
360 if (!current.equals(n)) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700361 candidate = n;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700362 break;
363 }
364 }
365
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700366 if (candidate == null) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700367 log.info("{} giving up and going to NONE for {}", current, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700368 rv.remove(MASTER, current);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700369 // master did change, but there is no master candidate.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700370 return null;
371 } else {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700372 log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
373 rv.replace(current, candidate, MASTER);
374 rv.reassign(candidate, STANDBY, NONE);
375 return candidate;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700376 }
377 }
378
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700379 //return the RoleValue structure for a device, or create one
380 private RoleValue getRoleValue(DeviceId deviceId) {
381 RoleValue value = roleMap.get(deviceId);
382 if (value == null) {
383 value = new RoleValue();
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700384 RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value);
385 if (concurrentlyAdded != null) {
386 return concurrentlyAdded;
387 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700388 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700389 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700390 }
391
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700392 //get first applicable node out of store-unique structure.
393 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
394 RoleValue value = roleMap.get(deviceId);
395 if (value != null) {
396 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700397 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700398 return null;
399 }
400
Ayaka Koshibec4047702014-10-07 14:43:52 -0700401 //adds or updates term information.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700402 // must be guarded by roleMap.lock(deviceId)
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700403 private void updateTerm(DeviceId deviceId) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700404 Integer term = terms.get(deviceId);
405 if (term == null) {
406 term = terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700407 if (term == null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700408 // initial term set successfully
409 return;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700410 }
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700411 // concurrent initialization detected,
412 // fall through to try incrementing
413 }
414 Integer nextTerm = term + 1;
415 boolean success = terms.replace(deviceId, term, nextTerm);
416 while (!success) {
417 term = terms.get(deviceId);
418 if (term == null) {
419 // something is very wrong, but write something to avoid
420 // infinite loop.
421 log.warn("Term info for {} disappeared.", deviceId);
422 term = putIfAbsent(terms, deviceId, nextTerm);
423 }
424 nextTerm = term + 1;
425 success = terms.replace(deviceId, term, nextTerm);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700426 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700427 }
428
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700429 private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> {
alshabib339a3d92014-09-26 17:54:32 -0700430
431 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700432 public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
Yuta HIGUCHIeb5a0b92014-10-29 15:45:55 -0700433 entryUpdated(event);
alshabib339a3d92014-09-26 17:54:32 -0700434 }
435
436 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700437 public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) {
alshabib339a3d92014-09-26 17:54:32 -0700438 }
439
440 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700441 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700442 notifyDelegate(new MastershipEvent(
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700443 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700444 }
445
446 @Override
447 public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) {
448 }
449
450 @Override
451 public void mapEvicted(MapEvent event) {
452 }
453
454 @Override
455 public void mapCleared(MapEvent event) {
alshabib339a3d92014-09-26 17:54:32 -0700456 }
457 }
458
tomb41d1ac2014-09-24 01:51:24 -0700459}