DistributedMastershipStore
- try to avoid unnecessary remote writes - avoid reads from blocking if possible - atomically read term info Change-Id: I50badc718726261ccb14a6feefc578b420d28923
Showing
3 changed files
with
181 additions
and
101 deletions
| ... | @@ -18,6 +18,7 @@ package org.onlab.onos.store.mastership.impl; | ... | @@ -18,6 +18,7 @@ package org.onlab.onos.store.mastership.impl; |
| 18 | import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED; | 18 | import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED; |
| 19 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.putIfAbsent; | 19 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.putIfAbsent; |
| 20 | 20 | ||
| 21 | +import java.util.HashSet; | ||
| 21 | import java.util.Map; | 22 | import java.util.Map; |
| 22 | import java.util.Set; | 23 | import java.util.Set; |
| 23 | 24 | ||
| ... | @@ -42,7 +43,6 @@ import org.onlab.onos.store.serializers.KryoNamespaces; | ... | @@ -42,7 +43,6 @@ import org.onlab.onos.store.serializers.KryoNamespaces; |
| 42 | import org.onlab.onos.store.serializers.KryoSerializer; | 43 | import org.onlab.onos.store.serializers.KryoSerializer; |
| 43 | import org.onlab.util.KryoNamespace; | 44 | import org.onlab.util.KryoNamespace; |
| 44 | 45 | ||
| 45 | -import com.google.common.collect.ImmutableSet; | ||
| 46 | import com.hazelcast.core.EntryEvent; | 46 | import com.hazelcast.core.EntryEvent; |
| 47 | import com.hazelcast.core.EntryListener; | 47 | import com.hazelcast.core.EntryListener; |
| 48 | import com.hazelcast.core.IAtomicLong; | 48 | import com.hazelcast.core.IAtomicLong; |
| ... | @@ -106,46 +106,50 @@ implements MastershipStore { | ... | @@ -106,46 +106,50 @@ implements MastershipStore { |
| 106 | 106 | ||
| 107 | @Override | 107 | @Override |
| 108 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 108 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
| 109 | - final RoleValue roleInfo = getRoleValue(deviceId); | 109 | + final RoleValue roleInfo = roleMap.get(deviceId); |
| 110 | - if (roleInfo.contains(MASTER, nodeId)) { | 110 | + if (roleInfo != null) { |
| 111 | - return MASTER; | 111 | + return roleInfo.getRole(nodeId); |
| 112 | - } | ||
| 113 | - if (roleInfo.contains(STANDBY, nodeId)) { | ||
| 114 | - return STANDBY; | ||
| 115 | } | 112 | } |
| 116 | return NONE; | 113 | return NONE; |
| 117 | } | 114 | } |
| 118 | 115 | ||
| 119 | @Override | 116 | @Override |
| 120 | - public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { | 117 | + public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) { |
| 121 | 118 | ||
| 122 | - MastershipRole role = getRole(nodeId, deviceId); | ||
| 123 | roleMap.lock(deviceId); | 119 | roleMap.lock(deviceId); |
| 124 | try { | 120 | try { |
| 125 | - RoleValue rv = getRoleValue(deviceId); | 121 | + final RoleValue rv = getRoleValue(deviceId); |
| 126 | - switch (role) { | 122 | + final MastershipRole currentRole = rv.getRole(newMaster); |
| 123 | + switch (currentRole) { | ||
| 127 | case MASTER: | 124 | case MASTER: |
| 128 | //reinforce mastership | 125 | //reinforce mastership |
| 129 | - rv.reassign(nodeId, STANDBY, NONE); | 126 | + // RoleInfo integrity check |
| 130 | - roleMap.put(deviceId, rv); | 127 | + boolean modified = rv.reassign(newMaster, STANDBY, NONE); |
| 128 | + if (modified) { | ||
| 129 | + roleMap.put(deviceId, rv); | ||
| 130 | + // should never reach here. | ||
| 131 | + log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId); | ||
| 132 | + // trigger BACKUPS_CHANGED? | ||
| 133 | + } | ||
| 131 | return null; | 134 | return null; |
| 132 | case STANDBY: | 135 | case STANDBY: |
| 133 | case NONE: | 136 | case NONE: |
| 134 | - NodeId current = rv.get(MASTER); | 137 | + final NodeId currentMaster = rv.get(MASTER); |
| 135 | - if (current != null) { | 138 | + if (currentMaster != null) { |
| 136 | - //backup and replace current master | 139 | + // place current master in STANDBY |
| 137 | - rv.reassign(current, NONE, STANDBY); | 140 | + rv.reassign(currentMaster, NONE, STANDBY); |
| 138 | - rv.replace(current, nodeId, MASTER); | 141 | + rv.replace(currentMaster, newMaster, MASTER); |
| 139 | } else { | 142 | } else { |
| 140 | //no master before so just add. | 143 | //no master before so just add. |
| 141 | - rv.add(MASTER, nodeId); | 144 | + rv.add(MASTER, newMaster); |
| 142 | } | 145 | } |
| 143 | - rv.reassign(nodeId, STANDBY, NONE); | 146 | + // remove newMaster from STANDBY |
| 144 | - roleMap.put(deviceId, rv); | 147 | + rv.reassign(newMaster, STANDBY, NONE); |
| 145 | updateTerm(deviceId); | 148 | updateTerm(deviceId); |
| 149 | + roleMap.put(deviceId, rv); | ||
| 146 | return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | 150 | return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); |
| 147 | default: | 151 | default: |
| 148 | - log.warn("unknown Mastership Role {}", role); | 152 | + log.warn("unknown Mastership Role {}", currentRole); |
| 149 | return null; | 153 | return null; |
| 150 | } | 154 | } |
| 151 | } finally { | 155 | } finally { |
| ... | @@ -161,66 +165,83 @@ implements MastershipStore { | ... | @@ -161,66 +165,83 @@ implements MastershipStore { |
| 161 | 165 | ||
| 162 | @Override | 166 | @Override |
| 163 | public RoleInfo getNodes(DeviceId deviceId) { | 167 | public RoleInfo getNodes(DeviceId deviceId) { |
| 164 | - roleMap.lock(deviceId); | 168 | + RoleValue rv = roleMap.get(deviceId); |
| 165 | - try { | 169 | + if (rv != null) { |
| 166 | - RoleValue rv = getRoleValue(deviceId); | ||
| 167 | return rv.roleInfo(); | 170 | return rv.roleInfo(); |
| 168 | - } finally { | 171 | + } else { |
| 169 | - roleMap.unlock(deviceId); | 172 | + return new RoleInfo(); |
| 170 | } | 173 | } |
| 171 | } | 174 | } |
| 172 | 175 | ||
| 173 | @Override | 176 | @Override |
| 174 | public Set<DeviceId> getDevices(NodeId nodeId) { | 177 | public Set<DeviceId> getDevices(NodeId nodeId) { |
| 175 | - ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder(); | 178 | + Set<DeviceId> devices = new HashSet<>(); |
| 176 | 179 | ||
| 177 | for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) { | 180 | for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) { |
| 178 | if (nodeId.equals(el.getValue().get(MASTER))) { | 181 | if (nodeId.equals(el.getValue().get(MASTER))) { |
| 179 | - builder.add(el.getKey()); | 182 | + devices.add(el.getKey()); |
| 180 | } | 183 | } |
| 181 | } | 184 | } |
| 182 | 185 | ||
| 183 | - return builder.build(); | 186 | + return devices; |
| 184 | } | 187 | } |
| 185 | 188 | ||
| 186 | @Override | 189 | @Override |
| 187 | public MastershipRole requestRole(DeviceId deviceId) { | 190 | public MastershipRole requestRole(DeviceId deviceId) { |
| 188 | - NodeId local = clusterService.getLocalNode().id(); | ||
| 189 | 191 | ||
| 192 | + // if no master => become master | ||
| 193 | + // if there already exists a master: | ||
| 194 | + // if I was the master return MASTER | ||
| 195 | + // else put myself in STANDBY and return STANDBY | ||
| 196 | + | ||
| 197 | + final NodeId local = clusterService.getLocalNode().id(); | ||
| 198 | + boolean modified = false; | ||
| 190 | roleMap.lock(deviceId); | 199 | roleMap.lock(deviceId); |
| 191 | try { | 200 | try { |
| 192 | - RoleValue rv = getRoleValue(deviceId); | 201 | + final RoleValue rv = getRoleValue(deviceId); |
| 193 | - MastershipRole role = getRole(local, deviceId); | 202 | + if (rv.get(MASTER) == null) { |
| 194 | - switch (role) { | 203 | + // there's no master become one |
| 204 | + // move out from STANDBY | ||
| 205 | + rv.reassign(local, STANDBY, NONE); | ||
| 206 | + rv.add(MASTER, local); | ||
| 207 | + | ||
| 208 | + updateTerm(deviceId); | ||
| 209 | + roleMap.put(deviceId, rv); | ||
| 210 | + return MASTER; | ||
| 211 | + } | ||
| 212 | + final MastershipRole currentRole = rv.getRole(local); | ||
| 213 | + switch (currentRole) { | ||
| 195 | case MASTER: | 214 | case MASTER: |
| 196 | - rv.reassign(local, STANDBY, NONE); | 215 | + // RoleInfo integrity check |
| 197 | - terms.putIfAbsent(deviceId, INIT); | 216 | + modified = rv.reassign(local, STANDBY, NONE); |
| 198 | - roleMap.put(deviceId, rv); | 217 | + if (modified) { |
| 199 | - break; | 218 | + log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId); |
| 219 | + // should never reach here, | ||
| 220 | + // but heal if we happened to be there | ||
| 221 | + roleMap.put(deviceId, rv); | ||
| 222 | + // trigger BACKUPS_CHANGED? | ||
| 223 | + } | ||
| 224 | + return currentRole; | ||
| 200 | case STANDBY: | 225 | case STANDBY: |
| 201 | - rv.reassign(local, NONE, STANDBY); | 226 | + // RoleInfo integrity check |
| 202 | - roleMap.put(deviceId, rv); | 227 | + modified = rv.reassign(local, NONE, STANDBY); |
| 203 | - terms.putIfAbsent(deviceId, INIT); | 228 | + if (modified) { |
| 204 | - break; | 229 | + log.warn("{} was in both NONE and STANDBY for {}", local, deviceId); |
| 205 | - case NONE: | 230 | + // should never reach here, |
| 206 | - //either we're the first standby, or first to device. | 231 | + // but heal if we happened to be there |
| 207 | - //for latter, claim mastership. | 232 | + roleMap.put(deviceId, rv); |
| 208 | - if (rv.get(MASTER) == null) { | 233 | + // trigger BACKUPS_CHANGED? |
| 209 | - rv.add(MASTER, local); | ||
| 210 | - rv.reassign(local, STANDBY, NONE); | ||
| 211 | - updateTerm(deviceId); | ||
| 212 | - role = MastershipRole.MASTER; | ||
| 213 | - } else { | ||
| 214 | - rv.add(STANDBY, local); | ||
| 215 | - rv.reassign(local, NONE, STANDBY); | ||
| 216 | - role = MastershipRole.STANDBY; | ||
| 217 | } | 234 | } |
| 235 | + return currentRole; | ||
| 236 | + case NONE: | ||
| 237 | + rv.reassign(local, NONE, STANDBY); | ||
| 218 | roleMap.put(deviceId, rv); | 238 | roleMap.put(deviceId, rv); |
| 219 | - break; | 239 | + // TODO: notifyDelegate BACKUPS_CHANGED |
| 240 | + return STANDBY; | ||
| 220 | default: | 241 | default: |
| 221 | - log.warn("unknown Mastership Role {}", role); | 242 | + log.warn("unknown Mastership Role {}", currentRole); |
| 222 | } | 243 | } |
| 223 | - return role; | 244 | + return currentRole; |
| 224 | } finally { | 245 | } finally { |
| 225 | roleMap.unlock(deviceId); | 246 | roleMap.unlock(deviceId); |
| 226 | } | 247 | } |
| ... | @@ -228,35 +249,58 @@ implements MastershipStore { | ... | @@ -228,35 +249,58 @@ implements MastershipStore { |
| 228 | 249 | ||
| 229 | @Override | 250 | @Override |
| 230 | public MastershipTerm getTermFor(DeviceId deviceId) { | 251 | public MastershipTerm getTermFor(DeviceId deviceId) { |
| 231 | - RoleValue rv = getRoleValue(deviceId); | 252 | + // term information and role must be read atomically |
| 232 | - if ((rv.get(MASTER) == null) || (terms.get(deviceId) == null)) { | 253 | + // acquiring write lock for the device |
| 233 | - return null; | 254 | + roleMap.lock(deviceId); |
| 255 | + try { | ||
| 256 | + RoleValue rv = getRoleValue(deviceId); | ||
| 257 | + final Integer term = terms.get(deviceId); | ||
| 258 | + final NodeId master = rv.get(MASTER); | ||
| 259 | + if ((master == null) || (term == null)) { | ||
| 260 | + return null; | ||
| 261 | + } | ||
| 262 | + return MastershipTerm.of(master, term); | ||
| 263 | + } finally { | ||
| 264 | + roleMap.unlock(deviceId); | ||
| 234 | } | 265 | } |
| 235 | - return MastershipTerm.of(rv.get(MASTER), terms.get(deviceId)); | ||
| 236 | } | 266 | } |
| 237 | 267 | ||
| 238 | @Override | 268 | @Override |
| 239 | public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) { | 269 | public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) { |
| 240 | - MastershipEvent event = null; | 270 | + // if nodeId was MASTER, rotate STANDBY |
| 271 | + // if nodeId was STANDBY no-op | ||
| 272 | + // if nodeId was NONE, add to STANDBY | ||
| 241 | 273 | ||
| 242 | roleMap.lock(deviceId); | 274 | roleMap.lock(deviceId); |
| 243 | try { | 275 | try { |
| 244 | - RoleValue rv = getRoleValue(deviceId); | 276 | + final RoleValue rv = getRoleValue(deviceId); |
| 245 | - MastershipRole role = getRole(nodeId, deviceId); | 277 | + final MastershipRole currentRole = getRole(nodeId, deviceId); |
| 246 | - switch (role) { | 278 | + switch (currentRole) { |
| 247 | case MASTER: | 279 | case MASTER: |
| 248 | - event = reelect(nodeId, deviceId, rv); | 280 | + NodeId newMaster = reelect(nodeId, deviceId, rv); |
| 249 | - //fall through to reinforce role | 281 | + rv.reassign(nodeId, NONE, STANDBY); |
| 282 | + if (newMaster != null) { | ||
| 283 | + updateTerm(deviceId); | ||
| 284 | + roleMap.put(deviceId, rv); | ||
| 285 | + return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | ||
| 286 | + } else { | ||
| 287 | + // no master candidate | ||
| 288 | + roleMap.put(deviceId, rv); | ||
| 289 | + // FIXME: Should there be new event type? | ||
| 290 | + // or should we issue null Master event? | ||
| 291 | + return null; | ||
| 292 | + } | ||
| 250 | case STANDBY: | 293 | case STANDBY: |
| 251 | - //fall through to reinforce role | 294 | + return null; |
| 252 | case NONE: | 295 | case NONE: |
| 253 | rv.reassign(nodeId, NONE, STANDBY); | 296 | rv.reassign(nodeId, NONE, STANDBY); |
| 254 | roleMap.put(deviceId, rv); | 297 | roleMap.put(deviceId, rv); |
| 255 | - break; | 298 | + // TODO: BACKUPS_CHANGED? |
| 299 | + return null; | ||
| 256 | default: | 300 | default: |
| 257 | - log.warn("unknown Mastership Role {}", role); | 301 | + log.warn("unknown Mastership Role {}", currentRole); |
| 258 | } | 302 | } |
| 259 | - return event; | 303 | + return null; |
| 260 | } finally { | 304 | } finally { |
| 261 | roleMap.unlock(deviceId); | 305 | roleMap.unlock(deviceId); |
| 262 | } | 306 | } |
| ... | @@ -264,56 +308,71 @@ implements MastershipStore { | ... | @@ -264,56 +308,71 @@ implements MastershipStore { |
| 264 | 308 | ||
| 265 | @Override | 309 | @Override |
| 266 | public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) { | 310 | public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) { |
| 267 | - MastershipEvent event = null; | 311 | + // relinquishRole is basically set to None |
| 312 | + | ||
| 313 | + // If nodeId was master reelect next and remove nodeId | ||
| 314 | + // else remove from STANDBY | ||
| 268 | 315 | ||
| 269 | roleMap.lock(deviceId); | 316 | roleMap.lock(deviceId); |
| 270 | try { | 317 | try { |
| 271 | - RoleValue rv = getRoleValue(deviceId); | 318 | + final RoleValue rv = getRoleValue(deviceId); |
| 272 | - MastershipRole role = getRole(nodeId, deviceId); | 319 | + final MastershipRole currentRole = rv.getRole(nodeId); |
| 273 | - switch (role) { | 320 | + switch (currentRole) { |
| 274 | case MASTER: | 321 | case MASTER: |
| 275 | - event = reelect(nodeId, deviceId, rv); | 322 | + NodeId newMaster = reelect(nodeId, deviceId, rv); |
| 276 | - if (event != null) { | 323 | + if (newMaster != null) { |
| 277 | updateTerm(deviceId); | 324 | updateTerm(deviceId); |
| 325 | + roleMap.put(deviceId, rv); | ||
| 326 | + return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | ||
| 327 | + } else { | ||
| 328 | + // no master candidate | ||
| 329 | + roleMap.put(deviceId, rv); | ||
| 330 | + // Should there be new event type? | ||
| 331 | + return null; | ||
| 278 | } | 332 | } |
| 279 | - //fall through to reinforce relinquishment | ||
| 280 | case STANDBY: | 333 | case STANDBY: |
| 281 | //fall through to reinforce relinquishment | 334 | //fall through to reinforce relinquishment |
| 282 | case NONE: | 335 | case NONE: |
| 283 | - rv.reassign(nodeId, STANDBY, NONE); | 336 | + boolean modified = rv.reassign(nodeId, STANDBY, NONE); |
| 284 | - roleMap.put(deviceId, rv); | 337 | + if (modified) { |
| 285 | - break; | 338 | + roleMap.put(deviceId, rv); |
| 339 | + // TODO: BACKUPS_CHANGED? | ||
| 340 | + return null; | ||
| 341 | + } | ||
| 342 | + return null; | ||
| 286 | default: | 343 | default: |
| 287 | - log.warn("unknown Mastership Role {}", role); | 344 | + log.warn("unknown Mastership Role {}", currentRole); |
| 288 | } | 345 | } |
| 289 | - return event; | 346 | + return null; |
| 290 | } finally { | 347 | } finally { |
| 291 | roleMap.unlock(deviceId); | 348 | roleMap.unlock(deviceId); |
| 292 | } | 349 | } |
| 293 | } | 350 | } |
| 294 | 351 | ||
| 352 | + // TODO: Consider moving this to RoleValue method | ||
| 295 | //helper to fetch a new master candidate for a given device. | 353 | //helper to fetch a new master candidate for a given device. |
| 296 | - private MastershipEvent reelect( | 354 | + private NodeId reelect( |
| 297 | NodeId current, DeviceId deviceId, RoleValue rv) { | 355 | NodeId current, DeviceId deviceId, RoleValue rv) { |
| 298 | 356 | ||
| 299 | //if this is an queue it'd be neater. | 357 | //if this is an queue it'd be neater. |
| 300 | - NodeId backup = null; | 358 | + NodeId candidate = null; |
| 301 | for (NodeId n : rv.nodesOfRole(STANDBY)) { | 359 | for (NodeId n : rv.nodesOfRole(STANDBY)) { |
| 302 | if (!current.equals(n)) { | 360 | if (!current.equals(n)) { |
| 303 | - backup = n; | 361 | + candidate = n; |
| 304 | break; | 362 | break; |
| 305 | } | 363 | } |
| 306 | } | 364 | } |
| 307 | 365 | ||
| 308 | - if (backup == null) { | 366 | + if (candidate == null) { |
| 309 | log.info("{} giving up and going to NONE for {}", current, deviceId); | 367 | log.info("{} giving up and going to NONE for {}", current, deviceId); |
| 310 | rv.remove(MASTER, current); | 368 | rv.remove(MASTER, current); |
| 369 | + // master did change, but there is no master candidate. | ||
| 311 | return null; | 370 | return null; |
| 312 | } else { | 371 | } else { |
| 313 | - log.info("{} trying to pass mastership for {} to {}", current, deviceId, backup); | 372 | + log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate); |
| 314 | - rv.replace(current, backup, MASTER); | 373 | + rv.replace(current, candidate, MASTER); |
| 315 | - rv.reassign(backup, STANDBY, NONE); | 374 | + rv.reassign(candidate, STANDBY, NONE); |
| 316 | - return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | 375 | + return candidate; |
| 317 | } | 376 | } |
| 318 | } | 377 | } |
| 319 | 378 | ||
| ... | @@ -340,6 +399,7 @@ implements MastershipStore { | ... | @@ -340,6 +399,7 @@ implements MastershipStore { |
| 340 | } | 399 | } |
| 341 | 400 | ||
| 342 | //adds or updates term information. | 401 | //adds or updates term information. |
| 402 | + // must be guarded by roleMap.lock(deviceId) | ||
| 343 | private void updateTerm(DeviceId deviceId) { | 403 | private void updateTerm(DeviceId deviceId) { |
| 344 | Integer term = terms.get(deviceId); | 404 | Integer term = terms.get(deviceId); |
| 345 | if (term == null) { | 405 | if (term == null) { | ... | ... |
| ... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onlab.onos.store.mastership.impl; | 16 | package org.onlab.onos.store.mastership.impl; |
| 17 | 17 | ||
| 18 | +import static org.onlab.onos.net.MastershipRole.MASTER; | ||
| 19 | +import static org.onlab.onos.net.MastershipRole.NONE; | ||
| 20 | +import static org.onlab.onos.net.MastershipRole.STANDBY; | ||
| 21 | + | ||
| 18 | import java.util.Collections; | 22 | import java.util.Collections; |
| 19 | import java.util.EnumMap; | 23 | import java.util.EnumMap; |
| 20 | import java.util.LinkedList; | 24 | import java.util.LinkedList; |
| ... | @@ -59,18 +63,30 @@ final class RoleValue { | ... | @@ -59,18 +63,30 @@ final class RoleValue { |
| 59 | return value.get(type).contains(nodeId); | 63 | return value.get(type).contains(nodeId); |
| 60 | } | 64 | } |
| 61 | 65 | ||
| 66 | + public MastershipRole getRole(NodeId nodeId) { | ||
| 67 | + if (contains(MASTER, nodeId)) { | ||
| 68 | + return MASTER; | ||
| 69 | + } | ||
| 70 | + if (contains(STANDBY, nodeId)) { | ||
| 71 | + return STANDBY; | ||
| 72 | + } | ||
| 73 | + return NONE; | ||
| 74 | + } | ||
| 75 | + | ||
| 62 | /** | 76 | /** |
| 63 | * Associates a node to a certain role. | 77 | * Associates a node to a certain role. |
| 64 | * | 78 | * |
| 65 | * @param type the role | 79 | * @param type the role |
| 66 | * @param nodeId the node ID of the node to associate | 80 | * @param nodeId the node ID of the node to associate |
| 81 | + * @return true if modified | ||
| 67 | */ | 82 | */ |
| 68 | - public void add(MastershipRole type, NodeId nodeId) { | 83 | + public boolean add(MastershipRole type, NodeId nodeId) { |
| 69 | List<NodeId> nodes = value.get(type); | 84 | List<NodeId> nodes = value.get(type); |
| 70 | 85 | ||
| 71 | if (!nodes.contains(nodeId)) { | 86 | if (!nodes.contains(nodeId)) { |
| 72 | - nodes.add(nodeId); | 87 | + return nodes.add(nodeId); |
| 73 | } | 88 | } |
| 89 | + return false; | ||
| 74 | } | 90 | } |
| 75 | 91 | ||
| 76 | /** | 92 | /** |
| ... | @@ -78,7 +94,7 @@ final class RoleValue { | ... | @@ -78,7 +94,7 @@ final class RoleValue { |
| 78 | * | 94 | * |
| 79 | * @param type the role | 95 | * @param type the role |
| 80 | * @param nodeId the ID of the node to remove | 96 | * @param nodeId the ID of the node to remove |
| 81 | - * @return | 97 | + * @return true if modified |
| 82 | */ | 98 | */ |
| 83 | public boolean remove(MastershipRole type, NodeId nodeId) { | 99 | public boolean remove(MastershipRole type, NodeId nodeId) { |
| 84 | List<NodeId> nodes = value.get(type); | 100 | List<NodeId> nodes = value.get(type); |
| ... | @@ -96,10 +112,12 @@ final class RoleValue { | ... | @@ -96,10 +112,12 @@ final class RoleValue { |
| 96 | * @param nodeId the Node ID of node changing roles | 112 | * @param nodeId the Node ID of node changing roles |
| 97 | * @param from the old role | 113 | * @param from the old role |
| 98 | * @param to the new role | 114 | * @param to the new role |
| 115 | + * @return true if modified | ||
| 99 | */ | 116 | */ |
| 100 | - public void reassign(NodeId nodeId, MastershipRole from, MastershipRole to) { | 117 | + public boolean reassign(NodeId nodeId, MastershipRole from, MastershipRole to) { |
| 101 | - remove(from, nodeId); | 118 | + boolean modified = remove(from, nodeId); |
| 102 | - add(to, nodeId); | 119 | + modified |= add(to, nodeId); |
| 120 | + return modified; | ||
| 103 | } | 121 | } |
| 104 | 122 | ||
| 105 | /** | 123 | /** |
| ... | @@ -109,10 +127,12 @@ final class RoleValue { | ... | @@ -109,10 +127,12 @@ final class RoleValue { |
| 109 | * @param from the old NodeId to replace | 127 | * @param from the old NodeId to replace |
| 110 | * @param to the new NodeId | 128 | * @param to the new NodeId |
| 111 | * @param type the role associated with the old NodeId | 129 | * @param type the role associated with the old NodeId |
| 130 | + * @return true if modified | ||
| 112 | */ | 131 | */ |
| 113 | - public void replace(NodeId from, NodeId to, MastershipRole type) { | 132 | + public boolean replace(NodeId from, NodeId to, MastershipRole type) { |
| 114 | - remove(type, from); | 133 | + boolean modified = remove(type, from); |
| 115 | - add(type, to); | 134 | + modified |= add(type, to); |
| 135 | + return modified; | ||
| 116 | } | 136 | } |
| 117 | 137 | ||
| 118 | /** | 138 | /** | ... | ... |
| ... | @@ -142,7 +142,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -142,7 +142,7 @@ public class DistributedMastershipStoreTest { |
| 142 | testStore.setCurrent(CN1); | 142 | testStore.setCurrent(CN1); |
| 143 | 143 | ||
| 144 | //if already MASTER, nothing should happen | 144 | //if already MASTER, nothing should happen |
| 145 | - testStore.put(DID2, N1, true, false, false); | 145 | + testStore.put(DID2, N1, true, false, true); |
| 146 | assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2)); | 146 | assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2)); |
| 147 | 147 | ||
| 148 | //populate maps with DID1, N1 thru NONE case | 148 | //populate maps with DID1, N1 thru NONE case | ... | ... |
-
Please register or login to post a comment