From commits-return-6149-archive-asf-public=cust-asf.ponee.io@zookeeper.apache.org Wed Feb 7 01:05:47 2018 Return-Path: X-Original-To: archive-asf-public@eu.ponee.io Delivered-To: archive-asf-public@eu.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by mx-eu-01.ponee.io (Postfix) with ESMTP id C2A52180657 for ; Wed, 7 Feb 2018 01:05:47 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id B2C57160C46; Wed, 7 Feb 2018 00:05:47 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id D8123160C45 for ; Wed, 7 Feb 2018 01:05:45 +0100 (CET) Received: (qmail 72597 invoked by uid 500); 7 Feb 2018 00:05:45 -0000 Mailing-List: contact commits-help@zookeeper.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zookeeper.apache.org Delivered-To: mailing list commits@zookeeper.apache.org Received: (qmail 72586 invoked by uid 99); 7 Feb 2018 00:05:44 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 07 Feb 2018 00:05:44 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id C4C44DFBBB; Wed, 7 Feb 2018 00:05:44 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: afine@apache.org To: commits@zookeeper.apache.org Message-Id: <24edda4f12894cc0b967950cd5a6012d@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: zookeeper git commit: ZOOKEEPER-2939: Added last/min/max proposal size JMX beans Date: Wed, 7 Feb 2018 00:05:44 +0000 (UTC) Repository: zookeeper Updated Branches: refs/heads/branch-3.5 0b6442a1e -> 5ae5f1076 ZOOKEEPER-2939: Added last/min/max proposal size JMX beans https://issues.apache.org/jira/browse/ZOOKEEPER-2939 - Refactor proposal serialization logic to a common place (SerializeUtils), - Add JMX metric to monitor jute.maxbuffer setting - Add JMX metric to monitor min/max/last size of generated proposals - Add proposal stats info to 'stat' 4lw command - Add proposal stats resetting to 'srst' 4lw command - Unit tests Author: Andor Molnár Author: Andor Molnar Reviewers: Patrick Hunt , Abraham Fine Closes #415 from anmolnar/ZOOKEEPER-2933 and squashes the following commits: cf6ea5ecb [Andor Molnar] ZOOKEEPER-2933. Added proposal size statistics to 'mntr' command cb28df6d6 [Andor Molnár] ZOOKEEPER-2939. Fixed findbugs issue: newline in format string 8e6b65f9f [Andor Molnár] ZOOKEEPER-2939: Added last/min/max proposal size JMX beans (cherry picked from commit aefb13f2b289e19e32c0fcc5714711b07989d67f) Signed-off-by: Abraham Fine Project: http://git-wip-us.apache.org/repos/asf/zookeeper/repo Commit: http://git-wip-us.apache.org/repos/asf/zookeeper/commit/5ae5f107 Tree: http://git-wip-us.apache.org/repos/asf/zookeeper/tree/5ae5f107 Diff: http://git-wip-us.apache.org/repos/asf/zookeeper/diff/5ae5f107 Branch: refs/heads/branch-3.5 Commit: 5ae5f1076e56947db5694ff8ab06c3d0b4f5d802 Parents: 0b6442a Author: Andor Molnár Authored: Tue Feb 6 16:05:18 2018 -0800 Committer: Abraham Fine Committed: Tue Feb 6 16:05:38 2018 -0800 ---------------------------------------------------------------------- build.xml | 2 +- .../org/apache/zookeeper/server/ZKDatabase.java | 17 +-- .../zookeeper/server/ZooKeeperServerBean.java | 6 + .../zookeeper/server/ZooKeeperServerMXBean.java | 5 + .../command/AbstractFourLetterCommand.java | 4 +- .../server/command/MonitorCommand.java | 4 + .../zookeeper/server/command/StatCommand.java | 12 +- .../server/command/StatResetCommand.java | 8 +- .../apache/zookeeper/server/quorum/Leader.java | 33 ++-- .../zookeeper/server/quorum/LeaderBean.java | 22 ++- .../zookeeper/server/quorum/LeaderMXBean.java | 20 +++ .../zookeeper/server/quorum/ProposalStats.java | 71 +++++++++ .../zookeeper/server/util/SerializeUtils.java | 20 +++ .../server/ZooKeeperServerStartupTest.java | 2 +- .../zookeeper/server/quorum/LeaderBeanTest.java | 151 +++++++++++++++++++ .../server/quorum/ProposalStatsTest.java | 58 +++++++ .../server/quorum/StatCommandTest.java | 106 +++++++++++++ .../server/quorum/StatResetCommandTest.java | 111 ++++++++++++++ .../server/util/SerializeUtilsTest.java | 128 ++++++++++++++++ 19 files changed, 736 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/build.xml ---------------------------------------------------------------------- diff --git a/build.xml b/build.xml index 9078148..ff45564 100644 --- a/build.xml +++ b/build.xml @@ -1827,7 +1827,7 @@ xmlns:cs="antlib:com.puppycrawl.tools.checkstyle.ant"> description="Create eclipse project files"> - + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/ZKDatabase.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/ZKDatabase.java b/src/java/main/org/apache/zookeeper/server/ZKDatabase.java index 16baf46..6679e78 100644 --- a/src/java/main/org/apache/zookeeper/server/ZKDatabase.java +++ b/src/java/main/org/apache/zookeeper/server/ZKDatabase.java @@ -18,7 +18,6 @@ package org.apache.zookeeper.server; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; @@ -32,7 +31,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; -import org.apache.jute.BinaryOutputArchive; import org.apache.jute.InputArchive; import org.apache.jute.OutputArchive; import org.apache.jute.Record; @@ -264,19 +262,8 @@ public class ZKDatabase { maxCommittedLog = request.zxid; } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos); - try { - request.getHdr().serialize(boa, "hdr"); - if (request.getTxn() != null) { - request.getTxn().serialize(boa, "txn"); - } - baos.close(); - } catch (IOException e) { - LOG.error("This really should be impossible", e); - } - QuorumPacket pp = new QuorumPacket(Leader.PROPOSAL, request.zxid, - baos.toByteArray(), null); + byte[] data = SerializeUtils.serializeRequest(request); + QuorumPacket pp = new QuorumPacket(Leader.PROPOSAL, request.zxid, data, null); Proposal p = new Proposal(); p.packet = pp; p.request = request; http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/ZooKeeperServerBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/ZooKeeperServerBean.java b/src/java/main/org/apache/zookeeper/server/ZooKeeperServerBean.java index 38780bb..3674066 100644 --- a/src/java/main/org/apache/zookeeper/server/ZooKeeperServerBean.java +++ b/src/java/main/org/apache/zookeeper/server/ZooKeeperServerBean.java @@ -20,6 +20,7 @@ package org.apache.zookeeper.server; import java.util.Date; +import org.apache.jute.BinaryInputArchive; import org.apache.zookeeper.Version; import org.apache.zookeeper.jmx.ZKMBeanInfo; @@ -167,4 +168,9 @@ public class ZooKeeperServerBean implements ZooKeeperServerMXBean, ZKMBeanInfo { public long getTxnLogElapsedSyncTime() { return zks.getTxnLogElapsedSyncTime(); } + + @Override + public int getJuteMaxBufferSize() { + return BinaryInputArchive.maxBuffer; + } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/ZooKeeperServerMXBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/ZooKeeperServerMXBean.java b/src/java/main/org/apache/zookeeper/server/ZooKeeperServerMXBean.java index e326e5b..a592131 100644 --- a/src/java/main/org/apache/zookeeper/server/ZooKeeperServerMXBean.java +++ b/src/java/main/org/apache/zookeeper/server/ZooKeeperServerMXBean.java @@ -130,4 +130,9 @@ public interface ZooKeeperServerMXBean { * Returns the elapsed sync of time of transaction log in milliseconds. */ public long getTxnLogElapsedSyncTime(); + + /** + * @return Returns the value of the following config setting: jute.maxbuffer + */ + public int getJuteMaxBufferSize(); } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java b/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java index 5a8a16e..fe78402 100644 --- a/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java +++ b/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java @@ -35,7 +35,9 @@ import org.slf4j.LoggerFactory; public abstract class AbstractFourLetterCommand { private static final Logger LOG = LoggerFactory .getLogger(AbstractFourLetterCommand.class); - protected static final String ZK_NOT_SERVING = "This ZooKeeper instance is not currently serving requests"; + + public static final String ZK_NOT_SERVING = "This ZooKeeper instance is not currently serving requests"; + protected PrintWriter pw; protected ServerCnxn serverCnxn; protected ZooKeeperServer zkServer; http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java b/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java index a3f5733..c32de4c 100644 --- a/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java +++ b/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java @@ -74,6 +74,10 @@ public class MonitorCommand extends AbstractFourLetterCommand { print("followers", leader.getLearners().size()); print("synced_followers", leader.getForwardingFollowers().size()); print("pending_syncs", leader.getNumPendingSyncs()); + + print("last_proposal_size", leader.getProposalStats().getLastProposalSize()); + print("max_proposal_size", leader.getProposalStats().getMaxProposalSize()); + print("min_proposal_size", leader.getProposalStats().getMinProposalSize()); } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/command/StatCommand.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/command/StatCommand.java b/src/java/main/org/apache/zookeeper/server/command/StatCommand.java index fbe42d0..d04f2f7 100644 --- a/src/java/main/org/apache/zookeeper/server/command/StatCommand.java +++ b/src/java/main/org/apache/zookeeper/server/command/StatCommand.java @@ -22,6 +22,10 @@ import java.io.PrintWriter; import org.apache.zookeeper.Version; import org.apache.zookeeper.server.ServerCnxn; +import org.apache.zookeeper.server.ServerStats; +import org.apache.zookeeper.server.quorum.Leader; +import org.apache.zookeeper.server.quorum.LeaderZooKeeperServer; +import org.apache.zookeeper.server.quorum.ProposalStats; import org.apache.zookeeper.server.quorum.ReadOnlyZooKeeperServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,9 +58,15 @@ public class StatCommand extends AbstractFourLetterCommand { } pw.println(); } - pw.print(zkServer.serverStats().toString()); + ServerStats serverStats = zkServer.serverStats(); + pw.print(serverStats.toString()); pw.print("Node count: "); pw.println(zkServer.getZKDatabase().getNodeCount()); + if (serverStats.getServerState().equals("leader")) { + Leader leader = ((LeaderZooKeeperServer)zkServer).getLeader(); + ProposalStats proposalStats = leader.getProposalStats(); + pw.printf("Proposal sizes last/min/max: %s%n", proposalStats.toString()); + } } } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java b/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java index 88ac4c3..2b2fa06 100644 --- a/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java +++ b/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java @@ -21,6 +21,8 @@ package org.apache.zookeeper.server.command; import java.io.PrintWriter; import org.apache.zookeeper.server.ServerCnxn; +import org.apache.zookeeper.server.ServerStats; +import org.apache.zookeeper.server.quorum.LeaderZooKeeperServer; public class StatResetCommand extends AbstractFourLetterCommand { public StatResetCommand(PrintWriter pw, ServerCnxn serverCnxn) { @@ -32,7 +34,11 @@ public class StatResetCommand extends AbstractFourLetterCommand { if (!isZKServerRunning()) { pw.println(ZK_NOT_SERVING); } else { - zkServer.serverStats().reset(); + ServerStats serverStats = zkServer.serverStats(); + serverStats.reset(); + if (serverStats.getServerState().equals("leader")) { + ((LeaderZooKeeperServer)zkServer).getLeader().getProposalStats().reset(); + } pw.println("Server stats reset."); } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/quorum/Leader.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/Leader.java b/src/java/main/org/apache/zookeeper/server/quorum/Leader.java index fe45305..9725cec 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/Leader.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/Leader.java @@ -50,6 +50,7 @@ import org.apache.zookeeper.server.RequestProcessor; import org.apache.zookeeper.server.ZooKeeperCriticalThread; import org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType; import org.apache.zookeeper.server.quorum.flexible.QuorumVerifier; +import org.apache.zookeeper.server.util.SerializeUtils; import org.apache.zookeeper.server.util.ZxidUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,6 +105,12 @@ public class Leader { private final HashSet learners = new HashSet(); + private final ProposalStats proposalStats; + + public ProposalStats getProposalStats() { + return proposalStats; + } + /** * Returns a copy of the current learner snapshot */ @@ -221,6 +228,7 @@ public class Leader { Leader(QuorumPeer self,LeaderZooKeeperServer zk) throws IOException { this.self = self; + this.proposalStats = new ProposalStats(); try { if (self.getQuorumListenOnAllIPs()) { ss = new ServerSocket(self.getQuorumAddress().getPort()); @@ -720,7 +728,6 @@ public class Leader { /** * @return True if committed, otherwise false. - * @param a proposal p **/ synchronized public boolean tryToCommit(Proposal p, long zxid, SocketAddress followerAddr) { // make sure that ops are committed in order. With reconfigurations it is now possible @@ -991,8 +998,6 @@ public class Leader { /** * Create an inform packet and send it to all observers. - * @param zxid - * @param proposal */ public void inform(Proposal proposal) { QuorumPacket qp = new QuorumPacket(Leader.INFORM, proposal.request.zxid, @@ -1003,8 +1008,6 @@ public class Leader { /** * Create an inform&activate packet and send it to all observers. - * @param zxid - * @param proposal */ public void informAndActivate(Proposal proposal, long designatedLeader) { byte[] proposalData = proposal.packet.getData(); @@ -1054,19 +1057,9 @@ public class Leader { throw new XidRolloverException(msg); } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos); - try { - request.getHdr().serialize(boa, "hdr"); - if (request.getTxn() != null) { - request.getTxn().serialize(boa, "txn"); - } - baos.close(); - } catch (IOException e) { - LOG.warn("This really should be impossible", e); - } - QuorumPacket pp = new QuorumPacket(Leader.PROPOSAL, request.zxid, - baos.toByteArray(), null); + byte[] data = SerializeUtils.serializeRequest(request); + proposalStats.setLastProposalSize(data.length); + QuorumPacket pp = new QuorumPacket(Leader.PROPOSAL, request.zxid, data, null); Proposal p = new Proposal(); p.packet = pp; @@ -1119,11 +1112,7 @@ public class Leader { /** * Sends a sync message to the appropriate server - * - * @param f - * @param r */ - public void sendSync(LearnerSyncRequest r){ QuorumPacket qp = new QuorumPacket(Leader.SYNC, 0, null, null); r.fh.queuePacket(qp); http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/quorum/LeaderBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/LeaderBean.java b/src/java/main/org/apache/zookeeper/server/quorum/LeaderBean.java index 6ab2c30..9f5eb24 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/LeaderBean.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/LeaderBean.java @@ -20,8 +20,6 @@ package org.apache.zookeeper.server.quorum; import org.apache.zookeeper.server.ZooKeeperServerBean; import org.apache.zookeeper.server.ZooKeeperServer; -import org.apache.zookeeper.server.quorum.LearnerHandler; -import org.apache.zookeeper.server.quorum.Leader; /** * Leader MBean interface implementation. @@ -54,4 +52,24 @@ public class LeaderBean extends ZooKeeperServerBean implements LeaderMXBean { public long getElectionTimeTaken() { return leader.self.getElectionTimeTaken(); } + + @Override + public int getLastProposalSize() { + return leader.getProposalStats().getLastProposalSize(); + } + + @Override + public int getMinProposalSize() { + return leader.getProposalStats().getMinProposalSize(); + } + + @Override + public int getMaxProposalSize() { + return leader.getProposalStats().getMaxProposalSize(); + } + + @Override + public void resetProposalStatistics() { + leader.getProposalStats().reset(); + } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/quorum/LeaderMXBean.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/LeaderMXBean.java b/src/java/main/org/apache/zookeeper/server/quorum/LeaderMXBean.java index 66428a4..7a1a439 100644 --- a/src/java/main/org/apache/zookeeper/server/quorum/LeaderMXBean.java +++ b/src/java/main/org/apache/zookeeper/server/quorum/LeaderMXBean.java @@ -38,4 +38,24 @@ public interface LeaderMXBean extends ZooKeeperServerMXBean { * @return time taken for leader election in milliseconds. */ public long getElectionTimeTaken(); + + /** + * @return size of latest generated proposal + */ + public int getLastProposalSize(); + + /** + * @return size of smallest generated proposal + */ + public int getMinProposalSize(); + + /** + * @return size of largest generated proposal + */ + public int getMaxProposalSize(); + + /** + * Resets statistics of proposal size (min/max/last) + */ + public void resetProposalStatistics(); } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/quorum/ProposalStats.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/quorum/ProposalStats.java b/src/java/main/org/apache/zookeeper/server/quorum/ProposalStats.java new file mode 100644 index 0000000..2f3a9c7 --- /dev/null +++ b/src/java/main/org/apache/zookeeper/server/quorum/ProposalStats.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zookeeper.server.quorum; + +/** + * Provides live statistics about a running Leader. + */ +public class ProposalStats { + /** + * Size of the last generated proposal. This should fit into server's jute.maxbuffer setting. + */ + private int lastProposalSize = -1; + + /** + * Size of the smallest proposal which has been generated since the server was started. + */ + private int minProposalSize = -1; + + /** + * Size of the largest proposal which has been generated since the server was started. + */ + private int maxProposalSize = -1; + + public synchronized int getLastProposalSize() { + return lastProposalSize; + } + + synchronized void setLastProposalSize(int value) { + lastProposalSize = value; + if (minProposalSize == -1 || value < minProposalSize) { + minProposalSize = value; + } + if (value > maxProposalSize) { + maxProposalSize = value; + } + } + + public synchronized int getMinProposalSize() { + return minProposalSize; + } + + public synchronized int getMaxProposalSize() { + return maxProposalSize; + } + + public synchronized void reset() { + lastProposalSize = -1; + minProposalSize = -1; + maxProposalSize = -1; + } + + public synchronized String toString() { + return String.format("%d/%d/%d", lastProposalSize, minProposalSize, maxProposalSize); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/main/org/apache/zookeeper/server/util/SerializeUtils.java ---------------------------------------------------------------------- diff --git a/src/java/main/org/apache/zookeeper/server/util/SerializeUtils.java b/src/java/main/org/apache/zookeeper/server/util/SerializeUtils.java index b7936f1..eccf527 100644 --- a/src/java/main/org/apache/zookeeper/server/util/SerializeUtils.java +++ b/src/java/main/org/apache/zookeeper/server/util/SerializeUtils.java @@ -19,11 +19,14 @@ package org.apache.zookeeper.server.util; import org.apache.jute.BinaryInputArchive; +import org.apache.jute.BinaryOutputArchive; import org.apache.jute.InputArchive; import org.apache.jute.OutputArchive; import org.apache.jute.Record; import org.apache.zookeeper.ZooDefs.OpCode; +import org.apache.zookeeper.common.IOUtils; import org.apache.zookeeper.server.DataTree; +import org.apache.zookeeper.server.Request; import org.apache.zookeeper.server.ZooTrace; import org.apache.zookeeper.txn.CreateContainerTxn; import org.apache.zookeeper.txn.CreateSessionTxn; @@ -40,6 +43,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.util.HashMap; @@ -148,4 +152,20 @@ public class SerializeUtils { dt.serialize(oa, "tree"); } + public static byte[] serializeRequest(Request request) { + if (request == null || request.getHdr() == null) return null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos); + try { + request.getHdr().serialize(boa, "hdr"); + if (request.getTxn() != null) { + request.getTxn().serialize(boa, "txn"); + } + } catch (IOException e) { + LOG.error("This really should be impossible", e); + } finally { + IOUtils.cleanup(LOG, baos); + } + return baos.toByteArray(); + } } http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java b/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java index da4b829..c78a9a0 100644 --- a/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java +++ b/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java @@ -18,6 +18,7 @@ package org.apache.zookeeper.server; import static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord; +import static org.apache.zookeeper.server.command.AbstractFourLetterCommand.ZK_NOT_SERVING; import java.io.File; import java.io.IOException; @@ -45,7 +46,6 @@ public class ZooKeeperServerStartupTest extends ZKTestCase { private static int PORT = PortAssignment.unique(); private static String HOST = "127.0.0.1"; private static String HOSTPORT = HOST + ":" + PORT; - private static final String ZK_NOT_SERVING = "This ZooKeeper instance is not currently serving requests"; private ServerCnxnFactory servcnxnf; private ZooKeeperServer zks; http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/test/org/apache/zookeeper/server/quorum/LeaderBeanTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/LeaderBeanTest.java b/src/java/test/org/apache/zookeeper/server/quorum/LeaderBeanTest.java new file mode 100644 index 0000000..c30541c --- /dev/null +++ b/src/java/test/org/apache/zookeeper/server/quorum/LeaderBeanTest.java @@ -0,0 +1,151 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zookeeper.server.quorum; + +import org.apache.jute.OutputArchive; +import org.apache.jute.Record; +import org.apache.zookeeper.server.Request; +import org.apache.zookeeper.server.ZKDatabase; +import org.apache.zookeeper.server.persistence.FileTxnSnapLog; +import org.apache.zookeeper.server.quorum.flexible.QuorumVerifier; +import org.apache.zookeeper.server.util.SerializeUtils; +import org.apache.zookeeper.test.ClientBase; +import org.apache.zookeeper.txn.TxnHeader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; + +public class LeaderBeanTest { + private Leader leader; + private LeaderBean leaderBean; + private FileTxnSnapLog fileTxnSnapLog; + private LeaderZooKeeperServer zks; + private QuorumPeer qp; + + @Before + public void setUp() throws IOException { + qp = new QuorumPeer(); + QuorumVerifier quorumVerifierMock = mock(QuorumVerifier.class); + qp.setQuorumVerifier(quorumVerifierMock, false); + File tmpDir = ClientBase.createEmptyTestDir(); + fileTxnSnapLog = new FileTxnSnapLog(new File(tmpDir, "data"), + new File(tmpDir, "data_txnlog")); + ZKDatabase zkDb = new ZKDatabase(fileTxnSnapLog); + + zks = new LeaderZooKeeperServer(fileTxnSnapLog, qp, zkDb); + leader = new Leader(qp, zks); + leaderBean = new LeaderBean(leader, zks); + } + + @After + public void tearDown() throws IOException { + fileTxnSnapLog.close(); + } + + @Test + public void testGetName() { + assertEquals("Leader", leaderBean.getName()); + } + + @Test + public void testGetCurrentZxid() { + // Arrange + zks.setZxid(1); + + // Assert + assertEquals("0x1", leaderBean.getCurrentZxid()); + } + + @Test + public void testGetElectionTimeTaken() { + // Arrange + qp.setElectionTimeTaken(1); + + // Assert + assertEquals(1, leaderBean.getElectionTimeTaken()); + } + + @Test + public void testGetProposalSize() throws IOException, Leader.XidRolloverException { + // Arrange + Request req = createMockRequest(); + + // Act + leader.propose(req); + + // Assert + byte[] data = SerializeUtils.serializeRequest(req); + assertEquals(data.length, leaderBean.getLastProposalSize()); + assertEquals(data.length, leaderBean.getMinProposalSize()); + assertEquals(data.length, leaderBean.getMaxProposalSize()); + } + + @Test + public void testResetProposalStats() throws IOException, Leader.XidRolloverException { + // Arrange + int initialProposalSize = leaderBean.getLastProposalSize(); + Request req = createMockRequest(); + + // Act + leader.propose(req); + + // Assert + assertNotEquals(initialProposalSize, leaderBean.getLastProposalSize()); + leaderBean.resetProposalStatistics(); + assertEquals(initialProposalSize, leaderBean.getLastProposalSize()); + assertEquals(initialProposalSize, leaderBean.getMinProposalSize()); + assertEquals(initialProposalSize, leaderBean.getMaxProposalSize()); + } + + private Request createMockRequest() throws IOException { + TxnHeader header = mock(TxnHeader.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + OutputArchive oa = (OutputArchive) args[0]; + oa.writeString("header", "test"); + return null; + } + }).when(header).serialize(any(OutputArchive.class), anyString()); + Record txn = mock(Record.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + OutputArchive oa = (OutputArchive) args[0]; + oa.writeString("record", "test"); + return null; + } + }).when(txn).serialize(any(OutputArchive.class), anyString()); + return new Request(1, 2, 3, header, txn, 4); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/test/org/apache/zookeeper/server/quorum/ProposalStatsTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/ProposalStatsTest.java b/src/java/test/org/apache/zookeeper/server/quorum/ProposalStatsTest.java new file mode 100644 index 0000000..1f71979 --- /dev/null +++ b/src/java/test/org/apache/zookeeper/server/quorum/ProposalStatsTest.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zookeeper.server.quorum; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ProposalStatsTest { + @Test + public void testSetProposalSizeSetMinMax() { + ProposalStats stats = new ProposalStats(); + assertEquals(-1, stats.getLastProposalSize()); + assertEquals(-1, stats.getMinProposalSize()); + assertEquals(-1, stats.getMaxProposalSize()); + stats.setLastProposalSize(10); + assertEquals(10, stats.getLastProposalSize()); + assertEquals(10, stats.getMinProposalSize()); + assertEquals(10, stats.getMaxProposalSize()); + stats.setLastProposalSize(20); + assertEquals(20, stats.getLastProposalSize()); + assertEquals(10, stats.getMinProposalSize()); + assertEquals(20, stats.getMaxProposalSize()); + stats.setLastProposalSize(5); + assertEquals(5, stats.getLastProposalSize()); + assertEquals(5, stats.getMinProposalSize()); + assertEquals(20, stats.getMaxProposalSize()); + } + + @Test + public void testReset() { + ProposalStats stats = new ProposalStats(); + stats.setLastProposalSize(10); + assertEquals(10, stats.getLastProposalSize()); + assertEquals(10, stats.getMinProposalSize()); + assertEquals(10, stats.getMaxProposalSize()); + stats.reset(); + assertEquals(-1, stats.getLastProposalSize()); + assertEquals(-1, stats.getMinProposalSize()); + assertEquals(-1, stats.getMaxProposalSize()); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/test/org/apache/zookeeper/server/quorum/StatCommandTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/StatCommandTest.java b/src/java/test/org/apache/zookeeper/server/quorum/StatCommandTest.java new file mode 100644 index 0000000..0328b7a --- /dev/null +++ b/src/java/test/org/apache/zookeeper/server/quorum/StatCommandTest.java @@ -0,0 +1,106 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zookeeper.server.quorum; + +import org.apache.zookeeper.server.ServerCnxn; +import org.apache.zookeeper.server.ServerCnxnFactory; +import org.apache.zookeeper.server.ServerStats; +import org.apache.zookeeper.server.ZKDatabase; +import org.apache.zookeeper.server.command.FourLetterCommands; +import org.apache.zookeeper.server.command.StatCommand; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class StatCommandTest { + private StringWriter outputWriter; + private StatCommand statCommand; + private ServerStats.Provider providerMock; + + @Before + public void setUp() throws IOException { + outputWriter = new StringWriter(); + ServerCnxn serverCnxnMock = mock(ServerCnxn.class); + + LeaderZooKeeperServer zks = mock(LeaderZooKeeperServer.class); + when(zks.isRunning()).thenReturn(true); + providerMock = mock(ServerStats.Provider.class); + when(zks.serverStats()).thenReturn(new ServerStats(providerMock)); + ZKDatabase zkDatabaseMock = mock(ZKDatabase.class); + when(zks.getZKDatabase()).thenReturn(zkDatabaseMock); + Leader leaderMock = mock(Leader.class); + when(leaderMock.getProposalStats()).thenReturn(new ProposalStats()); + when(zks.getLeader()).thenReturn(leaderMock); + + ServerCnxnFactory serverCnxnFactory = mock(ServerCnxnFactory.class); + ServerCnxn serverCnxn = mock(ServerCnxn.class); + List connections = new ArrayList<>(); + connections.add(serverCnxn); + when(serverCnxnFactory.getConnections()).thenReturn(connections); + + statCommand = new StatCommand(new PrintWriter(outputWriter), serverCnxnMock, FourLetterCommands.statCmd); + statCommand.setZkServer(zks); + statCommand.setFactory(serverCnxnFactory); + } + + @Test + public void testLeaderStatCommand() { + // Arrange + when(providerMock.getState()).thenReturn("leader"); + + // Act + statCommand.commandRun(); + + // Assert + String output = outputWriter.toString(); + assertCommonStrings(output); + assertThat(output, containsString("Mode: leader")); + assertThat(output, containsString("Proposal sizes last/min/max:")); + } + + @Test + public void testFollowerStatCommand() { + // Arrange + when(providerMock.getState()).thenReturn("follower"); + + // Act + statCommand.commandRun(); + + // Assert + String output = outputWriter.toString(); + assertCommonStrings(output); + assertThat(output, containsString("Mode: follower")); + } + + private void assertCommonStrings(String output) { + assertThat(output, containsString("Clients:")); + assertThat(output, containsString("Zookeeper version:")); + assertThat(output, containsString("Node count:")); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/test/org/apache/zookeeper/server/quorum/StatResetCommandTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/quorum/StatResetCommandTest.java b/src/java/test/org/apache/zookeeper/server/quorum/StatResetCommandTest.java new file mode 100644 index 0000000..ddaf831 --- /dev/null +++ b/src/java/test/org/apache/zookeeper/server/quorum/StatResetCommandTest.java @@ -0,0 +1,111 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zookeeper.server.quorum; + +import org.apache.zookeeper.server.ServerCnxn; +import org.apache.zookeeper.server.ServerStats; +import org.apache.zookeeper.server.ZooKeeperServer; +import org.apache.zookeeper.server.command.StatResetCommand; +import org.junit.Before; +import org.junit.Test; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import static org.apache.zookeeper.server.command.AbstractFourLetterCommand.ZK_NOT_SERVING; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class StatResetCommandTest { + private StatResetCommand statResetCommand; + private StringWriter outputWriter; + private ZooKeeperServer zks; + private ServerStats serverStats; + + @Before + public void setUp() { + outputWriter = new StringWriter(); + ServerCnxn serverCnxnMock = mock(ServerCnxn.class); + + zks = mock(ZooKeeperServer.class); + when(zks.isRunning()).thenReturn(true); + + serverStats = mock(ServerStats.class); + when(zks.serverStats()).thenReturn(serverStats); + + statResetCommand = new StatResetCommand(new PrintWriter(outputWriter), serverCnxnMock); + statResetCommand.setZkServer(zks); + } + + @Test + public void testStatResetWithZKNotRunning() { + // Arrange + when(zks.isRunning()).thenReturn(false); + + // Act + statResetCommand.commandRun(); + + // Assert + String output = outputWriter.toString(); + assertEquals(ZK_NOT_SERVING + "\n", output); + } + + @Test + public void testStatResetWithFollower() { + // Arrange + when(zks.isRunning()).thenReturn(true); + when(serverStats.getServerState()).thenReturn("follower"); + + // Act + statResetCommand.commandRun(); + + // Assert + String output = outputWriter.toString(); + assertEquals("Server stats reset.\n", output); + verify(serverStats, times(1)).reset(); + } + + @Test + public void testStatResetWithLeader() { + // Arrange + LeaderZooKeeperServer leaderZks = mock(LeaderZooKeeperServer.class); + when(leaderZks.isRunning()).thenReturn(true); + when(leaderZks.serverStats()).thenReturn(serverStats); + Leader leader = mock(Leader.class); + when(leaderZks.getLeader()).thenReturn(leader); + statResetCommand.setZkServer(leaderZks); + + when(serverStats.getServerState()).thenReturn("leader"); + + ProposalStats proposalStats = mock(ProposalStats.class); + when(leader.getProposalStats()).thenReturn(proposalStats); + + // Act + statResetCommand.commandRun(); + + // Assert + String output = outputWriter.toString(); + assertEquals("Server stats reset.\n", output); + verify(serverStats, times(1)).reset(); + verify(proposalStats, times(1)).reset(); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5ae5f107/src/java/test/org/apache/zookeeper/server/util/SerializeUtilsTest.java ---------------------------------------------------------------------- diff --git a/src/java/test/org/apache/zookeeper/server/util/SerializeUtilsTest.java b/src/java/test/org/apache/zookeeper/server/util/SerializeUtilsTest.java new file mode 100644 index 0000000..61893f7 --- /dev/null +++ b/src/java/test/org/apache/zookeeper/server/util/SerializeUtilsTest.java @@ -0,0 +1,128 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zookeeper.server.util; + +import org.apache.jute.BinaryOutputArchive; +import org.apache.jute.OutputArchive; +import org.apache.jute.Record; +import org.apache.zookeeper.server.Request; +import org.apache.zookeeper.txn.TxnHeader; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class SerializeUtilsTest { + + @Test + public void testSerializeRequestRequestIsNull() { + byte[] data = SerializeUtils.serializeRequest(null); + assertNull(data); + } + + @Test + public void testSerializeRequestRequestHeaderIsNull() { + Request request = new Request(0, 0, 0, null, null, 0); + byte[] data = SerializeUtils.serializeRequest(request); + assertNull(data); + } + + @Test + public void testSerializeRequestWithoutTxn() throws IOException { + // Arrange + TxnHeader header = mock(TxnHeader.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + OutputArchive oa = (OutputArchive) args[0]; + oa.writeString("header", "test"); + return null; + } + }).when(header).serialize(any(OutputArchive.class), anyString()); + Request request = new Request(1, 2, 3, header, null, 4); + + // Act + byte[] data = SerializeUtils.serializeRequest(request); + + // Assert + assertNotNull(data); + verify(header).serialize(any(OutputArchive.class), eq("hdr")); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos); + boa.writeString("header", "test"); + baos.close(); + assertArrayEquals(baos.toByteArray(), data); + } + + @Test + public void testSerializeRequestWithTxn() throws IOException { + // Arrange + TxnHeader header = mock(TxnHeader.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + OutputArchive oa = (OutputArchive) args[0]; + oa.writeString("header", "test"); + return null; + } + }).when(header).serialize(any(OutputArchive.class), anyString()); + Record txn = mock(Record.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + OutputArchive oa = (OutputArchive) args[0]; + oa.writeString("record", "test"); + return null; + } + }).when(txn).serialize(any(OutputArchive.class), anyString()); + Request request = new Request(1, 2, 3, header, txn, 4); + + // Act + byte[] data = SerializeUtils.serializeRequest(request); + + // Assert + assertNotNull(data); + InOrder inOrder = inOrder(header, txn); + inOrder.verify(header).serialize(any(OutputArchive.class), eq("hdr")); + inOrder.verify(txn).serialize(any(OutputArchive.class), eq("txn")); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos); + boa.writeString("header", "test"); + boa.writeString("record", "test"); + baos.close(); + assertArrayEquals(baos.toByteArray(), data); + } +}