blob: 42e07997c354682575b52ebf51bb71b9c300a2ec [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 Koshibee8e45352014-10-16 00:37:19 -070050import com.hazelcast.core.IAtomicLong;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -070051import com.hazelcast.core.MapEvent;
Yuta HIGUCHI41f2ec02014-10-27 09:54:43 -070052
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070053import static org.onlab.onos.net.MastershipRole.*;
54
tomb41d1ac2014-09-24 01:51:24 -070055/**
Ayaka Koshibec4047702014-10-07 14:43:52 -070056 * Distributed implementation of the mastership store. The store is
57 * responsible for the master selection process.
tomb41d1ac2014-09-24 01:51:24 -070058 */
59@Component(immediate = true)
60@Service
tom0755a362014-09-24 11:54:43 -070061public class DistributedMastershipStore
Yuta HIGUCHI2e963892014-09-27 13:00:39 -070062extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
alshabib339a3d92014-09-26 17:54:32 -070063implements MastershipStore {
tomb41d1ac2014-09-24 01:51:24 -070064
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070065 //term number representing that master has never been chosen yet
66 private static final Integer NOTHING = 0;
Ayaka Koshibec4047702014-10-07 14:43:52 -070067 //initial term/TTL value
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -070068 private static final Integer INIT = 1;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070069
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070070 //device to node roles
71 protected SMap<DeviceId, RoleValue> roleMap;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070072 //devices to terms
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070073 protected SMap<DeviceId, Integer> terms;
Ayaka Koshibee8e45352014-10-16 00:37:19 -070074 //last-known cluster size, used for tie-breaking when partitioning occurs
75 protected IAtomicLong clusterSize;
76
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
Ayaka Koshibe406d0102014-09-24 16:08:12 -070081 @Override
tomb41d1ac2014-09-24 01:51:24 -070082 @Activate
83 public void activate() {
84 super.activate();
85
Ayaka Koshibee8e45352014-10-16 00:37:19 -070086 this.serializer = new KryoSerializer() {
87 @Override
88 protected void setupKryoPool() {
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070089 serializerPool = KryoNamespace.newBuilder()
90 .register(KryoNamespaces.API)
Ayaka Koshibee8e45352014-10-16 00:37:19 -070091
92 .register(RoleValue.class, new RoleValueSerializer())
93 .build()
94 .populate(1);
95 }
96 };
97
Yuta HIGUCHI9def0472014-10-23 15:51:10 -070098 roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap("nodeRoles"), this.serializer);
Ayaka Koshibe67af1f42014-10-20 15:26:37 -070099 roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
Yuta HIGUCHI9def0472014-10-23 15:51:10 -0700100 terms = new SMap<>(theInstance.<byte[], byte[]>getMap("terms"), this.serializer);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700101 clusterSize = theInstance.getAtomicLong("clustersize");
Yuta HIGUCHIc8e19d42014-09-24 17:20:52 -0700102
tomb41d1ac2014-09-24 01:51:24 -0700103 log.info("Started");
104 }
105
106 @Deactivate
107 public void deactivate() {
108 log.info("Stopped");
109 }
110
111 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700112 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700113 final RoleValue roleInfo = roleMap.get(deviceId);
114 if (roleInfo != null) {
115 return roleInfo.getRole(nodeId);
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700116 }
117 return NONE;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700118 }
119
120 @Override
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700121 public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
tomb41d1ac2014-09-24 01:51:24 -0700122
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700123 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700124 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700125 final RoleValue rv = getRoleValue(deviceId);
126 final MastershipRole currentRole = rv.getRole(newMaster);
127 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700128 case MASTER:
Ayaka Koshibec4047702014-10-07 14:43:52 -0700129 //reinforce mastership
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700130 // RoleInfo integrity check
131 boolean modified = rv.reassign(newMaster, STANDBY, NONE);
132 if (modified) {
133 roleMap.put(deviceId, rv);
134 // should never reach here.
135 log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
136 // trigger BACKUPS_CHANGED?
137 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700138 return null;
139 case STANDBY:
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700140 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700141 final NodeId currentMaster = rv.get(MASTER);
142 if (currentMaster != null) {
143 // place current master in STANDBY
144 rv.reassign(currentMaster, NONE, STANDBY);
145 rv.replace(currentMaster, newMaster, MASTER);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700146 } else {
147 //no master before so just add.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700148 rv.add(MASTER, newMaster);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700149 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700150 // remove newMaster from STANDBY
151 rv.reassign(newMaster, STANDBY, NONE);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700152 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700153 roleMap.put(deviceId, rv);
Ayaka Koshibefc981cf2014-10-21 12:44:17 -0700154 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700155 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700156 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700157 return null;
158 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700159 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700160 roleMap.unlock(deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700161 }
162 }
163
164 @Override
165 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700166 return getNode(MASTER, deviceId);
tomb41d1ac2014-09-24 01:51:24 -0700167 }
168
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700169
170 @Override
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700171 public RoleInfo getNodes(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700172 RoleValue rv = roleMap.get(deviceId);
173 if (rv != null) {
Ayaka Koshibeabedb092014-10-20 17:01:31 -0700174 return rv.roleInfo();
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700175 } else {
176 return new RoleInfo();
Ayaka Koshibe45503ce2014-10-14 11:26:45 -0700177 }
178 }
179
tomb41d1ac2014-09-24 01:51:24 -0700180 @Override
181 public Set<DeviceId> getDevices(NodeId nodeId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700182 Set<DeviceId> devices = new HashSet<>();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700183
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700184 for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
185 if (nodeId.equals(el.getValue().get(MASTER))) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700186 devices.add(el.getKey());
tomb41d1ac2014-09-24 01:51:24 -0700187 }
188 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700189
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700190 return devices;
tomb41d1ac2014-09-24 01:51:24 -0700191 }
192
193 @Override
194 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700195
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700196 // if no master => become master
197 // if there already exists a master:
198 // if I was the master return MASTER
199 // else put myself in STANDBY and return STANDBY
200
201 final NodeId local = clusterService.getLocalNode().id();
202 boolean modified = false;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700203 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700204 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700205 final RoleValue rv = getRoleValue(deviceId);
206 if (rv.get(MASTER) == null) {
207 // there's no master become one
208 // move out from STANDBY
209 rv.reassign(local, STANDBY, NONE);
210 rv.add(MASTER, local);
211
212 updateTerm(deviceId);
213 roleMap.put(deviceId, rv);
214 return MASTER;
215 }
216 final MastershipRole currentRole = rv.getRole(local);
217 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700218 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700219 // RoleInfo integrity check
220 modified = rv.reassign(local, STANDBY, NONE);
221 if (modified) {
222 log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId);
223 // should never reach here,
224 // but heal if we happened to be there
225 roleMap.put(deviceId, rv);
226 // trigger BACKUPS_CHANGED?
227 }
228 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700229 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700230 // RoleInfo integrity check
231 modified = rv.reassign(local, NONE, STANDBY);
232 if (modified) {
233 log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
234 // should never reach here,
235 // but heal if we happened to be there
236 roleMap.put(deviceId, rv);
237 // trigger BACKUPS_CHANGED?
238 }
239 return currentRole;
240 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700241 rv.reassign(local, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700242 roleMap.put(deviceId, rv);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700243 // TODO: notifyDelegate BACKUPS_CHANGED
244 return STANDBY;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700245 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700246 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700247 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700248 return currentRole;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700249 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700250 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700251 }
tomb41d1ac2014-09-24 01:51:24 -0700252 }
253
254 @Override
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700255 public MastershipTerm getTermFor(DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700256 // term information and role must be read atomically
257 // acquiring write lock for the device
258 roleMap.lock(deviceId);
259 try {
260 RoleValue rv = getRoleValue(deviceId);
261 final Integer term = terms.get(deviceId);
262 final NodeId master = rv.get(MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700263 if (term == null) {
264 return MastershipTerm.of(null, NOTHING);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700265 }
266 return MastershipTerm.of(master, term);
267 } finally {
268 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700269 }
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700270 }
271
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700272 @Override
Ayaka Koshibec4047702014-10-07 14:43:52 -0700273 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700274 // if nodeId was MASTER, rotate STANDBY
275 // if nodeId was STANDBY no-op
276 // if nodeId was NONE, add to STANDBY
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700277
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700278 roleMap.lock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700279 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700280 final RoleValue rv = getRoleValue(deviceId);
281 final MastershipRole currentRole = getRole(nodeId, deviceId);
282 switch (currentRole) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700283 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700284 NodeId newMaster = reelect(nodeId, deviceId, rv);
285 rv.reassign(nodeId, NONE, STANDBY);
286 if (newMaster != null) {
287 updateTerm(deviceId);
288 roleMap.put(deviceId, rv);
289 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
290 } else {
291 // no master candidate
292 roleMap.put(deviceId, rv);
293 // FIXME: Should there be new event type?
294 // or should we issue null Master event?
295 return null;
296 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700297 case STANDBY:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700298 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700299 case NONE:
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700300 rv.reassign(nodeId, NONE, STANDBY);
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700301 roleMap.put(deviceId, rv);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700302 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700303 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700304 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700305 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700306 return null;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700307 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700308 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700309 }
310 }
311
Ayaka Koshibec4047702014-10-07 14:43:52 -0700312 @Override
313 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700314 // relinquishRole is basically set to None
315
316 // If nodeId was master reelect next and remove nodeId
317 // else remove from STANDBY
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700318
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700319 roleMap.lock(deviceId);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700320 try {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700321 final RoleValue rv = getRoleValue(deviceId);
322 final MastershipRole currentRole = rv.getRole(nodeId);
323 switch (currentRole) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700324 case MASTER:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700325 NodeId newMaster = reelect(nodeId, deviceId, rv);
326 if (newMaster != null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700327 updateTerm(deviceId);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700328 roleMap.put(deviceId, rv);
329 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
330 } else {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700331 // No master candidate - no more backups, device is likely
332 // fully disconnected
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700333 roleMap.put(deviceId, rv);
334 // Should there be new event type?
335 return null;
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700336 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700337 case STANDBY:
338 //fall through to reinforce relinquishment
339 case NONE:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700340 boolean modified = rv.reassign(nodeId, STANDBY, NONE);
341 if (modified) {
342 roleMap.put(deviceId, rv);
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700343 return new MastershipEvent(BACKUPS_CHANGED, deviceId, rv.roleInfo());
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700344 }
345 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700346 default:
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700347 log.warn("unknown Mastership Role {}", currentRole);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700348 }
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700349 return null;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700350 } finally {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700351 roleMap.unlock(deviceId);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700352 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700353 }
354
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700355 // TODO: Consider moving this to RoleValue method
Ayaka Koshibec4047702014-10-07 14:43:52 -0700356 //helper to fetch a new master candidate for a given device.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700357 private NodeId reelect(
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700358 NodeId current, DeviceId deviceId, RoleValue rv) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700359
360 //if this is an queue it'd be neater.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700361 NodeId candidate = null;
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700362 for (NodeId n : rv.nodesOfRole(STANDBY)) {
363 if (!current.equals(n)) {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700364 candidate = n;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700365 break;
366 }
367 }
368
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700369 if (candidate == null) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700370 log.info("{} giving up and going to NONE for {}", current, deviceId);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700371 rv.remove(MASTER, current);
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700372 // master did change, but there is no master candidate.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700373 return null;
374 } else {
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700375 log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
376 rv.replace(current, candidate, MASTER);
377 rv.reassign(candidate, STANDBY, NONE);
378 return candidate;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700379 }
380 }
381
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700382 //return the RoleValue structure for a device, or create one
383 private RoleValue getRoleValue(DeviceId deviceId) {
384 RoleValue value = roleMap.get(deviceId);
385 if (value == null) {
386 value = new RoleValue();
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700387 RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value);
388 if (concurrentlyAdded != null) {
389 return concurrentlyAdded;
390 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700391 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700392 return value;
Ayaka Koshibec4047702014-10-07 14:43:52 -0700393 }
394
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700395 //get first applicable node out of store-unique structure.
396 private NodeId getNode(MastershipRole role, DeviceId deviceId) {
397 RoleValue value = roleMap.get(deviceId);
398 if (value != null) {
399 return value.get(role);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700400 }
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700401 return null;
402 }
403
Ayaka Koshibec4047702014-10-07 14:43:52 -0700404 //adds or updates term information.
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700405 // must be guarded by roleMap.lock(deviceId)
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700406 private void updateTerm(DeviceId deviceId) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700407 Integer term = terms.get(deviceId);
408 if (term == null) {
409 term = terms.putIfAbsent(deviceId, INIT);
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700410 if (term == null) {
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700411 // initial term set successfully
412 return;
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700413 }
Yuta HIGUCHIf1d159a2014-10-29 23:31:40 -0700414 // concurrent initialization detected,
415 // fall through to try incrementing
416 }
417 Integer nextTerm = term + 1;
418 boolean success = terms.replace(deviceId, term, nextTerm);
419 while (!success) {
420 term = terms.get(deviceId);
421 if (term == null) {
422 // something is very wrong, but write something to avoid
423 // infinite loop.
424 log.warn("Term info for {} disappeared.", deviceId);
425 term = putIfAbsent(terms, deviceId, nextTerm);
426 }
427 nextTerm = term + 1;
428 success = terms.replace(deviceId, term, nextTerm);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700429 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700430 }
431
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700432 private class RemoteMasterShipEventHandler implements EntryListener<DeviceId, RoleValue> {
alshabib339a3d92014-09-26 17:54:32 -0700433
434 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700435 public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
Yuta HIGUCHIeb5a0b92014-10-29 15:45:55 -0700436 entryUpdated(event);
alshabib339a3d92014-09-26 17:54:32 -0700437 }
438
439 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700440 public void entryRemoved(EntryEvent<DeviceId, RoleValue> event) {
alshabib339a3d92014-09-26 17:54:32 -0700441 }
442
443 @Override
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700444 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700445 // compare old and current RoleValues. If master is different,
446 // emit MASTER_CHANGED. else, emit BACKUPS_CHANGED.
447 RoleValue oldValue = event.getOldValue();
448 RoleValue newValue = event.getValue();
449
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800450 // There will be no oldValue at the very first instance of an EntryEvent.
451 // Technically, the progression is: null event -> null master -> some master;
452 // We say a null master and a null oldValue are the same condition.
Yuta HIGUCHI780b1382014-11-03 14:36:39 -0800453 NodeId oldMaster = null;
454 if (oldValue != null) {
455 oldMaster = oldValue.get(MASTER);
456 }
457 NodeId newMaster = newValue.get(MASTER);
458
Ayaka Koshibe15f4d602014-11-03 16:26:27 -0800459 if (!Objects.equal(oldMaster, newMaster)) {
Ayaka Koshibe98bd12f2014-11-01 20:13:37 -0700460 notifyDelegate(new MastershipEvent(
461 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
462 } else {
463 notifyDelegate(new MastershipEvent(
464 BACKUPS_CHANGED, event.getKey(), event.getValue().roleInfo()));
465 }
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700466 }
467
468 @Override
469 public void entryEvicted(EntryEvent<DeviceId, RoleValue> event) {
470 }
471
472 @Override
473 public void mapEvicted(MapEvent event) {
474 }
475
476 @Override
477 public void mapCleared(MapEvent event) {
alshabib339a3d92014-09-26 17:54:32 -0700478 }
479 }
480
tomb41d1ac2014-09-24 01:51:24 -0700481}