You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by iv...@apache.org on 2012/02/01 12:58:18 UTC

svn commit: r1239096 - in /zookeeper/bookkeeper/trunk: ./ bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/ bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/

Author: ivank
Date: Wed Feb  1 11:58:17 2012
New Revision: 1239096

URL: http://svn.apache.org/viewvc?rev=1239096&view=rev
Log:
BOOKKEEPER-98: collect add/read statistics on bookie server (Sijie Guo via ivank)

Added:
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java.orig
      - copied, changed from r1239068, zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieBean.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieMXBean.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheBean.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheMXBean.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BKStats.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerBean.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerMXBean.java
Modified:
    zookeeper/bookkeeper/trunk/CHANGES.txt
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServer.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/NIOServerFactory.java

Modified: zookeeper/bookkeeper/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/CHANGES.txt?rev=1239096&r1=1239095&r2=1239096&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/CHANGES.txt (original)
+++ zookeeper/bookkeeper/trunk/CHANGES.txt Wed Feb  1 11:58:17 2012
@@ -22,8 +22,6 @@ Trunk (unreleased changes)
 
 	BOOKKEEPER-150: Entry is lost when recovering a ledger with not enough bookies. (Sijie Guo via ivank)
 
-        BOOKKEEPER-95: extends zookeeper JMX to monitor and manage bookie server (Sijie Guo via ivank)
-
         BOOKKEEPER-153: Ledger can't be opened or closed due to zero-length metadata (Sijie Guo via ivank)
 
         BOOKKEEPER-23: Timeout requests (ivank)
@@ -36,6 +34,13 @@ Trunk (unreleased changes)
 
     IMPROVEMENTS:
 
+      bookkeeper-server/
+
+        BOOKKEEPER-95: extends zookeeper JMX to monitor and manage bookie server (Sijie Guo via ivank)
+
+        BOOKKEEPER-98: collect add/read statistics on bookie server (Sijie Guo via ivank)
+
+
 Release 4.0.0 - 2011-11-30
 
   Non-backward compatible changes:

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java?rev=1239096&r1=1239095&r2=1239096&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java Wed Feb  1 11:58:17 2012
@@ -47,6 +47,8 @@ import org.apache.bookkeeper.meta.Ledger
 import org.apache.bookkeeper.meta.LedgerManagerFactory;
 import org.apache.bookkeeper.bookie.BookieException;
 import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.jmx.BKMBeanInfo;
+import org.apache.bookkeeper.jmx.BKMBeanRegistry;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -98,6 +100,10 @@ public class Bookie extends Thread {
     // Running flag
     private volatile boolean running = false;
 
+    // jmx related beans
+    BookieBean jmxBookieBean;
+    LedgerCacheBean jmxLedgerCacheBean;
+
     public static class NoLedgerException extends IOException {
         private static final long serialVersionUID = 1L;
         private long ledgerId;
@@ -389,6 +395,53 @@ public class Bookie extends Thread {
     }
 
     /**
+     * Register jmx with parent
+     *
+     * @param parent parent bk mbean info
+     */
+    public void registerJMX(BKMBeanInfo parent) {
+        try {
+            jmxBookieBean = new BookieBean(this);
+            BKMBeanRegistry.getInstance().register(jmxBookieBean, parent);
+
+            try {
+                jmxLedgerCacheBean = new LedgerCacheBean(this.ledgerCache);
+                BKMBeanRegistry.getInstance().register(jmxLedgerCacheBean, jmxBookieBean);
+            } catch (Exception e) {
+                LOG.warn("Failed to register with JMX for ledger cache", e);
+                jmxLedgerCacheBean = null;
+            }
+
+        } catch (Exception e) {
+            LOG.warn("Failed to register with JMX", e);
+            jmxBookieBean = null;
+        }
+    }
+
+    /**
+     * Unregister jmx
+     */
+    public void unregisterJMX() {
+        try {
+            if (jmxLedgerCacheBean != null) {
+                BKMBeanRegistry.getInstance().unregister(jmxLedgerCacheBean);
+            }
+        } catch (Exception e) {
+            LOG.warn("Failed to unregister with JMX", e);
+        }
+        try {
+            if (jmxBookieBean != null) {
+                BKMBeanRegistry.getInstance().unregister(jmxBookieBean);
+            }
+        } catch (Exception e) {
+            LOG.warn("Failed to unregister with JMX", e);
+        }
+        jmxBookieBean = null;
+        jmxLedgerCacheBean = null;
+    }
+
+
+    /**
      * Instantiate the ZooKeeper client for the Bookie.
      */
     private ZooKeeper instantiateZookeeperClient(String zkServers) throws IOException {

Copied: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java.orig (from r1239068, zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java)
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java.orig?p2=zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java.orig&p1=zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java&r1=1239068&r2=1239096&rev=1239096&view=diff
==============================================================================
    (empty)

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieBean.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieBean.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieBean.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieBean.java Wed Feb  1 11:58:17 2012
@@ -0,0 +1,52 @@
+/**
+ * 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.bookkeeper.bookie;
+
+import java.io.File;
+
+import org.apache.bookkeeper.bookie.Bookie.LastLogMark;
+import org.apache.bookkeeper.jmx.BKMBeanInfo;
+
+/**
+ * Bookie Bean
+ */
+public class BookieBean implements BookieMXBean, BKMBeanInfo {
+
+    protected Bookie bk;
+
+    public BookieBean(Bookie bk) {
+        this.bk = bk;
+    }
+
+    @Override
+    public String getName() {
+        return "Bookie";
+    }
+
+    @Override
+    public boolean isHidden() {
+        return false;
+    }
+
+    @Override
+    public int getQueueLength() {
+        return bk.queue.size();
+    }
+
+}

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieMXBean.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieMXBean.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieMXBean.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieMXBean.java Wed Feb  1 11:58:17 2012
@@ -0,0 +1,33 @@
+/**
+ * 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.bookkeeper.bookie;
+
+import java.io.File;
+
+import org.apache.bookkeeper.bookie.Bookie.LastLogMark;
+
+/**
+ * Bookie MBean
+ */
+public interface BookieMXBean {
+    /**
+     * @return log entry queue length
+     */
+    public int getQueueLength();
+}

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java?rev=1239096&r1=1239095&r2=1239096&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java Wed Feb  1 11:58:17 2012
@@ -104,10 +104,24 @@ public class LedgerCache {
         return entriesPerPage;
     }
 
+    /**
+     * @return page limitation in ledger cache
+     */
+    public int getPageLimit() {
+        return pageLimit;
+    }
+
     // The number of pages that have actually been used
     private int pageCount = 0;
     HashMap<Long, HashMap<Long,LedgerEntryPage>> pages = new HashMap<Long, HashMap<Long,LedgerEntryPage>>();
 
+    /**
+     * @return number of page used in ledger cache
+     */
+    public int getNumUsedPages() {
+        return pageCount;
+    }
+
     private void putIntoTable(HashMap<Long, HashMap<Long,LedgerEntryPage>> table, LedgerEntryPage lep) {
         HashMap<Long, LedgerEntryPage> map = table.get(lep.getLedger());
         if (map == null) {

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheBean.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheBean.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheBean.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheBean.java Wed Feb  1 11:58:17 2012
@@ -0,0 +1,79 @@
+/**
+ * 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.bookkeeper.bookie;
+
+import org.apache.bookkeeper.jmx.BKMBeanInfo;
+
+/**
+ * Ledger Cache Bean
+ */
+public class LedgerCacheBean implements LedgerCacheMXBean, BKMBeanInfo {
+
+    final LedgerCache lc;
+
+    public LedgerCacheBean(LedgerCache lc) {
+        this.lc = lc;
+    }
+
+    @Override
+    public String getName() {
+        return "LedgerCache";
+    }
+
+    @Override
+    public boolean isHidden() {
+        return false;
+    }
+
+    @Override
+    public int getPageCount() {
+        return lc.getNumUsedPages();
+    }
+
+    @Override
+    public int getPageSize() {
+        return lc.getPageSize();
+    }
+
+    @Override
+    public int getOpenFileLimit() {
+        return lc.openFileLimit;
+    }
+
+    @Override
+    public int getPageLimit() {
+        return lc.getPageLimit();
+    }
+
+    @Override
+    public int getNumCleanLedgers() {
+        return lc.cleanLedgers.size();
+    }
+
+    @Override
+    public int getNumDirtyLedgers() {
+        return lc.dirtyLedgers.size();
+    }
+
+    @Override
+    public int getNumOpenLedgers() {
+        return lc.openLedgers.size();
+    }
+
+}

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheMXBean.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheMXBean.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheMXBean.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCacheMXBean.java Wed Feb  1 11:58:17 2012
@@ -0,0 +1,60 @@
+/**
+ * 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.bookkeeper.bookie;
+
+/**
+ * Ledger Cache MBean
+ */
+public interface LedgerCacheMXBean {
+
+    /**
+     * @return number of page used in cache
+     */
+    public int getPageCount();
+
+    /**
+     * @return page size
+     */
+    public int getPageSize();
+
+    /**
+     * @return the limit of open files
+     */
+    public int getOpenFileLimit();
+
+    /**
+     * @return the limit number of pages
+     */
+    public int getPageLimit();
+
+    /**
+     * @return number of clean ledgers
+     */
+    public int getNumCleanLedgers();
+
+    /**
+     * @return number of dirty ledgers
+     */
+    public int getNumDirtyLedgers();
+
+    /**
+     * @return number of open ledgers
+     */
+    public int getNumOpenLedgers();
+}

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java?rev=1239096&r1=1239095&r2=1239096&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java Wed Feb  1 11:58:17 2012
@@ -50,6 +50,8 @@ public class ServerConfiguration extends
     // Zookeeper Parameters
     protected final static String ZK_TIMEOUT = "zkTimeout";
     protected final static String ZK_SERVERS = "zkServers";
+    // Statistics Parameters
+    protected final static String ENABLE_STATISTICS = "enableStatistics";
 
     // separator for ledger dir
     protected final static String SEP = ",";
@@ -374,4 +376,24 @@ public class ServerConfiguration extends
         return this;
     }
 
+    /**
+     * Is statistics enabled
+     *
+     * @return is statistics enabled
+     */
+    public boolean isStatisticsEnabled() {
+        return getBoolean(ENABLE_STATISTICS, true);
+    }
+
+    /**
+     * Turn on/off statistics
+     *
+     * @param enabled
+     *          Whether statistics enabled or not.
+     * @return server configuration
+     */
+    public ServerConfiguration setStatisticsEnabled(boolean enabled) {
+        setProperty(ENABLE_STATISTICS, Boolean.toString(enabled));
+        return this;
+    }
 }

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BKStats.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BKStats.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BKStats.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BKStats.java Wed Feb  1 11:58:17 2012
@@ -0,0 +1,236 @@
+/*
+ *
+ * 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.bookkeeper.proto;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * Bookie Server Stats
+ */
+public class BKStats {
+    private static BKStats instance = new BKStats();
+
+    public static BKStats getInstance() {
+        return instance;
+    }
+
+    /**
+     * A read view of stats, also used in CompositeViewData to expose to JMX
+     */
+    public static class OpStatData {
+        private final long maxLatency, minLatency;
+        private final double avgLatency;
+        private final long numSuccessOps, numFailedOps;
+        private final String latencyHist;
+
+        @ConstructorProperties({"maxLatency", "minLatency", "avgLatency",
+                                "numSuccessOps", "numFailedOps", "latencyHist"})
+        public OpStatData(long maxLatency, long minLatency, double avgLatency,
+                          long numSuccessOps, long numFailedOps, String latencyHist) {
+            this.maxLatency = maxLatency;
+            this.minLatency = minLatency == Long.MAX_VALUE ? 0 : minLatency;
+            this.avgLatency = avgLatency;
+            this.numSuccessOps = numSuccessOps;
+            this.numFailedOps = numFailedOps;
+            this.latencyHist = latencyHist;
+        }
+
+        public long getMaxLatency() {
+            return maxLatency;
+        }
+
+        public long getMinLatency() {
+            return minLatency;
+        }
+
+        public double getAvgLatency() {
+            return avgLatency;
+        }
+
+        public long getNumSuccessOps() {
+            return numSuccessOps;
+        }
+
+        public long getNumFailedOps() {
+            return numFailedOps;
+        }
+
+        public String getLatencyHist() {
+            return latencyHist;
+        }
+    }
+
+    /**
+     * Operation Statistics
+     */
+    public static class OpStats {
+        static final int NUM_BUCKETS = 3*9 + 2;
+
+        long maxLatency = 0;
+        long minLatency = Long.MAX_VALUE;
+        double totalLatency = 0.0f;
+        long numSuccessOps = 0;
+        long numFailedOps = 0;
+        long[] latencyBuckets = new long[NUM_BUCKETS];
+
+        OpStats() {}
+
+        /**
+         * Increment number of failed operations
+         */
+        synchronized public void incrementFailedOps() {
+            ++numFailedOps;
+        }
+
+        /**
+         * Update Latency
+         */
+        synchronized public void updateLatency(long latency) {
+            totalLatency += latency;
+            ++numSuccessOps;
+            if (latency < minLatency) {
+                minLatency = latency;
+            }
+            if (latency > maxLatency) {
+                maxLatency = latency;
+            }
+            int bucket;
+            if (latency <= 100) { // less than 100ms
+                bucket = (int)(latency / 10);
+            } else if (latency <= 1000) { // 100ms ~ 1000ms
+                bucket = 1 * 9 + (int)(latency / 100);
+            } else if (latency <= 10000) { // 1s ~ 10s
+                bucket = 2 * 9 + (int)(latency / 1000);
+            } else { // more than 10s
+                bucket = 3 * 9 + 1;
+            }
+            ++latencyBuckets[bucket];
+        }
+
+        public OpStatData toOpStatData() {
+            double avgLatency = numSuccessOps > 0 ? totalLatency / numSuccessOps : 0.0f;
+            StringBuilder sb = new StringBuilder();
+            for (int i=0; i<NUM_BUCKETS; i++) {
+                sb.append(latencyBuckets[i]);
+                if (i != NUM_BUCKETS - 1) {
+                    sb.append(',');
+                }
+            }
+
+            return new OpStatData(maxLatency, minLatency, avgLatency, numSuccessOps, numFailedOps, sb.toString());
+        }
+
+        /**
+         * Diff with base opstats
+         *
+         * @param base
+         *        base opstats
+         * @return diff opstats
+         */
+        public OpStats diff(OpStats base) {
+            OpStats diff = new OpStats();
+            diff.maxLatency = this.maxLatency > base.maxLatency ? this.maxLatency : base.maxLatency;
+            diff.minLatency = this.minLatency > base.minLatency ? base.minLatency : this.minLatency;
+            diff.totalLatency = this.totalLatency - base.totalLatency;
+            diff.numSuccessOps = this.numSuccessOps - base.numSuccessOps;
+            diff.numFailedOps = this.numFailedOps - base.numFailedOps;
+            for (int i = 0; i < NUM_BUCKETS; i++) {
+                diff.latencyBuckets[i] = this.latencyBuckets[i] - base.latencyBuckets[i];
+            }
+            return diff;
+        }
+
+        /**
+         * Copy stats from other OpStats
+         *
+         * @param other other op stats
+         * @return void
+         */
+        public synchronized void copyOf(OpStats other) {
+            this.maxLatency = other.maxLatency;
+            this.minLatency = other.minLatency;
+            this.totalLatency = other.totalLatency;
+            this.numSuccessOps = other.numSuccessOps;
+            this.numFailedOps = other.numFailedOps;
+            System.arraycopy(other.latencyBuckets, 0, this.latencyBuckets, 0, this.latencyBuckets.length);
+        }
+    }
+
+    public static final int STATS_ADD = 0;
+    public static final int STATS_READ = 1;
+    public static final int STATS_UNKNOWN = 2;
+    // NOTE: if add other stats, increment NUM_STATS
+    public static final int NUM_STATS = 3;
+
+    OpStats[] stats = new OpStats[NUM_STATS];
+
+    private BKStats() {
+        for (int i=0; i<NUM_STATS; i++) {
+            stats[i] = new OpStats();
+        }
+    }
+
+    /**
+     * Stats of operations
+     *
+     * @return op stats
+     */
+    public OpStats getOpStats(int type) {
+        return stats[type];
+    }
+
+    /**
+     * Set stats of a specified operation
+     *
+     * @param type operation type
+     * @param stat operation stats
+     */
+    public void setOpStats(int type, OpStats stat) {
+        stats[type] = stat;
+    }
+
+    /**
+     * Diff with base stats
+     *
+     * @param base base stats
+     * @return diff stats
+     */
+    public BKStats diff(BKStats base) {
+        BKStats diff = new BKStats();
+        for (int i=0; i<NUM_STATS; i++) {
+            diff.setOpStats(i, stats[i].diff(base.getOpStats(i)));
+        }
+        return diff;
+    }
+
+    /**
+     * Copy stats from other stats
+     *
+     * @param other other stats
+     * @return void
+     */
+    public void copyOf(BKStats other) {
+        for (int i=0; i<NUM_STATS; i++) {
+            stats[i].copyOf(other.getOpStats(i));
+        }
+    }
+}

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServer.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServer.java?rev=1239096&r1=1239095&r2=1239096&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServer.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServer.java Wed Feb  1 11:58:17 2012
@@ -29,11 +29,14 @@ import java.net.MalformedURLException;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 
+import javax.management.JMException;
+
 import org.apache.zookeeper.KeeperException;
 
 import org.apache.bookkeeper.bookie.Bookie;
 import org.apache.bookkeeper.bookie.BookieException;
 import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.jmx.BKMBeanRegistry;
 import org.apache.bookkeeper.proto.NIOServerFactory.Cnxn;
 import static org.apache.bookkeeper.proto.BookieProtocol.PacketHeader;
 import org.apache.commons.configuration.ConfigurationException;
@@ -58,10 +61,17 @@ public class BookieServer implements NIO
     DeathWatcher deathWatcher;
     static Logger LOG = LoggerFactory.getLogger(BookieServer.class);
 
+    // operation stats
+    final BKStats bkStats = BKStats.getInstance();
+    final boolean isStatsEnabled;
+    protected BookieServerBean jmxBkServerBean;
+
     public BookieServer(ServerConfiguration conf) 
             throws IOException, KeeperException, InterruptedException {
         this.conf = conf;
         this.bookie = new Bookie(conf);
+
+        isStatsEnabled = conf.isStatisticsEnabled();
     }
 
     public void start() throws IOException {
@@ -69,6 +79,9 @@ public class BookieServer implements NIO
         running = true;
         deathWatcher = new DeathWatcher(conf);
         deathWatcher.start();
+
+        // register jmx
+        registerJMX();
     }
 
     public InetSocketAddress getLocalAddress() {
@@ -86,6 +99,33 @@ public class BookieServer implements NIO
         nioServerFactory.shutdown();
         bookie.shutdown();
         running = false;
+
+        // unregister JMX
+        unregisterJMX();
+    }
+
+    protected void registerJMX() {
+        try {
+            jmxBkServerBean = new BookieServerBean(conf, this);
+            BKMBeanRegistry.getInstance().register(jmxBkServerBean, null);
+
+            bookie.registerJMX(jmxBkServerBean);
+        } catch (Exception e) {
+            LOG.warn("Failed to register with JMX", e);
+            jmxBkServerBean = null;
+        }
+    }
+
+    protected void unregisterJMX() {
+        try {
+            bookie.unregisterJMX();
+            if (jmxBkServerBean != null) {
+                BKMBeanRegistry.getInstance().unregister(jmxBkServerBean);
+            }
+        } catch (Exception e) {
+            LOG.warn("Failed to unregister with JMX", e);
+        }
+        jmxBkServerBean = null;
     }
 
     public boolean isRunning() {
@@ -266,6 +306,13 @@ public class BookieServer implements NIO
     public void processPacket(ByteBuffer packet, Cnxn src) {
         PacketHeader h = PacketHeader.fromInt(packet.getInt());
 
+        boolean success = false;
+        int statType = BKStats.STATS_UNKNOWN;
+        long startTime = 0;
+        if (isStatsEnabled) {
+            startTime = System.currentTimeMillis();
+        }
+
         // packet format is different between ADDENTRY and READENTRY
         long ledgerId = -1;
         long entryId = -1;
@@ -296,6 +343,7 @@ public class BookieServer implements NIO
         short flags = h.getFlags();
         switch (h.getOpCode()) {
         case BookieProtocol.ADDENTRY:
+            statType = BKStats.STATS_ADD;
             try {
                 // LOG.debug("Master key: " + new String(masterKey));
                 if ((flags & BookieProtocol.FLAG_RECOVERY_ADD) == BookieProtocol.FLAG_RECOVERY_ADD) {
@@ -303,6 +351,7 @@ public class BookieServer implements NIO
                 } else {
                     bookie.addEntry(packet.slice(), this, src, masterKey);
                 }
+                success = true;
             } catch (IOException e) {
                 LOG.error("Error writing " + entryId + "@" + ledgerId, e);
                 src.sendResponse(buildResponse(BookieProtocol.EIO, h.getVersion(), h.getOpCode(), ledgerId, entryId));
@@ -315,6 +364,7 @@ public class BookieServer implements NIO
             }
             break;
         case BookieProtocol.READENTRY:
+            statType = BKStats.STATS_READ;
             ByteBuffer[] rsp = new ByteBuffer[2];
             LOG.debug("Received new read request: " + ledgerId + ", " + entryId);
             int errorCode = BookieProtocol.EIO;
@@ -326,6 +376,7 @@ public class BookieServer implements NIO
                 rsp[1] = bookie.readEntry(ledgerId, entryId);
                 LOG.debug("##### Read entry ##### " + rsp[1].remaining());
                 errorCode = BookieProtocol.EOK;
+                success = true;
             } catch (Bookie.NoLedgerException e) {
                 if (LOG.isTraceEnabled()) {
                     LOG.error("Error reading " + entryId + "@" + ledgerId, e);
@@ -358,11 +409,19 @@ public class BookieServer implements NIO
             LOG.debug("Sending response for: " + entryId + ", " + new String(rsp[1].array()));
             src.sendResponse(rsp);
             break;
-        default: 
+        default:
             src.sendResponse(buildResponse(BookieProtocol.EBADREQ, h.getVersion(), h.getOpCode(), ledgerId, entryId));
         }
+        if (isStatsEnabled) {
+            if (success) {
+                long elapsedTime = System.currentTimeMillis() - startTime;
+                bkStats.getOpStats(statType).updateLatency(elapsedTime);
+            } else {
+                bkStats.getOpStats(statType).incrementFailedOps();
+            }
+        }
     }
-    
+
     private ByteBuffer buildResponse(int errorCode, byte version, byte opCode, long ledgerId, long entryId) {
         ByteBuffer rsp = ByteBuffer.allocate(24);
         rsp.putInt(new PacketHeader(version, 

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerBean.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerBean.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerBean.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerBean.java Wed Feb  1 11:58:17 2012
@@ -0,0 +1,90 @@
+/**
+ * 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.bookkeeper.proto;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.jmx.BKMBeanInfo;
+import org.apache.bookkeeper.proto.BKStats;
+import org.apache.bookkeeper.proto.BKStats.OpStats;
+import org.apache.bookkeeper.proto.BKStats.OpStatData;
+
+/**
+ * Bookie Server Bean
+ */
+public class BookieServerBean implements BookieServerMXBean, BKMBeanInfo {
+
+    protected final BookieServer bks;
+    protected final ServerConfiguration conf;
+    private final String name;
+
+    public BookieServerBean(ServerConfiguration conf, BookieServer bks) {
+        this.conf = conf;
+        this.bks = bks;
+        name = "BookieServer_" + conf.getBookiePort();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean isHidden() {
+        return false;
+    }
+
+    @Override
+    public long getNumPacketsReceived() {
+        return ServerStats.getInstance().getPacketsReceived();
+    }
+
+    @Override
+    public long getNumPacketsSent() {
+        return ServerStats.getInstance().getPacketsSent();
+    }
+
+    @Override
+    public OpStatData getAddStats() {
+        return bks.bkStats.getOpStats(BKStats.STATS_ADD).toOpStatData();
+    }
+
+    @Override
+    public OpStatData getReadStats() {
+        return bks.bkStats.getOpStats(BKStats.STATS_READ).toOpStatData();
+    }
+
+    @Override
+    public String getServerState() {
+        return bks.nioServerFactory.stats.getServerState();
+    }
+
+    @Override
+    public String getServerPort() {
+        try {
+            return InetAddress.getLocalHost().getHostAddress() + ":"
+                    + conf.getBookiePort();
+        } catch (UnknownHostException e) {
+            return "localhost:" + conf.getBookiePort();
+        }
+    }
+
+}

Added: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerMXBean.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerMXBean.java?rev=1239096&view=auto
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerMXBean.java (added)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieServerMXBean.java Wed Feb  1 11:58:17 2012
@@ -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.bookkeeper.proto;
+
+import org.apache.bookkeeper.proto.BKStats.OpStatData;
+
+/**
+ * Bookie Server MBean
+ */
+public interface BookieServerMXBean {
+
+    /**
+     * @return packets received
+     */
+    public long getNumPacketsReceived();
+
+    /**
+     * @return packets sent
+     */
+    public long getNumPacketsSent();
+
+    /**
+     * @return add stats
+     */
+    public OpStatData getAddStats();
+
+    /**
+     * @return read stats
+     */
+    public OpStatData getReadStats();
+
+    /**
+     * @return server state
+     */
+    public String getServerState();
+
+    /**
+     * @return server port
+     */
+    public String getServerPort();
+
+}

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/NIOServerFactory.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/NIOServerFactory.java?rev=1239096&r1=1239095&r2=1239096&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/NIOServerFactory.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/NIOServerFactory.java Wed Feb  1 11:58:17 2012
@@ -208,7 +208,7 @@ public class NIOServerFactory extends Th
                             readLength(k);
                         } else {
                             cnxnStats.packetsReceived++;
-                            stats.incrementPacketsReceived();
+                            ServerStats.getInstance().incrementPacketsReceived();
                             try {
                                 readRequest();
                             } finally {