blob: db7edc5fcc336d61d6ab62e5aa72ab64d3add7b3 [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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.mastership.impl;
tomb41d1ac2014-09-24 01:51:24 -070017
Brian O'Connorabafb502014-12-02 22:26:20 -080018import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED;
19import static org.onosproject.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
HIGUCHI Yuta59f02292015-02-25 19:51:48 -080022import java.util.ArrayList;
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -070023import java.util.HashSet;
HIGUCHI Yuta59f02292015-02-25 19:51:48 -080024import java.util.List;
alshabib339a3d92014-09-26 17:54:32 -070025import java.util.Map;
HIGUCHI Yuta59f02292015-02-25 19:51:48 -080026import java.util.Map.Entry;
alshabib339a3d92014-09-26 17:54:32 -070027import java.util.Set;
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -070028
tomb41d1ac2014-09-24 01:51:24 -070029import 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.Reference;
33import org.apache.felix.scr.annotations.ReferenceCardinality;
34import org.apache.felix.scr.annotations.Service;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.cluster.ClusterService;
36import org.onosproject.cluster.NodeId;
37import org.onosproject.cluster.RoleInfo;
38import org.onosproject.mastership.MastershipEvent;
39import org.onosproject.mastership.MastershipStore;
40import org.onosproject.mastership.MastershipStoreDelegate;
41import org.onosproject.mastership.MastershipTerm;
42import org.onosproject.net.DeviceId;
43import org.onosproject.net.MastershipRole;
44import org.onosproject.store.hz.AbstractHazelcastStore;
45import org.onosproject.store.hz.SMap;
46import org.onosproject.store.serializers.KryoNamespaces;
47import org.onosproject.store.serializers.KryoSerializer;
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070048import org.onlab.util.KryoNamespace;
tomb41d1ac2014-09-24 01:51:24 -070049
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -070050import com.google.common.base.Objects;
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080051import com.hazelcast.config.Config;
52import com.hazelcast.config.MapConfig;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070053import com.hazelcast.core.EntryEvent;
54import com.hazelcast.core.EntryListener;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070055import com.hazelcast.core.MapEvent;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070056
Brian O'Connorabafb502014-12-02 22:26:20 -080057import static org.onosproject.net.MastershipRole.*;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070058
tomb41d1ac2014-09-24 01:51:24 -070059/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070060 * Distributed implementation of the mastership store. The store is
61 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070062 */
63@Component(immediate = true)
64@Service
tom0755a362014-09-24 11:54:43 -070065public class DistributedMastershipStore
Yuta HIGUCHIb0daa152014-11-10 16:58:57 -080066 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
67 implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070068
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070069 //term number representing that master has never been chosen yet
70 private static final Integer NOTHING = 0;
Ayaka Koshibec4047702014-10-07 14:43:52 -070071 //initial term/TTL value
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070072 private static final Integer INIT = 1;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070073
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070074 //device to node roles
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080075 private static final String NODE_ROLES_MAP_NAME = "nodeRoles";
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070076 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070077 //devices to terms
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080078 private static final String TERMS_MAP_NAME = "terms";
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070079 protected SMap<DeviceId, Integer> terms;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070080
tomb41d1ac2014-09-24 01:51:24 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected ClusterService clusterService;
83
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -080084 private String listenerId;
85
Ayaka Koshibe406d0102014-09-24 16:08:12 -070086 @Override
tomb41d1ac2014-09-24 01:51:24 -070087 @Activate
88 public void activate() {
89 super.activate();
90
Ayaka Koshibee8e45352014-10-16 00:37:19 -070091 this.serializer = new KryoSerializer() {
92 @Override
93 protected void setupKryoPool() {
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070094 serializerPool = KryoNamespace.newBuilder()
95 .register(KryoNamespaces.API)
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080096 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
97 .register(new RoleValueSerializer(), RoleValue.class)
98 .build();
Ayaka Koshibee8e45352014-10-16 00:37:19 -070099 }
100 };
101
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -0800102 final Config config = theInstance.getConfig();
103
104 MapConfig nodeRolesCfg = config.getMapConfig(NODE_ROLES_MAP_NAME);
105 nodeRolesCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - nodeRolesCfg.getBackupCount());
106
107 MapConfig termsCfg = config.getMapConfig(TERMS_MAP_NAME);
108 termsCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - termsCfg.getBackupCount());
109
110 roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap(NODE_ROLES_MAP_NAME), this.serializer);
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -0800111 listenerId = roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -0800112 terms = new SMap<>(theInstance.<byte[], byte[]>getMap(TERMS_MAP_NAME), this.serializer);
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -0700113
tomb41d1ac2014-09-24 01:51:24 -0700114 log.info("Started");
115 }
116
117 @Deactivate
118 public void deactivate() {
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -0800119 roleMap.removeEntryListener(listenerId);
tomb41d1ac2014-09-24 01:51:24 -0700120 log.info("Stopped");
121 }
122
123 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700124 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700125 final RoleValue roleInfo = roleMap.get(deviceId);
126 if (roleInfo != null) {
127 return roleInfo.getRole(nodeId);
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700128 }
129 return NONE;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700130 }
131
132 @Override
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700133 public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -0700134
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700135 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700136 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700137 final RoleValue rv = getRoleValue(deviceId);
138 final MastershipRole currentRole = rv.getRole(newMaster);
139 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700140 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700141 //reinforce mastership
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700142 // RoleInfo integrity check
143 boolean modified = rv.reassign(newMaster, STANDBY, NONE);
144 if (modified) {
145 roleMap.put(deviceId, rv);
146 // should never reach here.
147 log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
148 // trigger BACKUPS_CHANGED?
149 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700150 return null;
151 case STANDBY:
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700152 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700153 final NodeId currentMaster = rv.get(MASTER);
154 if (currentMaster != null) {
155 // place current master in STANDBY
156 rv.reassign(currentMaster, NONE, STANDBY);
157 rv.replace(currentMaster, newMaster, MASTER);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700158 } else {
159 //no master before so just add.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700160 rv.add(MASTER, newMaster);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700161 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700162 // remove newMaster from STANDBY
163 rv.reassign(newMaster, STANDBY, NONE);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700164 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700165 roleMap.put(deviceId, rv);
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700166 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700167 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700168 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700169 return null;
170 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700171 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700172 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700173 }
174 }
175
176 @Override
177 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700178 return getNode(MASTER, deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700179 }
180
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700181
182 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700183 public RoleInfo getNodes(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700184 RoleValue rv = roleMap.get(deviceId);
185 if (rv != null) {
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700186 return rv.roleInfo();
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700187 } else {
188 return new RoleInfo();
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700189 }
190 }
191
tomb41d1ac2014-09-24 01:51:24 -0700192 @Override
193 public Set<DeviceId> getDevices(NodeId nodeId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700194 Set<DeviceId> devices = new HashSet<>();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700195
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700196 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
197 if (nodeId.equals(el.getValue().get(MASTER))) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700198 devices.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700199 }
200 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700201
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700202 return devices;
tomb41d1ac2014-09-24 01:51:24 -0700203 }
204
205 @Override
206 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700207
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700208 // if no master => become master
209 // if there already exists a master:
210 // if I was the master return MASTER
211 // else put myself in STANDBY and return STANDBY
212
213 final NodeId local = clusterService.getLocalNode().id();
214 boolean modified = false;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700215 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700216 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700217 final RoleValue rv = getRoleValue(deviceId);
218 if (rv.get(MASTER) == null) {
219 // there's no master become one
220 // move out from STANDBY
221 rv.reassign(local, STANDBY, NONE);
222 rv.add(MASTER, local);
223
224 updateTerm(deviceId);
225 roleMap.put(deviceId, rv);
226 return MASTER;
227 }
228 final MastershipRole currentRole = rv.getRole(local);
229 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700230 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700231 // RoleInfo integrity check
232 modified = rv.reassign(local, STANDBY, NONE);
233 if (modified) {
234 log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId);
235 // should never reach here,
236 // but heal if we happened to be there
237 roleMap.put(deviceId, rv);
238 // trigger BACKUPS_CHANGED?
239 }
240 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700241 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700242 // RoleInfo integrity check
243 modified = rv.reassign(local, NONE, STANDBY);
244 if (modified) {
245 log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
246 // should never reach here,
247 // but heal if we happened to be there
248 roleMap.put(deviceId, rv);
249 // trigger BACKUPS_CHANGED?
250 }
251 return currentRole;
252 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700253 rv.reassign(local, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700254 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700255 // TODO: notifyDelegate BACKUPS_CHANGED
256 return STANDBY;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700257 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700258 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700259 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700260 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700261 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700262 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700263 }
tomb41d1ac2014-09-24 01:51:24 -0700264 }
265
266 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700267 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700268 // term information and role must be read atomically
269 // acquiring write lock for the device
270 roleMap.lock(deviceId);
271 try {
272 RoleValue rv = getRoleValue(deviceId);
273 final Integer term = terms.get(deviceId);
274 final NodeId master = rv.get(MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700275 if (term == null) {
276 return MastershipTerm.of(null, NOTHING);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700277 }
278 return MastershipTerm.of(master, term);
279 } finally {
280 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700281 }
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700282 }
283
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700284 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700285 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700286 // if nodeId was MASTER, rotate STANDBY
287 // if nodeId was STANDBY no-op
288 // if nodeId was NONE, add to STANDBY
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700289
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700290 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700291 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700292 final RoleValue rv = getRoleValue(deviceId);
293 final MastershipRole currentRole = getRole(nodeId, deviceId);
294 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700295 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700296 NodeId newMaster = reelect(nodeId, deviceId, rv);
297 rv.reassign(nodeId, NONE, STANDBY);
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800298 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700299 if (newMaster != null) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700300 roleMap.put(deviceId, rv);
301 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
302 } else {
303 // no master candidate
304 roleMap.put(deviceId, rv);
Yuta HIGUCHI65934892014-12-04 17:47:44 -0800305 // TBD: Should there be new event type for no MASTER?
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800306 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700307 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700308 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700309 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700310 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700311 rv.reassign(nodeId, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700312 roleMap.put(deviceId, rv);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700313 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700314 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700315 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700316 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700317 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700318 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700319 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700320 }
321 }
322
Ayaka Koshibec4047702014-10-07 14:43:52 -0700323 @Override
324 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700325 // relinquishRole is basically set to None
326
327 // If nodeId was master reelect next and remove nodeId
328 // else remove from STANDBY
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700329
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700330 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700331 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700332 final RoleValue rv = getRoleValue(deviceId);
333 final MastershipRole currentRole = rv.getRole(nodeId);
334 switch (currentRole) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700335 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700336 NodeId newMaster = reelect(nodeId, deviceId, rv);
337 if (newMaster != null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700338 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700339 roleMap.put(deviceId, rv);
340 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
341 } else {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700342 // No master candidate - no more backups, device is likely
343 // fully disconnected
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700344 roleMap.put(deviceId, rv);
345 // Should there be new event type?
346 return null;
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700347 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700348 case STANDBY:
349 //fall through to reinforce relinquishment
350 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700351 boolean modified = rv.reassign(nodeId, STANDBY, NONE);
352 if (modified) {
353 roleMap.put(deviceId, rv);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700354 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700355 }
356 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700357 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700358 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700359 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700360 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700361 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700362 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700363 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700364 }
365
HIGUCHI Yuta59f02292015-02-25 19:51:48 -0800366 @Override
367 public void relinquishAllRole(NodeId nodeId) {
368
369 List<MastershipEvent> events = new ArrayList<>();
370 for (Entry<DeviceId, RoleValue> entry : roleMap.entrySet()) {
371 final DeviceId deviceId = entry.getKey();
372 final RoleValue roleValue = entry.getValue();
373
374 if (roleValue.contains(MASTER, nodeId) ||
375 roleValue.contains(STANDBY, nodeId)) {
376
377 MastershipEvent event = relinquishRole(nodeId, deviceId);
378 if (event != null) {
379 events.add(event);
380 }
381 }
382 }
383 notifyDelegate(events);
384 }
385
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700386 // TODO: Consider moving this to RoleValue method
Ayaka Koshibec4047702014-10-07 14:43:52 -0700387 //helper to fetch a new master candidate for a given device.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700388 private NodeId reelect(
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700389 NodeId current, DeviceId deviceId, RoleValue rv) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700390
391 //if this is an queue it'd be neater.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700392 NodeId candidate = null;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700393 for (NodeId n : rv.nodesOfRole(STANDBY)) {
394 if (!current.equals(n)) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700395 candidate = n;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700396 break;
397 }
398 }
399
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700400 if (candidate == null) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700401 log.info("{} giving up and going to NONE for {}", current, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700402 rv.remove(MASTER, current);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700403 // master did change, but there is no master candidate.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700404 return null;
405 } else {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700406 log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
407 rv.replace(current, candidate, MASTER);
408 rv.reassign(candidate, STANDBY, NONE);
409 return candidate;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700410 }
411 }
412
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700413 //return the RoleValue structure for a device, or create one
414 private RoleValue getRoleValue(DeviceId deviceId) {
415 RoleValue value = roleMap.get(deviceId);
416 if (value == null) {
417 value = new RoleValue();
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700418 RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value);
419 if (concurrentlyAdded != null) {
420 return concurrentlyAdded;
421 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700422 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700423 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700424 }
425
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700426 //get first applicable node out of store-unique structure.
427 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
428 RoleValue value = roleMap.get(deviceId);
429 if (value != null) {
430 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700431 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700432 return null;
433 }
434
Ayaka Koshibec4047702014-10-07 14:43:52 -0700435 //adds or updates term information.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700436 // must be guarded by roleMap.lock(deviceId)
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700437 private void updateTerm(DeviceId deviceId) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700438 Integer term = terms.get(deviceId);
439 if (term == null) {
440 term = terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700441 if (term == null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700442 // initial term set successfully
443 return;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700444 }
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700445 // concurrent initialization detected,
446 // fall through to try incrementing
447 }
448 Integer nextTerm = term + 1;
449 boolean success = terms.replace(deviceId, term, nextTerm);
450 while (!success) {
451 term = terms.get(deviceId);
452 if (term == null) {
453 // something is very wrong, but write something to avoid
454 // infinite loop.
455 log.warn("Term info for {} disappeared.", deviceId);
456 term = putIfAbsent(terms, deviceId, nextTerm);
457 }
458 nextTerm = term + 1;
459 success = terms.replace(deviceId, term, nextTerm);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700460 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700461 }
462
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700463 private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> {
alshabib339a3d92014-09-26 17:54:32 -0700464
465 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700466 public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
Yuta HIGUCHIeb5a0b92014-10-29 15:45:55 -0700467 entryUpdated(event);
alshabib339a3d92014-09-26 17:54:32 -0700468 }
469
470 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700471 public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) {
alshabib339a3d92014-09-26 17:54:32 -0700472 }
473
474 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700475 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700476 // compare old and current RoleValues. If master is different,
477 // emit MASTER_CHANGED. else, emit BACKUPS_CHANGED.
478 RoleValue oldValue = event.getOldValue();
479 RoleValue newValue = event.getValue();
480
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800481 // There will be no oldValue at the very first instance of an EntryEvent.
482 // Technically, the progression is: null event -> null master -> some master;
483 // We say a null master and a null oldValue are the same condition.
Yuta HIGUCHI780b1382014-11-03 14:36:39 -0800484 NodeId oldMaster = null;
485 if (oldValue != null) {
486 oldMaster = oldValue.get(MASTER);
487 }
488 NodeId newMaster = newValue.get(MASTER);
489
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800490 if (!Objects.equal(oldMaster, newMaster)) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700491 notifyDelegate(new MastershipEvent(
492 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
493 } else {
494 notifyDelegate(new MastershipEvent(
495 BACKUPS_CHANGED, event.getKey(), event.getValue().roleInfo()));
496 }
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700497 }
498
499 @Override
500 public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) {
501 }
502
503 @Override
504 public void mapEvicted(MapEvent event) {
505 }
506
507 @Override
508 public void mapCleared(MapEvent event) {
alshabib339a3d92014-09-26 17:54:32 -0700509 }
510 }
511
tomb41d1ac2014-09-24 01:51:24 -0700512}