Committed by
Madan Jampani
Create local storage for topic candidates mapping. This also includes:
- using Optional in Leadership, and some commenting. - using MutableBooleans + compute() part of: Device Mastership store on top of LeadershipService Reference: ONOS-76 Conflicts: core/api/src/main/java/org/onosproject/cluster/LeadershipService.java core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DistributedLeadershipManager.java Change-Id: I7f090abb123cf23bb5126a935a6e72be00f3e3ce
Showing
8 changed files
with
149 additions
and
68 deletions
... | @@ -85,7 +85,7 @@ public class LeaderCommand extends AbstractShellCommand { | ... | @@ -85,7 +85,7 @@ public class LeaderCommand extends AbstractShellCommand { |
85 | } | 85 | } |
86 | 86 | ||
87 | private void displayCandidates(Map<String, Leadership> leaderBoard, | 87 | private void displayCandidates(Map<String, Leadership> leaderBoard, |
88 | - Map<String, List<NodeId>> candidates) { | 88 | + Map<String, Leadership> candidates) { |
89 | print("--------------------------------------------------------------"); | 89 | print("--------------------------------------------------------------"); |
90 | print(FMT_C, "Topic", "Leader", "Candidates"); | 90 | print(FMT_C, "Topic", "Leader", "Candidates"); |
91 | print("--------------------------------------------------------------"); | 91 | print("--------------------------------------------------------------"); |
... | @@ -94,13 +94,13 @@ public class LeaderCommand extends AbstractShellCommand { | ... | @@ -94,13 +94,13 @@ public class LeaderCommand extends AbstractShellCommand { |
94 | .stream() | 94 | .stream() |
95 | .sorted(leadershipComparator) | 95 | .sorted(leadershipComparator) |
96 | .forEach(l -> { | 96 | .forEach(l -> { |
97 | - List<NodeId> list = candidates.get(l.topic()); | 97 | + List<NodeId> list = candidates.get(l.topic()).candidates(); |
98 | print(FMT_C, | 98 | print(FMT_C, |
99 | l.topic(), | 99 | l.topic(), |
100 | l.leader(), | 100 | l.leader(), |
101 | - list.remove(0).toString()); | 101 | + list.get(0).toString()); |
102 | // formatting hacks to get it into a table | 102 | // formatting hacks to get it into a table |
103 | - list.forEach(n -> print(FMT_C, " ", " ", n)); | 103 | + list.subList(1, list.size()).forEach(n -> print(FMT_C, " ", " ", n)); |
104 | print(FMT_C, " ", " ", " "); | 104 | print(FMT_C, " ", " ", " "); |
105 | }); | 105 | }); |
106 | print("--------------------------------------------------------------"); | 106 | print("--------------------------------------------------------------"); |
... | @@ -139,7 +139,7 @@ public class LeaderCommand extends AbstractShellCommand { | ... | @@ -139,7 +139,7 @@ public class LeaderCommand extends AbstractShellCommand { |
139 | print("%s", json(leaderBoard)); | 139 | print("%s", json(leaderBoard)); |
140 | } else { | 140 | } else { |
141 | if (showCandidates) { | 141 | if (showCandidates) { |
142 | - Map<String, List<NodeId>> candidates = leaderService.getCandidates(); | 142 | + Map<String, Leadership> candidates = leaderService.getCandidates(); |
143 | displayCandidates(leaderBoard, candidates); | 143 | displayCandidates(leaderBoard, candidates); |
144 | } else { | 144 | } else { |
145 | displayLeaders(leaderBoard); | 145 | displayLeaders(leaderBoard); | ... | ... |
... | @@ -17,6 +17,7 @@ package org.onosproject.cluster; | ... | @@ -17,6 +17,7 @@ package org.onosproject.cluster; |
17 | 17 | ||
18 | import java.util.Objects; | 18 | import java.util.Objects; |
19 | import java.util.List; | 19 | import java.util.List; |
20 | +import java.util.Optional; | ||
20 | 21 | ||
21 | import org.joda.time.DateTime; | 22 | import org.joda.time.DateTime; |
22 | 23 | ||
... | @@ -33,19 +34,21 @@ import com.google.common.collect.ImmutableList; | ... | @@ -33,19 +34,21 @@ import com.google.common.collect.ImmutableList; |
33 | * rest in decreasing preference order.</li> | 34 | * rest in decreasing preference order.</li> |
34 | * <li>The epoch is the logical age of a Leadership construct, and should be | 35 | * <li>The epoch is the logical age of a Leadership construct, and should be |
35 | * used for comparing two Leaderships, but only of the same topic.</li> | 36 | * used for comparing two Leaderships, but only of the same topic.</li> |
37 | + * <li>The leader may be null if its accuracy can't be guaranteed. This applies | ||
38 | + * to CANDIDATES_CHANGED events and candidate board contents.</li> | ||
36 | * </ul> | 39 | * </ul> |
37 | */ | 40 | */ |
38 | public class Leadership { | 41 | public class Leadership { |
39 | 42 | ||
40 | private final String topic; | 43 | private final String topic; |
41 | - private final NodeId leader; | 44 | + private final Optional<NodeId> leader; |
42 | private final List<NodeId> candidates; | 45 | private final List<NodeId> candidates; |
43 | private final long epoch; | 46 | private final long epoch; |
44 | private final long electedTime; | 47 | private final long electedTime; |
45 | 48 | ||
46 | public Leadership(String topic, NodeId leader, long epoch, long electedTime) { | 49 | public Leadership(String topic, NodeId leader, long epoch, long electedTime) { |
47 | this.topic = topic; | 50 | this.topic = topic; |
48 | - this.leader = leader; | 51 | + this.leader = Optional.of(leader); |
49 | this.candidates = ImmutableList.of(leader); | 52 | this.candidates = ImmutableList.of(leader); |
50 | this.epoch = epoch; | 53 | this.epoch = epoch; |
51 | this.electedTime = electedTime; | 54 | this.electedTime = electedTime; |
... | @@ -54,7 +57,16 @@ public class Leadership { | ... | @@ -54,7 +57,16 @@ public class Leadership { |
54 | public Leadership(String topic, NodeId leader, List<NodeId> candidates, | 57 | public Leadership(String topic, NodeId leader, List<NodeId> candidates, |
55 | long epoch, long electedTime) { | 58 | long epoch, long electedTime) { |
56 | this.topic = topic; | 59 | this.topic = topic; |
57 | - this.leader = leader; | 60 | + this.leader = Optional.of(leader); |
61 | + this.candidates = ImmutableList.copyOf(candidates); | ||
62 | + this.epoch = epoch; | ||
63 | + this.electedTime = electedTime; | ||
64 | + } | ||
65 | + | ||
66 | + public Leadership(String topic, List<NodeId> candidates, | ||
67 | + long epoch, long electedTime) { | ||
68 | + this.topic = topic; | ||
69 | + this.leader = Optional.empty(); | ||
58 | this.candidates = ImmutableList.copyOf(candidates); | 70 | this.candidates = ImmutableList.copyOf(candidates); |
59 | this.epoch = epoch; | 71 | this.epoch = epoch; |
60 | this.electedTime = electedTime; | 72 | this.electedTime = electedTime; |
... | @@ -74,8 +86,9 @@ public class Leadership { | ... | @@ -74,8 +86,9 @@ public class Leadership { |
74 | * | 86 | * |
75 | * @return leader node. | 87 | * @return leader node. |
76 | */ | 88 | */ |
89 | + // This will return Optional<NodeId> in the future. | ||
77 | public NodeId leader() { | 90 | public NodeId leader() { |
78 | - return leader; | 91 | + return leader.orElse(null); |
79 | } | 92 | } |
80 | 93 | ||
81 | /** | 94 | /** | ... | ... |
... | @@ -43,14 +43,14 @@ public class LeadershipEvent extends AbstractEvent<LeadershipEvent.Type, Leaders | ... | @@ -43,14 +43,14 @@ public class LeadershipEvent extends AbstractEvent<LeadershipEvent.Type, Leaders |
43 | LEADER_REELECTED, | 43 | LEADER_REELECTED, |
44 | 44 | ||
45 | /** | 45 | /** |
46 | - * Signifies that the leader has been booted and lost leadership. The event subject is the | 46 | + * Signifies that the leader has been booted and lost leadership. The |
47 | - * former leader. | 47 | + * event subject is the former leader. |
48 | */ | 48 | */ |
49 | LEADER_BOOTED, | 49 | LEADER_BOOTED, |
50 | 50 | ||
51 | /** | 51 | /** |
52 | * Signifies that the list of candidates for leadership for a topic has | 52 | * Signifies that the list of candidates for leadership for a topic has |
53 | - * changed. | 53 | + * changed. This event does not guarantee accurate leader information. |
54 | */ | 54 | */ |
55 | CANDIDATES_CHANGED | 55 | CANDIDATES_CHANGED |
56 | } | 56 | } | ... | ... |
... | @@ -76,9 +76,9 @@ public interface LeadershipService { | ... | @@ -76,9 +76,9 @@ public interface LeadershipService { |
76 | /** | 76 | /** |
77 | * Returns the candidates for all known topics. | 77 | * Returns the candidates for all known topics. |
78 | * | 78 | * |
79 | - * @return A map of topics to lists of NodeIds. | 79 | + * @return A mapping from topics to up-to-date candidate info. |
80 | */ | 80 | */ |
81 | - Map<String, List<NodeId>> getCandidates(); | 81 | + Map<String, Leadership> getCandidates(); |
82 | 82 | ||
83 | /** | 83 | /** |
84 | * Returns the candidates for a given topic. | 84 | * Returns the candidates for a given topic. | ... | ... |
... | @@ -65,7 +65,7 @@ public class LeadershipServiceAdapter implements LeadershipService { | ... | @@ -65,7 +65,7 @@ public class LeadershipServiceAdapter implements LeadershipService { |
65 | } | 65 | } |
66 | 66 | ||
67 | @Override | 67 | @Override |
68 | - public Map<String, List<NodeId>> getCandidates() { | 68 | + public Map<String, Leadership> getCandidates() { |
69 | return null; | 69 | return null; |
70 | } | 70 | } |
71 | 71 | ... | ... |
... | @@ -576,7 +576,7 @@ public class HazelcastLeadershipService implements LeadershipService { | ... | @@ -576,7 +576,7 @@ public class HazelcastLeadershipService implements LeadershipService { |
576 | } | 576 | } |
577 | 577 | ||
578 | @Override | 578 | @Override |
579 | - public Map<String, List<NodeId>> getCandidates() { | 579 | + public Map<String, Leadership> getCandidates() { |
580 | return null; | 580 | return null; |
581 | } | 581 | } |
582 | 582 | ... | ... |
... | @@ -12,6 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -12,6 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
12 | import org.apache.felix.scr.annotations.Reference; | 12 | import org.apache.felix.scr.annotations.Reference; |
13 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 13 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
14 | import org.apache.felix.scr.annotations.Service; | 14 | import org.apache.felix.scr.annotations.Service; |
15 | +import org.apache.commons.lang3.mutable.MutableBoolean; | ||
15 | import org.onlab.util.KryoNamespace; | 16 | import org.onlab.util.KryoNamespace; |
16 | import org.onosproject.cluster.ClusterService; | 17 | import org.onosproject.cluster.ClusterService; |
17 | import org.onosproject.cluster.ControllerNode; | 18 | import org.onosproject.cluster.ControllerNode; |
... | @@ -88,6 +89,7 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -88,6 +89,7 @@ public class DistributedLeadershipManager implements LeadershipService { |
88 | private AbstractListenerRegistry<LeadershipEvent, LeadershipEventListener> | 89 | private AbstractListenerRegistry<LeadershipEvent, LeadershipEventListener> |
89 | listenerRegistry; | 90 | listenerRegistry; |
90 | private final Map<String, Leadership> leaderBoard = Maps.newConcurrentMap(); | 91 | private final Map<String, Leadership> leaderBoard = Maps.newConcurrentMap(); |
92 | + private final Map<String, Leadership> candidateBoard = Maps.newConcurrentMap(); | ||
91 | private NodeId localNodeId; | 93 | private NodeId localNodeId; |
92 | 94 | ||
93 | private Set<String> activeTopics = Sets.newConcurrentHashSet(); | 95 | private Set<String> activeTopics = Sets.newConcurrentHashSet(); |
... | @@ -164,16 +166,14 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -164,16 +166,14 @@ public class DistributedLeadershipManager implements LeadershipService { |
164 | } | 166 | } |
165 | 167 | ||
166 | @Override | 168 | @Override |
167 | - public Map<String, List<NodeId>> getCandidates() { | 169 | + public Map<String, Leadership> getCandidates() { |
168 | - Map<String, List<NodeId>> candidates = Maps.newHashMap(); | 170 | + return ImmutableMap.copyOf(candidateBoard); |
169 | - candidateMap.entrySet().forEach(el -> candidates.put(el.getKey(), el.getValue().value())); | ||
170 | - return ImmutableMap.copyOf(candidates); | ||
171 | } | 171 | } |
172 | 172 | ||
173 | @Override | 173 | @Override |
174 | public List<NodeId> getCandidates(String path) { | 174 | public List<NodeId> getCandidates(String path) { |
175 | - Versioned<List<NodeId>> candidates = candidateMap.get(path); | 175 | + Leadership current = candidateBoard.get(path); |
176 | - return candidates == null ? ImmutableList.of() : ImmutableList.copyOf(candidates.value()); | 176 | + return current == null ? ImmutableList.of() : ImmutableList.copyOf(current.candidates()); |
177 | } | 177 | } |
178 | 178 | ||
179 | @Override | 179 | @Override |
... | @@ -207,13 +207,21 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -207,13 +207,21 @@ public class DistributedLeadershipManager implements LeadershipService { |
207 | List<NodeId> candidateList = Lists.newArrayList(candidates.value()); | 207 | List<NodeId> candidateList = Lists.newArrayList(candidates.value()); |
208 | if (!candidateList.contains(localNodeId)) { | 208 | if (!candidateList.contains(localNodeId)) { |
209 | candidateList.add(localNodeId); | 209 | candidateList.add(localNodeId); |
210 | - if (!candidateMap.replace(path, candidates.version(), candidateList)) { | 210 | + if (candidateMap.replace(path, candidates.version(), candidateList)) { |
211 | + Versioned<List<NodeId>> newCandidates = candidateMap.get(path); | ||
212 | + notifyCandidateAdded( | ||
213 | + path, candidateList, newCandidates.version(), newCandidates.creationTime()); | ||
214 | + } else { | ||
211 | rerunForLeadership(path); | 215 | rerunForLeadership(path); |
212 | return; | 216 | return; |
213 | } | 217 | } |
214 | } | 218 | } |
215 | } else { | 219 | } else { |
216 | - if (!(candidateMap.putIfAbsent(path, ImmutableList.of(localNodeId)) == null)) { | 220 | + List<NodeId> candidateList = ImmutableList.of(localNodeId); |
221 | + if ((candidateMap.putIfAbsent(path, candidateList) == null)) { | ||
222 | + Versioned<List<NodeId>> newCandidates = candidateMap.get(path); | ||
223 | + notifyCandidateAdded(path, candidateList, newCandidates.version(), newCandidates.creationTime()); | ||
224 | + } else { | ||
217 | rerunForLeadership(path); | 225 | rerunForLeadership(path); |
218 | return; | 226 | return; |
219 | } | 227 | } |
... | @@ -247,10 +255,19 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -247,10 +255,19 @@ public class DistributedLeadershipManager implements LeadershipService { |
247 | if (!candidateList.remove(localNodeId)) { | 255 | if (!candidateList.remove(localNodeId)) { |
248 | return; | 256 | return; |
249 | } | 257 | } |
250 | - boolean success = candidateList.isEmpty() | 258 | + boolean success = false; |
251 | - ? candidateMap.remove(path, candidates.version()) | 259 | + if (candidateList.isEmpty()) { |
252 | - : candidateMap.replace(path, candidates.version(), candidateList); | 260 | + if (candidateMap.remove(path, candidates.version())) { |
253 | - if (!success) { | 261 | + success = true; |
262 | + } | ||
263 | + } else { | ||
264 | + if (candidateMap.replace(path, candidates.version(), candidateList)) { | ||
265 | + success = true; | ||
266 | + } | ||
267 | + } | ||
268 | + if (success) { | ||
269 | + notifyCandidateRemoved(path, candidateList, candidates.version(), candidates.creationTime()); | ||
270 | + } else { | ||
254 | log.warn("Failed to withdraw from candidates list. Will retry"); | 271 | log.warn("Failed to withdraw from candidates list. Will retry"); |
255 | retryWithdraw(path); | 272 | retryWithdraw(path); |
256 | } | 273 | } |
... | @@ -321,21 +338,63 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -321,21 +338,63 @@ public class DistributedLeadershipManager implements LeadershipService { |
321 | } | 338 | } |
322 | } | 339 | } |
323 | 340 | ||
341 | + private void notifyCandidateAdded( | ||
342 | + String path, List<NodeId> candidates, long epoch, long electedTime) { | ||
343 | + Leadership newInfo = new Leadership(path, candidates, epoch, electedTime); | ||
344 | + final MutableBoolean updated = new MutableBoolean(false); | ||
345 | + candidateBoard.compute(path, (k, current) -> { | ||
346 | + if (current == null || current.epoch() < newInfo.epoch()) { | ||
347 | + log.info("updating candidateboard with {}", newInfo); | ||
348 | + updated.setTrue(); | ||
349 | + return newInfo; | ||
350 | + } | ||
351 | + return current; | ||
352 | + }); | ||
353 | + // maybe rethink types of candidates events | ||
354 | + if (updated.booleanValue()) { | ||
355 | + LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.CANDIDATES_CHANGED, newInfo); | ||
356 | + notifyPeers(event); | ||
357 | + } | ||
358 | + } | ||
359 | + | ||
360 | + private void notifyCandidateRemoved( | ||
361 | + String path, List<NodeId> candidates, long epoch, long electedTime) { | ||
362 | + Leadership newInfo = new Leadership(path, candidates, epoch, electedTime); | ||
363 | + final MutableBoolean updated = new MutableBoolean(false); | ||
364 | + candidateBoard.compute(path, (k, current) -> { | ||
365 | + if (current != null && current.epoch() == newInfo.epoch()) { | ||
366 | + log.info("updating candidateboard with {}", newInfo); | ||
367 | + updated.setTrue(); | ||
368 | + if (candidates.isEmpty()) { | ||
369 | + return null; | ||
370 | + } else { | ||
371 | + return newInfo; | ||
372 | + } | ||
373 | + } | ||
374 | + return current; | ||
375 | + }); | ||
376 | + // maybe rethink types of candidates events | ||
377 | + if (updated.booleanValue()) { | ||
378 | + LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.CANDIDATES_CHANGED, newInfo); | ||
379 | + notifyPeers(event); | ||
380 | + } | ||
381 | + } | ||
382 | + | ||
324 | private void notifyNewLeader(String path, NodeId leader, | 383 | private void notifyNewLeader(String path, NodeId leader, |
325 | List<NodeId> candidates, long epoch, long electedTime) { | 384 | List<NodeId> candidates, long epoch, long electedTime) { |
326 | Leadership newLeadership = new Leadership(path, leader, candidates, epoch, electedTime); | 385 | Leadership newLeadership = new Leadership(path, leader, candidates, epoch, electedTime); |
327 | - boolean updatedLeader = false; | 386 | + final MutableBoolean updatedLeader = new MutableBoolean(false); |
328 | log.debug("candidates for new Leadership {}", candidates); | 387 | log.debug("candidates for new Leadership {}", candidates); |
329 | - synchronized (leaderBoard) { | 388 | + leaderBoard.compute(path, (k, currentLeader) -> { |
330 | - Leadership currentLeader = leaderBoard.get(path); | ||
331 | if (currentLeader == null || currentLeader.epoch() < epoch) { | 389 | if (currentLeader == null || currentLeader.epoch() < epoch) { |
332 | log.debug("updating leaderboard with new {}", newLeadership); | 390 | log.debug("updating leaderboard with new {}", newLeadership); |
333 | - leaderBoard.put(path, newLeadership); | 391 | + updatedLeader.setTrue(); |
334 | - updatedLeader = true; | 392 | + return newLeadership; |
335 | } | 393 | } |
336 | - } | 394 | + return currentLeader; |
395 | + }); | ||
337 | 396 | ||
338 | - if (updatedLeader) { | 397 | + if (updatedLeader.booleanValue()) { |
339 | LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.LEADER_ELECTED, newLeadership); | 398 | LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.LEADER_ELECTED, newLeadership); |
340 | notifyPeers(event); | 399 | notifyPeers(event); |
341 | } | 400 | } |
... | @@ -352,21 +411,18 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -352,21 +411,18 @@ public class DistributedLeadershipManager implements LeadershipService { |
352 | Versioned<List<NodeId>> candidates = candidateMap.get(path); | 411 | Versioned<List<NodeId>> candidates = candidateMap.get(path); |
353 | Leadership oldLeadership = new Leadership( | 412 | Leadership oldLeadership = new Leadership( |
354 | path, leader, candidates.value(), epoch, electedTime); | 413 | path, leader, candidates.value(), epoch, electedTime); |
355 | - boolean updatedLeader = false; | 414 | + final MutableBoolean updatedLeader = new MutableBoolean(false); |
356 | - synchronized (leaderBoard) { | 415 | + leaderBoard.compute(path, (k, currentLeader) -> { |
357 | - Leadership currentLeader = leaderBoard.get(path); | ||
358 | if (currentLeader != null && currentLeader.epoch() == oldLeadership.epoch()) { | 416 | if (currentLeader != null && currentLeader.epoch() == oldLeadership.epoch()) { |
359 | - leaderBoard.remove(path); | 417 | + updatedLeader.setTrue(); |
360 | - updatedLeader = true; | 418 | + return null; |
361 | } | 419 | } |
362 | - } | 420 | + return currentLeader; |
421 | + }); | ||
363 | 422 | ||
364 | - if (updatedLeader) { | 423 | + if (updatedLeader.booleanValue()) { |
365 | LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.LEADER_BOOTED, oldLeadership); | 424 | LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.LEADER_BOOTED, oldLeadership); |
366 | - eventDispatcher.post(event); | 425 | + notifyPeers(event); |
367 | - clusterCommunicator.broadcast(event, | ||
368 | - LEADERSHIP_EVENT_MESSAGE_SUBJECT, | ||
369 | - SERIALIZER::encode); | ||
370 | } | 426 | } |
371 | } | 427 | } |
372 | 428 | ||
... | @@ -385,31 +441,37 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -385,31 +441,37 @@ public class DistributedLeadershipManager implements LeadershipService { |
385 | LeadershipEvent.Type eventType = leadershipEvent.type(); | 441 | LeadershipEvent.Type eventType = leadershipEvent.type(); |
386 | String topic = leadershipUpdate.topic(); | 442 | String topic = leadershipUpdate.topic(); |
387 | 443 | ||
388 | - boolean updateAccepted = false; | 444 | + MutableBoolean updateAccepted = new MutableBoolean(false); |
389 | - | 445 | + if (eventType.equals(LeadershipEvent.Type.LEADER_ELECTED)) { |
390 | - synchronized (leaderBoard) { | 446 | + leaderBoard.compute(topic, (k, currentLeadership) -> { |
391 | - Leadership currentLeadership = leaderBoard.get(topic); | ||
392 | - if (eventType.equals(LeadershipEvent.Type.LEADER_ELECTED)) { | ||
393 | if (currentLeadership == null || currentLeadership.epoch() < leadershipUpdate.epoch()) { | 447 | if (currentLeadership == null || currentLeadership.epoch() < leadershipUpdate.epoch()) { |
394 | - leaderBoard.put(topic, leadershipUpdate); | 448 | + updateAccepted.setTrue(); |
395 | - updateAccepted = true; | 449 | + return leadershipUpdate; |
396 | } | 450 | } |
397 | - } else if (eventType.equals(LeadershipEvent.Type.LEADER_BOOTED)) { | 451 | + return currentLeadership; |
398 | - if (currentLeadership != null && currentLeadership.epoch() == leadershipUpdate.epoch()) { | 452 | + }); |
399 | - leaderBoard.remove(topic); | 453 | + } else if (eventType.equals(LeadershipEvent.Type.LEADER_BOOTED)) { |
400 | - updateAccepted = true; | 454 | + leaderBoard.compute(topic, (k, currentLeadership) -> { |
455 | + if (currentLeadership == null || currentLeadership.epoch() < leadershipUpdate.epoch()) { | ||
456 | + updateAccepted.setTrue(); | ||
457 | + return null; | ||
401 | } | 458 | } |
402 | - } else if (eventType.equals(LeadershipEvent.Type.CANDIDATES_CHANGED)) { | 459 | + return currentLeadership; |
403 | - if (currentLeadership != null && currentLeadership.epoch() == leadershipUpdate.epoch()) { | 460 | + }); |
404 | - leaderBoard.replace(topic, leadershipUpdate); | 461 | + } else if (eventType.equals(LeadershipEvent.Type.CANDIDATES_CHANGED)) { |
405 | - updateAccepted = true; | 462 | + candidateBoard.compute(topic, (k, currentInfo) -> { |
463 | + if (currentInfo == null || currentInfo.epoch() <= leadershipUpdate.epoch()) { | ||
464 | + updateAccepted.setTrue(); | ||
465 | + return leadershipUpdate; | ||
406 | } | 466 | } |
407 | - } else { | 467 | + return currentInfo; |
408 | - throw new IllegalStateException("Unknown event type."); | 468 | + }); |
409 | - } | 469 | + } else { |
410 | - if (updateAccepted) { | 470 | + throw new IllegalStateException("Unknown event type."); |
411 | - eventDispatcher.post(leadershipEvent); | 471 | + } |
412 | - } | 472 | + |
473 | + if (updateAccepted.booleanValue()) { | ||
474 | + eventDispatcher.post(leadershipEvent); | ||
413 | } | 475 | } |
414 | } | 476 | } |
415 | } | 477 | } |
... | @@ -470,6 +532,12 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -470,6 +532,12 @@ public class DistributedLeadershipManager implements LeadershipService { |
470 | SERIALIZER::encode); | 532 | SERIALIZER::encode); |
471 | } | 533 | } |
472 | }); | 534 | }); |
535 | + candidateBoard.forEach((path, leadership) -> { | ||
536 | + LeadershipEvent event = new LeadershipEvent(LeadershipEvent.Type.CANDIDATES_CHANGED, leadership); | ||
537 | + clusterCommunicator.broadcast(event, | ||
538 | + LEADERSHIP_EVENT_MESSAGE_SUBJECT, | ||
539 | + SERIALIZER::encode); | ||
540 | + }); | ||
473 | } catch (Exception e) { | 541 | } catch (Exception e) { |
474 | log.debug("Failed to send leadership updates", e); | 542 | log.debug("Failed to send leadership updates", e); |
475 | } | 543 | } | ... | ... |
... | @@ -111,7 +111,7 @@ public class SimpleLeadershipManager implements LeadershipService { | ... | @@ -111,7 +111,7 @@ public class SimpleLeadershipManager implements LeadershipService { |
111 | } | 111 | } |
112 | 112 | ||
113 | @Override | 113 | @Override |
114 | - public Map<String, List<NodeId>> getCandidates() { | 114 | + public Map<String, Leadership> getCandidates() { |
115 | return null; | 115 | return null; |
116 | } | 116 | } |
117 | 117 | ... | ... |
-
Please register or login to post a comment