relinquishes mastership when device disconnects
Change-Id: I1aecc8862ce297569c358e1deb5ddc5fb52d5dd3
Showing
4 changed files
with
100 additions
and
114 deletions
... | @@ -78,22 +78,15 @@ implements MastershipService, MastershipAdminService { | ... | @@ -78,22 +78,15 @@ implements MastershipService, MastershipAdminService { |
78 | checkNotNull(deviceId, DEVICE_ID_NULL); | 78 | checkNotNull(deviceId, DEVICE_ID_NULL); |
79 | checkNotNull(role, ROLE_NULL); | 79 | checkNotNull(role, ROLE_NULL); |
80 | 80 | ||
81 | - MastershipRole current = store.getRole(nodeId, deviceId); | 81 | + MastershipEvent event = null; |
82 | - if (role.equals(current)) { | 82 | + if (role.equals(MastershipRole.MASTER)) { |
83 | - return; | 83 | + event = store.setMaster(nodeId, deviceId); |
84 | } else { | 84 | } else { |
85 | - MastershipEvent event = null; | 85 | + event = store.unsetMaster(nodeId, deviceId); |
86 | - if (role.equals(MastershipRole.MASTER)) { | 86 | + } |
87 | - //current was STANDBY, wanted MASTER | ||
88 | - event = store.setMaster(nodeId, deviceId); | ||
89 | - } else { | ||
90 | - //current was MASTER, wanted STANDBY | ||
91 | - event = store.unsetMaster(nodeId, deviceId); | ||
92 | - } | ||
93 | 87 | ||
94 | - if (event != null) { | 88 | + if (event != null) { |
95 | - post(event); | 89 | + post(event); |
96 | - } | ||
97 | } | 90 | } |
98 | } | 91 | } |
99 | 92 | ||
... | @@ -105,10 +98,7 @@ implements MastershipService, MastershipAdminService { | ... | @@ -105,10 +98,7 @@ implements MastershipService, MastershipAdminService { |
105 | 98 | ||
106 | @Override | 99 | @Override |
107 | public void relinquishMastership(DeviceId deviceId) { | 100 | public void relinquishMastership(DeviceId deviceId) { |
108 | - checkNotNull(deviceId, DEVICE_ID_NULL); | 101 | + MastershipRole role = getLocalRole(deviceId); |
109 | - | ||
110 | - MastershipRole role = store.getRole( | ||
111 | - clusterService.getLocalNode().id(), deviceId); | ||
112 | if (!role.equals(MastershipRole.MASTER)) { | 102 | if (!role.equals(MastershipRole.MASTER)) { |
113 | return; | 103 | return; |
114 | } | 104 | } | ... | ... |
... | @@ -202,7 +202,7 @@ public class DeviceManager | ... | @@ -202,7 +202,7 @@ public class DeviceManager |
202 | log.info("Device {} connected", deviceId); | 202 | log.info("Device {} connected", deviceId); |
203 | mastershipService.requestRoleFor(deviceId); | 203 | mastershipService.requestRoleFor(deviceId); |
204 | provider().roleChanged(event.subject(), | 204 | provider().roleChanged(event.subject(), |
205 | - mastershipService.getLocalRole(deviceId)); | 205 | + mastershipService.requestRoleFor(deviceId)); |
206 | post(event); | 206 | post(event); |
207 | } | 207 | } |
208 | } | 208 | } | ... | ... |
... | @@ -113,7 +113,6 @@ public class MastershipManagerTest { | ... | @@ -113,7 +113,6 @@ public class MastershipManagerTest { |
113 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | 113 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); |
114 | mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); | 114 | mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); |
115 | assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); | 115 | assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); |
116 | - | ||
117 | //hand both devices to NID_LOCAL | 116 | //hand both devices to NID_LOCAL |
118 | mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); | 117 | mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); |
119 | assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | 118 | assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | ... | ... |
... | @@ -5,7 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,7 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | import java.util.Collections; | 5 | import java.util.Collections; |
6 | import java.util.HashMap; | 6 | import java.util.HashMap; |
7 | import java.util.HashSet; | 7 | import java.util.HashSet; |
8 | -import java.util.List; | ||
9 | import java.util.Map; | 8 | import java.util.Map; |
10 | import java.util.Set; | 9 | import java.util.Set; |
11 | import java.util.concurrent.atomic.AtomicInteger; | 10 | import java.util.concurrent.atomic.AtomicInteger; |
... | @@ -27,8 +26,6 @@ import org.onlab.onos.store.AbstractStore; | ... | @@ -27,8 +26,6 @@ import org.onlab.onos.store.AbstractStore; |
27 | import org.onlab.packet.IpPrefix; | 26 | import org.onlab.packet.IpPrefix; |
28 | import org.slf4j.Logger; | 27 | import org.slf4j.Logger; |
29 | 28 | ||
30 | -import com.google.common.collect.Lists; | ||
31 | - | ||
32 | import static org.onlab.onos.cluster.MastershipEvent.Type.*; | 29 | import static org.onlab.onos.cluster.MastershipEvent.Type.*; |
33 | 30 | ||
34 | /** | 31 | /** |
... | @@ -50,8 +47,8 @@ public class SimpleMastershipStore | ... | @@ -50,8 +47,8 @@ public class SimpleMastershipStore |
50 | 47 | ||
51 | //devices mapped to their masters, to emulate multiple nodes | 48 | //devices mapped to their masters, to emulate multiple nodes |
52 | protected final Map<DeviceId, NodeId> masterMap = new HashMap<>(); | 49 | protected final Map<DeviceId, NodeId> masterMap = new HashMap<>(); |
53 | - //emulate backups | 50 | + //emulate backups with pile of nodes |
54 | - protected final Map<DeviceId, List<NodeId>> backupMap = new HashMap<>(); | 51 | + protected final Set<NodeId> backups = new HashSet<>(); |
55 | //terms | 52 | //terms |
56 | protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>(); | 53 | protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>(); |
57 | 54 | ||
... | @@ -67,38 +64,28 @@ public class SimpleMastershipStore | ... | @@ -67,38 +64,28 @@ public class SimpleMastershipStore |
67 | 64 | ||
68 | @Override | 65 | @Override |
69 | public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { | 66 | public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { |
67 | + MastershipRole role = getRole(nodeId, deviceId); | ||
70 | 68 | ||
71 | - NodeId current = masterMap.get(deviceId); | 69 | + synchronized (this) { |
72 | - List<NodeId> backups = backupMap.get(deviceId); | 70 | + switch (role) { |
73 | - | 71 | + case MASTER: |
74 | - if (current == null) { | 72 | + return null; |
75 | - if (backups == null) { | 73 | + case STANDBY: |
76 | - //add new mapping to everything | ||
77 | - synchronized (this) { | ||
78 | - masterMap.put(deviceId, nodeId); | ||
79 | - backups = Lists.newLinkedList(); | ||
80 | - backupMap.put(deviceId, backups); | ||
81 | - termMap.put(deviceId, new AtomicInteger()); | ||
82 | - } | ||
83 | - } else { | ||
84 | - //set master to new node and remove from backups if there | ||
85 | - synchronized (this) { | ||
86 | masterMap.put(deviceId, nodeId); | 74 | masterMap.put(deviceId, nodeId); |
87 | - backups.remove(nodeId); | ||
88 | termMap.get(deviceId).incrementAndGet(); | 75 | termMap.get(deviceId).incrementAndGet(); |
89 | - } | 76 | + backups.add(nodeId); |
77 | + break; | ||
78 | + case NONE: | ||
79 | + masterMap.put(deviceId, nodeId); | ||
80 | + termMap.put(deviceId, new AtomicInteger()); | ||
81 | + backups.add(nodeId); | ||
82 | + break; | ||
83 | + default: | ||
84 | + log.warn("unknown Mastership Role {}", role); | ||
85 | + return null; | ||
90 | } | 86 | } |
91 | - } else if (current.equals(nodeId)) { | ||
92 | - return null; | ||
93 | - } else { | ||
94 | - //add current to backup, set master to new node | ||
95 | - masterMap.put(deviceId, nodeId); | ||
96 | - backups.add(current); | ||
97 | - backups.remove(nodeId); | ||
98 | - termMap.get(deviceId).incrementAndGet(); | ||
99 | } | 87 | } |
100 | 88 | ||
101 | - updateStandby(nodeId, deviceId); | ||
102 | return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | 89 | return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); |
103 | } | 90 | } |
104 | 91 | ||
... | @@ -120,51 +107,61 @@ public class SimpleMastershipStore | ... | @@ -120,51 +107,61 @@ public class SimpleMastershipStore |
120 | 107 | ||
121 | @Override | 108 | @Override |
122 | public MastershipRole requestRole(DeviceId deviceId) { | 109 | public MastershipRole requestRole(DeviceId deviceId) { |
123 | - return getRole(instance.id(), deviceId); | 110 | + //query+possible reelection |
111 | + NodeId node = instance.id(); | ||
112 | + MastershipRole role = getRole(node, deviceId); | ||
113 | + | ||
114 | + switch (role) { | ||
115 | + case MASTER: | ||
116 | + break; | ||
117 | + case STANDBY: | ||
118 | + synchronized (this) { | ||
119 | + //try to "re-elect", since we're really not distributed | ||
120 | + NodeId rel = reelect(node); | ||
121 | + if (rel == null) { | ||
122 | + masterMap.put(deviceId, node); | ||
123 | + termMap.put(deviceId, new AtomicInteger()); | ||
124 | + role = MastershipRole.MASTER; | ||
125 | + } | ||
126 | + backups.add(node); | ||
127 | + } | ||
128 | + break; | ||
129 | + case NONE: | ||
130 | + //first to get to it, say we are master | ||
131 | + synchronized (this) { | ||
132 | + masterMap.put(deviceId, node); | ||
133 | + termMap.put(deviceId, new AtomicInteger()); | ||
134 | + backups.add(node); | ||
135 | + role = MastershipRole.MASTER; | ||
136 | + } | ||
137 | + break; | ||
138 | + default: | ||
139 | + log.warn("unknown Mastership Role {}", role); | ||
140 | + } | ||
141 | + return role; | ||
124 | } | 142 | } |
125 | 143 | ||
126 | @Override | 144 | @Override |
127 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 145 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
146 | + //just query | ||
128 | NodeId current = masterMap.get(deviceId); | 147 | NodeId current = masterMap.get(deviceId); |
129 | - List<NodeId> backups = backupMap.get(deviceId); | 148 | + MastershipRole role; |
130 | 149 | ||
131 | if (current == null) { | 150 | if (current == null) { |
132 | - //masterMap or backup doesn't contain device. Say new node is MASTER | 151 | + //degenerate case - only node is its own backup |
133 | - if (backups == null) { | 152 | + if (backups.contains(nodeId)) { |
134 | - synchronized (this) { | 153 | + role = MastershipRole.STANDBY; |
135 | - masterMap.put(deviceId, nodeId); | 154 | + } else { |
136 | - backups = Lists.newLinkedList(); | 155 | + role = MastershipRole.NONE; |
137 | - backupMap.put(deviceId, backups); | ||
138 | - termMap.put(deviceId, new AtomicInteger()); | ||
139 | - } | ||
140 | - updateStandby(nodeId, deviceId); | ||
141 | - return MastershipRole.MASTER; | ||
142 | - } | ||
143 | - | ||
144 | - //device once existed, but got removed, and is now getting a backup. | ||
145 | - if (!backups.contains(nodeId)) { | ||
146 | - synchronized (this) { | ||
147 | - backups.add(nodeId); | ||
148 | - termMap.put(deviceId, new AtomicInteger()); | ||
149 | - } | ||
150 | - updateStandby(nodeId, deviceId); | ||
151 | } | 156 | } |
152 | - | ||
153 | - } else if (current.equals(nodeId)) { | ||
154 | - return MastershipRole.MASTER; | ||
155 | } else { | 157 | } else { |
156 | - //once created, a device never has a null backups list. | 158 | + if (current.equals(nodeId)) { |
157 | - if (!backups.contains(nodeId)) { | 159 | + role = MastershipRole.MASTER; |
158 | - //we must have requested STANDBY setting | 160 | + } else { |
159 | - synchronized (this) { | 161 | + role = MastershipRole.STANDBY; |
160 | - backups.add(nodeId); | ||
161 | - termMap.put(deviceId, new AtomicInteger()); | ||
162 | - } | ||
163 | - updateStandby(nodeId, deviceId); | ||
164 | } | 162 | } |
165 | } | 163 | } |
166 | - | 164 | + return role; |
167 | - return MastershipRole.STANDBY; | ||
168 | } | 165 | } |
169 | 166 | ||
170 | @Override | 167 | @Override |
... | @@ -179,43 +176,43 @@ public class SimpleMastershipStore | ... | @@ -179,43 +176,43 @@ public class SimpleMastershipStore |
179 | 176 | ||
180 | @Override | 177 | @Override |
181 | public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { | 178 | public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { |
182 | - NodeId node = masterMap.get(deviceId); | 179 | + MastershipRole role = getRole(nodeId, deviceId); |
183 | - | 180 | + synchronized (this) { |
184 | - //TODO case where node is completely removed from the cluster? | 181 | + switch (role) { |
185 | - if (node.equals(nodeId)) { | 182 | + case MASTER: |
186 | - synchronized (this) { | 183 | + NodeId backup = reelect(nodeId); |
187 | - //pick new node. | 184 | + if (backup == null) { |
188 | - List<NodeId> backups = backupMap.get(deviceId); | 185 | + masterMap.remove(deviceId); |
189 | - | 186 | + } else { |
190 | - //no backups, so device is hosed | 187 | + masterMap.put(deviceId, backup); |
191 | - if (backups.isEmpty()) { | 188 | + termMap.get(deviceId).incrementAndGet(); |
192 | - masterMap.remove(deviceId); | 189 | + return new MastershipEvent(MASTER_CHANGED, deviceId, backup); |
190 | + } | ||
191 | + case STANDBY: | ||
192 | + case NONE: | ||
193 | + if (!termMap.containsKey(deviceId)) { | ||
194 | + termMap.put(deviceId, new AtomicInteger()); | ||
195 | + } | ||
193 | backups.add(nodeId); | 196 | backups.add(nodeId); |
194 | - return null; | 197 | + break; |
195 | - } | 198 | + default: |
196 | - NodeId backup = backups.remove(0); | 199 | + log.warn("unknown Mastership Role {}", role); |
197 | - masterMap.put(deviceId, backup); | ||
198 | - backups.add(nodeId); | ||
199 | - return new MastershipEvent(MASTER_CHANGED, deviceId, backup); | ||
200 | } | 200 | } |
201 | } | 201 | } |
202 | return null; | 202 | return null; |
203 | } | 203 | } |
204 | 204 | ||
205 | - //add node as STANDBY to maps un-scalably. | 205 | + //dumbly selects next-available node that's not the current one |
206 | - private void updateStandby(NodeId nodeId, DeviceId deviceId) { | 206 | + //emulate leader election |
207 | - for (Map.Entry<DeviceId, List<NodeId>> e : backupMap.entrySet()) { | 207 | + private NodeId reelect(NodeId nodeId) { |
208 | - DeviceId dev = e.getKey(); | 208 | + NodeId backup = null; |
209 | - if (dev.equals(deviceId)) { | 209 | + for (NodeId n : backups) { |
210 | - continue; | 210 | + if (!n.equals(nodeId)) { |
211 | - } | 211 | + backup = n; |
212 | - synchronized (this) { | 212 | + break; |
213 | - List<NodeId> nodes = e.getValue(); | ||
214 | - if (!nodes.contains(nodeId)) { | ||
215 | - nodes.add(nodeId); | ||
216 | - } | ||
217 | } | 213 | } |
218 | } | 214 | } |
215 | + return backup; | ||
219 | } | 216 | } |
220 | 217 | ||
221 | } | 218 | } | ... | ... |
-
Please register or login to post a comment