blob: fc89e3a4cf4ef54ad87bba2f0103f80ae990f0a2 [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
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070063 //term number representing that master has never been chosen yet
64 private static final Integer NOTHING = 0;
Ayaka Koshibec4047702014-10-07 14:43:52 -070065 //initial term/TTL value
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070066 private static final Integer INIT = 1;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070067
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070068 //device to node roles
69 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070070 //devices to terms
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070071 protected SMap<DeviceId, Integer> terms;
Ayaka Koshibee8e45352014-10-16 00:37:19 -070072 //last-known cluster size, used for tie-breaking when partitioning occurs
73 protected IAtomicLong clusterSize;
74
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070075
tomb41d1ac2014-09-24 01:51:24 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected ClusterService clusterService;
78
Ayaka Koshibe406d0102014-09-24 16:08:12 -070079 @Override
tomb41d1ac2014-09-24 01:51:24 -070080 @Activate
81 public void activate() {
82 super.activate();
83
Ayaka Koshibee8e45352014-10-16 00:37:19 -070084 this.serializer = new KryoSerializer() {
85 @Override
86 protected void setupKryoPool() {
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070087 serializerPool = KryoNamespace.newBuilder()
88 .register(KryoNamespaces.API)
Ayaka Koshibee8e45352014-10-16 00:37:19 -070089
90 .register(RoleValue.class, new RoleValueSerializer())
91 .build()
92 .populate(1);
93 }
94 };
95
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070096 roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap("nodeRoles"), this.serializer);
Ayaka Koshibe67af1f42014-10-20 15:26:37 -070097 roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070098 terms = new SMap<>(theInstance.<byte[], byte[]>getMap("terms"), this.serializer);
Ayaka Koshibee8e45352014-10-16 00:37:19 -070099 clusterSize = theInstance.getAtomicLong("clustersize");
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -0700100
tomb41d1ac2014-09-24 01:51:24 -0700101 log.info("Started");
102 }
103
104 @Deactivate
105 public void deactivate() {
106 log.info("Stopped");
107 }
108
109 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700110 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700111 final RoleValue roleInfo = roleMap.get(deviceId);
112 if (roleInfo != null) {
113 return roleInfo.getRole(nodeId);
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700114 }
115 return NONE;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700116 }
117
118 @Override
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700119 public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -0700120
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700121 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700122 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700123 final RoleValue rv = getRoleValue(deviceId);
124 final MastershipRole currentRole = rv.getRole(newMaster);
125 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700126 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700127 //reinforce mastership
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700128 // RoleInfo integrity check
129 boolean modified = rv.reassign(newMaster, STANDBY, NONE);
130 if (modified) {
131 roleMap.put(deviceId, rv);
132 // should never reach here.
133 log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
134 // trigger BACKUPS_CHANGED?
135 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700136 return null;
137 case STANDBY:
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700138 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700139 final NodeId currentMaster = rv.get(MASTER);
140 if (currentMaster != null) {
141 // place current master in STANDBY
142 rv.reassign(currentMaster, NONE, STANDBY);
143 rv.replace(currentMaster, newMaster, MASTER);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700144 } else {
145 //no master before so just add.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700146 rv.add(MASTER, newMaster);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700147 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700148 // remove newMaster from STANDBY
149 rv.reassign(newMaster, STANDBY, NONE);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700150 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700151 roleMap.put(deviceId, rv);
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700152 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700153 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700154 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700155 return null;
156 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700157 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700158 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700159 }
160 }
161
162 @Override
163 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700164 return getNode(MASTER, deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700165 }
166
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700167
168 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700169 public RoleInfo getNodes(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700170 RoleValue rv = roleMap.get(deviceId);
171 if (rv != null) {
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700172 return rv.roleInfo();
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700173 } else {
174 return new RoleInfo();
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700175 }
176 }
177
tomb41d1ac2014-09-24 01:51:24 -0700178 @Override
179 public Set<DeviceId> getDevices(NodeId nodeId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700180 Set<DeviceId> devices = new HashSet<>();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700181
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700182 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
183 if (nodeId.equals(el.getValue().get(MASTER))) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700184 devices.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700185 }
186 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700187
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700188 return devices;
tomb41d1ac2014-09-24 01:51:24 -0700189 }
190
191 @Override
192 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700193
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700194 // if no master => become master
195 // if there already exists a master:
196 // if I was the master return MASTER
197 // else put myself in STANDBY and return STANDBY
198
199 final NodeId local = clusterService.getLocalNode().id();
200 boolean modified = false;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700201 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700202 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700203 final RoleValue rv = getRoleValue(deviceId);
204 if (rv.get(MASTER) == null) {
205 // there's no master become one
206 // move out from STANDBY
207 rv.reassign(local, STANDBY, NONE);
208 rv.add(MASTER, local);
209
210 updateTerm(deviceId);
211 roleMap.put(deviceId, rv);
212 return MASTER;
213 }
214 final MastershipRole currentRole = rv.getRole(local);
215 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700216 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700217 // RoleInfo integrity check
218 modified = rv.reassign(local, STANDBY, NONE);
219 if (modified) {
220 log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId);
221 // should never reach here,
222 // but heal if we happened to be there
223 roleMap.put(deviceId, rv);
224 // trigger BACKUPS_CHANGED?
225 }
226 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700227 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700228 // RoleInfo integrity check
229 modified = rv.reassign(local, NONE, STANDBY);
230 if (modified) {
231 log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
232 // should never reach here,
233 // but heal if we happened to be there
234 roleMap.put(deviceId, rv);
235 // trigger BACKUPS_CHANGED?
236 }
237 return currentRole;
238 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700239 rv.reassign(local, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700240 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700241 // TODO: notifyDelegate BACKUPS_CHANGED
242 return STANDBY;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700243 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700244 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700245 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700246 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700247 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700248 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700249 }
tomb41d1ac2014-09-24 01:51:24 -0700250 }
251
252 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700253 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700254 // term information and role must be read atomically
255 // acquiring write lock for the device
256 roleMap.lock(deviceId);
257 try {
258 RoleValue rv = getRoleValue(deviceId);
259 final Integer term = terms.get(deviceId);
260 final NodeId master = rv.get(MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700261 if (term == null) {
262 return MastershipTerm.of(null, NOTHING);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700263 }
264 return MastershipTerm.of(master, term);
265 } finally {
266 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700267 }
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700268 }
269
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700270 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700271 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700272 // if nodeId was MASTER, rotate STANDBY
273 // if nodeId was STANDBY no-op
274 // if nodeId was NONE, add to STANDBY
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700275
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700276 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700277 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700278 final RoleValue rv = getRoleValue(deviceId);
279 final MastershipRole currentRole = getRole(nodeId, deviceId);
280 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700281 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700282 NodeId newMaster = reelect(nodeId, deviceId, rv);
283 rv.reassign(nodeId, NONE, STANDBY);
284 if (newMaster != null) {
285 updateTerm(deviceId);
286 roleMap.put(deviceId, rv);
287 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
288 } else {
289 // no master candidate
290 roleMap.put(deviceId, rv);
291 // FIXME: Should there be new event type?
292 // or should we issue null Master event?
293 return null;
294 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700295 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700296 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700297 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700298 rv.reassign(nodeId, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700299 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700300 // TODO: BACKUPS_CHANGED?
301 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700302 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700303 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700304 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700305 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700306 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700307 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700308 }
309 }
310
Ayaka Koshibec4047702014-10-07 14:43:52 -0700311 @Override
312 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700313 // relinquishRole is basically set to None
314
315 // If nodeId was master reelect next and remove nodeId
316 // else remove from STANDBY
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700317
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700318 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700319 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700320 final RoleValue rv = getRoleValue(deviceId);
321 final MastershipRole currentRole = rv.getRole(nodeId);
322 switch (currentRole) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700323 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700324 NodeId newMaster = reelect(nodeId, deviceId, rv);
325 if (newMaster != null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700326 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700327 roleMap.put(deviceId, rv);
328 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
329 } else {
330 // no master candidate
331 roleMap.put(deviceId, rv);
332 // Should there be new event type?
333 return null;
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700334 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700335 case STANDBY:
336 //fall through to reinforce relinquishment
337 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700338 boolean modified = rv.reassign(nodeId, STANDBY, NONE);
339 if (modified) {
340 roleMap.put(deviceId, rv);
341 // TODO: BACKUPS_CHANGED?
342 return null;
343 }
344 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700345 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700346 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700347 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700348 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700349 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700350 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700351 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700352 }
353
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700354 // TODO: Consider moving this to RoleValue method
Ayaka Koshibec4047702014-10-07 14:43:52 -0700355 //helper to fetch a new master candidate for a given device.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700356 private NodeId reelect(
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700357 NodeId current, DeviceId deviceId, RoleValue rv) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700358
359 //if this is an queue it'd be neater.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700360 NodeId candidate = null;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700361 for (NodeId n : rv.nodesOfRole(STANDBY)) {
362 if (!current.equals(n)) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700363 candidate = n;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700364 break;
365 }
366 }
367
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700368 if (candidate == null) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700369 log.info("{} giving up and going to NONE for {}", current, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700370 rv.remove(MASTER, current);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700371 // master did change, but there is no master candidate.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700372 return null;
373 } else {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700374 log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
375 rv.replace(current, candidate, MASTER);
376 rv.reassign(candidate, STANDBY, NONE);
377 return candidate;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700378 }
379 }
380
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700381 //return the RoleValue structure for a device, or create one
382 private RoleValue getRoleValue(DeviceId deviceId) {
383 RoleValue value = roleMap.get(deviceId);
384 if (value == null) {
385 value = new RoleValue();
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700386 RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value);
387 if (concurrentlyAdded != null) {
388 return concurrentlyAdded;
389 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700390 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700391 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700392 }
393
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700394 //get first applicable node out of store-unique structure.
395 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
396 RoleValue value = roleMap.get(deviceId);
397 if (value != null) {
398 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700399 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700400 return null;
401 }
402
Ayaka Koshibec4047702014-10-07 14:43:52 -0700403 //adds or updates term information.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700404 // must be guarded by roleMap.lock(deviceId)
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700405 private void updateTerm(DeviceId deviceId) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700406 Integer term = terms.get(deviceId);
407 if (term == null) {
408 term = terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700409 if (term == null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700410 // initial term set successfully
411 return;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700412 }
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700413 // concurrent initialization detected,
414 // fall through to try incrementing
415 }
416 Integer nextTerm = term + 1;
417 boolean success = terms.replace(deviceId, term, nextTerm);
418 while (!success) {
419 term = terms.get(deviceId);
420 if (term == null) {
421 // something is very wrong, but write something to avoid
422 // infinite loop.
423 log.warn("Term info for {} disappeared.", deviceId);
424 term = putIfAbsent(terms, deviceId, nextTerm);
425 }
426 nextTerm = term + 1;
427 success = terms.replace(deviceId, term, nextTerm);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700428 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700429 }
430
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700431 private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> {
alshabib339a3d92014-09-26 17:54:32 -0700432
433 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700434 public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
Yuta HIGUCHIeb5a0b92014-10-29 15:45:55 -0700435 entryUpdated(event);
alshabib339a3d92014-09-26 17:54:32 -0700436 }
437
438 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700439 public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) {
alshabib339a3d92014-09-26 17:54:32 -0700440 }
441
442 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700443 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700444 notifyDelegate(new MastershipEvent(
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700445 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700446 }
447
448 @Override
449 public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) {
450 }
451
452 @Override
453 public void mapEvicted(MapEvent event) {
454 }
455
456 @Override
457 public void mapCleared(MapEvent event) {
alshabib339a3d92014-09-26 17:54:32 -0700458 }
459 }
460
tomb41d1ac2014-09-24 01:51:24 -0700461}