Selaa lähdekoodia

ZOOKEEPER-8. Stat enchaned to include num of children and size

git-svn-id: https://svn.apache.org/repos/asf/hadoop/zookeeper/trunk@702583 13f79535-47bb-0310-9956-ffa450edef68
Patrick D. Hunt 16 vuotta sitten
vanhempi
commit
ff98502017

+ 3 - 0
CHANGES.txt

@@ -13,6 +13,9 @@ Non-backward compatible changes:
   ZOOKEEPER-38. headers (version+) in log/snap files (Andrew Kornev and Mahadev
   Konar via breed)
 
+  ZOOKEEPER-8. Stat enchaned to include num of children and size
+  (phunt)
+
 Backward compatibile changes:
 
   BUGFIXES: 

+ 42 - 17
docs/zookeeperProgrammers.html

@@ -652,12 +652,37 @@ document.write("Last Published: " + document.lastModified);
           zero.</p>
         
 </li>
+
+        
+<li>
+          
+<p>
+<strong>dataLength</strong>
+</p>
+
+          
+<p>The length of the data field of this znode.</p>
+        
+</li>
+
+        
+<li>
+          
+<p>
+<strong>numChildren</strong>
+</p>
+
+          
+<p>The number of children of this znode.</p>
+        
+</li>
+
       
 </ul>
 </div>
 
   
-<a name="N1018F"></a><a name="ch_zkSessions"></a>
+<a name="N101A3"></a><a name="ch_zkSessions"></a>
 <h2 class="h3">ZooKeeper Sessions</h2>
 <div class="section">
 <p>When a client gets a handle to the ZooKeeper service, ZooKeeper
@@ -685,7 +710,7 @@ document.write("Last Published: " + document.lastModified);
 </div>
 
   
-<a name="N1019F"></a><a name="ch_zkWatches"></a>
+<a name="N101B3"></a><a name="ch_zkWatches"></a>
 <h2 class="h3">ZooKeeper Watches</h2>
 <div class="section">
 <p>All of the read operations in ZooKeeper - <strong>getData()</strong>, <strong>getChildren()</strong>, and <strong>exists()</strong> - have the option of setting a watch as a
@@ -760,7 +785,7 @@ document.write("Last Published: " + document.lastModified);
     client gets a disconnect event, it must consider that an implicit trigger
     of all watches. When a client reconnects to a new server, the client
     should re-set any watches that it is still interested in.</p>
-<a name="N101D5"></a><a name="sc_WatchGuarantees"></a>
+<a name="N101E9"></a><a name="sc_WatchGuarantees"></a>
 <h3 class="h4">What ZooKeeper Guarantees about Watches</h3>
 <p>With regard to watches, ZooKeeper maintains these
       guarantees:</p>
@@ -795,7 +820,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
       
 </ul>
-<a name="N101FA"></a><a name="sc_WatchRememberThese"></a>
+<a name="N1020E"></a><a name="sc_WatchRememberThese"></a>
 <h3 class="h4">Things to Remember about Watches</h3>
 <ul>
         
@@ -838,13 +863,13 @@ document.write("Last Published: " + document.lastModified);
 </div>
 
   
-<a name="N1021D"></a><a name="sc_ZooKeeperAccessControl"></a>
+<a name="N10231"></a><a name="sc_ZooKeeperAccessControl"></a>
 <h2 class="h3">ZooKeeper access control using ACLs</h2>
 <div class="section">
 <p>ZooKeeper uses ACLs to control access to its znodes (the data nodes of a ZooKeeper data tree). The ACL implementation is quite similar to UNIX file access permissions: it employs permission bits to allow/disallow various operations against a node and the scope to which the bits apply. Unlike standard UNIX permissions, a ZooKeeper node is not limited by the three standard scopes for user (owner of the file), group, and world (other). ZooKeeper does not have a notion of an owner of a znode. Instead, an ACL specifies sets of ids and permissions that are associated with those ids.</p>
 <p>ZooKeeper supports pluggable authentication schemes. Ids are specified using the form <em>scheme:id</em>, where <em>scheme</em> is a the authentication scheme that the id corresponds to. For example, <em>host:host1.corp.com</em> is an id for a host named <em>host1.corp.com</em>.</p>
 <p>When a client connects to ZooKeeper and authenticates itself, ZooKeeper associates all the ids that correspond to a client with the clients connection. These ids are checked against the ACLs of znodes when a clients tries to access a node. ACLs are made up of pairs of <em>(scheme:expression, perms)</em>. The format of the <em>expression</em> is specific to the scheme. For example, the pair <em>(ip:19.22.0.0/16, READ)</em> gives the <em>READ</em> permission to any clients with an IP address that starts with 19.22.</p>
-<a name="N10244"></a><a name="sc_ACLPermissions"></a>
+<a name="N10258"></a><a name="sc_ACLPermissions"></a>
 <h3 class="h4">ACL Permissions</h3>
 <p>Zookeeper supports the following permissions:</p>
 <ul>
@@ -880,7 +905,7 @@ document.write("Last Published: " + document.lastModified);
 <p>
 <em>CREATE</em> without <em>DELETE</em>: clients create requests by creating zookeeper nodes in a parent directory. You want all clients to be able to add, but only request processor can delete. (This is kind of like the APPEND permission for files.)</p>
 <p>Also, the <em>ADMIN</em> permission is there since Zookeeper doesn&rsquo;t have a notion of file owner. In some sense the <em>ADMIN</em> permission designates the entity as the owner. Zookeeper doesn&rsquo;t support the LOOKUP permission (execute permission bit on directories to allow you to LOOKUP even though you can't list the directory). Everyone implicitly has LOOKUP permission. This allows you to stat a node, but nothing more. (The problem is, if you want to call zoo_exists() on a node that doesn't exist, there is no permission to check.)</p>
-<a name="N1029A"></a><a name="sc_BuiltinACLSchemes"></a>
+<a name="N102AE"></a><a name="sc_BuiltinACLSchemes"></a>
 <h4>Builtin ACL Schemes</h4>
 <p>ZooKeeeper has the following built in schemes:</p>
 <ul>
@@ -911,7 +936,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
       
 </ul>
-<a name="N102EF"></a><a name="Zookeeper+C+client+API"></a>
+<a name="N10303"></a><a name="Zookeeper+C+client+API"></a>
 <h4>Zookeeper C client API</h4>
 <p>The following constants are provided by the zookeeper C library:</p>
 <ul>
@@ -1098,7 +1123,7 @@ int main(int argc, char argv) {
 </div>
 
   
-<a name="N1040C"></a><a name="ch_zkGuarantees"></a>
+<a name="N10420"></a><a name="ch_zkGuarantees"></a>
 <h2 class="h3">Consistency Guarantees</h2>
 <div class="section">
 <p>ZooKeeper is a high performance, scalable service. Both reads and
@@ -1225,12 +1250,12 @@ int main(int argc, char argv) {
 </div>
 
   
-<a name="N1047A"></a><a name="ch_bindings"></a>
+<a name="N1048E"></a><a name="ch_bindings"></a>
 <h2 class="h3">Bindings</h2>
 <div class="section">
 <p>The ZooKeeper client libraries come in two languages: Java and C.
     The following sections describe these.</p>
-<a name="N10483"></a><a name="Java+Binding"></a>
+<a name="N10497"></a><a name="Java+Binding"></a>
 <h3 class="h4">Java Binding</h3>
 <p>There are two packages that make up the ZooKeeper Java binding:
       <strong>org.apache.zookeeper</strong> and <strong>org.apache.zookeeper.data</strong>. The rest of the
@@ -1297,7 +1322,7 @@ int main(int argc, char argv) {
       (SESSION_EXPIRED and AUTH_FAILED), the ZooKeeper object becomes invalid,
       the two threads shut down, and any further ZooKeeper calls throw
       errors.</p>
-<a name="N104CC"></a><a name="C+Binding"></a>
+<a name="N104E0"></a><a name="C+Binding"></a>
 <h3 class="h4">C Binding</h3>
 <p>The C binding has a single-threaded and multi-threaded library.
       The multi-threaded library is easiest to use and is most similar to the
@@ -1314,7 +1339,7 @@ int main(int argc, char argv) {
       (i.e. FreeBSD 4.x). In all other cases, application developers should
       link with zookeeper_mt, as it includes support for both Sync and Async
       API.</p>
-<a name="N104DB"></a><a name="Installation"></a>
+<a name="N104EF"></a><a name="Installation"></a>
 <h4>Installation</h4>
 <p>If you're building the client from a check-out from the Apache
         repository, follow the steps outlined below. If you're building from a
@@ -1445,7 +1470,7 @@ int main(int argc, char argv) {
 </li>
         
 </ol>
-<a name="N10584"></a><a name="Using+the+Client"></a>
+<a name="N10598"></a><a name="Using+the+Client"></a>
 <h4>Using the Client</h4>
 <p>You can test your client by running a zookeeper server (see
         instructions on the project wiki page on how to run it) and connecting
@@ -1498,7 +1523,7 @@ int main(int argc, char argv) {
 </div>
 
    
-<a name="N105C3"></a><a name="ch_guideToZkOperations"></a>
+<a name="N105D7"></a><a name="ch_guideToZkOperations"></a>
 <h2 class="h3">Building Blocks: A Guide to ZooKeeper Operations</h2>
 <div class="section">
 <p>
@@ -1570,7 +1595,7 @@ int main(int argc, char argv) {
 </div>
   
   
-<a name="N10605"></a><a name="ch_programStructureWithExample"></a>
+<a name="N10619"></a><a name="ch_programStructureWithExample"></a>
 <h2 class="h3">Program Structure, with Simple Example</h2>
 <div class="section">
 <p>
@@ -1579,7 +1604,7 @@ int main(int argc, char argv) {
 </div>
 
   
-<a name="N10610"></a><a name="ch_gotchas"></a>
+<a name="N10624"></a><a name="ch_gotchas"></a>
 <h2 class="h3">Gotchas: Common Problems and Troubleshooting</h2>
 <div class="section">
 <p>So now you know ZooKeeper. It's fast, simple, your application

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 5
docs/zookeeperProgrammers.pdf


+ 13 - 0
src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml

@@ -331,6 +331,19 @@
           ephemeral node. If it is not an ephemeral node, it will be
           zero.</para>
         </listitem>
+
+        <listitem>
+          <para><emphasis role="bold">dataLength</emphasis></para>
+
+          <para>The length of the data field of this znode.</para>
+        </listitem>
+
+        <listitem>
+          <para><emphasis role="bold">numChildren</emphasis></para>
+
+          <para>The number of children of this znode.</para>
+        </listitem>
+
       </itemizedlist>
     </section>
   </section>

+ 19 - 5
src/java/main/org/apache/zookeeper/server/DataNode.java

@@ -29,6 +29,7 @@ import org.apache.jute.OutputArchive;
 import org.apache.jute.Record;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 
 /**
  * This class contains the data for a node in the data tree.
@@ -42,7 +43,7 @@ public class DataNode implements Record {
         // default rather than public constructor
     }
 
-    DataNode(DataNode parent, byte data[], List<ACL> acl, Stat stat) {
+    DataNode(DataNode parent, byte data[], List<ACL> acl, StatPersisted stat) {
         this.parent = parent;
         this.data = data;
         this.acl = acl;
@@ -56,10 +57,23 @@ public class DataNode implements Record {
 
     List<ACL> acl;
 
-    public Stat stat;
+    public StatPersisted stat;
 
     HashSet<String> children = new HashSet<String>();
 
+    public void copyStat(Stat to) {
+        to.setAversion(stat.getAversion());
+        to.setCtime(stat.getCtime());
+        to.setCversion(stat.getCversion());
+        to.setCzxid(stat.getCzxid());
+        to.setMtime(stat.getMtime());
+        to.setMzxid(stat.getMzxid());
+        to.setVersion(stat.getVersion());
+        to.setEphemeralOwner(stat.getEphemeralOwner());
+        to.setDataLength(data.length);
+        to.setNumChildren(children.size());
+    }
+
     public void deserialize(InputArchive archive, String tag)
             throws IOException {
         archive.startRecord("node");
@@ -75,8 +89,8 @@ public class DataNode implements Record {
             }
         }
         archive.endVector("acl");
-        stat = new Stat();
-        stat.deserialize(archive, "stat");
+        stat = new StatPersisted();
+        stat.deserialize(archive, "statpersisted");
         archive.endRecord("node");
     }
 
@@ -91,7 +105,7 @@ public class DataNode implements Record {
             }
         }
         archive.endVector(acl, "acl");
-        stat.serialize(archive, "stat");
+        stat.serialize(archive, "statpersisted");
         archive.endRecord(this, "node");
     }
 }

+ 23 - 9
src/java/main/org/apache/zookeeper/server/DataTree.java

@@ -32,13 +32,13 @@ import org.apache.jute.Record;
 import org.apache.log4j.Logger;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.Watcher.Event.EventType;
-import org.apache.zookeeper.Watcher.Event.KeeperState;
 import org.apache.zookeeper.KeeperException.Code;
 import org.apache.zookeeper.Watcher.Event;
+import org.apache.zookeeper.Watcher.Event.EventType;
 import org.apache.zookeeper.ZooDefs.OpCode;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 import org.apache.zookeeper.txn.CreateTxn;
 import org.apache.zookeeper.txn.DeleteTxn;
 import org.apache.zookeeper.txn.ErrorTxn;
@@ -109,7 +109,8 @@ public class DataTree {
      * This is a pointer to the root of the DataTree. It is the source of truth,
      * but we usually use the nodes hashmap to find nodes in the tree.
      */
-    private DataNode root = new DataNode(null, new byte[0], null, new Stat());
+    private DataNode root =
+        new DataNode(null, new byte[0], null, new StatPersisted());
 
     public DataTree() {
         /* Rather than fight it, let root have an alias */
@@ -117,6 +118,17 @@ public class DataTree {
         nodes.put("/", root);
     }
 
+    static public void copyStatPersisted(StatPersisted from, StatPersisted to) {
+        to.setAversion(from.getAversion());
+        to.setCtime(from.getCtime());
+        to.setCversion(from.getCversion());
+        to.setCzxid(from.getCzxid());
+        to.setMtime(from.getMtime());
+        to.setMzxid(from.getMzxid());
+        to.setVersion(from.getVersion());
+        to.setEphemeralOwner(from.getEphemeralOwner());
+    }
+
     static public void copyStat(Stat from, Stat to) {
         to.setAversion(from.getAversion());
         to.setCtime(from.getCtime());
@@ -126,6 +138,8 @@ public class DataTree {
         to.setMzxid(from.getMzxid());
         to.setVersion(from.getVersion());
         to.setEphemeralOwner(from.getEphemeralOwner());
+        to.setDataLength(from.getDataLength());
+        to.setNumChildren(from.getNumChildren());
     }
 
     // public void remooveInterest(String path, Watcher nw) {
@@ -161,7 +175,7 @@ public class DataTree {
         int lastSlash = path.lastIndexOf('/');
         String parentName = path.substring(0, lastSlash);
         String childName = path.substring(lastSlash + 1);
-        Stat stat = new Stat();
+        StatPersisted stat = new StatPersisted();
         stat.setCtime(time);
         stat.setMtime(time);
         stat.setCzxid(zxid);
@@ -250,7 +264,7 @@ public class DataTree {
             n.stat.setMtime(time);
             n.stat.setMzxid(zxid);
             n.stat.setVersion(version);
-            copyStat(n.stat, s);
+            n.copyStat(s);
         }
         dataWatches.triggerWatch(path, EventType.NodeDataChanged);
         return s;
@@ -262,7 +276,7 @@ public class DataTree {
             throw new KeeperException.NoNodeException();
         }
         synchronized (n) {
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             if (watcher != null) {
                 dataWatches.addWatch(path, watcher);
             }
@@ -280,7 +294,7 @@ public class DataTree {
             throw new KeeperException.NoNodeException();
         }
         synchronized (n) {
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             return stat;
         }
     }
@@ -310,7 +324,7 @@ public class DataTree {
         synchronized (n) {
             n.stat.setAversion(version);
             n.acl = acl;
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             return stat;
         }
     }
@@ -322,7 +336,7 @@ public class DataTree {
             throw new KeeperException.NoNodeException();
         }
         synchronized (n) {
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             return new ArrayList<ACL>(n.acl);
         }
     }

+ 2 - 1
src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java

@@ -35,6 +35,7 @@ import org.apache.zookeeper.ZooDefs.OpCode;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Id;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 import org.apache.zookeeper.proto.CreateRequest;
 import org.apache.zookeeper.proto.DeleteRequest;
 import org.apache.zookeeper.proto.SetACLRequest;
@@ -220,7 +221,7 @@ public class PrepRequestProcessor extends Thread implements RequestProcessor {
                 txn = new CreateTxn(path, createRequest.getData(),
                         createRequest.getAcl(),
                         createMode.isEphemeral());
-                Stat s = new Stat();
+                StatPersisted s = new StatPersisted();
                 if (createMode.isEphemeral()) {
                     s.setEphemeralOwner(request.sessionId);
                 }

+ 5 - 4
src/java/main/org/apache/zookeeper/server/ZooKeeperServer.java

@@ -40,6 +40,7 @@ import org.apache.zookeeper.ZooDefs.OpCode;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Id;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 import org.apache.zookeeper.proto.RequestHeader;
 import org.apache.zookeeper.server.SessionTracker.SessionExpirer;
 import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
@@ -378,7 +379,7 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
      * and FinalRP.
      */
     static class ChangeRecord {
-        ChangeRecord(long zxid, String path, Stat stat, int childCount,
+        ChangeRecord(long zxid, String path, StatPersisted stat, int childCount,
                 List<ACL> acl) {
             this.zxid = zxid;
             this.path = path;
@@ -391,7 +392,7 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
 
         String path;
 
-        Stat stat; /* Make sure to create a new object when changing */
+        StatPersisted stat; /* Make sure to create a new object when changing */
 
         int childCount;
 
@@ -399,9 +400,9 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
 
         @SuppressWarnings("unchecked")
         ChangeRecord duplicate(long zxid) {
-            Stat stat = new Stat();
+            StatPersisted stat = new StatPersisted();
             if (this.stat != null) {
-                DataTree.copyStat(this.stat, stat);
+                DataTree.copyStatPersisted(this.stat, stat);
             }
             return new ChangeRecord(zxid, path, stat, childCount,
                     acl == null ? new ArrayList<ACL>() : new ArrayList(acl));

+ 198 - 0
src/java/test/org/apache/zookeeper/test/StatTest.java

@@ -0,0 +1,198 @@
+/**
+ * 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.test;
+
+import java.io.IOException;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.data.Stat;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class StatTest extends ClientBase {
+    private ZooKeeper zk;
+    
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        zk = createClient();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        
+        zk.close();
+    }
+    
+    /**
+     * Create a new Stat, fill in dummy values trying to catch failure
+     * to copy in client or server code.
+     * 
+     * @return a new stat with dummy values
+     */
+    private Stat newStat() {
+        Stat stat = new Stat();
+        
+        stat.setAversion(100);
+        stat.setCtime(100);
+        stat.setCversion(100);
+        stat.setCzxid(100);
+        stat.setDataLength(100);
+        stat.setEphemeralOwner(100);
+        stat.setMtime(100);
+        stat.setMzxid(100);
+        stat.setNumChildren(100);
+        stat.setVersion(100);
+        
+        return stat;
+    }
+
+    @Test
+    public void testBasic()
+        throws IOException, KeeperException, InterruptedException
+    {
+        String name = "/foo";
+        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        
+        Stat stat;
+        
+        stat = newStat();
+        zk.getData(name, false, stat);
+        
+        assertEquals(stat.getCzxid(), stat.getMzxid());
+        assertEquals(stat.getCtime(), stat.getMtime());
+        assertEquals(0, stat.getCversion());
+        assertEquals(0, stat.getVersion());
+        assertEquals(0, stat.getAversion());
+        assertEquals(0, stat.getEphemeralOwner());
+        assertEquals(name.length(), stat.getDataLength());
+        assertEquals(0, stat.getNumChildren());
+    }
+
+    @Test
+    public void testChild()
+        throws IOException, KeeperException, InterruptedException
+    {
+        String name = "/foo";
+        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        
+        String childname = name + "/bar";
+        zk.create(childname, childname.getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.EPHEMERAL);
+
+        Stat stat;
+        
+        stat = newStat();
+        zk.getData(name, false, stat);
+
+        assertEquals(stat.getCzxid(), stat.getMzxid());
+        assertEquals(stat.getCtime(), stat.getMtime());
+        assertEquals(1, stat.getCversion());
+        assertEquals(0, stat.getVersion());
+        assertEquals(0, stat.getAversion());
+        assertEquals(0, stat.getEphemeralOwner());
+        assertEquals(name.length(), stat.getDataLength());
+        assertEquals(1, stat.getNumChildren());
+
+        stat = newStat();
+        zk.getData(childname, false, stat);
+
+        assertEquals(stat.getCzxid(), stat.getMzxid());
+        assertEquals(stat.getCtime(), stat.getMtime());
+        assertEquals(0, stat.getCversion());
+        assertEquals(0, stat.getVersion());
+        assertEquals(0, stat.getAversion());
+        assertEquals(zk.getSessionId(), stat.getEphemeralOwner());
+        assertEquals(childname.length(), stat.getDataLength());
+        assertEquals(0, stat.getNumChildren());
+    }
+
+    @Test
+    public void testChildren()
+        throws IOException, KeeperException, InterruptedException
+    {
+        String name = "/foo";
+        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        
+        for(int i = 0; i < 10; i++) {
+            String childname = name + "/bar" + i;
+            zk.create(childname, childname.getBytes(), Ids.OPEN_ACL_UNSAFE,
+                    CreateMode.EPHEMERAL);
+
+            Stat stat;
+            
+            stat = newStat();
+            zk.getData(name, false, stat);
+    
+            assertEquals(stat.getCzxid(), stat.getMzxid());
+            assertEquals(stat.getCtime(), stat.getMtime());
+            assertEquals(i + 1, stat.getCversion());
+            assertEquals(0, stat.getVersion());
+            assertEquals(0, stat.getAversion());
+            assertEquals(0, stat.getEphemeralOwner());
+            assertEquals(name.length(), stat.getDataLength());
+            assertEquals(i + 1, stat.getNumChildren());
+        }
+    }
+
+    @Test
+    public void testDataSizeChange()
+        throws IOException, KeeperException, InterruptedException
+    {
+        String name = "/foo";
+        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        
+        Stat stat;
+        
+        stat = newStat();
+        zk.getData(name, false, stat);
+        
+        assertEquals(stat.getCzxid(), stat.getMzxid());
+        assertEquals(stat.getCtime(), stat.getMtime());
+        assertEquals(0, stat.getCversion());
+        assertEquals(0, stat.getVersion());
+        assertEquals(0, stat.getAversion());
+        assertEquals(0, stat.getEphemeralOwner());
+        assertEquals(name.length(), stat.getDataLength());
+        assertEquals(0, stat.getNumChildren());
+
+        zk.setData(name, (name + name).getBytes(), -1);
+        
+        stat = newStat();
+        zk.getData(name, false, stat);
+        
+        assertNotSame(stat.getCzxid(), stat.getMzxid());
+        assertNotSame(stat.getCtime(), stat.getMtime());
+        assertEquals(0, stat.getCversion());
+        assertEquals(1, stat.getVersion());
+        assertEquals(0, stat.getAversion());
+        assertEquals(0, stat.getEphemeralOwner());
+        assertEquals(name.length() * 2, stat.getDataLength());
+        assertEquals(0, stat.getNumChildren());
+    }
+}

+ 39 - 25
src/zookeeper.jute

@@ -18,22 +18,36 @@
 
 module org.apache.zookeeper.data {
     class Id {
-    	ustring scheme;
-    	ustring id;
+        ustring scheme;
+        ustring id;
     }
     class ACL {
         int perms;
-	Id id;
+        Id id;
     }
+    // information shared with the client
     class Stat {
-        long czxid;
-        long mzxid;
-        long ctime; 
-        long mtime;
-        int version; 
-        int cversion; 
-        int aversion; 
-	long ephemeralOwner;
+        long czxid;      // created zxid
+        long mzxid;      // last modified zxid
+        long ctime;      // created
+        long mtime;      // last modified
+        int version;     // version
+        int cversion;    // child version
+        int aversion;    // acl version
+        long ephemeralOwner; // owner id if ephemeral, 0 otw
+        int dataLength;  //length of the data in the node
+        int numChildren; //number of children of this node
+    }
+    // information explicitly stored by the server persistently
+    class StatPersisted {
+        long czxid;      // created zxid
+        long mzxid;      // last modified zxid
+        long ctime;      // created
+        long mtime;      // last modified
+        int version;     // version
+        int cversion;    // child version
+        int aversion;    // acl version
+        long ephemeralOwner; // owner id if ephemeral, 0 otw
     }
 }
 module org.apache.zookeeper.proto {
@@ -45,7 +59,7 @@ module org.apache.zookeeper.proto {
 
     class ConnectRequest {
         int protocolVersion;
-	long lastZxidSeen;
+        long lastZxidSeen;
         int timeOut;
         long sessionId;
         buffer passwd;
@@ -61,14 +75,14 @@ module org.apache.zookeeper.proto {
         int type;
     }
     class AuthPacket {
-	int type;
-	ustring scheme;
-	buffer auth;
+        int type;
+        ustring scheme;
+        buffer auth;
     }
     class ReplyHeader {
         int xid;
         long zxid;
-	int err;
+        int err;
     }
     class GetDataRequest {
         ustring path;
@@ -106,7 +120,7 @@ module org.apache.zookeeper.proto {
         ustring path;
         int max;
     }
-	class SyncRequest {
+    class SyncRequest {
         ustring path;
     }
     class SyncResponse {
@@ -126,7 +140,7 @@ module org.apache.zookeeper.proto {
     class WatcherEvent {
         int type;  // event type
         int state; // state of the Keeper client runtime
-        ustring path; 
+        ustring path;
     }
 
     class CreateResponse {
@@ -137,7 +151,7 @@ module org.apache.zookeeper.proto {
         boolean watch;
     }
     class ExistsResponse {
-	org.apache.zookeeper.data.Stat stat;
+        org.apache.zookeeper.data.Stat stat;
     }
     class GetDataResponse {
         buffer data;
@@ -156,8 +170,8 @@ module org.apache.zookeeper.server.quorum {
     class QuorumPacket {
         int type; // Request, Ack, Commit, Ping
         long zxid;
-	buffer data; // Only significant when type is request
-	vector<org.apache.zookeeper.data.Id> authinfo;
+        buffer data; // Only significant when type is request
+        vector<org.apache.zookeeper.data.Id> authinfo;
     }
 }
 
@@ -172,8 +186,8 @@ module org.apache.zookeeper.server.persistence {
 module org.apache.zookeeper.txn {
     class TxnHeader {
         long clientId;
-	int cxid;
-	long zxid;
+        int cxid;
+        long zxid;
         long time;
         int type;
     }
@@ -181,7 +195,7 @@ module org.apache.zookeeper.txn {
         ustring path;
         buffer data;
         vector<org.apache.zookeeper.data.ACL> acl;
-	boolean ephemeral;
+        boolean ephemeral;
     }
     class DeleteTxn {
         ustring path;
@@ -201,7 +215,7 @@ module org.apache.zookeeper.txn {
         int max;
     }
     class CreateSessionTxn {
-	int timeOut;
+        int timeOut;
     }
     class ErrorTxn {
         int err;

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä