refactored MastershipStore to not use ILock
Change-Id: Ic254f6faddba3427d3380910ca90d3d65a29f40b
Showing
7 changed files
with
199 additions
and
39 deletions
This diff is collapsed. Click to expand it.
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 | ... | ... |
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