Repository: zookeeper Updated Branches: refs/heads/branch-3.5 f81fb443f -> 4694b8ada
ZOOKEEPER-3066: Expose on JMX of Followers the id of the current leader Expose a new JMX attribute "isLeader" in RemotePeerBean and LocalPeerBean Author: Enrico Olivelli <[email protected]> Reviewers: Andor Molnar <[email protected]> Closes #546 from eolivelli/fix/ZOOKEEPER-3066-leader-jmx and squashes the following commits: bf09e37d [Enrico Olivelli] clean up spaces ded4ce20 [Enrico Olivelli] reorder imports 81d7bb1c [Enrico Olivelli] split tests into LocalPeerBeanTest and QuorumPeerTest a1984ef1 [Enrico Olivelli] fix typo eb8d1bea [Enrico Olivelli] split tests 86b116b0 [Enrico Olivelli] enhance tests b5000efc [Enrico Olivelli] clean up test 43782fe5 [Enrico Olivelli] introduce mockito tests 2778e742 [Enrico Olivelli] revert "ZOOKEEPER-3066 add servers restart to test case" 5f120631 [Enrico Olivelli] ZOOKEEPER-3066 add servers restart to test case 067aed9e [Enrico Olivelli] ZOOKEEPER-3066 Expose on JMX of Followers the id of the current leader Enhance RemotePeerMXBean and LocalPeerMXBean by adding information about leadership (cherry picked from commit 3465e0ced5edda2e1299662f6b75a1979b6bdc6e) Signed-off-by: Andor Molnar <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/zookeeper/repo Commit: http://git-wip-us.apache.org/repos/asf/zookeeper/commit/4694b8ad Tree: http://git-wip-us.apache.org/repos/asf/zookeeper/tree/4694b8ad Diff: http://git-wip-us.apache.org/repos/asf/zookeeper/diff/4694b8ad Branch: refs/heads/branch-3.5 Commit: 4694b8ada3484847749a90a871aa9c9439a3a0a4 Parents: f81fb44 Author: Enrico Olivelli <[email protected]> Authored: Tue Jun 26 11:18:38 2018 +0200 Committer: Andor Molnar <[email protected]> Committed: Tue Jun 26 11:19:04 2018 +0200 ---------------------------------------------------------------------- .../zookeeper/server/quorum/LocalPeerBean.java | 5 +++ .../server/quorum/LocalPeerMXBean.java | 5 +++ .../zookeeper/server/quorum/QuorumPeer.java | 18 +++++++++-- .../zookeeper/server/quorum/RemotePeerBean.java | 12 +++++-- .../server/quorum/RemotePeerMXBean.java | 5 +++ .../server/quorum/LocalPeerBeanTest.java | 25 ++++++++++++++- .../zookeeper/server/quorum/QuorumPeerTest.java | 30 ++++++++++++++++++ .../server/quorum/RemotePeerBeanTest.java | 21 ++++++++++++- .../zookeeper/test/HierarchicalQuorumTest.java | 33 +++++++++++++++----- 9 files changed, 140 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerBean.java b/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerBean.java index 361eb94..91d779b 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerBean.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerBean.java @@ -109,4 +109,9 @@ public class LocalPeerBean extends ServerBean implements LocalPeerMXBean { public boolean isPartOfEnsemble() { return peer.getView().containsKey(peer.getId()); } + + @Override + public boolean isLeader() { + return peer.isLeader(peer.getId()); + } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java b/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java index b2ad8db..8b1947b 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java @@ -104,4 +104,9 @@ public interface LocalPeerMXBean extends ServerMXBean { * @return true if quorum peer is part of the ensemble, false otherwise */ public boolean isPartOfEnsemble(); + + /** + * @return true if the peer is the current leader + */ + public boolean isLeader(); } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/main/org/apache/zookeeper/server/quorum/QuorumPeer.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/QuorumPeer.java b/src/java/main/org/apache/zookeeper/server/quorum/QuorumPeer.java index 0ad9235..7aa68e8 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/QuorumPeer.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/QuorumPeer.java @@ -149,6 +149,10 @@ public class QuorumPeer extends ZooKeeperThread implements QuorumStats.Provider public QuorumServer(long id, InetSocketAddress addr) { this(id, addr, (InetSocketAddress)null, (InetSocketAddress)null, LearnerType.PARTICIPANT); } + + public long getId() { + return id; + } /** * Performs a DNS lookup for server address and election address. @@ -467,6 +471,11 @@ public class QuorumPeer extends ZooKeeperThread implements QuorumStats.Provider return myid; } + // VisibleForTesting + void setId(long id) { + this.myid = id; + } + /** * This is who I think the leader currently is. */ @@ -1112,7 +1121,7 @@ public class QuorumPeer extends ZooKeeperThread implements QuorumStats.Provider jmxLocalPeerBean = null; } } else { - RemotePeerBean rBean = new RemotePeerBean(s); + RemotePeerBean rBean = new RemotePeerBean(this, s); try { MBeanRegistry.getInstance().register(rBean, jmxQuorumBean); jmxRemotePeerBean.put(s.id, rBean); @@ -1914,7 +1923,7 @@ public class QuorumPeer extends ZooKeeperThread implements QuorumStats.Provider joiningMembers.remove(getId()); // remove self as it is local bean for (Long id : joiningMembers) { QuorumServer qs = newMembers.get(id); - RemotePeerBean rBean = new RemotePeerBean(qs); + RemotePeerBean rBean = new RemotePeerBean(this, qs); try { MBeanRegistry.getInstance().register(rBean, jmxQuorumBean); jmxRemotePeerBean.put(qs.id, rBean); @@ -2088,4 +2097,9 @@ public class QuorumPeer extends ZooKeeperThread implements QuorumStats.Provider this.quorumCnxnThreadsSize, this.isQuorumSaslAuthEnabled()); } + + boolean isLeader(long id) { + Vote vote = getCurrentVote(); + return vote != null && id == vote.getId(); + } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerBean.java b/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerBean.java index dcf5684..285f11a 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerBean.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerBean.java @@ -26,9 +26,11 @@ import org.apache.zookeeper.jmx.ZKMBeanInfo; */ public class RemotePeerBean implements RemotePeerMXBean,ZKMBeanInfo { private QuorumPeer.QuorumServer peer; - - public RemotePeerBean(QuorumPeer.QuorumServer peer){ + private final QuorumPeer localPeer; + + public RemotePeerBean(QuorumPeer localPeer, QuorumPeer.QuorumServer peer){ this.peer=peer; + this.localPeer = localPeer; } public void setQuorumServer(QuorumPeer.QuorumServer peer) { @@ -61,4 +63,10 @@ public class RemotePeerBean implements RemotePeerMXBean,ZKMBeanInfo { public String getLearnerType() { return peer.type.toString(); } + + @Override + public boolean isLeader() { + return localPeer.isLeader(peer.getId()); + } + } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerMXBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerMXBean.java b/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerMXBean.java index 35d4d08..cfeaa4b 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerMXBean.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/RemotePeerMXBean.java @@ -45,4 +45,9 @@ public interface RemotePeerMXBean { * @return the learner type */ public String getLearnerType(); + + /** + * @return true if the peer is the current leader + */ + public boolean isLeader(); } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/test/org/apache/zookeeper/server/quorum/LocalPeerBeanTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/LocalPeerBeanTest.java b/src/java/test/org/apache/zookeeper/server/quorum/LocalPeerBeanTest.java index 96688ff..563a501 100644 --- a/src/java/test/org/apache/zookeeper/server/quorum/LocalPeerBeanTest.java +++ b/src/java/test/org/apache/zookeeper/server/quorum/LocalPeerBeanTest.java @@ -20,11 +20,14 @@ package org.apache.zookeeper.server.quorum; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.net.InetAddress; import java.net.InetSocketAddress; - import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Test; @@ -79,4 +82,24 @@ public class LocalPeerBeanTest { cnxnFactory.shutdown(); } + @Test + public void testLocalPeerIsLeader() throws Exception { + long localPeerId = 7; + QuorumPeer peer = mock(QuorumPeer.class); + when(peer.getId()).thenReturn(localPeerId); + when(peer.isLeader(eq(localPeerId))).thenReturn(true); + LocalPeerBean localPeerBean = new LocalPeerBean(peer); + assertTrue(localPeerBean.isLeader()); + } + + @Test + public void testLocalPeerIsNotLeader() throws Exception { + long localPeerId = 7; + QuorumPeer peer = mock(QuorumPeer.class); + when(peer.getId()).thenReturn(localPeerId); + when(peer.isLeader(eq(localPeerId))).thenReturn(false); + LocalPeerBean localPeerBean = new LocalPeerBean(peer); + assertFalse(localPeerBean.isLeader()); + } + } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerTest.java b/src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerTest.java index fae7e5b..43ed24b 100644 --- a/src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerTest.java +++ b/src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerTest.java @@ -84,4 +84,34 @@ public class QuorumPeerTest { peer2.shutdown(); } + @Test + public void testLocalPeerIsLeader() throws Exception { + long localPeerId = 7; + QuorumPeer peer = new QuorumPeer(); + peer.setId(localPeerId); + Vote voteLocalPeerIsLeader = new Vote(localPeerId, 0); + peer.setCurrentVote(voteLocalPeerIsLeader); + assertTrue(peer.isLeader(localPeerId)); + } + + @Test + public void testLocalPeerIsNotLeader() throws Exception { + long localPeerId = 7; + long otherPeerId = 17; + QuorumPeer peer = new QuorumPeer(); + peer.setId(localPeerId); + Vote voteLocalPeerIsNotLeader = new Vote(otherPeerId, 0); + peer.setCurrentVote(voteLocalPeerIsNotLeader); + assertFalse(peer.isLeader(localPeerId)); + } + + @Test + public void testIsNotLeaderBecauseNoVote() throws Exception { + long localPeerId = 7; + QuorumPeer peer = new QuorumPeer(); + peer.setId(localPeerId); + peer.setCurrentVote(null); + assertFalse(peer.isLeader(localPeerId)); + } + } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/test/org/apache/zookeeper/server/quorum/RemotePeerBeanTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/RemotePeerBeanTest.java b/src/java/test/org/apache/zookeeper/server/quorum/RemotePeerBeanTest.java index b75a7fb..fbb0acc 100644 --- a/src/java/test/org/apache/zookeeper/server/quorum/RemotePeerBeanTest.java +++ b/src/java/test/org/apache/zookeeper/server/quorum/RemotePeerBeanTest.java @@ -19,7 +19,12 @@ package org.apache.zookeeper.server.quorum; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Matchers.eq; import java.net.InetSocketAddress; @@ -36,10 +41,24 @@ public class RemotePeerBeanTest { InetSocketAddress peerCommunicationAddress = null; // Here peerCommunicationAddress is null, also clientAddr is null QuorumServer peer = new QuorumServer(1, peerCommunicationAddress); - RemotePeerBean remotePeerBean = new RemotePeerBean(peer); + RemotePeerBean remotePeerBean = new RemotePeerBean(null, peer); String clientAddress = remotePeerBean.getClientAddress(); assertNotNull(clientAddress); assertEquals(0, clientAddress.length()); } + @Test + @SuppressWarnings("unchecked") + public void testIsLeader() { + long peerId = 7; + QuorumPeer.QuorumServer quorumServerMock = mock(QuorumPeer.QuorumServer.class); + when(quorumServerMock.getId()).thenReturn(peerId); + QuorumPeer peerMock = mock(QuorumPeer.class); + RemotePeerBean remotePeerBean = new RemotePeerBean(peerMock, quorumServerMock); + when(peerMock.isLeader(eq(peerId))).thenReturn(true); + assertTrue(remotePeerBean.isLeader()); + when(peerMock.isLeader(eq(peerId))).thenReturn(false); + assertFalse(remotePeerBean.isLeader()); + } + } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/4694b8ad/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java b/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java index 3050093..e477c98 100644 --- a/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java +++ b/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java @@ -235,30 +235,30 @@ public class HierarchicalQuorumTest extends ClientBase { CONNECTION_TIMEOUT)); LOG.info(hp + " is accepting client connections"); } - + final int numberOfPeers = 5; // interesting to see what's there... JMXEnv.dump(); // make sure we have these 5 servers listed Set<String> ensureNames = new LinkedHashSet<String>(); - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= numberOfPeers; i++) { ensureNames.add("InMemoryDataTree"); } - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= numberOfPeers; i++) { ensureNames.add("name0=ReplicatedServer_id" + i + ",name1=replica." + i + ",name2="); } - for (int i = 1; i <= 5; i++) { - for (int j = 1; j <= 5; j++) { + for (int i = 1; i <= numberOfPeers; i++) { + for (int j = 1; j <= numberOfPeers; j++) { ensureNames.add("name0=ReplicatedServer_id" + i + ",name1=replica." + j); } } - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= numberOfPeers; i++) { ensureNames.add("name0=ReplicatedServer_id" + i); } JMXEnv.ensureAll(ensureNames.toArray(new String[ensureNames.size()])); - - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= numberOfPeers; i++) { + // LocalPeerBean String bean = CommonNames.DOMAIN + ":name0=ReplicatedServer_id" + i + ",name1=replica." + i; JMXEnv.ensureBeanAttribute(bean, "ConfigVersion"); @@ -266,6 +266,23 @@ public class HierarchicalQuorumTest extends ClientBase { JMXEnv.ensureBeanAttribute(bean, "ClientAddress"); JMXEnv.ensureBeanAttribute(bean, "ElectionAddress"); JMXEnv.ensureBeanAttribute(bean, "QuorumSystemInfo"); + JMXEnv.ensureBeanAttribute(bean, "Leader"); + } + + for (int i = 1; i <= numberOfPeers; i++) { + for (int j = 1; j <= numberOfPeers; j++) { + if (j != i) { + // RemotePeerBean + String bean = CommonNames.DOMAIN + ":name0=ReplicatedServer_id" + i + + ",name1=replica." + j; + JMXEnv.ensureBeanAttribute(bean, "Name"); + JMXEnv.ensureBeanAttribute(bean, "LearnerType"); + JMXEnv.ensureBeanAttribute(bean, "ClientAddress"); + JMXEnv.ensureBeanAttribute(bean, "ElectionAddress"); + JMXEnv.ensureBeanAttribute(bean, "QuorumAddress"); + JMXEnv.ensureBeanAttribute(bean, "Leader"); + } + } } }
