Hey folks,

I needed a way to keep track of individual ZK instances' memory usage
without using JMX, so I went and added a new four letter word: memo

Example usage:
# echo memo | nc 127.0.0.1 44011
Maximum memory: 514850816
Free memory: 479290568
Total memory: 514850816

This exposes the same data that ZOOKEEPER-716 logs, basically the
runtime's maximum/free/total memory.

Attached patch is against branch-3.4.13 as that's the version we're
currently using.

Any feedback is highly appreciated.
Should I go ahead and create a PR/Jira issue?

Thanks,

 - Bram
diff --git a/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml b/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
index d88ddbdb..858448d4 100644
--- a/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
+++ b/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
@@ -1180,6 +1180,14 @@ server.3=zoo3:2888:3888</programlisting>
             </listitem>
           </varlistentry>
 
+          <varlistentry>
+            <term>memo</term>
+
+            <listitem>
+              <para>Gets server memory usage information.</para>
+            </listitem>
+          </varlistentry>
+
           <varlistentry>
             <term>gtmk</term>
 
diff --git a/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java b/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
index 24cc7b46..b922c407 100644
--- a/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
+++ b/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
@@ -850,6 +850,29 @@ public void commandRun() {
         }
     }
 
+    /**
+     * The memo command prints basic memory usage information (in bytes):
+     *  - The JVM's max memory (Xmx)
+     *  - The current free memory
+     *  - The totally allocated memory
+     */
+    private class MemoCommand extends CommandThread {
+	public MemoCommand(PrintWriter pw) {
+	    super(pw);
+	}
+	
+	@Override
+	public void commandRun() {
+		final Runtime runtime = Runtime.getRuntime();
+		pw.print("Maximum memory: ");
+		pw.println(runtime.maxMemory());
+		pw.print("Free memory: ");
+		pw.println(runtime.freeMemory());
+		pw.print("Total memory: ");
+		pw.println(runtime.totalMemory());
+	}
+    }
+
     private class NopCommand extends CommandThread {
         private String msg;
 
@@ -969,6 +992,10 @@ private boolean checkFourLetterWord(final SelectionKey k, final int len)
             IsroCommand isro = new IsroCommand(pwriter);
             isro.start();
             return true;
+        } else if (len == memoCmd) {
+            MemoCommand memo = new MemoCommand(pwriter);
+            memo.start();
+            return true;
         }
         return false;
     }
diff --git a/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java b/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
index 271fc19e..428e9a85 100644
--- a/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
+++ b/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
@@ -630,6 +630,29 @@ public void commandRun() {
         }
     }
 
+    /**
+     * The memo command prints basic memory usage information (in bytes):
+     *  - The JVM's max memory (Xmx)
+     *  - The current free memory
+     *  - The totally allocated memory
+     */
+    private class MemoCommand extends CommandThread {
+	public MemoCommand(PrintWriter pw) {
+	    super(pw);
+	}
+	
+	@Override
+	public void commandRun() {
+		final Runtime runtime = Runtime.getRuntime();
+		pw.print("Maximum memory: ");
+		pw.println(runtime.maxMemory());
+		pw.print("Free memory: ");
+		pw.println(runtime.freeMemory());
+		pw.print("Total memory: ");
+		pw.println(runtime.totalMemory());
+	}
+    }
+
     private class NopCommand extends CommandThread {
         private String msg;
 
@@ -728,6 +751,10 @@ private boolean checkFourLetterWord(final Channel channel,
             IsroCommand isro = new IsroCommand(pwriter);
             isro.start();
             return true;
+        } else if (len == memoCmd) {
+            MemoCommand memo = new MemoCommand(pwriter);
+            memo.start();
+            return true;
         }
         return false;
     }
diff --git a/src/java/main/org/apache/zookeeper/server/ServerCnxn.java b/src/java/main/org/apache/zookeeper/server/ServerCnxn.java
index dfa1d74e..95968ba2 100644
--- a/src/java/main/org/apache/zookeeper/server/ServerCnxn.java
+++ b/src/java/main/org/apache/zookeeper/server/ServerCnxn.java
@@ -240,6 +240,13 @@ public String toString() {
     protected final static int isroCmd = ByteBuffer.wrap("isro".getBytes())
             .getInt();
 
+    /*
+     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
+     * Zk Admin</a>. this link is for all the commands.
+     */
+    protected final static int memoCmd = ByteBuffer.wrap("memo".getBytes())
+	    .getInt();
+
     final static Map<Integer, String> cmd2String = new HashMap<Integer, String>();
 
     private static final String ZOOKEEPER_4LW_COMMANDS_WHITELIST = "zookeeper.4lw.commands.whitelist";
@@ -344,6 +351,7 @@ public synchronized static boolean isEnabled(String command) {
         cmd2String.put(wchsCmd, "wchs");
         cmd2String.put(mntrCmd, "mntr");
         cmd2String.put(isroCmd, "isro");
+        cmd2String.put(memoCmd, "memo");
     }
 
     protected void packetReceived() {
diff --git a/src/java/test/org/apache/zookeeper/test/FourLetterWordsTest.java b/src/java/test/org/apache/zookeeper/test/FourLetterWordsTest.java
index bc8d0713..4f054082 100644
--- a/src/java/test/org/apache/zookeeper/test/FourLetterWordsTest.java
+++ b/src/java/test/org/apache/zookeeper/test/FourLetterWordsTest.java
@@ -106,6 +106,10 @@ public void testFourLetterWords() throws Exception {
         verify("mntr", "fsync_threshold_exceed_count");
         verify("stat", "Connections");
         verify("srvr", "Connections");
+
+        verify("memo", "Free memory");
+        verify("memo", "Total memory");
+        verify("memo", "Maximum memory");
     }
 
     private String sendRequest(String cmd) throws IOException {

Reply via email to