@Before public void before() throws InterruptedException { when(leaderElectionService.blockOnBecomingLeader()).thenReturn(leadershipToken); when(leaderElectionService.getCurrentTokenIfLeading()).thenReturn(Optional.empty()); when(leaderElectionService.getSuspectedLeaderInMemory()).thenReturn(Optional.empty()); when(leaderElectionService.isStillLeading(leadershipToken)).thenReturn( LeaderElectionService.StillLeadingStatus.LEADING); }
@Override public Set<PingableLeader> getPotentialLeaders() { return delegate.getPotentialLeaders(); }
@Test public void leasesLeadershipState() throws InterruptedException { LeadershipToken leasedToken = leased.blockOnBecomingLeader(); when(delegate.isStillLeading(token)).thenReturn(StillLeadingStatus.LEADING); assertThat(leased.isStillLeading(leasedToken)).isEqualTo(StillLeadingStatus.LEADING); assertThat(leased.isStillLeading(leasedToken)).isEqualTo(StillLeadingStatus.LEADING); verify(delegate).isStillLeading(token); }
@Test @SuppressWarnings("SelfEquals") // We're asserting that calling .equals on a proxy does not redirect // the .equals call to the instance its being proxied. public void shouldAllowObjectMethodsWhenLeading() { when(mockLeader.getSuspectedLeaderInMemory()).thenReturn(Optional.empty()); when(mockLeader.getCurrentTokenIfLeading()).thenReturn(Optional.empty()); when(mockLeader.isStillLeading(any(LeaderElectionService.LeadershipToken.class))) .thenReturn(LeaderElectionService.StillLeadingStatus.LEADING); Runnable proxy = AwaitingLeadershipProxy.newProxyInstance(Runnable.class, delegateSupplier, mockLeader); assertThat(proxy.hashCode()).isNotNull(); assertThat(proxy.equals(proxy)).isTrue(); assertThat(proxy.equals(null)).isFalse(); assertThat(proxy.toString()).startsWith("com.palantir.leader.proxy.AwaitingLeadershipProxy@"); }
@Test public void shouldGainLeadershipImmediatelyIfAlreadyLeading() throws Exception { when(leaderElectionService.getCurrentTokenIfLeading()).thenReturn(Optional.of(leadershipToken)); Callable proxy = proxyFor(() -> null); proxy.call(); verify(leaderElectionService, never()).blockOnBecomingLeader(); }
@Override public Optional<HostAndPort> getSuspectedLeaderInMemory() { return delegate.getSuspectedLeaderInMemory(); }
private boolean gainLeadershipBlocking() { log.debug("Block until gained leadership"); try { LeadershipToken leadershipToken = leaderElectionService.blockOnBecomingLeader(); onGainedLeadership(leadershipToken); return true; } catch (InterruptedException e) { log.warn("attempt to gain leadership interrupted", e); } catch (Throwable e) { log.error("problem blocking on leadership", e); } return false; }
for (int i = 0; i < MAX_NO_QUORUM_RETRIES; i++) { leading = leaderElectionService.isStillLeading(leadershipToken); if (leading != StillLeadingStatus.NO_QUORUM) { break;
@Override public Optional<LeadershipToken> getCurrentTokenIfLeading() { return delegate.getCurrentTokenIfLeading().map(leaseTokens::getIfPresent); }
@Test @SuppressWarnings("SelfEquals") // We're asserting that calling .equals on a proxy does not redirect // the .equals call to the instance its being proxied. public void shouldAllowObjectMethodsWhenNotLeading() { when(mockLeader.getSuspectedLeaderInMemory()).thenReturn(Optional.empty()); when(mockLeader.getCurrentTokenIfLeading()).thenReturn(Optional.empty()); when(mockLeader.isStillLeading(any(LeaderElectionService.LeadershipToken.class))) .thenReturn(LeaderElectionService.StillLeadingStatus.NOT_LEADING); Runnable proxy = AwaitingLeadershipProxy.newProxyInstance(Runnable.class, delegateSupplier, mockLeader); assertThat(proxy.hashCode()).isNotNull(); assertThat(proxy.equals(proxy)).isTrue(); assertThat(proxy.equals(null)).isFalse(); assertThat(proxy.toString()).startsWith("com.palantir.leader.proxy.AwaitingLeadershipProxy@"); }
@Test public void shouldBlockOnGainingLeadershipIfNotCurrentlyLeading() throws Exception { Callable proxy = proxyFor(() -> null); waitForLeadershipToBeGained(); proxy.call(); verify(leaderElectionService).getCurrentTokenIfLeading(); verify(leaderElectionService).blockOnBecomingLeader(); }
private NotCurrentLeaderException notCurrentLeaderException(String message, @Nullable Throwable cause) { Optional<HostAndPort> maybeLeader = leaderElectionService.getSuspectedLeaderInMemory(); if (maybeLeader.isPresent()) { HostAndPort leaderHint = maybeLeader.get(); return new NotCurrentLeaderException(message + "; hinting suspected leader host " + leaderHint, cause, leaderHint); } else { return new NotCurrentLeaderException(message, cause); } }
private void loseLeadership(Callable proxy) throws InterruptedException { when(leaderElectionService.isStillLeading(any())) .thenReturn(LeaderElectionService.StillLeadingStatus.NOT_LEADING); when(leaderElectionService.blockOnBecomingLeader()).then(invocation -> { // never return LockSupport.park(); return null; }); // make a call so the proxy will realize that it has lost leadership assertThatThrownBy(proxy::call).isInstanceOf(NotCurrentLeaderException.class) .hasMessage("method invoked on a non-leader (leadership lost)"); }
@Override public LeadershipToken blockOnBecomingLeader() throws InterruptedException { try { return leaseTokens.get(delegate.blockOnBecomingLeader()); } catch (CompletionException e) { if (e.getCause() instanceof InterruptedException) { throw new InterruptedException(); } throw e; } }
private LeasingLeadershipToken createLeaseToken(LeadershipToken token) throws InterruptedException { LeasingLeadershipToken wrapped = new LeasingLeadershipToken(token, leaseRefresh, () -> delegate.isStillLeading(token), leasingRequirements); NanoTime.sleepUntil(NanoTime.now().plus(leaseExpiry)); return wrapped; } }
private void tryToGainLeadership() { Optional<LeadershipToken> currentToken = leaderElectionService.getCurrentTokenIfLeading(); if (currentToken.isPresent()) { onGainedLeadership(currentToken.get()); } else { tryToGainLeadershipAsync(); } }
@Before public void before() throws InterruptedException { // cache forever leased = new LeasingLeaderElectionService(() -> true, delegate, Duration.ofDays(1), TIMEOUT); when(delegate.blockOnBecomingLeader()).thenReturn(token); when(delegate.getCurrentTokenIfLeading()).thenReturn(Optional.of(token)); }
@Test public void canSerializeNoSuspectedLeader() throws JsonProcessingException { LeaderElectionService leaderElectionService = mock(LeaderElectionService.class); when(leaderElectionService.getSuspectedLeaderInMemory()).thenReturn(Optional.empty()); // Be very careful about changing the following! Doing so would be a wire break. assertThat(MAPPER.writeValueAsString(leaderElectionService.getSuspectedLeaderInMemory())).isEqualTo("null"); }
public LeadershipToken gainLeadership(int leaderNum, boolean checkAfterwards) { LeaderElectionService.LeadershipToken token = null; try { token = leader(leaderNum).blockOnBecomingLeader(); } catch (InterruptedException e) { fail(e.getMessage()); } if (checkAfterwards) { assertEquals( "leader should still be leading right after becoming leader", StillLeadingStatus.LEADING, leader(leaderNum).isStillLeading(token)); } return token; }
@Test public void shouldRetryBecomingLeader() throws Exception { when(leaderElectionService.blockOnBecomingLeader()) .thenThrow(new RuntimeException()) .thenReturn(leadershipToken); Runnable proxy = AwaitingLeadershipProxy.newProxyInstance( Runnable.class, delegateSupplier, leaderElectionService); Thread.sleep(1000); //wait for retrying on gaining leadership proxy.run(); verify(leaderElectionService, atLeast(2)).blockOnBecomingLeader(); }