Committed by
Gerrit Code Review
ONOS-2026: Address polling issue in LeaderElection
Change-Id: Ib5c94d932de6b2c3419b07a97d6fe91d5c588538
Showing
1 changed file
with
61 additions
and
51 deletions
... | @@ -84,7 +84,8 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -84,7 +84,8 @@ public class DistributedLeadershipManager implements LeadershipService { |
84 | 84 | ||
85 | private final Logger log = getLogger(getClass()); | 85 | private final Logger log = getLogger(getClass()); |
86 | private ExecutorService messageHandlingExecutor; | 86 | private ExecutorService messageHandlingExecutor; |
87 | - private ScheduledExecutorService retryLeaderLockExecutor; | 87 | + private ScheduledExecutorService electionRunner; |
88 | + private ScheduledExecutorService lockExecutor; | ||
88 | private ScheduledExecutorService staleLeadershipPurgeExecutor; | 89 | private ScheduledExecutorService staleLeadershipPurgeExecutor; |
89 | private ScheduledExecutorService leadershipStatusBroadcaster; | 90 | private ScheduledExecutorService leadershipStatusBroadcaster; |
90 | 91 | ||
... | @@ -98,6 +99,7 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -98,6 +99,7 @@ public class DistributedLeadershipManager implements LeadershipService { |
98 | 99 | ||
99 | private NodeId localNodeId; | 100 | private NodeId localNodeId; |
100 | private Set<String> activeTopics = Sets.newConcurrentHashSet(); | 101 | private Set<String> activeTopics = Sets.newConcurrentHashSet(); |
102 | + private Map<String, CompletableFuture<Leadership>> pendingFutures = Maps.newConcurrentMap(); | ||
101 | 103 | ||
102 | private static final int ELECTION_JOIN_ATTEMPT_INTERVAL_SEC = 2; | 104 | private static final int ELECTION_JOIN_ATTEMPT_INTERVAL_SEC = 2; |
103 | private static final int DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC = 2; | 105 | private static final int DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC = 2; |
... | @@ -125,7 +127,9 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -125,7 +127,9 @@ public class DistributedLeadershipManager implements LeadershipService { |
125 | 127 | ||
126 | messageHandlingExecutor = Executors.newSingleThreadExecutor( | 128 | messageHandlingExecutor = Executors.newSingleThreadExecutor( |
127 | groupedThreads("onos/store/leadership", "message-handler")); | 129 | groupedThreads("onos/store/leadership", "message-handler")); |
128 | - retryLeaderLockExecutor = Executors.newScheduledThreadPool( | 130 | + electionRunner = Executors.newSingleThreadScheduledExecutor( |
131 | + groupedThreads("onos/store/leadership", "election-runner")); | ||
132 | + lockExecutor = Executors.newScheduledThreadPool( | ||
129 | 4, groupedThreads("onos/store/leadership", "election-thread-%d")); | 133 | 4, groupedThreads("onos/store/leadership", "election-thread-%d")); |
130 | staleLeadershipPurgeExecutor = Executors.newSingleThreadScheduledExecutor( | 134 | staleLeadershipPurgeExecutor = Executors.newSingleThreadScheduledExecutor( |
131 | groupedThreads("onos/store/leadership", "stale-leadership-evictor")); | 135 | groupedThreads("onos/store/leadership", "stale-leadership-evictor")); |
... | @@ -139,6 +143,9 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -139,6 +143,9 @@ public class DistributedLeadershipManager implements LeadershipService { |
139 | 143 | ||
140 | clusterService.addListener(clusterEventListener); | 144 | clusterService.addListener(clusterEventListener); |
141 | 145 | ||
146 | + electionRunner.scheduleWithFixedDelay( | ||
147 | + this::electLeaders, 0, DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, TimeUnit.SECONDS); | ||
148 | + | ||
142 | leadershipStatusBroadcaster.scheduleWithFixedDelay( | 149 | leadershipStatusBroadcaster.scheduleWithFixedDelay( |
143 | this::sendLeadershipStatus, 0, LEADERSHIP_STATUS_UPDATE_INTERVAL_SEC, TimeUnit.SECONDS); | 150 | this::sendLeadershipStatus, 0, LEADERSHIP_STATUS_UPDATE_INTERVAL_SEC, TimeUnit.SECONDS); |
144 | 151 | ||
... | @@ -160,8 +167,9 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -160,8 +167,9 @@ public class DistributedLeadershipManager implements LeadershipService { |
160 | eventDispatcher.removeSink(LeadershipEvent.class); | 167 | eventDispatcher.removeSink(LeadershipEvent.class); |
161 | clusterCommunicator.removeSubscriber(LEADERSHIP_EVENT_MESSAGE_SUBJECT); | 168 | clusterCommunicator.removeSubscriber(LEADERSHIP_EVENT_MESSAGE_SUBJECT); |
162 | 169 | ||
170 | + electionRunner.shutdown(); | ||
163 | messageHandlingExecutor.shutdown(); | 171 | messageHandlingExecutor.shutdown(); |
164 | - retryLeaderLockExecutor.shutdown(); | 172 | + lockExecutor.shutdown(); |
165 | staleLeadershipPurgeExecutor.shutdown(); | 173 | staleLeadershipPurgeExecutor.shutdown(); |
166 | leadershipStatusBroadcaster.shutdown(); | 174 | leadershipStatusBroadcaster.shutdown(); |
167 | 175 | ||
... | @@ -236,7 +244,12 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -236,7 +244,12 @@ public class DistributedLeadershipManager implements LeadershipService { |
236 | candidates.creationTime()))); | 244 | candidates.creationTime()))); |
237 | log.debug("In the leadership race for topic {} with candidates {}", path, candidates); | 245 | log.debug("In the leadership race for topic {} with candidates {}", path, candidates); |
238 | activeTopics.add(path); | 246 | activeTopics.add(path); |
239 | - tryLeaderLock(path, future); | 247 | + Leadership leadership = electLeader(path, candidates.value()); |
248 | + if (leadership == null) { | ||
249 | + pendingFutures.put(path, future); | ||
250 | + } else { | ||
251 | + future.complete(leadership); | ||
252 | + } | ||
240 | } catch (ConsistentMapException e) { | 253 | } catch (ConsistentMapException e) { |
241 | log.debug("Failed to enter topic leader race for {}. Retrying.", path, e); | 254 | log.debug("Failed to enter topic leader race for {}. Retrying.", path, e); |
242 | rerunForLeadership(path, future); | 255 | rerunForLeadership(path, future); |
... | @@ -315,7 +328,6 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -315,7 +328,6 @@ public class DistributedLeadershipManager implements LeadershipService { |
315 | localNodeId, | 328 | localNodeId, |
316 | leader.version(), | 329 | leader.version(), |
317 | leader.creationTime()))); | 330 | leader.creationTime()))); |
318 | - retryLock(path, new CompletableFuture<>()); | ||
319 | return true; | 331 | return true; |
320 | } | 332 | } |
321 | } | 333 | } |
... | @@ -355,50 +367,55 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -355,50 +367,55 @@ public class DistributedLeadershipManager implements LeadershipService { |
355 | return true; | 367 | return true; |
356 | } | 368 | } |
357 | 369 | ||
358 | - private void tryLeaderLock(String path, CompletableFuture<Leadership> future) { | 370 | + private Leadership electLeader(String path, List<NodeId> candidates) { |
359 | - if (!activeTopics.contains(path) || Objects.equals(localNodeId, getLeader(path))) { | 371 | + Leadership currentLeadership = getLeadership(path); |
360 | - return; | 372 | + if (currentLeadership != null) { |
361 | - } | 373 | + return currentLeadership; |
362 | - try { | 374 | + } else { |
363 | - Versioned<List<NodeId>> candidates = candidateMap.get(path); | 375 | + NodeId topCandidate = candidates |
364 | - if (candidates != null) { | 376 | + .stream() |
365 | - List<NodeId> activeNodes = candidates.value() | 377 | + .filter(n -> clusterService.getState(n) == ACTIVE) |
366 | - .stream() | 378 | + .findFirst() |
367 | - .filter(n -> clusterService.getState(n) == ACTIVE) | 379 | + .orElse(null); |
368 | - .collect(Collectors.toList()); | 380 | + try { |
369 | - if (localNodeId.equals(activeNodes.get(LEADER_CANDIDATE_POS))) { | 381 | + Versioned<NodeId> leader = localNodeId.equals(topCandidate) |
370 | - leaderLockAttempt(path, candidates.value(), future); | 382 | + ? leaderMap.computeIfAbsent(path, p -> localNodeId) : leaderMap.get(path); |
371 | - } else { | 383 | + if (leader != null) { |
372 | - retryLock(path, future); | 384 | + Leadership newLeadership = new Leadership(path, |
385 | + leader.value(), | ||
386 | + leader.version(), | ||
387 | + leader.creationTime()); | ||
388 | + publish(new LeadershipEvent( | ||
389 | + LeadershipEvent.Type.LEADER_ELECTED, | ||
390 | + newLeadership)); | ||
391 | + return newLeadership; | ||
373 | } | 392 | } |
374 | - } else { | 393 | + } catch (Exception e) { |
375 | - throw new IllegalStateException("should not be here"); | 394 | + log.debug("Failed to elect leader for {}", path, e); |
376 | } | 395 | } |
377 | - } catch (Exception e) { | ||
378 | - log.debug("Failed to fetch candidate information for {}", path, e); | ||
379 | - retryLock(path, future); | ||
380 | } | 396 | } |
397 | + return null; | ||
381 | } | 398 | } |
382 | 399 | ||
383 | - private void leaderLockAttempt(String path, List<NodeId> candidates, CompletableFuture<Leadership> future) { | 400 | + private void electLeaders() { |
384 | try { | 401 | try { |
385 | - Versioned<NodeId> leader = leaderMap.computeIfAbsent(path, p -> localNodeId); | 402 | + candidateMap.entrySet().forEach(entry -> { |
386 | - if (Objects.equals(leader.value(), localNodeId)) { | 403 | + String path = entry.getKey(); |
387 | - log.debug("Assumed leadership for {}", path); | 404 | + List<NodeId> candidates = entry.getValue().value(); |
388 | - Leadership leadership = new Leadership(path, | 405 | + if (activeTopics.contains(path)) { |
389 | - leader.value(), | 406 | + lockExecutor.submit(() -> { |
390 | - leader.version(), | 407 | + Leadership leadership = electLeader(path, candidates); |
391 | - leader.creationTime()); | 408 | + if (leadership != null) { |
392 | - future.complete(leadership); | 409 | + CompletableFuture<Leadership> future = pendingFutures.remove(path); |
393 | - publish(new LeadershipEvent( | 410 | + if (future != null) { |
394 | - LeadershipEvent.Type.LEADER_ELECTED, | 411 | + future.complete(leadership); |
395 | - leadership)); | 412 | + } |
396 | - } else { | 413 | + } |
397 | - retryLock(path, future); | 414 | + }); |
398 | - } | 415 | + } |
416 | + }); | ||
399 | } catch (Exception e) { | 417 | } catch (Exception e) { |
400 | - log.debug("Attempt to acquire leadership lock for topic {} failed", path, e); | 418 | + log.debug("Failure electing leaders", e); |
401 | - retryLock(path, future); | ||
402 | } | 419 | } |
403 | } | 420 | } |
404 | 421 | ||
... | @@ -451,21 +468,14 @@ public class DistributedLeadershipManager implements LeadershipService { | ... | @@ -451,21 +468,14 @@ public class DistributedLeadershipManager implements LeadershipService { |
451 | } | 468 | } |
452 | 469 | ||
453 | private void rerunForLeadership(String path, CompletableFuture<Leadership> future) { | 470 | private void rerunForLeadership(String path, CompletableFuture<Leadership> future) { |
454 | - retryLeaderLockExecutor.schedule( | 471 | + lockExecutor.schedule( |
455 | () -> doRunForLeadership(path, future), | 472 | () -> doRunForLeadership(path, future), |
456 | ELECTION_JOIN_ATTEMPT_INTERVAL_SEC, | 473 | ELECTION_JOIN_ATTEMPT_INTERVAL_SEC, |
457 | TimeUnit.SECONDS); | 474 | TimeUnit.SECONDS); |
458 | } | 475 | } |
459 | 476 | ||
460 | - private void retryLock(String path, CompletableFuture<Leadership> future) { | ||
461 | - retryLeaderLockExecutor.schedule( | ||
462 | - () -> tryLeaderLock(path, future), | ||
463 | - DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, | ||
464 | - TimeUnit.SECONDS); | ||
465 | - } | ||
466 | - | ||
467 | private void retryWithdraw(String path, CompletableFuture<Void> future) { | 477 | private void retryWithdraw(String path, CompletableFuture<Void> future) { |
468 | - retryLeaderLockExecutor.schedule( | 478 | + lockExecutor.schedule( |
469 | () -> doWithdraw(path, future), | 479 | () -> doWithdraw(path, future), |
470 | DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, | 480 | DELAY_BETWEEN_LEADER_LOCK_ATTEMPTS_SEC, |
471 | TimeUnit.SECONDS); | 481 | TimeUnit.SECONDS); | ... | ... |
-
Please register or login to post a comment