Ayaka Koshibe

refactored MastershipStore to not use ILock

Change-Id: Ic254f6faddba3427d3380910ca90d3d65a29f40b
...@@ -2,6 +2,7 @@ package org.onlab.onos.store.mastership.impl; ...@@ -2,6 +2,7 @@ package org.onlab.onos.store.mastership.impl;
2 2
3 import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED; 3 import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED;
4 4
5 +import java.util.Collections;
5 import java.util.LinkedList; 6 import java.util.LinkedList;
6 import java.util.List; 7 import java.util.List;
7 import java.util.Map; 8 import java.util.Map;
...@@ -22,12 +23,15 @@ import org.onlab.onos.mastership.MastershipTerm; ...@@ -22,12 +23,15 @@ import org.onlab.onos.mastership.MastershipTerm;
22 import org.onlab.onos.net.DeviceId; 23 import org.onlab.onos.net.DeviceId;
23 import org.onlab.onos.net.MastershipRole; 24 import org.onlab.onos.net.MastershipRole;
24 import org.onlab.onos.store.common.AbstractHazelcastStore; 25 import org.onlab.onos.store.common.AbstractHazelcastStore;
26 +import org.onlab.onos.store.common.SMap;
27 +import org.onlab.onos.store.serializers.KryoSerializer;
25 28
26 import com.google.common.collect.ImmutableSet; 29 import com.google.common.collect.ImmutableSet;
27 -import com.hazelcast.core.ILock;
28 import com.hazelcast.core.IMap; 30 import com.hazelcast.core.IMap;
29 import com.hazelcast.core.MultiMap; 31 import com.hazelcast.core.MultiMap;
30 32
33 +import static org.onlab.onos.net.MastershipRole.*;
34 +
31 /** 35 /**
32 * Distributed implementation of the mastership store. The store is 36 * Distributed implementation of the mastership store. The store is
33 * responsible for the master selection process. 37 * responsible for the master selection process.
...@@ -38,36 +42,26 @@ public class DistributedMastershipStore ...@@ -38,36 +42,26 @@ public class DistributedMastershipStore
38 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate> 42 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
39 implements MastershipStore { 43 implements MastershipStore {
40 44
41 - //arbitrary lock name
42 - private static final String LOCK = "lock";
43 //initial term/TTL value 45 //initial term/TTL value
44 private static final Integer INIT = 0; 46 private static final Integer INIT = 0;
45 47
46 - //devices to masters 48 + //device to node roles
47 - protected IMap<byte[], byte[]> masters; 49 + protected SMap<DeviceId, RoleValue> roleMap;
48 //devices to terms 50 //devices to terms
49 - protected IMap<byte[], Integer> terms; 51 + protected SMap<DeviceId, Integer> terms;
50 -
51 - //re-election related, disjoint-set structures:
52 - //device-nodes multiset of available nodes
53 - protected MultiMap<byte[], byte[]> standbys;
54 - //device-nodes multiset for nodes that have given up on device
55 - protected MultiMap<byte[], byte[]> unusable;
56 52
57 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 53 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 protected ClusterService clusterService; 54 protected ClusterService clusterService;
59 55
56 + @SuppressWarnings({ "unchecked", "rawtypes" })
60 @Override 57 @Override
61 @Activate 58 @Activate
62 public void activate() { 59 public void activate() {
63 super.activate(); 60 super.activate();
64 61
65 - masters = theInstance.getMap("masters"); 62 + roleMap = new SMap(theInstance.getMap("nodeRoles"), new KryoSerializer());
66 - terms = theInstance.getMap("terms"); 63 + terms = new SMap(theInstance.getMap("terms"), new KryoSerializer());
67 - standbys = theInstance.getMultiMap("backups"); 64 + // roleMap.addEntryListener(new RemoteMasterShipEventHandler(), true);
68 - unusable = theInstance.getMultiMap("unusable");
69 -
70 - masters.addEntryListener(new RemoteMasterShipEventHandler(), true);
71 65
72 log.info("Started"); 66 log.info("Started");
73 } 67 }
...@@ -79,12 +73,9 @@ implements MastershipStore { ...@@ -79,12 +73,9 @@ implements MastershipStore {
79 73
80 @Override 74 @Override
81 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { 75 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
82 - byte[] did = serialize(deviceId); 76 + NodeId current = getNode(MASTER, deviceId);
83 - byte[] nid = serialize(nodeId);
84 -
85 - NodeId current = deserialize(masters.get(did));
86 if (current == null) { 77 if (current == null) {
87 - if (standbys.containsEntry(did, nid)) { 78 + if (isRole(STANDBY, nodeId, deviceId)) {
88 //was previously standby, or set to standby from master 79 //was previously standby, or set to standby from master
89 return MastershipRole.STANDBY; 80 return MastershipRole.STANDBY;
90 } else { 81 } else {
...@@ -103,69 +94,66 @@ implements MastershipStore { ...@@ -103,69 +94,66 @@ implements MastershipStore {
103 94
104 @Override 95 @Override
105 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { 96 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
106 - byte [] did = serialize(deviceId);
107 - byte [] nid = serialize(nodeId);
108 97
109 - ILock lock = theInstance.getLock(LOCK);
110 - lock.lock();
111 - try {
112 MastershipRole role = getRole(nodeId, deviceId); 98 MastershipRole role = getRole(nodeId, deviceId);
99 + roleMap.lock(deviceId);
100 + try {
101 + RoleValue rv = getRoleValue(deviceId);
113 switch (role) { 102 switch (role) {
114 case MASTER: 103 case MASTER:
115 //reinforce mastership 104 //reinforce mastership
116 - evict(nid, did); 105 + rv.reassign(nodeId, STANDBY, NONE);
117 return null; 106 return null;
118 case STANDBY: 107 case STANDBY:
119 - //make current master standby 108 + NodeId current = rv.get(MASTER);
120 - byte [] current = masters.get(did);
121 if (current != null) { 109 if (current != null) {
122 - backup(current, did); 110 + //backup and replace current master
111 + rv.reassign(nodeId, NONE, STANDBY);
112 + rv.replace(current, nodeId, MASTER);
113 + } else {
114 + //no master before so just add.
115 + rv.add(MASTER, nodeId);
123 } 116 }
124 - //assign specified node as new master 117 + rv.reassign(nodeId, STANDBY, NONE);
125 - masters.put(did, nid); 118 + updateTerm(deviceId);
126 - evict(nid, did);
127 - updateTerm(did);
128 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); 119 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
129 case NONE: 120 case NONE:
130 - masters.put(did, nid); 121 + rv.add(MASTER, nodeId);
131 - evict(nid, did); 122 + rv.reassign(nodeId, STANDBY, NONE);
132 - updateTerm(did); 123 + updateTerm(deviceId);
133 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); 124 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
134 default: 125 default:
135 log.warn("unknown Mastership Role {}", role); 126 log.warn("unknown Mastership Role {}", role);
136 return null; 127 return null;
137 } 128 }
138 } finally { 129 } finally {
139 - lock.unlock(); 130 + roleMap.unlock(deviceId);
140 } 131 }
141 } 132 }
142 133
143 @Override 134 @Override
144 public NodeId getMaster(DeviceId deviceId) { 135 public NodeId getMaster(DeviceId deviceId) {
145 - return deserialize(masters.get(serialize(deviceId))); 136 + return getMaster(deviceId);
146 } 137 }
147 138
148 139
149 @Override 140 @Override
150 public List<NodeId> getNodes(DeviceId deviceId) { 141 public List<NodeId> getNodes(DeviceId deviceId) {
151 - byte [] did = serialize(deviceId);
152 List<NodeId> nodes = new LinkedList<>(); 142 List<NodeId> nodes = new LinkedList<>();
153 143
154 - //add current master to head - if there is one 144 + //add current master to head - if there is one.
155 - ILock lock = theInstance.getLock(LOCK); 145 + roleMap.lock(deviceId);
156 - lock.lock();
157 try { 146 try {
158 - byte [] master = masters.get(did); 147 + RoleValue rv = getRoleValue(deviceId);
148 + NodeId master = rv.get(MASTER);
159 if (master != null) { 149 if (master != null) {
160 - nodes.add((NodeId) deserialize(master)); 150 + nodes.add(master);
161 } 151 }
162 - 152 + //We ignore NONE nodes.
163 - for (byte [] el : standbys.get(serialize(deviceId))) { 153 + nodes.addAll(rv.nodesOfRole(STANDBY));
164 - nodes.add((NodeId) deserialize(el)); 154 + return Collections.unmodifiableList(nodes);
165 - }
166 - return nodes;
167 } finally { 155 } finally {
168 - lock.unlock(); 156 + roleMap.unlock(deviceId);
169 } 157 }
170 } 158 }
171 159
...@@ -173,9 +161,9 @@ implements MastershipStore { ...@@ -173,9 +161,9 @@ implements MastershipStore {
173 public Set<DeviceId> getDevices(NodeId nodeId) { 161 public Set<DeviceId> getDevices(NodeId nodeId) {
174 ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder(); 162 ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder();
175 163
176 - for (Map.Entry<byte[], byte[]> entry : masters.entrySet()) { 164 + for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
177 - if (nodeId.equals(deserialize(entry.getValue()))) { 165 + if (nodeId.equals(el.getValue().get(MASTER))) {
178 - builder.add((DeviceId) deserialize(entry.getKey())); 166 + builder.add(el.getKey());
179 } 167 }
180 } 168 }
181 169
...@@ -185,26 +173,24 @@ implements MastershipStore { ...@@ -185,26 +173,24 @@ implements MastershipStore {
185 @Override 173 @Override
186 public MastershipRole requestRole(DeviceId deviceId) { 174 public MastershipRole requestRole(DeviceId deviceId) {
187 NodeId local = clusterService.getLocalNode().id(); 175 NodeId local = clusterService.getLocalNode().id();
188 - byte [] did = serialize(deviceId);
189 - byte [] lnid = serialize(local);
190 176
191 - ILock lock = theInstance.getLock(LOCK); 177 + roleMap.lock(deviceId);
192 - lock.lock();
193 try { 178 try {
179 + RoleValue rv = getRoleValue(deviceId);
194 MastershipRole role = getRole(local, deviceId); 180 MastershipRole role = getRole(local, deviceId);
195 switch (role) { 181 switch (role) {
196 case MASTER: 182 case MASTER:
197 - evict(lnid, did); 183 + rv.reassign(local, STANDBY, NONE);
198 break; 184 break;
199 case STANDBY: 185 case STANDBY:
200 - backup(lnid, did); 186 + rv.reassign(local, NONE, STANDBY);
201 - terms.putIfAbsent(did, INIT); 187 + terms.putIfAbsent(deviceId, INIT);
202 break; 188 break;
203 case NONE: 189 case NONE:
204 //claim mastership 190 //claim mastership
205 - masters.put(did, lnid); 191 + rv.add(MASTER, local);
206 - evict(lnid, did); 192 + rv.reassign(local, STANDBY, NONE);
207 - updateTerm(did); 193 + updateTerm(deviceId);
208 role = MastershipRole.MASTER; 194 role = MastershipRole.MASTER;
209 break; 195 break;
210 default: 196 default:
...@@ -212,128 +198,128 @@ implements MastershipStore { ...@@ -212,128 +198,128 @@ implements MastershipStore {
212 } 198 }
213 return role; 199 return role;
214 } finally { 200 } finally {
215 - lock.unlock(); 201 + roleMap.unlock(deviceId);
216 } 202 }
217 } 203 }
218 204
219 @Override 205 @Override
220 public MastershipTerm getTermFor(DeviceId deviceId) { 206 public MastershipTerm getTermFor(DeviceId deviceId) {
221 - byte[] did = serialize(deviceId); 207 + RoleValue rv = getRoleValue(deviceId);
222 - if ((masters.get(did) == null) || 208 + if ((rv.get(MASTER) == null) || (terms.get(deviceId) == null)) {
223 - (terms.get(did) == null)) {
224 return null; 209 return null;
225 } 210 }
226 - return MastershipTerm.of( 211 + return MastershipTerm.of(rv.get(MASTER), terms.get(deviceId));
227 - (NodeId) deserialize(masters.get(did)), terms.get(did));
228 } 212 }
229 213
230 @Override 214 @Override
231 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) { 215 public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
232 - byte [] did = serialize(deviceId);
233 - byte [] nid = serialize(nodeId);
234 MastershipEvent event = null; 216 MastershipEvent event = null;
235 217
236 - ILock lock = theInstance.getLock(LOCK); 218 + roleMap.lock(deviceId);
237 - lock.lock();
238 try { 219 try {
220 + RoleValue rv = getRoleValue(deviceId);
239 MastershipRole role = getRole(nodeId, deviceId); 221 MastershipRole role = getRole(nodeId, deviceId);
240 switch (role) { 222 switch (role) {
241 case MASTER: 223 case MASTER:
242 event = reelect(nodeId, deviceId); 224 event = reelect(nodeId, deviceId);
243 - backup(nid, did); 225 + //fall through to reinforce role
244 - break;
245 case STANDBY: 226 case STANDBY:
246 //fall through to reinforce role 227 //fall through to reinforce role
247 case NONE: 228 case NONE:
248 - backup(nid, did); 229 + rv.reassign(nodeId, NONE, STANDBY);
249 break; 230 break;
250 default: 231 default:
251 log.warn("unknown Mastership Role {}", role); 232 log.warn("unknown Mastership Role {}", role);
252 } 233 }
253 return event; 234 return event;
254 } finally { 235 } finally {
255 - lock.unlock(); 236 + roleMap.unlock(deviceId);
256 } 237 }
257 } 238 }
258 239
259 @Override 240 @Override
260 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) { 241 public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
261 - byte [] did = serialize(deviceId);
262 - byte [] nid = serialize(nodeId);
263 MastershipEvent event = null; 242 MastershipEvent event = null;
264 243
265 - ILock lock = theInstance.getLock(LOCK); 244 + roleMap.lock(deviceId);
266 - lock.lock();
267 try { 245 try {
246 + RoleValue rv = getRoleValue(deviceId);
268 MastershipRole role = getRole(nodeId, deviceId); 247 MastershipRole role = getRole(nodeId, deviceId);
269 switch (role) { 248 switch (role) {
270 case MASTER: 249 case MASTER:
271 event = reelect(nodeId, deviceId); 250 event = reelect(nodeId, deviceId);
272 - evict(nid, did); 251 + //fall through to reinforce relinquishment
273 - break;
274 case STANDBY: 252 case STANDBY:
275 //fall through to reinforce relinquishment 253 //fall through to reinforce relinquishment
276 case NONE: 254 case NONE:
277 - evict(nid, did); 255 + rv.reassign(nodeId, STANDBY, NONE);
278 break; 256 break;
279 default: 257 default:
280 log.warn("unknown Mastership Role {}", role); 258 log.warn("unknown Mastership Role {}", role);
281 } 259 }
282 return event; 260 return event;
283 } finally { 261 } finally {
284 - lock.unlock(); 262 + roleMap.unlock(deviceId);
285 } 263 }
286 } 264 }
287 265
288 //helper to fetch a new master candidate for a given device. 266 //helper to fetch a new master candidate for a given device.
289 private MastershipEvent reelect(NodeId current, DeviceId deviceId) { 267 private MastershipEvent reelect(NodeId current, DeviceId deviceId) {
290 - byte [] did = serialize(deviceId); 268 + RoleValue rv = roleMap.get(deviceId);
291 - byte [] nid = serialize(current);
292 269
293 //if this is an queue it'd be neater. 270 //if this is an queue it'd be neater.
294 - byte [] backup = null; 271 + NodeId backup = null;
295 - for (byte [] n : standbys.get(serialize(deviceId))) { 272 + for (NodeId n : rv.nodesOfRole(STANDBY)) {
296 - if (!current.equals(deserialize(n))) { 273 + if (!current.equals(n)) {
297 backup = n; 274 backup = n;
298 break; 275 break;
299 } 276 }
300 } 277 }
301 278
302 if (backup == null) { 279 if (backup == null) {
303 - masters.remove(did, nid); 280 + rv.remove(MASTER, current);
304 return null; 281 return null;
305 } else { 282 } else {
306 - masters.put(did, backup); 283 + rv.replace(current, backup, MASTER);
307 - evict(backup, did); 284 + rv.reassign(backup, STANDBY, NONE);
308 - Integer term = terms.get(did); 285 + Integer term = terms.get(deviceId);
309 - terms.put(did, ++term); 286 + terms.put(deviceId, ++term);
310 return new MastershipEvent( 287 return new MastershipEvent(
311 - MASTER_CHANGED, deviceId, (NodeId) deserialize(backup)); 288 + MASTER_CHANGED, deviceId, backup);
312 } 289 }
313 } 290 }
314 291
315 - //adds node to pool(s) of backups and moves them from unusable. 292 + //return the RoleValue structure for a device, or create one
316 - private void backup(byte [] nodeId, byte [] deviceId) { 293 + private RoleValue getRoleValue(DeviceId deviceId) {
317 - if (!standbys.containsEntry(deviceId, nodeId)) { 294 + RoleValue value = roleMap.get(deviceId);
318 - standbys.put(deviceId, nodeId); 295 + if (value == null) {
319 - } 296 + value = new RoleValue();
320 - if (unusable.containsEntry(deviceId, nodeId)) { 297 + roleMap.put(deviceId, value);
321 - unusable.remove(deviceId, nodeId);
322 } 298 }
299 + return value;
323 } 300 }
324 301
325 - //adds node to unusable and evicts it from backup pool. 302 + //get first applicable node out of store-unique structure.
326 - private void evict(byte [] nodeId, byte [] deviceId) { 303 + private NodeId getNode(MastershipRole role, DeviceId deviceId) {
327 - if (!unusable.containsEntry(deviceId, nodeId)) { 304 + RoleValue value = roleMap.get(deviceId);
328 - unusable.put(deviceId, nodeId); 305 + if (value != null) {
306 + return value.get(role);
307 + }
308 + return null;
329 } 309 }
330 - if (standbys.containsEntry(deviceId, nodeId)) { 310 +
331 - standbys.remove(deviceId, nodeId); 311 + //check if node is a certain role given a device
312 + private boolean isRole(
313 + MastershipRole role, NodeId nodeId, DeviceId deviceId) {
314 + RoleValue value = roleMap.get(deviceId);
315 + if (value != null) {
316 + return value.contains(role, nodeId);
332 } 317 }
318 + return false;
333 } 319 }
334 320
335 //adds or updates term information. 321 //adds or updates term information.
336 - private void updateTerm(byte [] deviceId) { 322 + private void updateTerm(DeviceId deviceId) {
337 Integer term = terms.get(deviceId); 323 Integer term = terms.get(deviceId);
338 if (term == null) { 324 if (term == null) {
339 terms.put(deviceId, INIT); 325 terms.put(deviceId, INIT);
......
1 +package org.onlab.onos.store.mastership.impl;
2 +
3 +import java.util.Collections;
4 +import java.util.LinkedList;
5 +import java.util.List;
6 +import java.util.Map;
7 +
8 +import org.onlab.onos.cluster.NodeId;
9 +import org.onlab.onos.net.MastershipRole;
10 +
11 +/**
12 + * A structure that holds node mastership roles associated with a
13 + * {@link DeviceId}. This structure needs to be locked through IMap.
14 + */
15 +public class RoleValue {
16 +
17 + Map<MastershipRole, List<NodeId>> value;
18 +
19 + public RoleValue() {
20 + value.put(MastershipRole.MASTER, new LinkedList<NodeId>());
21 + value.put(MastershipRole.STANDBY, new LinkedList<NodeId>());
22 + value.put(MastershipRole.NONE, new LinkedList<NodeId>());
23 + }
24 +
25 + public Map<MastershipRole, List<NodeId>> value() {
26 + return Collections.unmodifiableMap(value);
27 + }
28 +
29 + public List<NodeId> nodesOfRole(MastershipRole type) {
30 + return value.get(type);
31 + }
32 +
33 + public NodeId get(MastershipRole type) {
34 + return value.get(type).isEmpty() ? null : value.get(type).get(0);
35 + }
36 +
37 + public boolean contains(MastershipRole type, NodeId nodeId) {
38 + return value.get(type).contains(nodeId);
39 + }
40 +
41 + /**
42 + * Associates a node to a certain role.
43 + *
44 + * @param type the role
45 + * @param nodeId the node ID of the node to associate
46 + */
47 + public void add(MastershipRole type, NodeId nodeId) {
48 + List<NodeId> nodes = value.get(type);
49 +
50 + if (!nodes.contains(nodeId)) {
51 + nodes.add(nodeId);
52 + }
53 + }
54 +
55 + /**
56 + * Removes a node from a certain role.
57 + *
58 + * @param type the role
59 + * @param nodeId the ID of the node to remove
60 + * @return
61 + */
62 + public boolean remove(MastershipRole type, NodeId nodeId) {
63 + List<NodeId> nodes = value.get(type);
64 + if (!nodes.isEmpty()) {
65 + return nodes.remove(nodeId);
66 + } else {
67 + return false;
68 + }
69 + }
70 +
71 + /**
72 + * Reassigns a node from one role to another. If the node was not of the
73 + * old role, it will still be assigned the new role.
74 + *
75 + * @param nodeId the Node ID of node changing roles
76 + * @param from the old role
77 + * @param to the new role
78 + */
79 + // might want to add anyways as default behavior
80 + public void reassign(NodeId nodeId, MastershipRole from, MastershipRole to) {
81 + remove(from, nodeId);
82 + add(to, nodeId);
83 + }
84 +
85 + /**
86 + * Replaces a node in one role with another node. Even if there is no node to
87 + * replace, the new node is associated to the role.
88 + *
89 + * @param from the old NodeId to replace
90 + * @param to the new NodeId
91 + * @param type the role associated with the old NodeId
92 + */
93 + // might want to add anyways as default behavior
94 + public void replace(NodeId from, NodeId to, MastershipRole type) {
95 + remove(type, from);
96 + add(type, to);
97 + }
98 +
99 +}
...@@ -27,6 +27,7 @@ import org.onlab.onos.mastership.MastershipStoreDelegate; ...@@ -27,6 +27,7 @@ import org.onlab.onos.mastership.MastershipStoreDelegate;
27 import org.onlab.onos.mastership.MastershipTerm; 27 import org.onlab.onos.mastership.MastershipTerm;
28 import org.onlab.onos.mastership.MastershipEvent.Type; 28 import org.onlab.onos.mastership.MastershipEvent.Type;
29 import org.onlab.onos.net.DeviceId; 29 import org.onlab.onos.net.DeviceId;
30 +import org.onlab.onos.net.MastershipRole;
30 import org.onlab.onos.store.common.StoreManager; 31 import org.onlab.onos.store.common.StoreManager;
31 import org.onlab.onos.store.common.StoreService; 32 import org.onlab.onos.store.common.StoreService;
32 import org.onlab.onos.store.common.TestStoreManager; 33 import org.onlab.onos.store.common.TestStoreManager;
...@@ -101,7 +102,7 @@ public class DistributedMastershipStoreTest { ...@@ -101,7 +102,7 @@ public class DistributedMastershipStoreTest {
101 102
102 @Test 103 @Test
103 public void getMaster() { 104 public void getMaster() {
104 - assertTrue("wrong store state:", dms.masters.isEmpty()); 105 + assertTrue("wrong store state:", dms.roleMap.isEmpty());
105 106
106 testStore.put(DID1, N1, true, false, false); 107 testStore.put(DID1, N1, true, false, false);
107 assertEquals("wrong master:", N1, dms.getMaster(DID1)); 108 assertEquals("wrong master:", N1, dms.getMaster(DID1));
...@@ -110,7 +111,7 @@ public class DistributedMastershipStoreTest { ...@@ -110,7 +111,7 @@ public class DistributedMastershipStoreTest {
110 111
111 @Test 112 @Test
112 public void getDevices() { 113 public void getDevices() {
113 - assertTrue("wrong store state:", dms.masters.isEmpty()); 114 + assertTrue("wrong store state:", dms.roleMap.isEmpty());
114 115
115 testStore.put(DID1, N1, true, false, false); 116 testStore.put(DID1, N1, true, false, false);
116 testStore.put(DID2, N1, true, false, false); 117 testStore.put(DID2, N1, true, false, false);
...@@ -161,7 +162,7 @@ public class DistributedMastershipStoreTest { ...@@ -161,7 +162,7 @@ public class DistributedMastershipStoreTest {
161 assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID2).type()); 162 assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID2).type());
162 assertEquals("wrong term", MastershipTerm.of(N2, 0), dms.getTermFor(DID2)); 163 assertEquals("wrong term", MastershipTerm.of(N2, 0), dms.getTermFor(DID2));
163 //disconnect and reconnect - sign of failing re-election or single-instance channel 164 //disconnect and reconnect - sign of failing re-election or single-instance channel
164 - testStore.reset(true, false, false); 165 + dms.roleMap.clear();
165 dms.setMaster(N2, DID2); 166 dms.setMaster(N2, DID2);
166 assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2)); 167 assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
167 } 168 }
...@@ -191,13 +192,15 @@ public class DistributedMastershipStoreTest { ...@@ -191,13 +192,15 @@ public class DistributedMastershipStoreTest {
191 assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1)); 192 assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1));
192 assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1)); 193 assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1));
193 194
194 - assertEquals("wrong number of retired nodes", 2, dms.unusable.size()); 195 + assertEquals("wrong number of retired nodes", 2,
196 + dms.roleMap.get(DID1).nodesOfRole(NONE).size());
195 197
196 //bring nodes back 198 //bring nodes back
197 assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1)); 199 assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
198 testStore.setCurrent(CN1); 200 testStore.setCurrent(CN1);
199 assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1)); 201 assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1));
200 - assertEquals("wrong number of backup nodes", 1, dms.standbys.size()); 202 + assertEquals("wrong number of backup nodes", 1,
203 + dms.roleMap.get(DID1).nodesOfRole(STANDBY).size());
201 204
202 //NONE - nothing happens 205 //NONE - nothing happens
203 assertNull("wrong event:", dms.relinquishRole(N1, DID2)); 206 assertNull("wrong event:", dms.relinquishRole(N1, DID2));
...@@ -238,55 +241,44 @@ public class DistributedMastershipStoreTest { ...@@ -238,55 +241,44 @@ public class DistributedMastershipStoreTest {
238 //helper to populate master/backup structures 241 //helper to populate master/backup structures
239 public void put(DeviceId dev, NodeId node, 242 public void put(DeviceId dev, NodeId node,
240 boolean master, boolean backup, boolean term) { 243 boolean master, boolean backup, boolean term) {
241 - byte [] n = serialize(node); 244 + RoleValue rv = dms.roleMap.get(dev);
242 - byte [] d = serialize(dev); 245 + if (rv == null) {
246 + rv = new RoleValue();
247 + dms.roleMap.put(dev, rv);
248 + }
243 249
244 if (master) { 250 if (master) {
245 - dms.masters.put(d, n); 251 + rv.add(MASTER, node);
246 - dms.unusable.put(d, n); 252 + rv.reassign(node, STANDBY, NONE);
247 - dms.standbys.remove(d, n);
248 } 253 }
249 if (backup) { 254 if (backup) {
250 - dms.standbys.put(d, n); 255 + rv.add(STANDBY, node);
251 - dms.masters.remove(d, n); 256 + rv.remove(MASTER, node);
252 - dms.unusable.remove(d, n); 257 + rv.remove(NONE, node);
253 } 258 }
254 if (term) { 259 if (term) {
255 - dms.terms.put(d, 0); 260 + dms.terms.put(dev, 0);
256 } 261 }
257 } 262 }
258 263
259 //a dumb utility function. 264 //a dumb utility function.
260 public void dump() { 265 public void dump() {
261 - System.out.println("standbys"); 266 + for (Map.Entry<DeviceId, RoleValue> el : dms.roleMap.entrySet()) {
262 - for (Map.Entry<byte [], byte []> e : standbys.entrySet()) { 267 + System.out.println("DID: " + el.getKey());
263 - System.out.println(deserialize(e.getKey()) + ":" + deserialize(e.getValue())); 268 + for (MastershipRole role : MastershipRole.values()) {
264 - } 269 + System.out.println(role.toString() + ":");
265 - System.out.println("unusable"); 270 + for (NodeId n : el.getValue().nodesOfRole(role)) {
266 - for (Map.Entry<byte [], byte []> e : unusable.entrySet()) { 271 + System.out.println("\t" + n);
267 - System.out.println(deserialize(e.getKey()) + ":" + deserialize(e.getValue()));
268 } 272 }
269 } 273 }
270 -
271 - //clears structures
272 - public void reset(boolean store, boolean backup, boolean term) {
273 - if (store) {
274 - dms.masters.clear();
275 - dms.unusable.clear();
276 - }
277 - if (backup) {
278 - dms.standbys.clear();
279 - }
280 - if (term) {
281 - dms.terms.clear();
282 } 274 }
283 } 275 }
284 276
285 //increment term for a device 277 //increment term for a device
286 public void increment(DeviceId dev) { 278 public void increment(DeviceId dev) {
287 - Integer t = dms.terms.get(serialize(dev)); 279 + Integer t = dms.terms.get(dev);
288 if (t != null) { 280 if (t != null) {
289 - dms.terms.put(serialize(dev), ++t); 281 + dms.terms.put(dev, ++t);
290 } 282 }
291 } 283 }
292 284
......
...@@ -19,7 +19,6 @@ import org.onlab.onos.net.DeviceId; ...@@ -19,7 +19,6 @@ import org.onlab.onos.net.DeviceId;
19 import org.onlab.onos.net.Element; 19 import org.onlab.onos.net.Element;
20 import org.onlab.onos.net.Link; 20 import org.onlab.onos.net.Link;
21 import org.onlab.onos.net.LinkKey; 21 import org.onlab.onos.net.LinkKey;
22 -import org.onlab.onos.net.MastershipRole;
23 import org.onlab.onos.net.Port; 22 import org.onlab.onos.net.Port;
24 import org.onlab.onos.net.PortNumber; 23 import org.onlab.onos.net.PortNumber;
25 import org.onlab.onos.net.device.DefaultDeviceDescription; 24 import org.onlab.onos.net.device.DefaultDeviceDescription;
...@@ -27,6 +26,7 @@ import org.onlab.onos.net.device.DefaultPortDescription; ...@@ -27,6 +26,7 @@ import org.onlab.onos.net.device.DefaultPortDescription;
27 import org.onlab.onos.net.link.DefaultLinkDescription; 26 import org.onlab.onos.net.link.DefaultLinkDescription;
28 import org.onlab.onos.net.provider.ProviderId; 27 import org.onlab.onos.net.provider.ProviderId;
29 import org.onlab.onos.store.Timestamp; 28 import org.onlab.onos.store.Timestamp;
29 +import org.onlab.onos.store.mastership.impl.RoleValue;
30 import org.onlab.packet.IpAddress; 30 import org.onlab.packet.IpAddress;
31 import org.onlab.packet.IpPrefix; 31 import org.onlab.packet.IpPrefix;
32 import org.onlab.util.KryoPool; 32 import org.onlab.util.KryoPool;
...@@ -66,7 +66,7 @@ public final class KryoPoolUtil { ...@@ -66,7 +66,7 @@ public final class KryoPoolUtil {
66 DefaultDevice.class, 66 DefaultDevice.class,
67 DefaultDeviceDescription.class, 67 DefaultDeviceDescription.class,
68 DefaultLinkDescription.class, 68 DefaultLinkDescription.class,
69 - MastershipRole.class, 69 + RoleValue.class,
70 Port.class, 70 Port.class,
71 DefaultPortDescription.class, 71 DefaultPortDescription.class,
72 Element.class, 72 Element.class,
...@@ -84,7 +84,7 @@ public final class KryoPoolUtil { ...@@ -84,7 +84,7 @@ public final class KryoPoolUtil {
84 .register(ConnectPoint.class, new ConnectPointSerializer()) 84 .register(ConnectPoint.class, new ConnectPointSerializer())
85 .register(DefaultLink.class, new DefaultLinkSerializer()) 85 .register(DefaultLink.class, new DefaultLinkSerializer())
86 .register(MastershipTerm.class, new MastershipTermSerializer()) 86 .register(MastershipTerm.class, new MastershipTermSerializer())
87 - .register(MastershipRole.class, new MastershipRoleSerializer()) 87 + .register(RoleValue.class, new RoleValueSerializer())
88 88
89 .build(); 89 .build();
90 90
......
1 +package org.onlab.onos.store.serializers;
2 +
3 +import java.util.List;
4 +import java.util.Map;
5 +
6 +import org.onlab.onos.cluster.NodeId;
7 +import org.onlab.onos.net.MastershipRole;
8 +import org.onlab.onos.store.mastership.impl.RoleValue;
9 +
10 +import com.esotericsoftware.kryo.Kryo;
11 +import com.esotericsoftware.kryo.Serializer;
12 +import com.esotericsoftware.kryo.io.Input;
13 +import com.esotericsoftware.kryo.io.Output;
14 +
15 +/**
16 + * Serializer for RoleValues used by {@link DistributedMastershipStore}
17 + */
18 +public class RoleValueSerializer extends Serializer<RoleValue> {
19 +
20 + //RoleValues are assumed to hold a Map of MastershipRoles (an enum)
21 + //to a List of NodeIds.
22 +
23 + @Override
24 + public RoleValue read(Kryo kryo, Input input, Class<RoleValue> type) {
25 + RoleValue rv = new RoleValue();
26 + int size = input.readInt();
27 + for (int i = 0; i < size; i++) {
28 + MastershipRole role = MastershipRole.values()[input.readInt()];
29 + int s = input.readInt();
30 + for (int j = 0; j < s; j++) {
31 + rv.add(role, new NodeId(input.readString()));
32 + }
33 + }
34 + return rv;
35 + }
36 +
37 + @Override
38 + public void write(Kryo kryo, Output output, RoleValue type) {
39 + output.writeInt(type.value().size());
40 +
41 + for (Map.Entry<MastershipRole, List<NodeId>> el :
42 + type.value().entrySet()) {
43 + output.writeInt(el.getKey().ordinal());
44 +
45 + List<NodeId> nodes = el.getValue();
46 + output.writeInt(nodes.size());
47 + for (NodeId n : nodes) {
48 + output.writeString(n.toString());
49 + }
50 + }
51 + }
52 +
53 +}
...@@ -26,6 +26,7 @@ import org.onlab.onos.net.MastershipRole; ...@@ -26,6 +26,7 @@ import org.onlab.onos.net.MastershipRole;
26 import org.onlab.onos.net.PortNumber; 26 import org.onlab.onos.net.PortNumber;
27 import org.onlab.onos.net.SparseAnnotations; 27 import org.onlab.onos.net.SparseAnnotations;
28 import org.onlab.onos.net.provider.ProviderId; 28 import org.onlab.onos.net.provider.ProviderId;
29 +import org.onlab.onos.store.mastership.impl.RoleValue;
29 import org.onlab.packet.IpAddress; 30 import org.onlab.packet.IpAddress;
30 import org.onlab.packet.IpPrefix; 31 import org.onlab.packet.IpPrefix;
31 import org.onlab.util.KryoPool; 32 import org.onlab.util.KryoPool;
...@@ -58,6 +59,13 @@ public class KryoSerializerTest { ...@@ -58,6 +59,13 @@ public class KryoSerializerTest {
58 .remove("A1") 59 .remove("A1")
59 .set("B3", "b3") 60 .set("B3", "b3")
60 .build(); 61 .build();
62 + private static final RoleValue RV = new RoleValue();
63 + static {
64 + RV.add(MastershipRole.MASTER, new NodeId("node1"));
65 + RV.add(MastershipRole.STANDBY, new NodeId("node2"));
66 + RV.add(MastershipRole.STANDBY, new NodeId("node3"));
67 + RV.add(MastershipRole.NONE, new NodeId("node4"));
68 + };
61 69
62 private static KryoPool kryos; 70 private static KryoPool kryos;
63 71
......
...@@ -2,6 +2,7 @@ package org.onlab.onos.store.trivial.impl; ...@@ -2,6 +2,7 @@ package org.onlab.onos.store.trivial.impl;
2 2
3 import static org.slf4j.LoggerFactory.getLogger; 3 import static org.slf4j.LoggerFactory.getLogger;
4 4
5 +import java.util.ArrayList;
5 import java.util.Collections; 6 import java.util.Collections;
6 import java.util.HashMap; 7 import java.util.HashMap;
7 import java.util.HashSet; 8 import java.util.HashSet;
...@@ -97,7 +98,14 @@ public class SimpleMastershipStore ...@@ -97,7 +98,14 @@ public class SimpleMastershipStore
97 98
98 @Override 99 @Override
99 public List<NodeId> getNodes(DeviceId deviceId) { 100 public List<NodeId> getNodes(DeviceId deviceId) {
100 - return null; 101 + List<NodeId> nodes = new ArrayList<>();
102 +
103 + nodes.addAll(backups);
104 + if (!nodes.contains(masterMap.get(deviceId))) {
105 + nodes.add(masterMap.get(deviceId));
106 + }
107 +
108 + return Collections.unmodifiableList(nodes);
101 } 109 }
102 110
103 @Override 111 @Override
......