Ayaka Koshibe

relinquishes mastership when device disconnects

Change-Id: I1aecc8862ce297569c358e1deb5ddc5fb52d5dd3
...@@ -78,16 +78,10 @@ implements MastershipService, MastershipAdminService { ...@@ -78,16 +78,10 @@ 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);
82 - if (role.equals(current)) {
83 - return;
84 - } else {
85 MastershipEvent event = null; 81 MastershipEvent event = null;
86 if (role.equals(MastershipRole.MASTER)) { 82 if (role.equals(MastershipRole.MASTER)) {
87 - //current was STANDBY, wanted MASTER
88 event = store.setMaster(nodeId, deviceId); 83 event = store.setMaster(nodeId, deviceId);
89 } else { 84 } else {
90 - //current was MASTER, wanted STANDBY
91 event = store.unsetMaster(nodeId, deviceId); 85 event = store.unsetMaster(nodeId, deviceId);
92 } 86 }
93 87
...@@ -95,7 +89,6 @@ implements MastershipService, MastershipAdminService { ...@@ -95,7 +89,6 @@ implements MastershipService, MastershipAdminService {
95 post(event); 89 post(event);
96 } 90 }
97 } 91 }
98 - }
99 92
100 @Override 93 @Override
101 public MastershipRole getLocalRole(DeviceId deviceId) { 94 public MastershipRole getLocalRole(DeviceId deviceId) {
...@@ -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);
72 - List<NodeId> backups = backupMap.get(deviceId);
73 -
74 - if (current == null) {
75 - if (backups == null) {
76 - //add new mapping to everything
77 synchronized (this) { 69 synchronized (this) {
78 - masterMap.put(deviceId, nodeId); 70 + switch (role) {
79 - backups = Lists.newLinkedList(); 71 + case MASTER:
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);
87 - backups.remove(nodeId);
88 - termMap.get(deviceId).incrementAndGet();
89 - }
90 - }
91 - } else if (current.equals(nodeId)) {
92 return null; 72 return null;
93 - } else { 73 + case STANDBY:
94 - //add current to backup, set master to new node
95 masterMap.put(deviceId, nodeId); 74 masterMap.put(deviceId, nodeId);
96 - backups.add(current);
97 - backups.remove(nodeId);
98 termMap.get(deviceId).incrementAndGet(); 75 termMap.get(deviceId).incrementAndGet();
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;
86 + }
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
124 - } 111 + NodeId node = instance.id();
125 - 112 + MastershipRole role = getRole(node, deviceId);
126 - @Override 113 +
127 - public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { 114 + switch (role) {
128 - NodeId current = masterMap.get(deviceId); 115 + case MASTER:
129 - List<NodeId> backups = backupMap.get(deviceId); 116 + break;
130 - 117 + case STANDBY:
131 - if (current == null) {
132 - //masterMap or backup doesn't contain device. Say new node is MASTER
133 - if (backups == null) {
134 synchronized (this) { 118 synchronized (this) {
135 - masterMap.put(deviceId, nodeId); 119 + //try to "re-elect", since we're really not distributed
136 - backups = Lists.newLinkedList(); 120 + NodeId rel = reelect(node);
137 - backupMap.put(deviceId, backups); 121 + if (rel == null) {
122 + masterMap.put(deviceId, node);
138 termMap.put(deviceId, new AtomicInteger()); 123 termMap.put(deviceId, new AtomicInteger());
124 + role = MastershipRole.MASTER;
139 } 125 }
140 - updateStandby(nodeId, deviceId); 126 + backups.add(node);
141 - return MastershipRole.MASTER;
142 } 127 }
143 - 128 + break;
144 - //device once existed, but got removed, and is now getting a backup. 129 + case NONE:
145 - if (!backups.contains(nodeId)) { 130 + //first to get to it, say we are master
146 synchronized (this) { 131 synchronized (this) {
147 - backups.add(nodeId); 132 + masterMap.put(deviceId, node);
148 termMap.put(deviceId, new AtomicInteger()); 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);
149 } 140 }
150 - updateStandby(nodeId, deviceId); 141 + return role;
151 } 142 }
152 143
153 - } else if (current.equals(nodeId)) { 144 + @Override
154 - return MastershipRole.MASTER; 145 + public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
146 + //just query
147 + NodeId current = masterMap.get(deviceId);
148 + MastershipRole role;
149 +
150 + if (current == null) {
151 + //degenerate case - only node is its own backup
152 + if (backups.contains(nodeId)) {
153 + role = MastershipRole.STANDBY;
155 } else { 154 } else {
156 - //once created, a device never has a null backups list. 155 + role = MastershipRole.NONE;
157 - if (!backups.contains(nodeId)) {
158 - //we must have requested STANDBY setting
159 - synchronized (this) {
160 - backups.add(nodeId);
161 - termMap.put(deviceId, new AtomicInteger());
162 } 156 }
163 - updateStandby(nodeId, deviceId); 157 + } else {
158 + if (current.equals(nodeId)) {
159 + role = MastershipRole.MASTER;
160 + } else {
161 + role = MastershipRole.STANDBY;
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 -
184 - //TODO case where node is completely removed from the cluster?
185 - if (node.equals(nodeId)) {
186 synchronized (this) { 180 synchronized (this) {
187 - //pick new node. 181 + switch (role) {
188 - List<NodeId> backups = backupMap.get(deviceId); 182 + case MASTER:
189 - 183 + NodeId backup = reelect(nodeId);
190 - //no backups, so device is hosed 184 + if (backup == null) {
191 - if (backups.isEmpty()) {
192 masterMap.remove(deviceId); 185 masterMap.remove(deviceId);
193 - backups.add(nodeId); 186 + } else {
194 - return null;
195 - }
196 - NodeId backup = backups.remove(0);
197 masterMap.put(deviceId, backup); 187 masterMap.put(deviceId, backup);
198 - backups.add(nodeId); 188 + termMap.get(deviceId).incrementAndGet();
199 return new MastershipEvent(MASTER_CHANGED, deviceId, backup); 189 return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
200 } 190 }
191 + case STANDBY:
192 + case NONE:
193 + if (!termMap.containsKey(deviceId)) {
194 + termMap.put(deviceId, new AtomicInteger());
201 } 195 }
202 - return null; 196 + backups.add(nodeId);
197 + break;
198 + default:
199 + log.warn("unknown Mastership Role {}", role);
203 } 200 }
204 -
205 - //add node as STANDBY to maps un-scalably.
206 - private void updateStandby(NodeId nodeId, DeviceId deviceId) {
207 - for (Map.Entry<DeviceId, List<NodeId>> e : backupMap.entrySet()) {
208 - DeviceId dev = e.getKey();
209 - if (dev.equals(deviceId)) {
210 - continue;
211 } 201 }
212 - synchronized (this) { 202 + return null;
213 - List<NodeId> nodes = e.getValue();
214 - if (!nodes.contains(nodeId)) {
215 - nodes.add(nodeId);
216 } 203 }
204 +
205 + //dumbly selects next-available node that's not the current one
206 + //emulate leader election
207 + private NodeId reelect(NodeId nodeId) {
208 + NodeId backup = null;
209 + for (NodeId n : backups) {
210 + if (!n.equals(nodeId)) {
211 + backup = n;
212 + break;
217 } 213 }
218 } 214 }
215 + return backup;
219 } 216 }
220 217
221 } 218 }
......