refactored MastershipStore to not use ILock
Change-Id: Ic254f6faddba3427d3380910ca90d3d65a29f40b
Showing
7 changed files
with
300 additions
and
154 deletions
... | @@ -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); | 98 | + MastershipRole role = getRole(nodeId, deviceId); |
110 | - lock.lock(); | 99 | + roleMap.lock(deviceId); |
111 | try { | 100 | try { |
112 | - MastershipRole role = getRole(nodeId, deviceId); | 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 | - } | ||
162 | - | ||
163 | - for (byte [] el : standbys.get(serialize(deviceId))) { | ||
164 | - nodes.add((NodeId) deserialize(el)); | ||
165 | } | 151 | } |
166 | - return nodes; | 152 | + //We ignore NONE nodes. |
153 | + nodes.addAll(rv.nodesOfRole(STANDBY)); | ||
154 | + return Collections.unmodifiableList(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); | ||
329 | } | 307 | } |
330 | - if (standbys.containsEntry(deviceId, nodeId)) { | 308 | + return null; |
331 | - standbys.remove(deviceId, nodeId); | 309 | + } |
310 | + | ||
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())); | 272 | + } |
268 | - } | 273 | + } |
269 | - } | ||
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 | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/RoleValueSerializer.java
0 → 100644
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 | ... | ... |
-
Please register or login to post a comment