Ayaka Koshibe

relinquishes mastership when device disconnects

Change-Id: I1aecc8862ce297569c358e1deb5ddc5fb52d5dd3
...@@ -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 }
......