blob: acae21e57dee3813300ff08a28c950d449bfdf4c [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;
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -070019import static org.onlab.onos.mastership.MastershipEvent.Type.BACKUPS_CHANGED;
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -070020import static org.apache.commons.lang3.concurrent.ConcurrentUtils.putIfAbsent;
alshabib339a3d92014-09-26 17:54:32 -070021
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -070022import java.util.HashSet;
alshabib339a3d92014-09-26 17:54:32 -070023import java.util.Map;
alshabib339a3d92014-09-26 17:54:32 -070024import java.util.Set;
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070025
tomb41d1ac2014-09-24 01:51:24 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
29import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
31import org.apache.felix.scr.annotations.Service;
32import org.onlab.onos.cluster.ClusterService;
tomb41d1ac2014-09-24 01:51:24 -070033import org.onlab.onos.cluster.NodeId;
Ayaka Koshibeabedb092014-10-20 17:01:31 -070034import org.onlab.onos.cluster.RoleInfo;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070035import org.onlab.onos.mastership.MastershipEvent;
36import org.onlab.onos.mastership.MastershipStore;
37import org.onlab.onos.mastership.MastershipStoreDelegate;
38import org.onlab.onos.mastership.MastershipTerm;
tomb41d1ac2014-09-24 01:51:24 -070039import org.onlab.onos.net.DeviceId;
40import org.onlab.onos.net.MastershipRole;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070041import org.onlab.onos.store.hz.AbstractHazelcastStore;
42import org.onlab.onos.store.hz.SMap;
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070043import org.onlab.onos.store.serializers.KryoNamespaces;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070044import org.onlab.onos.store.serializers.KryoSerializer;
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070045import org.onlab.util.KryoNamespace;
tomb41d1ac2014-09-24 01:51:24 -070046
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -070047import com.google.common.base.Objects;
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080048import com.hazelcast.config.Config;
49import com.hazelcast.config.MapConfig;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070050import com.hazelcast.core.EntryEvent;
51import com.hazelcast.core.EntryListener;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070052import com.hazelcast.core.MapEvent;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070053
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070054import static org.onlab.onos.net.MastershipRole.*;
55
tomb41d1ac2014-09-24 01:51:24 -070056/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070057 * Distributed implementation of the mastership store. The store is
58 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070059 */
60@Component(immediate = true)
61@Service
tom0755a362014-09-24 11:54:43 -070062public class DistributedMastershipStore
Yuta HIGUCHIb0daa152014-11-10 16:58:57 -080063 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
64 implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070065
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070066 //term number representing that master has never been chosen yet
67 private static final Integer NOTHING = 0;
Ayaka Koshibec4047702014-10-07 14:43:52 -070068 //initial term/TTL value
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070069 private static final Integer INIT = 1;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070070
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070071 //device to node roles
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080072 private static final String NODE_ROLES_MAP_NAME = "nodeRoles";
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070073 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070074 //devices to terms
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080075 private static final String TERMS_MAP_NAME = "terms";
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070076 protected SMap<DeviceId, Integer> terms;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070077
tomb41d1ac2014-09-24 01:51:24 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected ClusterService clusterService;
80
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -080081 private String listenerId;
82
Ayaka Koshibe406d0102014-09-24 16:08:12 -070083 @Override
tomb41d1ac2014-09-24 01:51:24 -070084 @Activate
85 public void activate() {
86 super.activate();
87
Ayaka Koshibee8e45352014-10-16 00:37:19 -070088 this.serializer = new KryoSerializer() {
89 @Override
90 protected void setupKryoPool() {
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070091 serializerPool = KryoNamespace.newBuilder()
92 .register(KryoNamespaces.API)
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080093 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
94 .register(new RoleValueSerializer(), RoleValue.class)
95 .build();
Ayaka Koshibee8e45352014-10-16 00:37:19 -070096 }
97 };
98
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080099 final Config config = theInstance.getConfig();
100
101 MapConfig nodeRolesCfg = config.getMapConfig(NODE_ROLES_MAP_NAME);
102 nodeRolesCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - nodeRolesCfg.getBackupCount());
103
104 MapConfig termsCfg = config.getMapConfig(TERMS_MAP_NAME);
105 termsCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - termsCfg.getBackupCount());
106
107 roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap(NODE_ROLES_MAP_NAME), this.serializer);
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -0800108 listenerId = roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -0800109 terms = new SMap<>(theInstance.<byte[], byte[]>getMap(TERMS_MAP_NAME), this.serializer);
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -0700110
tomb41d1ac2014-09-24 01:51:24 -0700111 log.info("Started");
112 }
113
114 @Deactivate
115 public void deactivate() {
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -0800116 roleMap.removeEntryListener(listenerId);
tomb41d1ac2014-09-24 01:51:24 -0700117 log.info("Stopped");
118 }
119
120 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700121 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700122 final RoleValue roleInfo = roleMap.get(deviceId);
123 if (roleInfo != null) {
124 return roleInfo.getRole(nodeId);
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700125 }
126 return NONE;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700127 }
128
129 @Override
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700130 public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -0700131
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700132 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700133 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700134 final RoleValue rv = getRoleValue(deviceId);
135 final MastershipRole currentRole = rv.getRole(newMaster);
136 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700137 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700138 //reinforce mastership
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700139 // RoleInfo integrity check
140 boolean modified = rv.reassign(newMaster, STANDBY, NONE);
141 if (modified) {
142 roleMap.put(deviceId, rv);
143 // should never reach here.
144 log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
145 // trigger BACKUPS_CHANGED?
146 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700147 return null;
148 case STANDBY:
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700149 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700150 final NodeId currentMaster = rv.get(MASTER);
151 if (currentMaster != null) {
152 // place current master in STANDBY
153 rv.reassign(currentMaster, NONE, STANDBY);
154 rv.replace(currentMaster, newMaster, MASTER);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700155 } else {
156 //no master before so just add.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700157 rv.add(MASTER, newMaster);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700158 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700159 // remove newMaster from STANDBY
160 rv.reassign(newMaster, STANDBY, NONE);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700161 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700162 roleMap.put(deviceId, rv);
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700163 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700164 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700165 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700166 return null;
167 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700168 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700169 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700170 }
171 }
172
173 @Override
174 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700175 return getNode(MASTER, deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700176 }
177
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700178
179 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700180 public RoleInfo getNodes(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700181 RoleValue rv = roleMap.get(deviceId);
182 if (rv != null) {
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700183 return rv.roleInfo();
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700184 } else {
185 return new RoleInfo();
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700186 }
187 }
188
tomb41d1ac2014-09-24 01:51:24 -0700189 @Override
190 public Set<DeviceId> getDevices(NodeId nodeId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700191 Set<DeviceId> devices = new HashSet<>();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700192
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700193 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
194 if (nodeId.equals(el.getValue().get(MASTER))) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700195 devices.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700196 }
197 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700198
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700199 return devices;
tomb41d1ac2014-09-24 01:51:24 -0700200 }
201
202 @Override
203 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700204
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700205 // if no master => become master
206 // if there already exists a master:
207 // if I was the master return MASTER
208 // else put myself in STANDBY and return STANDBY
209
210 final NodeId local = clusterService.getLocalNode().id();
211 boolean modified = false;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700212 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700213 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700214 final RoleValue rv = getRoleValue(deviceId);
215 if (rv.get(MASTER) == null) {
216 // there's no master become one
217 // move out from STANDBY
218 rv.reassign(local, STANDBY, NONE);
219 rv.add(MASTER, local);
220
221 updateTerm(deviceId);
222 roleMap.put(deviceId, rv);
223 return MASTER;
224 }
225 final MastershipRole currentRole = rv.getRole(local);
226 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700227 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700228 // RoleInfo integrity check
229 modified = rv.reassign(local, STANDBY, NONE);
230 if (modified) {
231 log.warn("{} was in both MASTER 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;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700238 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700239 // RoleInfo integrity check
240 modified = rv.reassign(local, NONE, STANDBY);
241 if (modified) {
242 log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
243 // should never reach here,
244 // but heal if we happened to be there
245 roleMap.put(deviceId, rv);
246 // trigger BACKUPS_CHANGED?
247 }
248 return currentRole;
249 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700250 rv.reassign(local, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700251 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700252 // TODO: notifyDelegate BACKUPS_CHANGED
253 return STANDBY;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700254 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700255 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700256 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700257 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700258 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700259 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700260 }
tomb41d1ac2014-09-24 01:51:24 -0700261 }
262
263 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700264 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700265 // term information and role must be read atomically
266 // acquiring write lock for the device
267 roleMap.lock(deviceId);
268 try {
269 RoleValue rv = getRoleValue(deviceId);
270 final Integer term = terms.get(deviceId);
271 final NodeId master = rv.get(MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700272 if (term == null) {
273 return MastershipTerm.of(null, NOTHING);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700274 }
275 return MastershipTerm.of(master, term);
276 } finally {
277 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700278 }
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700279 }
280
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700281 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700282 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700283 // if nodeId was MASTER, rotate STANDBY
284 // if nodeId was STANDBY no-op
285 // if nodeId was NONE, add to STANDBY
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700286
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700287 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700288 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700289 final RoleValue rv = getRoleValue(deviceId);
290 final MastershipRole currentRole = getRole(nodeId, deviceId);
291 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700292 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700293 NodeId newMaster = reelect(nodeId, deviceId, rv);
294 rv.reassign(nodeId, NONE, STANDBY);
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800295 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700296 if (newMaster != null) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700297 roleMap.put(deviceId, rv);
298 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
299 } else {
300 // no master candidate
301 roleMap.put(deviceId, rv);
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800302 // TODO: Should there be new event type for no MASTER?
303 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700304 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700305 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700306 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700307 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700308 rv.reassign(nodeId, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700309 roleMap.put(deviceId, rv);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700310 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700311 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700312 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700313 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700314 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700315 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700316 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700317 }
318 }
319
Ayaka Koshibec4047702014-10-07 14:43:52 -0700320 @Override
321 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700322 // relinquishRole is basically set to None
323
324 // If nodeId was master reelect next and remove nodeId
325 // else remove from STANDBY
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700326
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700327 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700328 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700329 final RoleValue rv = getRoleValue(deviceId);
330 final MastershipRole currentRole = rv.getRole(nodeId);
331 switch (currentRole) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700332 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700333 NodeId newMaster = reelect(nodeId, deviceId, rv);
334 if (newMaster != null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700335 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700336 roleMap.put(deviceId, rv);
337 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
338 } else {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700339 // No master candidate - no more backups, device is likely
340 // fully disconnected
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700341 roleMap.put(deviceId, rv);
342 // Should there be new event type?
343 return null;
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700344 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700345 case STANDBY:
346 //fall through to reinforce relinquishment
347 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700348 boolean modified = rv.reassign(nodeId, STANDBY, NONE);
349 if (modified) {
350 roleMap.put(deviceId, rv);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700351 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700352 }
353 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700354 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700355 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700356 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700357 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700358 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700359 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700360 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700361 }
362
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700363 // TODO: Consider moving this to RoleValue method
Ayaka Koshibec4047702014-10-07 14:43:52 -0700364 //helper to fetch a new master candidate for a given device.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700365 private NodeId reelect(
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700366 NodeId current, DeviceId deviceId, RoleValue rv) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700367
368 //if this is an queue it'd be neater.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700369 NodeId candidate = null;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700370 for (NodeId n : rv.nodesOfRole(STANDBY)) {
371 if (!current.equals(n)) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700372 candidate = n;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700373 break;
374 }
375 }
376
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700377 if (candidate == null) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700378 log.info("{} giving up and going to NONE for {}", current, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700379 rv.remove(MASTER, current);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700380 // master did change, but there is no master candidate.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700381 return null;
382 } else {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700383 log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
384 rv.replace(current, candidate, MASTER);
385 rv.reassign(candidate, STANDBY, NONE);
386 return candidate;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700387 }
388 }
389
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700390 //return the RoleValue structure for a device, or create one
391 private RoleValue getRoleValue(DeviceId deviceId) {
392 RoleValue value = roleMap.get(deviceId);
393 if (value == null) {
394 value = new RoleValue();
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700395 RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value);
396 if (concurrentlyAdded != null) {
397 return concurrentlyAdded;
398 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700399 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700400 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700401 }
402
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700403 //get first applicable node out of store-unique structure.
404 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
405 RoleValue value = roleMap.get(deviceId);
406 if (value != null) {
407 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700408 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700409 return null;
410 }
411
Ayaka Koshibec4047702014-10-07 14:43:52 -0700412 //adds or updates term information.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700413 // must be guarded by roleMap.lock(deviceId)
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700414 private void updateTerm(DeviceId deviceId) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700415 Integer term = terms.get(deviceId);
416 if (term == null) {
417 term = terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700418 if (term == null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700419 // initial term set successfully
420 return;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700421 }
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700422 // concurrent initialization detected,
423 // fall through to try incrementing
424 }
425 Integer nextTerm = term + 1;
426 boolean success = terms.replace(deviceId, term, nextTerm);
427 while (!success) {
428 term = terms.get(deviceId);
429 if (term == null) {
430 // something is very wrong, but write something to avoid
431 // infinite loop.
432 log.warn("Term info for {} disappeared.", deviceId);
433 term = putIfAbsent(terms, deviceId, nextTerm);
434 }
435 nextTerm = term + 1;
436 success = terms.replace(deviceId, term, nextTerm);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700437 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700438 }
439
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700440 private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> {
alshabib339a3d92014-09-26 17:54:32 -0700441
442 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700443 public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
Yuta HIGUCHIeb5a0b92014-10-29 15:45:55 -0700444 entryUpdated(event);
alshabib339a3d92014-09-26 17:54:32 -0700445 }
446
447 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700448 public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) {
alshabib339a3d92014-09-26 17:54:32 -0700449 }
450
451 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700452 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700453 // compare old and current RoleValues. If master is different,
454 // emit MASTER_CHANGED. else, emit BACKUPS_CHANGED.
455 RoleValue oldValue = event.getOldValue();
456 RoleValue newValue = event.getValue();
457
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800458 // There will be no oldValue at the very first instance of an EntryEvent.
459 // Technically, the progression is: null event -> null master -> some master;
460 // We say a null master and a null oldValue are the same condition.
Yuta HIGUCHI780b1382014-11-03 14:36:39 -0800461 NodeId oldMaster = null;
462 if (oldValue != null) {
463 oldMaster = oldValue.get(MASTER);
464 }
465 NodeId newMaster = newValue.get(MASTER);
466
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800467 if (!Objects.equal(oldMaster, newMaster)) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700468 notifyDelegate(new MastershipEvent(
469 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
470 } else {
471 notifyDelegate(new MastershipEvent(
472 BACKUPS_CHANGED, event.getKey(), event.getValue().roleInfo()));
473 }
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700474 }
475
476 @Override
477 public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) {
478 }
479
480 @Override
481 public void mapEvicted(MapEvent event) {
482 }
483
484 @Override
485 public void mapCleared(MapEvent event) {
alshabib339a3d92014-09-26 17:54:32 -0700486 }
487 }
488
tomb41d1ac2014-09-24 01:51:24 -0700489}