blob: bf15ddc508192dd9386e0264df64f504a30f666d [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;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070048import com.hazelcast.core.EntryEvent;
49import com.hazelcast.core.EntryListener;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070050import com.hazelcast.core.MapEvent;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070051
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070052import static org.onlab.onos.net.MastershipRole.*;
53
tomb41d1ac2014-09-24 01:51:24 -070054/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070055 * Distributed implementation of the mastership store. The store is
56 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070057 */
58@Component(immediate = true)
59@Service
tom0755a362014-09-24 11:54:43 -070060public class DistributedMastershipStore
Yuta HIGUCHIb0daa152014-11-10 16:58:57 -080061 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
62 implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070063
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070064 //term number representing that master has never been chosen yet
65 private static final Integer NOTHING = 0;
Ayaka Koshibec4047702014-10-07 14:43:52 -070066 //initial term/TTL value
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070067 private static final Integer INIT = 1;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070068
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070069 //device to node roles
70 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070071 //devices to terms
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070072 protected SMap<DeviceId, Integer> terms;
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
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -080077 private String listenerId;
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)
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080089 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
90 .register(new RoleValueSerializer(), RoleValue.class)
91 .build();
Ayaka Koshibee8e45352014-10-16 00:37:19 -070092 }
93 };
94
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070095 roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap("nodeRoles"), this.serializer);
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -080096 listenerId = roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070097 terms = new SMap<>(theInstance.<byte[], byte[]>getMap("terms"), this.serializer);
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() {
Yuta HIGUCHId1a63e92014-12-02 13:14:28 -0800104 roleMap.removeEntryListener(listenerId);
tomb41d1ac2014-09-24 01:51:24 -0700105 log.info("Stopped");
106 }
107
108 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700109 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700110 final RoleValue roleInfo = roleMap.get(deviceId);
111 if (roleInfo != null) {
112 return roleInfo.getRole(nodeId);
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700113 }
114 return NONE;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700115 }
116
117 @Override
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700118 public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -0700119
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700120 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700121 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700122 final RoleValue rv = getRoleValue(deviceId);
123 final MastershipRole currentRole = rv.getRole(newMaster);
124 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700125 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700126 //reinforce mastership
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700127 // RoleInfo integrity check
128 boolean modified = rv.reassign(newMaster, STANDBY, NONE);
129 if (modified) {
130 roleMap.put(deviceId, rv);
131 // should never reach here.
132 log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
133 // trigger BACKUPS_CHANGED?
134 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700135 return null;
136 case STANDBY:
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700137 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700138 final NodeId currentMaster = rv.get(MASTER);
139 if (currentMaster != null) {
140 // place current master in STANDBY
141 rv.reassign(currentMaster, NONE, STANDBY);
142 rv.replace(currentMaster, newMaster, MASTER);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700143 } else {
144 //no master before so just add.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700145 rv.add(MASTER, newMaster);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700146 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700147 // remove newMaster from STANDBY
148 rv.reassign(newMaster, STANDBY, NONE);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700149 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700150 roleMap.put(deviceId, rv);
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700151 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700152 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700153 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700154 return null;
155 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700156 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700157 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700158 }
159 }
160
161 @Override
162 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700163 return getNode(MASTER, deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700164 }
165
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700166
167 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700168 public RoleInfo getNodes(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700169 RoleValue rv = roleMap.get(deviceId);
170 if (rv != null) {
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700171 return rv.roleInfo();
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700172 } else {
173 return new RoleInfo();
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700174 }
175 }
176
tomb41d1ac2014-09-24 01:51:24 -0700177 @Override
178 public Set<DeviceId> getDevices(NodeId nodeId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700179 Set<DeviceId> devices = new HashSet<>();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700180
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700181 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
182 if (nodeId.equals(el.getValue().get(MASTER))) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700183 devices.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700184 }
185 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700186
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700187 return devices;
tomb41d1ac2014-09-24 01:51:24 -0700188 }
189
190 @Override
191 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700192
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700193 // if no master => become master
194 // if there already exists a master:
195 // if I was the master return MASTER
196 // else put myself in STANDBY and return STANDBY
197
198 final NodeId local = clusterService.getLocalNode().id();
199 boolean modified = false;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700200 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700201 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700202 final RoleValue rv = getRoleValue(deviceId);
203 if (rv.get(MASTER) == null) {
204 // there's no master become one
205 // move out from STANDBY
206 rv.reassign(local, STANDBY, NONE);
207 rv.add(MASTER, local);
208
209 updateTerm(deviceId);
210 roleMap.put(deviceId, rv);
211 return MASTER;
212 }
213 final MastershipRole currentRole = rv.getRole(local);
214 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700215 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700216 // RoleInfo integrity check
217 modified = rv.reassign(local, STANDBY, NONE);
218 if (modified) {
219 log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId);
220 // should never reach here,
221 // but heal if we happened to be there
222 roleMap.put(deviceId, rv);
223 // trigger BACKUPS_CHANGED?
224 }
225 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700226 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700227 // RoleInfo integrity check
228 modified = rv.reassign(local, NONE, STANDBY);
229 if (modified) {
230 log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
231 // should never reach here,
232 // but heal if we happened to be there
233 roleMap.put(deviceId, rv);
234 // trigger BACKUPS_CHANGED?
235 }
236 return currentRole;
237 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700238 rv.reassign(local, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700239 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700240 // TODO: notifyDelegate BACKUPS_CHANGED
241 return STANDBY;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700242 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700243 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700244 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700245 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700246 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700247 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700248 }
tomb41d1ac2014-09-24 01:51:24 -0700249 }
250
251 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700252 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700253 // term information and role must be read atomically
254 // acquiring write lock for the device
255 roleMap.lock(deviceId);
256 try {
257 RoleValue rv = getRoleValue(deviceId);
258 final Integer term = terms.get(deviceId);
259 final NodeId master = rv.get(MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700260 if (term == null) {
261 return MastershipTerm.of(null, NOTHING);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700262 }
263 return MastershipTerm.of(master, term);
264 } finally {
265 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700266 }
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700267 }
268
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700269 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700270 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700271 // if nodeId was MASTER, rotate STANDBY
272 // if nodeId was STANDBY no-op
273 // if nodeId was NONE, add to STANDBY
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700274
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700275 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700276 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700277 final RoleValue rv = getRoleValue(deviceId);
278 final MastershipRole currentRole = getRole(nodeId, deviceId);
279 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700280 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700281 NodeId newMaster = reelect(nodeId, deviceId, rv);
282 rv.reassign(nodeId, NONE, STANDBY);
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800283 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700284 if (newMaster != null) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700285 roleMap.put(deviceId, rv);
286 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
287 } else {
288 // no master candidate
289 roleMap.put(deviceId, rv);
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800290 // TODO: Should there be new event type for no MASTER?
291 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700292 }
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);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700298 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700299 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700300 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700301 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700302 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700303 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700304 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700305 }
306 }
307
Ayaka Koshibec4047702014-10-07 14:43:52 -0700308 @Override
309 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700310 // relinquishRole is basically set to None
311
312 // If nodeId was master reelect next and remove nodeId
313 // else remove from STANDBY
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700314
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700315 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700316 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700317 final RoleValue rv = getRoleValue(deviceId);
318 final MastershipRole currentRole = rv.getRole(nodeId);
319 switch (currentRole) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700320 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700321 NodeId newMaster = reelect(nodeId, deviceId, rv);
322 if (newMaster != null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700323 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700324 roleMap.put(deviceId, rv);
325 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
326 } else {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700327 // No master candidate - no more backups, device is likely
328 // fully disconnected
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700329 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);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700339 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700340 }
341 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700342 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700343 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700344 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700345 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700346 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700347 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700348 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700349 }
350
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700351 // TODO: Consider moving this to RoleValue method
Ayaka Koshibec4047702014-10-07 14:43:52 -0700352 //helper to fetch a new master candidate for a given device.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700353 private NodeId reelect(
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700354 NodeId current, DeviceId deviceId, RoleValue rv) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700355
356 //if this is an queue it'd be neater.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700357 NodeId candidate = null;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700358 for (NodeId n : rv.nodesOfRole(STANDBY)) {
359 if (!current.equals(n)) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700360 candidate = n;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700361 break;
362 }
363 }
364
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700365 if (candidate == null) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700366 log.info("{} giving up and going to NONE for {}", current, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700367 rv.remove(MASTER, current);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700368 // master did change, but there is no master candidate.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700369 return null;
370 } else {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700371 log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
372 rv.replace(current, candidate, MASTER);
373 rv.reassign(candidate, STANDBY, NONE);
374 return candidate;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700375 }
376 }
377
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700378 //return the RoleValue structure for a device, or create one
379 private RoleValue getRoleValue(DeviceId deviceId) {
380 RoleValue value = roleMap.get(deviceId);
381 if (value == null) {
382 value = new RoleValue();
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700383 RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value);
384 if (concurrentlyAdded != null) {
385 return concurrentlyAdded;
386 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700387 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700388 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700389 }
390
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700391 //get first applicable node out of store-unique structure.
392 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
393 RoleValue value = roleMap.get(deviceId);
394 if (value != null) {
395 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700396 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700397 return null;
398 }
399
Ayaka Koshibec4047702014-10-07 14:43:52 -0700400 //adds or updates term information.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700401 // must be guarded by roleMap.lock(deviceId)
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700402 private void updateTerm(DeviceId deviceId) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700403 Integer term = terms.get(deviceId);
404 if (term == null) {
405 term = terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700406 if (term == null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700407 // initial term set successfully
408 return;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700409 }
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700410 // concurrent initialization detected,
411 // fall through to try incrementing
412 }
413 Integer nextTerm = term + 1;
414 boolean success = terms.replace(deviceId, term, nextTerm);
415 while (!success) {
416 term = terms.get(deviceId);
417 if (term == null) {
418 // something is very wrong, but write something to avoid
419 // infinite loop.
420 log.warn("Term info for {} disappeared.", deviceId);
421 term = putIfAbsent(terms, deviceId, nextTerm);
422 }
423 nextTerm = term + 1;
424 success = terms.replace(deviceId, term, nextTerm);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700425 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700426 }
427
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700428 private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> {
alshabib339a3d92014-09-26 17:54:32 -0700429
430 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700431 public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
Yuta HIGUCHIeb5a0b92014-10-29 15:45:55 -0700432 entryUpdated(event);
alshabib339a3d92014-09-26 17:54:32 -0700433 }
434
435 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700436 public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) {
alshabib339a3d92014-09-26 17:54:32 -0700437 }
438
439 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700440 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700441 // compare old and current RoleValues. If master is different,
442 // emit MASTER_CHANGED. else, emit BACKUPS_CHANGED.
443 RoleValue oldValue = event.getOldValue();
444 RoleValue newValue = event.getValue();
445
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800446 // There will be no oldValue at the very first instance of an EntryEvent.
447 // Technically, the progression is: null event -> null master -> some master;
448 // We say a null master and a null oldValue are the same condition.
Yuta HIGUCHI780b1382014-11-03 14:36:39 -0800449 NodeId oldMaster = null;
450 if (oldValue != null) {
451 oldMaster = oldValue.get(MASTER);
452 }
453 NodeId newMaster = newValue.get(MASTER);
454
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800455 if (!Objects.equal(oldMaster, newMaster)) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700456 notifyDelegate(new MastershipEvent(
457 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
458 } else {
459 notifyDelegate(new MastershipEvent(
460 BACKUPS_CHANGED, event.getKey(), event.getValue().roleInfo()));
461 }
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700462 }
463
464 @Override
465 public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) {
466 }
467
468 @Override
469 public void mapEvicted(MapEvent event) {
470 }
471
472 @Override
473 public void mapCleared(MapEvent event) {
alshabib339a3d92014-09-26 17:54:32 -0700474 }
475 }
476
tomb41d1ac2014-09-24 01:51:24 -0700477}