소스 검색

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 년 전
부모
커밋
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
   ZOOKEEPER-38. headers (version+) in log/snap files (Andrew Kornev and Mahadev
   Konar via breed)
   Konar via breed)
 
 
+  ZOOKEEPER-8. Stat enchaned to include num of children and size
+  (phunt)
+
 Backward compatibile changes:
 Backward compatibile changes:
 
 
   BUGFIXES: 
   BUGFIXES: 

+ 42 - 17
docs/zookeeperProgrammers.html

@@ -652,12 +652,37 @@ document.write("Last Published: " + document.lastModified);
           zero.</p>
           zero.</p>
         
         
 </li>
 </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>
 </ul>
 </div>
 </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>
 <h2 class="h3">ZooKeeper Sessions</h2>
 <div class="section">
 <div class="section">
 <p>When a client gets a handle to the ZooKeeper service, ZooKeeper
 <p>When a client gets a handle to the ZooKeeper service, ZooKeeper
@@ -685,7 +710,7 @@ document.write("Last Published: " + document.lastModified);
 </div>
 </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>
 <h2 class="h3">ZooKeeper Watches</h2>
 <div class="section">
 <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
 <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
     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
     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>
     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>
 <h3 class="h4">What ZooKeeper Guarantees about Watches</h3>
 <p>With regard to watches, ZooKeeper maintains these
 <p>With regard to watches, ZooKeeper maintains these
       guarantees:</p>
       guarantees:</p>
@@ -795,7 +820,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
 </li>
       
       
 </ul>
 </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>
 <h3 class="h4">Things to Remember about Watches</h3>
 <ul>
 <ul>
         
         
@@ -838,13 +863,13 @@ document.write("Last Published: " + document.lastModified);
 </div>
 </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>
 <h2 class="h3">ZooKeeper access control using ACLs</h2>
 <div class="section">
 <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 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>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>
 <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>
 <h3 class="h4">ACL Permissions</h3>
 <p>Zookeeper supports the following permissions:</p>
 <p>Zookeeper supports the following permissions:</p>
 <ul>
 <ul>
@@ -880,7 +905,7 @@ document.write("Last Published: " + document.lastModified);
 <p>
 <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>
 <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>
 <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>
 <h4>Builtin ACL Schemes</h4>
 <p>ZooKeeeper has the following built in schemes:</p>
 <p>ZooKeeeper has the following built in schemes:</p>
 <ul>
 <ul>
@@ -911,7 +936,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
 </li>
       
       
 </ul>
 </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>
 <h4>Zookeeper C client API</h4>
 <p>The following constants are provided by the zookeeper C library:</p>
 <p>The following constants are provided by the zookeeper C library:</p>
 <ul>
 <ul>
@@ -1098,7 +1123,7 @@ int main(int argc, char argv) {
 </div>
 </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>
 <h2 class="h3">Consistency Guarantees</h2>
 <div class="section">
 <div class="section">
 <p>ZooKeeper is a high performance, scalable service. Both reads and
 <p>ZooKeeper is a high performance, scalable service. Both reads and
@@ -1225,12 +1250,12 @@ int main(int argc, char argv) {
 </div>
 </div>
 
 
   
   
-<a name="N1047A"></a><a name="ch_bindings"></a>
+<a name="N1048E"></a><a name="ch_bindings"></a>
 <h2 class="h3">Bindings</h2>
 <h2 class="h3">Bindings</h2>
 <div class="section">
 <div class="section">
 <p>The ZooKeeper client libraries come in two languages: Java and C.
 <p>The ZooKeeper client libraries come in two languages: Java and C.
     The following sections describe these.</p>
     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>
 <h3 class="h4">Java Binding</h3>
 <p>There are two packages that make up the ZooKeeper Java binding:
 <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
       <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,
       (SESSION_EXPIRED and AUTH_FAILED), the ZooKeeper object becomes invalid,
       the two threads shut down, and any further ZooKeeper calls throw
       the two threads shut down, and any further ZooKeeper calls throw
       errors.</p>
       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>
 <h3 class="h4">C Binding</h3>
 <p>The C binding has a single-threaded and multi-threaded library.
 <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
       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
       (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
       link with zookeeper_mt, as it includes support for both Sync and Async
       API.</p>
       API.</p>
-<a name="N104DB"></a><a name="Installation"></a>
+<a name="N104EF"></a><a name="Installation"></a>
 <h4>Installation</h4>
 <h4>Installation</h4>
 <p>If you're building the client from a check-out from the Apache
 <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
         repository, follow the steps outlined below. If you're building from a
@@ -1445,7 +1470,7 @@ int main(int argc, char argv) {
 </li>
 </li>
         
         
 </ol>
 </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>
 <h4>Using the Client</h4>
 <p>You can test your client by running a zookeeper server (see
 <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
         instructions on the project wiki page on how to run it) and connecting
@@ -1498,7 +1523,7 @@ int main(int argc, char argv) {
 </div>
 </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>
 <h2 class="h3">Building Blocks: A Guide to ZooKeeper Operations</h2>
 <div class="section">
 <div class="section">
 <p>
 <p>
@@ -1570,7 +1595,7 @@ int main(int argc, char argv) {
 </div>
 </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>
 <h2 class="h3">Program Structure, with Simple Example</h2>
 <div class="section">
 <div class="section">
 <p>
 <p>
@@ -1579,7 +1604,7 @@ int main(int argc, char argv) {
 </div>
 </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>
 <h2 class="h3">Gotchas: Common Problems and Troubleshooting</h2>
 <div class="section">
 <div class="section">
 <p>So now you know ZooKeeper. It's fast, simple, your application
 <p>So now you know ZooKeeper. It's fast, simple, your application

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 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
           ephemeral node. If it is not an ephemeral node, it will be
           zero.</para>
           zero.</para>
         </listitem>
         </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>
       </itemizedlist>
     </section>
     </section>
   </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.jute.Record;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 
 
 /**
 /**
  * This class contains the data for a node in the data tree.
  * 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
         // 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.parent = parent;
         this.data = data;
         this.data = data;
         this.acl = acl;
         this.acl = acl;
@@ -56,10 +57,23 @@ public class DataNode implements Record {
 
 
     List<ACL> acl;
     List<ACL> acl;
 
 
-    public Stat stat;
+    public StatPersisted stat;
 
 
     HashSet<String> children = new HashSet<String>();
     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)
     public void deserialize(InputArchive archive, String tag)
             throws IOException {
             throws IOException {
         archive.startRecord("node");
         archive.startRecord("node");
@@ -75,8 +89,8 @@ public class DataNode implements Record {
             }
             }
         }
         }
         archive.endVector("acl");
         archive.endVector("acl");
-        stat = new Stat();
-        stat.deserialize(archive, "stat");
+        stat = new StatPersisted();
+        stat.deserialize(archive, "statpersisted");
         archive.endRecord("node");
         archive.endRecord("node");
     }
     }
 
 
@@ -91,7 +105,7 @@ public class DataNode implements Record {
             }
             }
         }
         }
         archive.endVector(acl, "acl");
         archive.endVector(acl, "acl");
-        stat.serialize(archive, "stat");
+        stat.serialize(archive, "statpersisted");
         archive.endRecord(this, "node");
         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.log4j.Logger;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.Watcher;
 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.KeeperException.Code;
 import org.apache.zookeeper.Watcher.Event;
 import org.apache.zookeeper.Watcher.Event;
+import org.apache.zookeeper.Watcher.Event.EventType;
 import org.apache.zookeeper.ZooDefs.OpCode;
 import org.apache.zookeeper.ZooDefs.OpCode;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 import org.apache.zookeeper.txn.CreateTxn;
 import org.apache.zookeeper.txn.CreateTxn;
 import org.apache.zookeeper.txn.DeleteTxn;
 import org.apache.zookeeper.txn.DeleteTxn;
 import org.apache.zookeeper.txn.ErrorTxn;
 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,
      * 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.
      * 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() {
     public DataTree() {
         /* Rather than fight it, let root have an alias */
         /* Rather than fight it, let root have an alias */
@@ -117,6 +118,17 @@ public class DataTree {
         nodes.put("/", root);
         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) {
     static public void copyStat(Stat from, Stat to) {
         to.setAversion(from.getAversion());
         to.setAversion(from.getAversion());
         to.setCtime(from.getCtime());
         to.setCtime(from.getCtime());
@@ -126,6 +138,8 @@ public class DataTree {
         to.setMzxid(from.getMzxid());
         to.setMzxid(from.getMzxid());
         to.setVersion(from.getVersion());
         to.setVersion(from.getVersion());
         to.setEphemeralOwner(from.getEphemeralOwner());
         to.setEphemeralOwner(from.getEphemeralOwner());
+        to.setDataLength(from.getDataLength());
+        to.setNumChildren(from.getNumChildren());
     }
     }
 
 
     // public void remooveInterest(String path, Watcher nw) {
     // public void remooveInterest(String path, Watcher nw) {
@@ -161,7 +175,7 @@ public class DataTree {
         int lastSlash = path.lastIndexOf('/');
         int lastSlash = path.lastIndexOf('/');
         String parentName = path.substring(0, lastSlash);
         String parentName = path.substring(0, lastSlash);
         String childName = path.substring(lastSlash + 1);
         String childName = path.substring(lastSlash + 1);
-        Stat stat = new Stat();
+        StatPersisted stat = new StatPersisted();
         stat.setCtime(time);
         stat.setCtime(time);
         stat.setMtime(time);
         stat.setMtime(time);
         stat.setCzxid(zxid);
         stat.setCzxid(zxid);
@@ -250,7 +264,7 @@ public class DataTree {
             n.stat.setMtime(time);
             n.stat.setMtime(time);
             n.stat.setMzxid(zxid);
             n.stat.setMzxid(zxid);
             n.stat.setVersion(version);
             n.stat.setVersion(version);
-            copyStat(n.stat, s);
+            n.copyStat(s);
         }
         }
         dataWatches.triggerWatch(path, EventType.NodeDataChanged);
         dataWatches.triggerWatch(path, EventType.NodeDataChanged);
         return s;
         return s;
@@ -262,7 +276,7 @@ public class DataTree {
             throw new KeeperException.NoNodeException();
             throw new KeeperException.NoNodeException();
         }
         }
         synchronized (n) {
         synchronized (n) {
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             if (watcher != null) {
             if (watcher != null) {
                 dataWatches.addWatch(path, watcher);
                 dataWatches.addWatch(path, watcher);
             }
             }
@@ -280,7 +294,7 @@ public class DataTree {
             throw new KeeperException.NoNodeException();
             throw new KeeperException.NoNodeException();
         }
         }
         synchronized (n) {
         synchronized (n) {
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             return stat;
             return stat;
         }
         }
     }
     }
@@ -310,7 +324,7 @@ public class DataTree {
         synchronized (n) {
         synchronized (n) {
             n.stat.setAversion(version);
             n.stat.setAversion(version);
             n.acl = acl;
             n.acl = acl;
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             return stat;
             return stat;
         }
         }
     }
     }
@@ -322,7 +336,7 @@ public class DataTree {
             throw new KeeperException.NoNodeException();
             throw new KeeperException.NoNodeException();
         }
         }
         synchronized (n) {
         synchronized (n) {
-            copyStat(n.stat, stat);
+            n.copyStat(stat);
             return new ArrayList<ACL>(n.acl);
             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.ACL;
 import org.apache.zookeeper.data.Id;
 import org.apache.zookeeper.data.Id;
 import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 import org.apache.zookeeper.proto.CreateRequest;
 import org.apache.zookeeper.proto.CreateRequest;
 import org.apache.zookeeper.proto.DeleteRequest;
 import org.apache.zookeeper.proto.DeleteRequest;
 import org.apache.zookeeper.proto.SetACLRequest;
 import org.apache.zookeeper.proto.SetACLRequest;
@@ -220,7 +221,7 @@ public class PrepRequestProcessor extends Thread implements RequestProcessor {
                 txn = new CreateTxn(path, createRequest.getData(),
                 txn = new CreateTxn(path, createRequest.getData(),
                         createRequest.getAcl(),
                         createRequest.getAcl(),
                         createMode.isEphemeral());
                         createMode.isEphemeral());
-                Stat s = new Stat();
+                StatPersisted s = new StatPersisted();
                 if (createMode.isEphemeral()) {
                 if (createMode.isEphemeral()) {
                     s.setEphemeralOwner(request.sessionId);
                     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.ACL;
 import org.apache.zookeeper.data.Id;
 import org.apache.zookeeper.data.Id;
 import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.data.StatPersisted;
 import org.apache.zookeeper.proto.RequestHeader;
 import org.apache.zookeeper.proto.RequestHeader;
 import org.apache.zookeeper.server.SessionTracker.SessionExpirer;
 import org.apache.zookeeper.server.SessionTracker.SessionExpirer;
 import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
 import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
@@ -378,7 +379,7 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
      * and FinalRP.
      * and FinalRP.
      */
      */
     static class ChangeRecord {
     static class ChangeRecord {
-        ChangeRecord(long zxid, String path, Stat stat, int childCount,
+        ChangeRecord(long zxid, String path, StatPersisted stat, int childCount,
                 List<ACL> acl) {
                 List<ACL> acl) {
             this.zxid = zxid;
             this.zxid = zxid;
             this.path = path;
             this.path = path;
@@ -391,7 +392,7 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
 
 
         String path;
         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;
         int childCount;
 
 
@@ -399,9 +400,9 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
 
 
         @SuppressWarnings("unchecked")
         @SuppressWarnings("unchecked")
         ChangeRecord duplicate(long zxid) {
         ChangeRecord duplicate(long zxid) {
-            Stat stat = new Stat();
+            StatPersisted stat = new StatPersisted();
             if (this.stat != null) {
             if (this.stat != null) {
-                DataTree.copyStat(this.stat, stat);
+                DataTree.copyStatPersisted(this.stat, stat);
             }
             }
             return new ChangeRecord(zxid, path, stat, childCount,
             return new ChangeRecord(zxid, path, stat, childCount,
                     acl == null ? new ArrayList<ACL>() : new ArrayList(acl));
                     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 {
 module org.apache.zookeeper.data {
     class Id {
     class Id {
-    	ustring scheme;
-    	ustring id;
+        ustring scheme;
+        ustring id;
     }
     }
     class ACL {
     class ACL {
         int perms;
         int perms;
-	Id id;
+        Id id;
     }
     }
+    // information shared with the client
     class Stat {
     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 {
 module org.apache.zookeeper.proto {
@@ -45,7 +59,7 @@ module org.apache.zookeeper.proto {
 
 
     class ConnectRequest {
     class ConnectRequest {
         int protocolVersion;
         int protocolVersion;
-	long lastZxidSeen;
+        long lastZxidSeen;
         int timeOut;
         int timeOut;
         long sessionId;
         long sessionId;
         buffer passwd;
         buffer passwd;
@@ -61,14 +75,14 @@ module org.apache.zookeeper.proto {
         int type;
         int type;
     }
     }
     class AuthPacket {
     class AuthPacket {
-	int type;
-	ustring scheme;
-	buffer auth;
+        int type;
+        ustring scheme;
+        buffer auth;
     }
     }
     class ReplyHeader {
     class ReplyHeader {
         int xid;
         int xid;
         long zxid;
         long zxid;
-	int err;
+        int err;
     }
     }
     class GetDataRequest {
     class GetDataRequest {
         ustring path;
         ustring path;
@@ -106,7 +120,7 @@ module org.apache.zookeeper.proto {
         ustring path;
         ustring path;
         int max;
         int max;
     }
     }
-	class SyncRequest {
+    class SyncRequest {
         ustring path;
         ustring path;
     }
     }
     class SyncResponse {
     class SyncResponse {
@@ -126,7 +140,7 @@ module org.apache.zookeeper.proto {
     class WatcherEvent {
     class WatcherEvent {
         int type;  // event type
         int type;  // event type
         int state; // state of the Keeper client runtime
         int state; // state of the Keeper client runtime
-        ustring path; 
+        ustring path;
     }
     }
 
 
     class CreateResponse {
     class CreateResponse {
@@ -137,7 +151,7 @@ module org.apache.zookeeper.proto {
         boolean watch;
         boolean watch;
     }
     }
     class ExistsResponse {
     class ExistsResponse {
-	org.apache.zookeeper.data.Stat stat;
+        org.apache.zookeeper.data.Stat stat;
     }
     }
     class GetDataResponse {
     class GetDataResponse {
         buffer data;
         buffer data;
@@ -156,8 +170,8 @@ module org.apache.zookeeper.server.quorum {
     class QuorumPacket {
     class QuorumPacket {
         int type; // Request, Ack, Commit, Ping
         int type; // Request, Ack, Commit, Ping
         long zxid;
         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 {
 module org.apache.zookeeper.txn {
     class TxnHeader {
     class TxnHeader {
         long clientId;
         long clientId;
-	int cxid;
-	long zxid;
+        int cxid;
+        long zxid;
         long time;
         long time;
         int type;
         int type;
     }
     }
@@ -181,7 +195,7 @@ module org.apache.zookeeper.txn {
         ustring path;
         ustring path;
         buffer data;
         buffer data;
         vector<org.apache.zookeeper.data.ACL> acl;
         vector<org.apache.zookeeper.data.ACL> acl;
-	boolean ephemeral;
+        boolean ephemeral;
     }
     }
     class DeleteTxn {
     class DeleteTxn {
         ustring path;
         ustring path;
@@ -201,7 +215,7 @@ module org.apache.zookeeper.txn {
         int max;
         int max;
     }
     }
     class CreateSessionTxn {
     class CreateSessionTxn {
-	int timeOut;
+        int timeOut;
     }
     }
     class ErrorTxn {
     class ErrorTxn {
         int err;
         int err;

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.