This is an automated email from the ASF dual-hosted git repository.

andor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new ff132ab  ZOOKEEPER-3324: Add read/write metrics for top level znodes
ff132ab is described below

commit ff132ab9dd3dd83df1dbfae5bc9f0cc53f6a4d45
Author: Jie Huang <[email protected]>
AuthorDate: Fri Apr 12 12:29:32 2019 +0200

    ZOOKEEPER-3324: Add read/write metrics for top level znodes
    
    another example of Set metrics.
    
    Author: Jie Huang <[email protected]>
    
    Reviewers: [email protected]
    
    Closes #860 from jhuan31/ZOOKEEPER-3324
---
 .../java/org/apache/zookeeper/server/DataTree.java | 55 ++++++++++++++++++--
 .../org/apache/zookeeper/server/ServerMetrics.java |  3 ++
 .../org/apache/zookeeper/server/DataTreeTest.java  | 60 ++++++++++++++++++++++
 3 files changed, 113 insertions(+), 5 deletions(-)

diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/DataTree.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/DataTree.java
index bf1d9a3..706912c 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/DataTree.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/DataTree.java
@@ -135,6 +135,11 @@ public class DataTree {
     private final PathTrie pTrie = new PathTrie();
 
     /**
+     * over-the-wire size of znode's stat. Counting the fields of Stat class
+     */
+    public static final int STAT_OVERHEAD_BYTES = (6 * 8) + (5 * 4);
+
+    /**
      * This hashtable lists the paths of the ephemeral nodes of a session.
      */
     private final Map<Long, HashSet<String>> ephemerals =
@@ -509,6 +514,7 @@ public class DataTree {
             // ok we have some match and need to update
             updateCountBytes(lastPrefix, bytes, 1);
         }
+        updateWriteStat(path, bytes);
         dataWatches.triggerWatch(path, Event.EventType.NodeCreated);
         childWatches.triggerWatch(parentName.equals("") ? "/" : parentName,
                 Event.EventType.NodeChildrenChanged);
@@ -592,6 +598,9 @@ public class DataTree {
             }
             updateCountBytes(lastPrefix, bytes,-1);
         }
+
+        updateWriteStat(path, 0L);
+
         if (LOG.isTraceEnabled()) {
             ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,
                     "dataWatches.triggerWatch " + path);
@@ -623,12 +632,14 @@ public class DataTree {
         }
         // now update if the path is in a quota subtree.
         String lastPrefix = getMaxPrefixWithQuota(path);
+        long dataBytes = data == null ? 0 : data.length;
         if(lastPrefix != null) {
-            long dataBytes = data == null ? 0 : data.length;
             this.updateCountBytes(lastPrefix, dataBytes
                     - (lastdata == null ? 0 : lastdata.length), 0);
         }
         nodeDataSize.addAndGet(getNodeSize(path, data) - getNodeSize(path, 
lastdata));
+
+        updateWriteStat(path, dataBytes);
         dataWatches.triggerWatch(path, EventType.NodeDataChanged);
         return s;
     }
@@ -656,6 +667,7 @@ public class DataTree {
     public byte[] getData(String path, Stat stat, Watcher watcher)
             throws KeeperException.NoNodeException {
         DataNode n = nodes.get(path);
+        byte[] data = null;
         if (n == null) {
             throw new KeeperException.NoNodeException();
         }
@@ -664,8 +676,10 @@ public class DataTree {
             if (watcher != null) {
                 dataWatches.addWatch(path, watcher);
             }
-            return n.data;
+            data = n.data;
         }
+        updateReadStat(path, data == null ? 0 : data.length);
+        return data;
     }
 
     public Stat statNode(String path, Watcher watcher)
@@ -680,8 +694,9 @@ public class DataTree {
         }
         synchronized (n) {
             n.copyStat(stat);
-            return stat;
         }
+        updateReadStat(path, 0L);
+        return stat;
     }
 
     public List<String> getChildren(String path, Stat stat, Watcher watcher)
@@ -690,17 +705,25 @@ public class DataTree {
         if (n == null) {
             throw new KeeperException.NoNodeException();
         }
+        List<String> children;
         synchronized (n) {
             if (stat != null) {
                 n.copyStat(stat);
             }
-            List<String> children=new ArrayList<String>(n.getChildren());
+            children = new ArrayList<String>(n.getChildren());
 
             if (watcher != null) {
                 childWatches.addWatch(path, watcher);
             }
-            return children;
         }
+
+        int bytes = 0;
+        for (String child : children) {
+            bytes += child.length();
+        }
+        updateReadStat(path, bytes);
+
+        return children;
     }
 
     public int getAllChildrenNumber(String path) {
@@ -1504,4 +1527,26 @@ public class DataTree {
     public ReferenceCountedACLCache getReferenceCountedAclCache() {
         return aclCache;
     }
+
+    private String getTopNamespace(String path) {
+        String[] parts = path.split("/");
+        return parts.length > 1 ? parts[1] : null;
+    }
+
+    private void updateReadStat(String path, long bytes) {
+        String namespace = getTopNamespace(path);
+        if (namespace == null) {
+            return;
+        }
+        long totalBytes = path.length() + bytes + STAT_OVERHEAD_BYTES;
+        ServerMetrics.READ_PER_NAMESPACE.add(namespace, totalBytes);
+    }
+
+    private void updateWriteStat(String path, long bytes) {
+        String namespace = getTopNamespace(path);
+        if (namespace == null) {
+            return;
+        }
+        ServerMetrics.WRITE_PER_NAMESPACE.add(namespace, path.length() + 
bytes);
+    }
 }
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerMetrics.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerMetrics.java
index a664872..1d384fe 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerMetrics.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerMetrics.java
@@ -76,6 +76,9 @@ public enum ServerMetrics {
 
     UNRECOVERABLE_ERROR_COUNT(new SimpleCounter("unrecoverable_error_count")),
 
+    WRITE_PER_NAMESPACE(new AvgMinMaxCounterSet("write_per_namespace")),
+    READ_PER_NAMESPACE(new AvgMinMaxCounterSet("read_per_namespace")),
+
     BYTES_RECEIVED_COUNT(new SimpleCounter("bytes_received_count")),
 
     /**
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/DataTreeTest.java 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/DataTreeTest.java
index d7550a7..d3f40d2 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/DataTreeTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/DataTreeTest.java
@@ -45,6 +45,8 @@ import org.apache.jute.BinaryOutputArchive;
 import org.apache.jute.Record;
 import org.apache.zookeeper.common.PathTrie;
 import java.lang.reflect.*;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -358,4 +360,62 @@ public class DataTreeTest extends ZKTestCase {
         //add these three init 
nodes:/zookeeper,/zookeeper/quota,/zookeeper/config,so the number is 8.
         Assert.assertEquals( 8, dt.getAllChildrenNumber("/"));
     }
+
+    @Test
+    public void testDataTreeMetrics() throws Exception {
+        ServerMetrics.resetAll();
+
+
+        long readBytes1 = 0;
+        long readBytes2 = 0;
+        long writeBytes1 = 0;
+        long writeBytes2 = 0;
+
+        final String TOP1 = "top1";
+        final String TOP2 = "ttop2";
+        final String TOP1PATH = "/" + TOP1;
+        final String TOP2PATH = "/" + TOP2;
+        final String CHILD1 = "child1";
+        final String CHILD2 = "springishere";
+        final String CHILD1PATH = TOP1PATH + "/" + CHILD1;
+        final String CHILD2PATH = TOP1PATH + "/" + CHILD2;
+
+        final int TOP2_LEN = 50;
+        final int CHILD1_LEN = 100;
+        final int CHILD2_LEN = 250;
+
+        DataTree dt = new DataTree();
+        dt.createNode(TOP1PATH, null, null, -1, 1, 1, 1);
+        writeBytes1 += TOP1PATH.length();
+        dt.createNode(TOP2PATH, new byte[TOP2_LEN], null, -1, 1, 1, 1);
+        writeBytes2 += TOP2PATH.length() + TOP2_LEN;
+        dt.createNode(CHILD1PATH, null, null, -1, 1, 1, 1);
+        writeBytes1 += CHILD1PATH.length();
+        dt.setData(CHILD1PATH, new byte[CHILD1_LEN], 1, -1, 1);
+        writeBytes1 += CHILD1PATH.length() + CHILD1_LEN;
+        dt.createNode(CHILD2PATH, new byte[CHILD2_LEN], null, -1, 1, 1, 1);
+        writeBytes1 += CHILD2PATH.length() + CHILD2_LEN;
+        dt.getData(TOP1PATH, new Stat(), null);
+        readBytes1 += TOP1PATH.length() + DataTree.STAT_OVERHEAD_BYTES;
+        dt.getData(TOP2PATH, new Stat(), null);
+        readBytes2 += TOP2PATH.length() + TOP2_LEN + 
DataTree.STAT_OVERHEAD_BYTES;
+        dt.statNode(CHILD2PATH, null);
+        readBytes1 += CHILD2PATH.length() + DataTree.STAT_OVERHEAD_BYTES;
+        dt.getChildren(TOP1PATH, new Stat(), null);
+        readBytes1 += TOP1PATH.length() + CHILD1.length() + CHILD2.length() + 
DataTree.STAT_OVERHEAD_BYTES;
+        dt.deleteNode(TOP1PATH, 1);
+        writeBytes1 += TOP1PATH.length();
+        
+        Map<String, Object> values = ServerMetrics.getAllValues();
+
+        Assert.assertEquals(writeBytes1, values.get("sum_" + TOP1+ 
"_write_per_namespace"));
+        Assert.assertEquals(5L, values.get("cnt_" + TOP1 + 
"_write_per_namespace"));
+        Assert.assertEquals(writeBytes2, values.get("sum_" + TOP2+ 
"_write_per_namespace"));
+        Assert.assertEquals(1L, values.get("cnt_" + TOP2 + 
"_write_per_namespace"));
+
+        Assert.assertEquals(readBytes1, values.get("sum_" + TOP1+ 
"_read_per_namespace"));
+        Assert.assertEquals(3L, values.get("cnt_" + TOP1 + 
"_read_per_namespace"));
+        Assert.assertEquals(readBytes2, values.get("sum_" + TOP2+ 
"_read_per_namespace"));
+        Assert.assertEquals(1L, values.get("cnt_" + TOP2 + 
"_read_per_namespace"));
+    }
 }

Reply via email to