From 11456ffc55cdef25b78ee04e95f9720ae42983ad Mon Sep 17 00:00:00 2001 From: Fangmin Lyu Date: Sun, 25 Nov 2018 16:41:25 -0800 Subject: [PATCH] [ZOOKEEPER-3203] Track the number of non voting followers in ZK --- .../zookeeper/server/admin/Commands.java | 1 + .../server/command/MonitorCommand.java | 1 + .../zookeeper/server/quorum/Leader.java | 14 +++++++++- .../zookeeper/server/quorum/LeaderBean.java | 9 +++++++ .../zookeeper/server/quorum/LeaderMXBean.java | 5 ++++ .../server/quorum/LeaderBeanTest.java | 26 ++++++++++++++++++- 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java index 29e18456a8b..f1e5500563c 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java @@ -369,6 +369,7 @@ public CommandResponse run(ZooKeeperServer zkServer, Map kwargs) response.put("learners", leader.getLearners().size()); response.put("synced_followers", leader.getForwardingFollowers().size()); + response.put("synced_non_voting_followers", leader.getNonVotingFollowers().size()); response.put("synced_observers", leader.getObservingLearners().size()); response.put("pending_syncs", leader.getNumPendingSyncs()); response.put("leader_uptime", leader.getUptime()); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/command/MonitorCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/command/MonitorCommand.java index b89d5574736..75d1dea6553 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/command/MonitorCommand.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/command/MonitorCommand.java @@ -73,6 +73,7 @@ public void commandRun() { print("learners", leader.getLearners().size()); print("synced_followers", leader.getForwardingFollowers().size()); + print("synced_non_voting_followers", leader.getNonVotingFollowers().size()); print("pending_syncs", leader.getNumPendingSyncs()); print("last_proposal_size", leader.getProposalStats().getLastBufferSize()); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java index 397ea6d4e86..c284debfc49 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java @@ -152,7 +152,19 @@ public List getForwardingFollowers() { } } - private void addForwardingFollower(LearnerHandler lh) { + public List getNonVotingFollowers() { + List nonVotingFollowers = new ArrayList(); + synchronized (forwardingFollowers) { + for (LearnerHandler lh : forwardingFollowers) { + if (!isParticipant(lh.getSid())) { + nonVotingFollowers.add(lh); + } + } + } + return nonVotingFollowers; + } + + void addForwardingFollower(LearnerHandler lh) { synchronized (forwardingFollowers) { forwardingFollowers.add(lh); } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderBean.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderBean.java index 0c3be4a2528..1c178f6bd9d 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderBean.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderBean.java @@ -51,6 +51,15 @@ public String followerInfo() { return sb.toString(); } + @Override + public String nonVotingFollowerInfo() { + StringBuilder sb = new StringBuilder(); + for (LearnerHandler handler : leader.getNonVotingFollowers()) { + sb.append(handler.toString()).append("\n"); + } + return sb.toString(); + } + @Override public long getElectionTimeTaken() { return leader.self.getElectionTimeTaken(); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderMXBean.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderMXBean.java index 7a1a439fa02..4aed18608d5 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderMXBean.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LeaderMXBean.java @@ -34,6 +34,11 @@ public interface LeaderMXBean extends ZooKeeperServerMXBean { */ public String followerInfo(); + /** + * @return information about current non-voting followers + */ + public String nonVotingFollowerInfo(); + /** * @return time taken for leader election in milliseconds. */ diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LeaderBeanTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LeaderBeanTest.java index 69dac1ff186..38539b3f880 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LeaderBeanTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LeaderBeanTest.java @@ -45,6 +45,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNotEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; @@ -58,6 +59,7 @@ public class LeaderBeanTest { private FileTxnSnapLog fileTxnSnapLog; private LeaderZooKeeperServer zks; private QuorumPeer qp; + private QuorumVerifier quorumVerifierMock; @Before public void setUp() throws IOException, X509Exception { @@ -73,7 +75,7 @@ public void setUp() throws IOException, X509Exception { new InetSocketAddress(clientIP, PortAssignment.unique()), new InetSocketAddress(clientIP, clientPort), LearnerType.PARTICIPANT)); - QuorumVerifier quorumVerifierMock = mock(QuorumVerifier.class); + quorumVerifierMock = mock(QuorumVerifier.class); when(quorumVerifierMock.getAllMembers()).thenReturn(peersView); qp.setQuorumVerifier(quorumVerifierMock, false); @@ -173,12 +175,21 @@ public Object answer(InvocationOnMock invocation) throws Throwable { @Test public void testFollowerInfo() throws IOException { + Map votingMembers = new HashMap(); + votingMembers.put(1L, null); + votingMembers.put(2L, null); + votingMembers.put(3L, null); + when(quorumVerifierMock.getVotingMembers()).thenReturn(votingMembers); + LearnerHandler follower = mock(LearnerHandler.class); when(follower.getLearnerType()).thenReturn(LearnerType.PARTICIPANT); when(follower.toString()).thenReturn("1"); + when(follower.getSid()).thenReturn(1L); leader.addLearnerHandler(follower); + leader.addForwardingFollower(follower); assertEquals("1\n", leaderBean.followerInfo()); + assertEquals("", leaderBean.nonVotingFollowerInfo()); LearnerHandler observer = mock(LearnerHandler.class); when(observer.getLearnerType()).thenReturn(LearnerType.OBSERVER); @@ -186,5 +197,18 @@ public void testFollowerInfo() throws IOException { leader.addLearnerHandler(observer); assertEquals("1\n", leaderBean.followerInfo()); + assertEquals("", leaderBean.nonVotingFollowerInfo()); + + LearnerHandler nonVotingFollower = mock(LearnerHandler.class); + when(nonVotingFollower.getLearnerType()).thenReturn(LearnerType.PARTICIPANT); + when(nonVotingFollower.toString()).thenReturn("5"); + when(nonVotingFollower.getSid()).thenReturn(5L); + leader.addLearnerHandler(nonVotingFollower); + leader.addForwardingFollower(nonVotingFollower); + + String followerInfo = leaderBean.followerInfo(); + assertTrue(followerInfo.contains("1")); + assertTrue(followerInfo.contains("5")); + assertEquals("5\n", leaderBean.nonVotingFollowerInfo()); } }