You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by ma...@apache.org on 2009/06/25 00:59:34 UTC
svn commit: r788205 [1/2] - in /hadoop/zookeeper/trunk: ./ docs/ src/c/src/
src/c/tests/ src/docs/src/documentation/content/xdocs/
src/java/main/org/apache/zookeeper/ src/java/test/org/apache/zookeeper/test/
Author: mahadev
Date: Wed Jun 24 22:59:34 2009
New Revision: 788205
URL: http://svn.apache.org/viewvc?rev=788205&view=rev
Log:
ZOOKEEPER-237. Add a Chroot request (phunt and mahadev)
Added:
hadoop/zookeeper/trunk/src/java/test/org/apache/zookeeper/test/ChrootAsyncTest.java
hadoop/zookeeper/trunk/src/java/test/org/apache/zookeeper/test/ChrootClientTest.java
hadoop/zookeeper/trunk/src/java/test/org/apache/zookeeper/test/ChrootTest.java
Modified:
hadoop/zookeeper/trunk/CHANGES.txt
hadoop/zookeeper/trunk/docs/zookeeperAdmin.html
hadoop/zookeeper/trunk/docs/zookeeperAdmin.pdf
hadoop/zookeeper/trunk/docs/zookeeperProgrammers.html
hadoop/zookeeper/trunk/docs/zookeeperProgrammers.pdf
hadoop/zookeeper/trunk/docs/zookeeperStarted.html
hadoop/zookeeper/trunk/docs/zookeeperStarted.pdf
hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h
hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c
hadoop/zookeeper/trunk/src/c/src/zookeeper.c
hadoop/zookeeper/trunk/src/c/tests/TestClient.cc
hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml
hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperStarted.xml
hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ClientCnxn.java
hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ZooKeeper.java
hadoop/zookeeper/trunk/src/java/test/org/apache/zookeeper/test/ClientBase.java
hadoop/zookeeper/trunk/src/java/test/org/apache/zookeeper/test/ClientTest.java
Modified: hadoop/zookeeper/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/CHANGES.txt?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/CHANGES.txt (original)
+++ hadoop/zookeeper/trunk/CHANGES.txt Wed Jun 24 22:59:34 2009
@@ -251,6 +251,8 @@
ZOOKEEPER-395. Python bindings. (henry robinson via mahadev)
+ ZOOKEEPER-237. Add a Chroot request (phunt and mahadev)
+
Release 3.1.0 - 2009-02-06
Non-backward compatible changes:
Modified: hadoop/zookeeper/trunk/docs/zookeeperAdmin.html
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/docs/zookeeperAdmin.html?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/docs/zookeeperAdmin.html (original)
+++ hadoop/zookeeper/trunk/docs/zookeeperAdmin.html Wed Jun 24 22:59:34 2009
@@ -1450,8 +1450,11 @@
<a name="N104A0"></a><a name="sc_bestPractices"></a>
<h3 class="h4">Best Practices</h3>
<p>For best results, take note of the following list of good
- Zookeeper practices. <em>[tbd...]</em>
-</p>
+ Zookeeper practices:</p>
+<p>For multi-tennant installations see the <a href="zookeeperProgrammers.html#ch_zkSessions">section</a>
+ detailing ZooKeeper "chroot" support, this can be very useful
+ when deploying many applications/services interfacing to a
+ single ZooKeeper cluster.</p>
</div>
<p align="right">
Modified: hadoop/zookeeper/trunk/docs/zookeeperAdmin.pdf
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/docs/zookeeperAdmin.pdf?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
Binary files - no diff available.
Modified: hadoop/zookeeper/trunk/docs/zookeeperProgrammers.html
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/docs/zookeeperProgrammers.html?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/docs/zookeeperProgrammers.html (original)
+++ hadoop/zookeeper/trunk/docs/zookeeperProgrammers.html Wed Jun 24 22:59:34 2009
@@ -758,7 +758,7 @@
<h2 class="h3">ZooKeeper Sessions</h2>
<div class="section">
<p>To create a client session the application code must provide
- a string containing a comma separated list of host:port pairs,
+ a connection string containing a comma separated list of host:port pairs,
each corresponding to a ZooKeeper server (e.g. "127.0.0.1:4545" or
"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"). The ZooKeeper
client library will pick an arbitrary server and try to connect to
@@ -766,6 +766,23 @@
disconnected from the server for any reason, the client will
automatically try the next server in the list, until a connection
is (re-)established.</p>
+<p>
+<strong>Added in 3.2.0</strong>: An
+ optional "chroot" suffix may also be appended to the connection
+ string. This will run the client commands while interpreting all
+ paths relative to this root (similar to the unix chroot
+ command). If used the example would look like:
+ "127.0.0.1:4545/app/a" or
+ "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" where the
+ client would be rooted at "/app/a" and all paths would be relative
+ to this root - ie getting/setting/etc... "/foo/bar" would result
+ in operations being run on "/app/a/foo/bar" (from the server
+ perspective). This feature is particularly useful in multi-tenant
+ environments where each user of a particular ZooKeeper service
+ could be rooted differently. This makes re-use much simpler as
+ each user can code his/her application as if it were rooted at
+ "/", while actual location (say /app/a) could be determined at
+ deployment time.</p>
<p>When a client gets a handle to the ZooKeeper service,
ZooKeeper creates a ZooKeeper session, represented as a 64-bit
number, that it assigns to the client. If the client connects to a
@@ -825,7 +842,7 @@
</div>
-<a name="N101C9"></a><a name="ch_zkWatches"></a>
+<a name="N101CF"></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
@@ -908,7 +925,7 @@
general this all occurs transparently. There is one case where a watch
may be missed: a watch for the existance of a znode not yet created will
be missed if the znode is created and deleted while disconnected.</p>
-<a name="N101FF"></a><a name="sc_WatchGuarantees"></a>
+<a name="N10205"></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>
@@ -943,7 +960,7 @@
</li>
</ul>
-<a name="N10224"></a><a name="sc_WatchRememberThese"></a>
+<a name="N1022A"></a><a name="sc_WatchRememberThese"></a>
<h3 class="h4">Things to Remember about Watches</h3>
<ul>
@@ -1002,7 +1019,7 @@
</div>
-<a name="N10250"></a><a name="sc_ZooKeeperAccessControl"></a>
+<a name="N10256"></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
@@ -1037,7 +1054,7 @@
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="N10283"></a><a name="sc_ACLPermissions"></a>
+<a name="N10289"></a><a name="sc_ACLPermissions"></a>
<h3 class="h4">ACL Permissions</h3>
<p>ZooKeeper supports the following permissions:</p>
<ul>
@@ -1093,7 +1110,7 @@
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="N102D9"></a><a name="sc_BuiltinACLSchemes"></a>
+<a name="N102DF"></a><a name="sc_BuiltinACLSchemes"></a>
<h4>Builtin ACL Schemes</h4>
<p>ZooKeeeper has the following built in schemes:</p>
<ul>
@@ -1142,7 +1159,7 @@
</ul>
-<a name="N1031D"></a><a name="ZooKeeper+C+client+API"></a>
+<a name="N10323"></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>
@@ -1364,7 +1381,7 @@
</div>
-<a name="N10434"></a><a name="sc_ZooKeeperPluggableAuthentication"></a>
+<a name="N1043A"></a><a name="sc_ZooKeeperPluggableAuthentication"></a>
<h2 class="h3">Pluggable ZooKeeper authentication</h2>
<div class="section">
<p>ZooKeeper runs in a variety of different environments with
@@ -1450,7 +1467,7 @@
</div>
-<a name="N104A0"></a><a name="ch_zkGuarantees"></a>
+<a name="N104A6"></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
@@ -1576,12 +1593,12 @@
</div>
-<a name="N10507"></a><a name="ch_bindings"></a>
+<a name="N1050D"></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="N10510"></a><a name="Java+Binding"></a>
+<a name="N10516"></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
@@ -1648,7 +1665,7 @@
(SESSION_EXPIRED and AUTH_FAILED), the ZooKeeper object becomes invalid.
On a close, the two threads shut down and any further access on zookeeper
handle is undefined behavior and should be avoided. </p>
-<a name="N10559"></a><a name="C+Binding"></a>
+<a name="N1055F"></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
@@ -1665,7 +1682,7 @@
(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="N10568"></a><a name="Installation"></a>
+<a name="N1056E"></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
@@ -1796,7 +1813,7 @@
</li>
</ol>
-<a name="N10611"></a><a name="Using+the+C+Client"></a>
+<a name="N10617"></a><a name="Using+the+C+Client"></a>
<h4>Using the C 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
@@ -1854,7 +1871,7 @@
</div>
-<a name="N10657"></a><a name="ch_guideToZkOperations"></a>
+<a name="N1065D"></a><a name="ch_guideToZkOperations"></a>
<h2 class="h3">Building Blocks: A Guide to ZooKeeper Operations</h2>
<div class="section">
<p>This section surveys all the operations a developer can perform
@@ -1872,28 +1889,28 @@
</li>
</ul>
-<a name="N1066B"></a><a name="sc_errorsZk"></a>
+<a name="N10671"></a><a name="sc_errorsZk"></a>
<h3 class="h4">Handling Errors</h3>
<p>Both the Java and C client bindings may report errors. The Java client binding does so by throwing KeeperException, calling code() on the exception will return the specific error code. The C client binding returns an error code as defined in the enum ZOO_ERRORS. API callbacks indicate result code for both language bindings. See the API documentation (javadoc for Java, doxygen for C) for full details on the possible errors and their meaning.</p>
-<a name="N10675"></a><a name="sc_connectingToZk"></a>
+<a name="N1067B"></a><a name="sc_connectingToZk"></a>
<h3 class="h4">Connecting to ZooKeeper</h3>
<p></p>
-<a name="N1067E"></a><a name="sc_readOps"></a>
+<a name="N10684"></a><a name="sc_readOps"></a>
<h3 class="h4">Read Operations</h3>
<p></p>
-<a name="N10687"></a><a name="sc_writeOps"></a>
+<a name="N1068D"></a><a name="sc_writeOps"></a>
<h3 class="h4">Write Operations</h3>
<p></p>
-<a name="N10690"></a><a name="sc_handlingWatches"></a>
+<a name="N10696"></a><a name="sc_handlingWatches"></a>
<h3 class="h4">Handling Watches</h3>
<p></p>
-<a name="N10699"></a><a name="sc_miscOps"></a>
+<a name="N1069F"></a><a name="sc_miscOps"></a>
<h3 class="h4">Miscelleaneous ZooKeeper Operations</h3>
<p></p>
</div>
-<a name="N106A3"></a><a name="ch_programStructureWithExample"></a>
+<a name="N106A9"></a><a name="ch_programStructureWithExample"></a>
<h2 class="h3">Program Structure, with Simple Example</h2>
<div class="section">
<p>
@@ -1902,7 +1919,7 @@
</div>
-<a name="N106AE"></a><a name="ch_gotchas"></a>
+<a name="N106B4"></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
Modified: hadoop/zookeeper/trunk/docs/zookeeperProgrammers.pdf
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/docs/zookeeperProgrammers.pdf?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
Binary files - no diff available.
Modified: hadoop/zookeeper/trunk/docs/zookeeperStarted.html
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/docs/zookeeperStarted.html?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/docs/zookeeperStarted.html (original)
+++ hadoop/zookeeper/trunk/docs/zookeeperStarted.html Wed Jun 24 22:59:34 2009
@@ -518,7 +518,7 @@
<p>ZooKeeper has a Java bindings and C bindings. They are
functionally equivalent. The C bindings exist in two variants: single
threaded and multi-threaded. These differ only in how the messaging loop
- is done. For more information, see the <a href="zookeeperProgrammers.html#ch_programStructureWithExample.html">Programming
+ is done. For more information, see the <a href="zookeeperProgrammers.html#ch_programStructureWithExample">Programming
Examples in the ZooKeeper Programmer's Guide</a> for
sample code using of the different APIs.</p>
<a name="N1013E"></a><a name="sc_RunningReplicatedZooKeeper"></a>
Modified: hadoop/zookeeper/trunk/docs/zookeeperStarted.pdf
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/docs/zookeeperStarted.pdf?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
Binary files - no diff available.
Modified: hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h (original)
+++ hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h Wed Jun 24 22:59:34 2009
@@ -208,6 +208,8 @@
zk_hashtable* active_node_watchers;
zk_hashtable* active_exist_watchers;
zk_hashtable* active_child_watchers;
+ /** used for chroot path at the client side **/
+ char *chroot;
};
@@ -222,7 +224,8 @@
int process_async(int outstanding_sync);
void process_completions(zhandle_t *zh);
int flush_send_queue(zhandle_t*zh, int timeout);
-
+char* sub_string(zhandle_t *zh, const char* server_path);
+void free_duplicate_path(char* free_path, const char* path);
void zoo_lock_auth(zhandle_t *zh);
void zoo_unlock_auth(zhandle_t *zh);
Modified: hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c (original)
+++ hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c Wed Jun 24 22:59:34 2009
@@ -266,10 +266,12 @@
static void do_foreach_watcher(watcher_object_t* wo,zhandle_t* zh,
const char* path,int type,int state)
{
+ char *client_path = sub_string(zh, path);
while(wo!=0){
- wo->watcher(zh,type,state,path,wo->context);
+ wo->watcher(zh,type,state,client_path,wo->context);
wo=wo->next;
}
+ free_duplicate_path(client_path, path);
}
watcher_object_list_t *collectWatchers(zhandle_t *zh,int type, char *path)
Modified: hadoop/zookeeper/trunk/src/c/src/zookeeper.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/zookeeper.c?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/zookeeper.c (original)
+++ hadoop/zookeeper/trunk/src/c/src/zookeeper.c Wed Jun 24 22:59:34 2009
@@ -186,6 +186,7 @@
static __attribute__((unused)) void print_completion_queue(zhandle_t *zh);
static void *SYNCHRONOUS_MARKER = (void*)&SYNCHRONOUS_MARKER;
+static int isValidPath(const char* path, const int flags);
const void *zoo_get_context(zhandle_t *zh)
{
@@ -372,6 +373,12 @@
free(zh->addrs);
zh->addrs = NULL;
}
+
+ if (zh->chroot != 0) {
+ free(zh->chroot);
+ zh->chroot = NULL;
+ }
+
free_auth_info(&zh->auth_h);
destroy_zk_hashtable(zh->active_node_watchers);
destroy_zk_hashtable(zh->active_exist_watchers);
@@ -413,7 +420,7 @@
zh->addrs = 0;
}
if (!hosts) {
- LOG_ERROR(("out of memory"));
+ LOG_ERROR(("out of memory"));
errno=ENOMEM;
return ZSYSTEMERROR;
}
@@ -607,6 +614,7 @@
int errnosave;
zhandle_t *zh = calloc(1, sizeof(*zh));
+ char *index_chroot;
if (!zh) {
return 0;
}
@@ -624,7 +632,28 @@
errno=EINVAL;
goto abort;
}
- zh->hostname = strdup(host);
+ //parse the host to get the chroot if
+ //available
+ index_chroot = strchr(host, '/');
+ if (index_chroot) {
+ zh->chroot = strdup(index_chroot);
+ // if chroot is just / set it to null
+ if (strlen(zh->chroot) == 1) {
+ zh->chroot = NULL;
+ }
+ // cannot use strndup so allocate and strcpy
+ zh->hostname = (char *) malloc(index_chroot - host + 1);
+ zh->hostname = strncpy(zh->hostname, host, (index_chroot - host));
+ //strncpy does not null terminate
+ *(zh->hostname + (index_chroot - host) +1) = '\0';
+
+ } else {
+ zh->chroot = NULL;
+ zh->hostname = strdup(host);
+ }
+ if (zh->chroot && !isValidPath(zh->chroot, 0)) {
+ goto abort;
+ }
if (zh->hostname == 0) {
goto abort;
}
@@ -661,6 +690,54 @@
return 0;
}
+/**
+ * deallocated the free_path only its beeen allocated
+ * and not equal to path
+ */
+void free_duplicate_path(char *free_path, const char* path) {
+ if (free_path != path) {
+ free(free_path);
+ }
+}
+
+/**
+ prepend the chroot path if available else return the path
+*/
+static char* prepend_string(zhandle_t *zh, const char* client_path) {
+ char *ret_str;
+ if (zh->chroot == NULL)
+ return (char *) client_path;
+ // handle the chroot itself, client_path = "/"
+ if (strlen(client_path) == 1) {
+ return strdup(zh->chroot);
+ }
+ ret_str = (char *) malloc(strlen(zh->chroot) + strlen(client_path) + 1);
+ strcpy(ret_str, zh->chroot);
+ return strcat(ret_str, client_path);
+}
+
+/**
+ strip off the chroot string from the server path
+ if there is one else return the exact path
+ */
+char* sub_string(zhandle_t *zh, const char* server_path) {
+ char *ret_str;
+ if (zh->chroot == NULL)
+ return (char *) server_path;
+ if (strncmp(server_path, zh->chroot, strlen(zh->chroot) != 0)) {
+ LOG_ERROR(("server path %s does not include chroot path %s",
+ server_path, zh->chroot));
+ return NULL;
+ }
+ if (strlen(server_path) == strlen(zh->chroot)) {
+ //return "/"
+ ret_str = strdup("/");
+ return ret_str;
+ }
+ ret_str = strdup(server_path + strlen(zh->chroot));
+ return ret_str;
+}
+
static buffer_list_t *allocate_buffer(char *buff, int len)
{
buffer_list_t *buffer = calloc(1, sizeof(*buffer));
@@ -1679,7 +1756,6 @@
deserialize_WatcherEvent(ia, "event", &evt);
type = evt.type;
path = evt.path;
-
/* We are doing a notification, so there is no pending request */
completion_list_t *c =
create_completion_entry(WATCHER_EVENT_XID,-1,0,0,0);
@@ -1847,8 +1923,7 @@
if (process_async(zh->outstanding_sync)) {
process_completions(zh);
}
- return api_epilog(zh,ZOK);
-}
+ return api_epilog(zh,ZOK);}
int zoo_state(zhandle_t *zh)
{
@@ -2093,24 +2168,29 @@
data_completion_t dc, const void *data)
{
struct oarchive *oa;
+ char *server_path = prepend_string(zh, path);
struct RequestHeader h = { .xid = get_xid(), .type = GETDATA_OP};
- struct GetDataRequest req = { (char*)path, watcher!=0 };
+ struct GetDataRequest req = { (char*)server_path, watcher!=0 };
int rc;
-
- if (zh==0 || !isValidPath(path, 0))
+
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa=create_buffer_oarchive();
rc = serialize_RequestHeader(oa, "header", &h);
rc = rc < 0 ? rc : serialize_GetDataRequest(oa, "req", &req);
enter_critical(zh);
rc = rc < 0 ? rc : add_data_completion(zh, h.xid, dc, data,
- create_watcher_registration(path,data_result_checker,watcher,watcherCtx));
+ create_watcher_registration(server_path,data_result_checker,watcher,watcherCtx));
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
-
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2128,13 +2208,19 @@
struct RequestHeader h = { .xid = get_xid(), .type = SETDATA_OP};
struct SetDataRequest req;
int rc;
+ char *server_path;
+ server_path = prepend_string(zh, path);
- if (zh==0 || !isValidPath(path, 0))
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
- req.path = (char*)path;
+ req.path = (char*)server_path;
req.data.buff = (char*)buffer;
req.data.len = buflen;
req.version = version;
@@ -2145,6 +2231,7 @@
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2163,13 +2250,19 @@
struct RequestHeader h = { .xid = get_xid(), .type = CREATE_OP };
struct CreateRequest req;
int rc;
+ char *server_path;
- if (zh==0 || !isValidPath(path, flags))
+ server_path = prepend_string(zh, path);
+ if (zh==0 || !isValidPath(server_path, flags)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
- req.path = (char*)path;
+ req.path = (char*)server_path;
req.flags = flags;
req.data.buff = (char*)value;
req.data.len = valuelen;
@@ -2186,6 +2279,7 @@
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2203,13 +2297,19 @@
struct RequestHeader h = { .xid = get_xid(), .type = DELETE_OP};
struct DeleteRequest req;
int rc;
+ char *server_path;
- if (zh==0 || !isValidPath(path, 0))
+ server_path = prepend_string(zh, path);
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
- req.path = (char*)path;
+ req.path = (char*)server_path;
req.version = version;
rc = serialize_RequestHeader(oa, "header", &h);
rc = rc < 0 ? rc : serialize_DeleteRequest(oa, "req", &req);
@@ -2218,6 +2318,7 @@
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2240,23 +2341,29 @@
{
struct oarchive *oa;
struct RequestHeader h = { .xid = get_xid(), .type = EXISTS_OP };
- struct ExistsRequest req = {(char*)path, watcher!=0 };
+ char *server_path = prepend_string(zh, path);
+ struct ExistsRequest req = {(char*)server_path, watcher!=0 };
int rc;
- if (zh==0 || !isValidPath(path, 0))
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
rc = serialize_RequestHeader(oa, "header", &h);
rc = rc < 0 ? rc : serialize_ExistsRequest(oa, "req", &req);
enter_critical(zh);
rc = rc < 0 ? rc : add_stat_completion(zh, h.xid, completion, data,
- create_watcher_registration(path,exists_result_checker,
+ create_watcher_registration(server_path,exists_result_checker,
watcher,watcherCtx));
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2279,22 +2386,28 @@
{
struct oarchive *oa;
struct RequestHeader h = { .xid = get_xid(), .type = GETCHILDREN_OP};
- struct GetChildrenRequest req={(char*)path, watcher!=0 };
+ char * server_path = prepend_string(zh, path);
+ struct GetChildrenRequest req = {(char*)server_path, watcher!=0 };
int rc;
-
- if (zh==0 || !isValidPath(path, 0))
+
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
rc = serialize_RequestHeader(oa, "header", &h);
rc = rc < 0 ? rc : serialize_GetChildrenRequest(oa, "req", &req);
enter_critical(zh);
rc = rc < 0 ? rc : add_strings_completion(zh, h.xid, dc, data,
- create_watcher_registration(path,child_result_checker,watcher,watcherCtx));
+ create_watcher_registration(server_path,child_result_checker,watcher,watcherCtx));
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2312,13 +2425,19 @@
struct RequestHeader h = { .xid = get_xid(), .type = SYNC_OP};
struct SyncRequest req;
int rc;
-
- if (zh==0 || !isValidPath(path, 0))
+ char *server_path;
+
+ server_path = prepend_string(zh, path);
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
- req.path = (char*)path;
+ req.path = (char*)server_path;
rc = serialize_RequestHeader(oa, "header", &h);
rc = rc < 0 ? rc : serialize_SyncRequest(oa, "req", &req);
enter_critical(zh);
@@ -2326,6 +2445,7 @@
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2344,13 +2464,19 @@
struct RequestHeader h = { .xid = get_xid(), .type = GETACL_OP};
struct GetACLRequest req;
int rc;
+ char *server_path;
- if (zh==0 || !isValidPath(path, 0))
+ server_path = prepend_string(zh, path);
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
- req.path = (char*)path;
+ req.path = (char*)server_path;
rc = serialize_RequestHeader(oa, "header", &h);
rc = rc < 0 ? rc : serialize_GetACLRequest(oa, "req", &req);
enter_critical(zh);
@@ -2358,6 +2484,7 @@
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
@@ -2375,13 +2502,19 @@
struct RequestHeader h = { .xid = get_xid(), .type = SETACL_OP};
struct SetACLRequest req;
int rc;
-
- if (zh==0 || !isValidPath(path, 0))
+ char *server_path;
+
+ server_path = prepend_string(zh, path);
+ if (zh==0 || !isValidPath(server_path, 0)) {
+ free_duplicate_path(server_path, path);
return ZBADARGUMENTS;
- if (is_unrecoverable(zh))
+ }
+ if (is_unrecoverable(zh)) {
+ free_duplicate_path(server_path, path);
return ZINVALIDSTATE;
+ }
oa = create_buffer_oarchive();
- req.path = (char*)path;
+ req.path = (char*)server_path;
req.acl = *acl;
req.version = version;
rc = serialize_RequestHeader(oa, "header", &h);
@@ -2391,6 +2524,7 @@
rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),
get_buffer_len(oa));
leave_critical(zh);
+ free_duplicate_path(server_path, path);
/* We queued the buffer, so don't free it */
close_buffer_oarchive(&oa, 0);
Modified: hadoop/zookeeper/trunk/src/c/tests/TestClient.cc
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/tests/TestClient.cc?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/tests/TestClient.cc (original)
+++ hadoop/zookeeper/trunk/src/c/tests/TestClient.cc Wed Jun 24 22:59:34 2009
@@ -164,6 +164,7 @@
CPPUNIT_TEST(testPathValidation);
CPPUNIT_TEST(testPing);
CPPUNIT_TEST(testAcl);
+ CPPUNIT_TEST(testChroot);
CPPUNIT_TEST(testAuth);
CPPUNIT_TEST(testWatcherAutoResetWithGlobal);
CPPUNIT_TEST(testWatcherAutoResetWithLocal);
@@ -191,7 +192,7 @@
const char *getHostPorts() {
return hostPorts;
}
-
+
zhandle_t *createClient(watchctx_t *ctx) {
zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0,
ctx, 0);
@@ -200,6 +201,14 @@
return zk;
}
+ zhandle_t *createchClient(watchctx_t *ctx) {
+ zhandle_t *zk = zookeeper_init(hp_chroot, watcher, 10000, 0,
+ ctx, 0);
+ ctx->zh = zk;
+ sleep(1);
+ return zk;
+ }
+
public:
@@ -273,6 +282,7 @@
static zhandle_t *async_zk;
static volatile int count;
+ static char* hp_chroot;
static void statCompletion(int rc, const struct Stat *stat, const void *data) {
int tmp = (int) (long) data;
@@ -293,6 +303,35 @@
}
}
+ static void create_completion_fn(int rc, const char* value, const void *data) {
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ count++;
+ }
+
+ static void waitForCreateCompletion(int seconds) {
+ time_t expires = time(0) + seconds;
+ while(count == 0 && time(0) < expires) {
+ sleep(1);
+ }
+ count--;
+ }
+
+ static void watcher_chroot_fn(zhandle_t *zh, int type,
+ int state, const char *path,void *watcherCtx) {
+ // check for path
+ char *client_path = (char *) watcherCtx;
+ CPPUNIT_ASSERT(strcmp(client_path, path) == 0);
+ count ++;
+ }
+
+ static void waitForChrootWatch(int seconds) {
+ time_t expires = time(0) + seconds;
+ while (count == 0 && time(0) < expires) {
+ sleep(1);
+ }
+ count--;
+ }
+
static void waitForVoidCompletion(int seconds) {
time_t expires = time(0) + seconds;
while(count == 0 && time(0) < expires) {
@@ -522,7 +561,93 @@
verifyCreateOk("/f/.f/f", zk);
verifyCreateOk("/f/f./f", zk);
}
-
+
+ void testChroot() {
+ // the c client async callbacks do
+ // not callback with the path, so
+ // we dont need to test taht for now
+ // we should fix that though soon!
+ watchctx_t ctx, ctx_ch;
+ zhandle_t *zk, *zk_ch;
+ char buf[60];
+ int rc, len;
+ struct Stat stat;
+ const char* data = "garbage";
+ const char* retStr = "/chroot";
+ const char* root= "/";
+ hp_chroot = "127.0.0.1:22181/test/mahadev";
+ zk_ch = createchClient(&ctx_ch);
+ CPPUNIT_ASSERT(zk_ch != NULL);
+ zk = createClient(&ctx);
+ rc = zoo_create(zk, "/test", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ rc = zoo_create(zk, "/test/mahadev", data, 7, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ // try an exists with /
+ len = 60;
+ rc = zoo_get(zk_ch, "/", 0, buf, &len, &stat);
+ CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
+ //check if the data is the same
+ CPPUNIT_ASSERT(strncmp(buf, data, 7) == 0);
+ //check for watches
+ rc = zoo_wexists(zk_ch, "/chroot", watcher_chroot_fn, (void *) retStr, &stat);
+ //now check if we can do create/delete/get/sets/acls/getChildren and others
+ //check create
+ rc = zoo_create(zk_ch, "/chroot", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0,0);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ waitForChrootWatch(3);
+ CPPUNIT_ASSERT(count == 0);
+ rc = zoo_create(zk_ch, "/chroot/child", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ rc = zoo_exists(zk, "/test/mahadev/chroot/child", 0, &stat);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+
+ rc = zoo_delete(zk_ch, "/chroot/child", -1);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ rc = zoo_exists(zk, "/test/mahadev/chroot/child", 0, &stat);
+ CPPUNIT_ASSERT_EQUAL((int) ZNONODE, rc);
+ rc = zoo_wget(zk_ch, "/chroot", watcher_chroot_fn, (char*) retStr,
+ buf, &len, &stat);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ rc = zoo_set(zk_ch, "/chroot",buf, 3, -1);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ waitForChrootWatch(3);
+ CPPUNIT_ASSERT(count == 0);
+ // check for getchildren
+ struct String_vector children;
+ rc = zoo_get_children(zk_ch, "/", 0, &children);
+ CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
+ CPPUNIT_ASSERT_EQUAL((int)1, children.count);
+ //check if te child if chroot
+ CPPUNIT_ASSERT(strcmp((retStr+1), children.data[0]) == 0);
+ // check for get/set acl
+ struct ACL_vector acl;
+ rc = zoo_get_acl(zk_ch, "/", &acl, &stat);
+ CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
+ CPPUNIT_ASSERT_EQUAL((int)1, acl.count);
+ CPPUNIT_ASSERT_EQUAL(ZOO_PERM_ALL, acl.data->perms);
+ // set acl
+ rc = zoo_set_acl(zk_ch, "/chroot", -1, &ZOO_READ_ACL_UNSAFE);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ // see if you add children
+ rc = zoo_create(zk_ch, "/chroot/child1", "",0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+ CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, rc);
+ //add wget children test
+ rc = zoo_wget_children(zk_ch, "/", watcher_chroot_fn, (char*) root, &children);
+ CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
+
+ //now create a node
+ rc = zoo_create(zk_ch, "/child2", "",0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+ CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+ waitForChrootWatch(3);
+ CPPUNIT_ASSERT(count == 0);
+ //check for one async call just to make sure
+ rc = zoo_acreate(zk_ch, "/child3", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0,
+ create_completion_fn, 0);
+ waitForCreateCompletion(3);
+ CPPUNIT_ASSERT(count == 0);
+ }
+
void testAsyncWatcherAutoReset()
{
watchctx_t ctx;
@@ -747,4 +872,5 @@
volatile int Zookeeper_simpleSystem::count;
zhandle_t *Zookeeper_simpleSystem::async_zk;
const char Zookeeper_simpleSystem::hostPorts[] = "127.0.0.1:22181";
+char* Zookeeper_simpleSystem::hp_chroot;
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_simpleSystem);
Modified: hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml (original)
+++ hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml Wed Jun 24 22:59:34 2009
@@ -1139,7 +1139,15 @@
<title>Best Practices</title>
<para>For best results, take note of the following list of good
- Zookeeper practices. <emphasis>[tbd...]</emphasis></para>
+ Zookeeper practices:</para>
+
+
+ <para>For multi-tennant installations see the <ulink
+ url="zookeeperProgrammers.html#ch_zkSessions">section</ulink>
+ detailing ZooKeeper "chroot" support, this can be very useful
+ when deploying many applications/services interfacing to a
+ single ZooKeeper cluster.</para>
+
</section>
</section>
</article>
Modified: hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml (original)
+++ hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml Wed Jun 24 22:59:34 2009
@@ -359,7 +359,7 @@
<title>ZooKeeper Sessions</title>
<para>To create a client session the application code must provide
- a string containing a comma separated list of host:port pairs,
+ a connection string containing a comma separated list of host:port pairs,
each corresponding to a ZooKeeper server (e.g. "127.0.0.1:4545" or
"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"). The ZooKeeper
client library will pick an arbitrary server and try to connect to
@@ -368,6 +368,23 @@
automatically try the next server in the list, until a connection
is (re-)established.</para>
+ <para> <emphasis role="bold">Added in 3.2.0</emphasis>: An
+ optional "chroot" suffix may also be appended to the connection
+ string. This will run the client commands while interpreting all
+ paths relative to this root (similar to the unix chroot
+ command). If used the example would look like:
+ "127.0.0.1:4545/app/a" or
+ "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" where the
+ client would be rooted at "/app/a" and all paths would be relative
+ to this root - ie getting/setting/etc... "/foo/bar" would result
+ in operations being run on "/app/a/foo/bar" (from the server
+ perspective). This feature is particularly useful in multi-tenant
+ environments where each user of a particular ZooKeeper service
+ could be rooted differently. This makes re-use much simpler as
+ each user can code his/her application as if it were rooted at
+ "/", while actual location (say /app/a) could be determined at
+ deployment time.</para>
+
<para>When a client gets a handle to the ZooKeeper service,
ZooKeeper creates a ZooKeeper session, represented as a 64-bit
number, that it assigns to the client. If the client connects to a
Modified: hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperStarted.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperStarted.xml?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperStarted.xml (original)
+++ hadoop/zookeeper/trunk/src/docs/src/documentation/content/xdocs/zookeeperStarted.xml Wed Jun 24 22:59:34 2009
@@ -328,7 +328,7 @@
functionally equivalent. The C bindings exist in two variants: single
threaded and multi-threaded. These differ only in how the messaging loop
is done. For more information, see the <ulink
- url="zookeeperProgrammers.html#ch_programStructureWithExample.html">Programming
+ url="zookeeperProgrammers.html#ch_programStructureWithExample">Programming
Examples in the ZooKeeper Programmer's Guide</ulink> for
sample code using of the different APIs.</para>
</section>
Modified: hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ClientCnxn.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ClientCnxn.java?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ClientCnxn.java (original)
+++ hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ClientCnxn.java Wed Jun 24 22:59:34 2009
@@ -50,6 +50,7 @@
import org.apache.zookeeper.ZooDefs.OpCode;
import org.apache.zookeeper.ZooKeeper.States;
import org.apache.zookeeper.ZooKeeper.WatchRegistration;
+import org.apache.zookeeper.common.PathUtils;
import org.apache.zookeeper.proto.AuthPacket;
import org.apache.zookeeper.proto.ConnectRequest;
import org.apache.zookeeper.proto.ConnectResponse;
@@ -133,6 +134,8 @@
private byte sessionPasswd[] = new byte[16];
+ final String chrootPath;
+
final SendThread sendThread;
final EventThread eventThread;
@@ -176,7 +179,10 @@
ByteBuffer bb;
- String path;
+ /** Client's view of the path (may differ due to chroot) **/
+ String clientPath;
+ /** Servers's view of the path (may differ due to chroot) **/
+ String serverPath;
ReplyHeader replyHeader;
@@ -226,7 +232,8 @@
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("path:" + path);
+ sb.append("clientPath:" + clientPath);
+ sb.append(" serverPath:" + serverPath);
sb.append(" finished:" + finished);
sb.append(" header:: " + header);
@@ -285,6 +292,23 @@
this.watcher = watcher;
this.sessionId = sessionId;
this.sessionPasswd = sessionPasswd;
+
+ // parse out chroot, if any
+ int off = hosts.indexOf('/');
+ if (off >= 0) {
+ String chrootPath = hosts.substring(off);
+ // ignore "/" chroot spec, same as null
+ if (chrootPath.length() == 1) {
+ this.chrootPath = null;
+ } else {
+ PathUtils.validatePath(chrootPath);
+ this.chrootPath = chrootPath;
+ }
+ hosts = hosts.substring(0, off);
+ } else {
+ this.chrootPath = null;
+ }
+
String hostsList[] = hosts.split(",");
for (String host : hostsList) {
int port = 2181;
@@ -406,7 +430,7 @@
} else {
Packet p = (Packet) event;
int rc = 0;
- String path = p.path;
+ String clientPath = p.clientPath;
if (p.replyHeader.getErr() != 0) {
rc = p.replyHeader.getErr();
}
@@ -418,62 +442,65 @@
StatCallback cb = (StatCallback) p.cb;
if (rc == 0) {
if (p.response instanceof ExistsResponse) {
- cb.processResult(rc, path, p.ctx,
+ cb.processResult(rc, clientPath, p.ctx,
((ExistsResponse) p.response)
.getStat());
} else if (p.response instanceof SetDataResponse) {
- cb.processResult(rc, path, p.ctx,
+ cb.processResult(rc, clientPath, p.ctx,
((SetDataResponse) p.response)
.getStat());
} else if (p.response instanceof SetACLResponse) {
- cb.processResult(rc, path, p.ctx,
+ cb.processResult(rc, clientPath, p.ctx,
((SetACLResponse) p.response)
.getStat());
}
} else {
- cb.processResult(rc, path, p.ctx, null);
+ cb.processResult(rc, clientPath, p.ctx, null);
}
} else if (p.response instanceof GetDataResponse) {
DataCallback cb = (DataCallback) p.cb;
GetDataResponse rsp = (GetDataResponse) p.response;
if (rc == 0) {
- cb.processResult(rc, path, p.ctx, rsp
+ cb.processResult(rc, clientPath, p.ctx, rsp
.getData(), rsp.getStat());
} else {
- cb.processResult(rc, path, p.ctx, null,
+ cb.processResult(rc, clientPath, p.ctx, null,
null);
}
} else if (p.response instanceof GetACLResponse) {
ACLCallback cb = (ACLCallback) p.cb;
GetACLResponse rsp = (GetACLResponse) p.response;
if (rc == 0) {
- cb.processResult(rc, path, p.ctx, rsp
+ cb.processResult(rc, clientPath, p.ctx, rsp
.getAcl(), rsp.getStat());
} else {
- cb.processResult(rc, path, p.ctx, null,
+ cb.processResult(rc, clientPath, p.ctx, null,
null);
}
} else if (p.response instanceof GetChildrenResponse) {
ChildrenCallback cb = (ChildrenCallback) p.cb;
GetChildrenResponse rsp = (GetChildrenResponse) p.response;
if (rc == 0) {
- cb.processResult(rc, path, p.ctx, rsp
+ cb.processResult(rc, clientPath, p.ctx, rsp
.getChildren());
} else {
- cb.processResult(rc, path, p.ctx, null);
+ cb.processResult(rc, clientPath, p.ctx, null);
}
} else if (p.response instanceof CreateResponse) {
StringCallback cb = (StringCallback) p.cb;
CreateResponse rsp = (CreateResponse) p.response;
if (rc == 0) {
- cb.processResult(rc, path, p.ctx, rsp
- .getPath());
+ cb.processResult(rc, clientPath, p.ctx,
+ (chrootPath == null
+ ? rsp.getPath()
+ : rsp.getPath()
+ .substring(chrootPath.length())));
} else {
- cb.processResult(rc, path, p.ctx, null);
+ cb.processResult(rc, clientPath, p.ctx, null);
}
} else if (p.cb instanceof VoidCallback) {
VoidCallback cb = (VoidCallback) p.cb;
- cb.processResult(rc, path, p.ctx);
+ cb.processResult(rc, clientPath, p.ctx);
}
}
} catch (Throwable t) {
@@ -601,6 +628,13 @@
+ Long.toHexString(sessionId));
WatcherEvent event = new WatcherEvent();
event.deserialize(bbia, "response");
+
+ // convert from a server path to a client path
+ if (chrootPath != null) {
+ String serverPath = event.getPath();
+ event.setPath(serverPath.substring(chrootPath.length()));
+ }
+
WatchedEvent we = new WatchedEvent(event);
if (LOG.isDebugEnabled()) {
LOG.debug("Got " + we + " for sessionid 0x"
@@ -791,7 +825,7 @@
private void sendPing() {
lastPingSentNs = System.nanoTime();
RequestHeader h = new RequestHeader(-2, OpCode.ping);
- queuePacket(h, null, null, null, null, null, null, null);
+ queuePacket(h, null, null, null, null, null, null, null, null);
}
int lastConnectIndex = -1;
@@ -1059,7 +1093,7 @@
throws InterruptedException {
ReplyHeader r = new ReplyHeader();
Packet packet = queuePacket(h, r, request, response, null, null, null,
- watchRegistration);
+ null, watchRegistration);
synchronized (packet) {
while (!packet.finished) {
packet.wait();
@@ -1069,8 +1103,9 @@
}
Packet queuePacket(RequestHeader h, ReplyHeader r, Record request,
- Record response, AsyncCallback cb, String path, Object ctx,
- WatchRegistration watchRegistration) {
+ Record response, AsyncCallback cb, String clientPath,
+ String serverPath, Object ctx, WatchRegistration watchRegistration)
+ {
Packet packet = null;
synchronized (outgoingQueue) {
if (h.getType() != OpCode.ping && h.getType() != OpCode.auth) {
@@ -1080,7 +1115,8 @@
watchRegistration);
packet.cb = cb;
packet.ctx = ctx;
- packet.path = path;
+ packet.clientPath = clientPath;
+ packet.serverPath = serverPath;
if (!zooKeeper.state.isAlive()) {
conLossPacket(packet);
} else {
@@ -1098,7 +1134,7 @@
if (zooKeeper.state == States.CONNECTED) {
queuePacket(new RequestHeader(-4, OpCode.auth), null,
new AuthPacket(0, scheme, auth), null, null, null, null,
- null);
+ null, null);
}
}
}
Modified: hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ZooKeeper.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ZooKeeper.java?rev=788205&r1=788204&r2=788205&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ZooKeeper.java (original)
+++ hadoop/zookeeper/trunk/src/java/main/org/apache/zookeeper/ZooKeeper.java Wed Jun 24 22:59:34 2009
@@ -148,7 +148,9 @@
* @see org.apache.zookeeper.ClientWatchManager#materialize(Event.KeeperState, Event.EventType, java.lang.String)
*/
public Set<Watcher> materialize(Watcher.Event.KeeperState state,
- Watcher.Event.EventType type, String path) {
+ Watcher.Event.EventType type,
+ String clientPath)
+ {
Set<Watcher> result = new HashSet<Watcher>();
switch (type) {
@@ -183,36 +185,36 @@
case NodeDataChanged:
case NodeCreated:
synchronized (dataWatches) {
- addTo(dataWatches.remove(path), result);
+ addTo(dataWatches.remove(clientPath), result);
}
synchronized (existWatches) {
- addTo(existWatches.remove(path), result);
+ addTo(existWatches.remove(clientPath), result);
}
break;
case NodeChildrenChanged:
synchronized (childWatches) {
- addTo(childWatches.remove(path), result);
+ addTo(childWatches.remove(clientPath), result);
}
break;
case NodeDeleted:
synchronized (dataWatches) {
- addTo(dataWatches.remove(path), result);
+ addTo(dataWatches.remove(clientPath), result);
}
// XXX This shouldn't be needed, but just in case
synchronized (existWatches) {
- Set<Watcher> list = existWatches.remove(path);
+ Set<Watcher> list = existWatches.remove(clientPath);
if (list != null) {
- addTo(existWatches.remove(path), result);
+ addTo(existWatches.remove(clientPath), result);
LOG.warn("We are triggering an exists watch for delete! Shouldn't happen!");
}
}
synchronized (childWatches) {
- addTo(childWatches.remove(path), result);
+ addTo(childWatches.remove(clientPath), result);
}
break;
default:
String msg = "Unhandled watch event type " + type
- + " with state " + state + " on path " + path;
+ + " with state " + state + " on path " + clientPath;
LOG.error(msg);
throw new RuntimeException(msg);
}
@@ -226,11 +228,11 @@
*/
abstract class WatchRegistration {
private Watcher watcher;
- private String path;
- public WatchRegistration(Watcher watcher, String path)
+ private String clientPath;
+ public WatchRegistration(Watcher watcher, String clientPath)
{
this.watcher = watcher;
- this.path = path;
+ this.clientPath = clientPath;
}
abstract protected Map<String, Set<Watcher>> getWatches(int rc);
@@ -244,10 +246,10 @@
if (shouldAddWatch(rc)) {
Map<String, Set<Watcher>> watches = getWatches(rc);
synchronized(watches) {
- Set<Watcher> watchers = watches.get(path);
+ Set<Watcher> watchers = watches.get(clientPath);
if (watchers == null) {
watchers = new HashSet<Watcher>();
- watches.put(path, watchers);
+ watches.put(clientPath, watchers);
}
watchers.add(watcher);
}
@@ -268,8 +270,8 @@
* even in the case where NONODE result code is returned.
*/
class ExistsWatchRegistration extends WatchRegistration {
- public ExistsWatchRegistration(Watcher watcher, String path) {
- super(watcher, path);
+ public ExistsWatchRegistration(Watcher watcher, String clientPath) {
+ super(watcher, clientPath);
}
@Override
@@ -284,8 +286,8 @@
}
class DataWatchRegistration extends WatchRegistration {
- public DataWatchRegistration(Watcher watcher, String path) {
- super(watcher, path);
+ public DataWatchRegistration(Watcher watcher, String clientPath) {
+ super(watcher, clientPath);
}
@Override
@@ -295,8 +297,8 @@
}
class ChildWatchRegistration extends WatchRegistration {
- public ChildWatchRegistration(Watcher watcher, String path) {
- super(watcher, path);
+ public ChildWatchRegistration(Watcher watcher, String clientPath) {
+ super(watcher, clientPath);
}
@Override
@@ -318,17 +320,27 @@
protected final ClientCnxn cnxn;
/**
- * To create a client(ZooKeeper) object, the application needs to pass a
- * string containing a comma separated list of host:port pairs, each
- * corresponding to a ZooKeeper server.
+ * To create a ZooKeeper client object, the application needs to pass a
+ * connection string containing a comma separated list of host:port pairs,
+ * each corresponding to a ZooKeeper server.
* <p>
* The client object will pick an arbitrary server and try to connect to it.
* If failed, it will try the next one in the list, until a connection is
* established, or all the servers have been tried.
+ * <p>
+ * Added in 3.2.0: An optional "chroot" suffix may also be appended to the
+ * connection string. This will run the client commands while interpreting
+ * all paths relative to this root (similar to the unix chroot command).
*
- * @param host
+ * @param connectString
* comma separated host:port pairs, each corresponding to a zk
* server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"
+ * If the optional chroot suffix is used the example would look
+ * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a"
+ * where the client would be rooted at "/app/a" and all paths
+ * would be relative to this root - ie getting/setting/etc...
+ * "/foo/bar" would result in operations being run on
+ * "/app/a/foo/bar" (from the server perspective).
* @param sessionTimeout
* session timeout in milliseconds
* @param watcher
@@ -336,35 +348,47 @@
* also be notified for node events
*
* @throws IOException in cases of network failure
+ * @throws IllegalArgumentException if an invalid chroot path is specified
*/
- public ZooKeeper(String host, int sessionTimeout, Watcher watcher)
- throws IOException {
- LOG.info("Initiating client connection, host=" + host
+ public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)
+ throws IOException
+ {
+ LOG.info("Initiating client connection, connectString=" + connectString
+ " sessionTimeout=" + sessionTimeout + " watcher=" + watcher);
watchManager.defaultWatcher = watcher;
- cnxn = new ClientCnxn(host, sessionTimeout, this, watchManager);
+ cnxn = new ClientCnxn(connectString, sessionTimeout, this, watchManager);
cnxn.start();
}
/**
- * To create a client(ZooKeeper) object, the application needs to pass a
- * string containing a comma separated list of host:port pairs, each
- * corresponding to a ZooKeeper server.
+ * To create a ZooKeeper client object, the application needs to pass a
+ * connection string containing a comma separated list of host:port pairs,
+ * each corresponding to a ZooKeeper server.
* <p>
* The client object will pick an arbitrary server and try to connect to it.
* If failed, it will try the next one in the list, until a connection is
* established, or all the servers have been tried.
* <p>
+ * Added in 3.2.0: An optional "chroot" suffix may also be appended to the
+ * connection string. This will run the client commands while interpreting
+ * all paths relative to this root (similar to the unix chroot command).
+ * <p>
* Use {@link #getSessionId} and {@link #getSessionPasswd} on an established
* client connection, these values must be passed as sessionId and
* sessionPasswd respectively if reconnecting. Otherwise, if not
* reconnecting, use the other constructor which does not require these
* parameters.
*
- * @param host
+ * @param connectString
* comma separated host:port pairs, each corresponding to a zk
* server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"
+ * If the optional chroot suffix is used the example would look
+ * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a"
+ * where the client would be rooted at "/app/a" and all paths
+ * would be relative to this root - ie getting/setting/etc...
+ * "/foo/bar" would result in operations being run on
+ * "/app/a/foo/bar" (from the server perspective).
* @param sessionTimeout
* session timeout in milliseconds
* @param watcher
@@ -376,10 +400,13 @@
* password for this session
*
* @throws IOException in cases of network failure
+ * @throws IllegalArgumentException if an invalid chroot path is specified
*/
- public ZooKeeper(String host, int sessionTimeout, Watcher watcher,
- long sessionId, byte[] sessionPasswd) throws IOException {
- LOG.info("Initiating client connection, host=" + host
+ public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,
+ long sessionId, byte[] sessionPasswd)
+ throws IOException
+ {
+ LOG.info("Initiating client connection, connectString=" + connectString
+ " sessionTimeout=" + sessionTimeout
+ " watcher=" + watcher
+ " sessionId=" + sessionId
@@ -387,7 +414,7 @@
+ (sessionPasswd == null ? "<null>" : "<hidden>"));
watchManager.defaultWatcher = watcher;
- cnxn = new ClientCnxn(host, sessionTimeout, this, watchManager,
+ cnxn = new ClientCnxn(connectString, sessionTimeout, this, watchManager,
sessionId, sessionPasswd);
cnxn.start();
}
@@ -429,9 +456,6 @@
* their parents) will be triggered.
*
* @throws InterruptedException
- *
- * @throws IOException
- * @throws InterruptedException
*/
public synchronized void close() throws InterruptedException {
LOG.info("Closing session: 0x" + Long.toHexString(getSessionId()));
@@ -446,6 +470,25 @@
}
/**
+ * Prepend the chroot to the client path (if present). The expectation of
+ * this function is that the client path has been validated before this
+ * function is called
+ * @param clientPath path to the node
+ * @return server view of the path (chroot prepended to client path)
+ */
+ private String prependChroot(String clientPath) {
+ if (cnxn.chrootPath != null) {
+ // handle clientPath = "/"
+ if (clientPath.length() == 1) {
+ return cnxn.chrootPath;
+ }
+ return cnxn.chrootPath + clientPath;
+ } else {
+ return clientPath;
+ }
+ }
+
+ /**
* Create a node with the given path. The node data will be the given data,
* and node acl will be the given acl.
* <p>
@@ -495,16 +538,18 @@
* and/or sequential
* @return the actual path of the created node
* @throws KeeperException if the server returns a non-zero error code
- * @throws org.apache.zookeeper.KeeperException.InvalidACLException if the ACL is invalid
+ * @throws KeeperException.InvalidACLException if the ACL is invalid
* @throws InterruptedException if the transaction is interrupted
* @throws IllegalArgumentException if an invalid path is specified
*/
- public String create(String path, byte data[], List<ACL> acl,
+ public String create(final String path, byte data[], List<ACL> acl,
CreateMode createMode)
throws KeeperException, InterruptedException
{
- // also handle the case where server will append name suffix
- PathUtils.validatePath(path, createMode.isSequential());
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath, createMode.isSequential());
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.create);
@@ -512,7 +557,7 @@
CreateResponse response = new CreateResponse();
request.setData(data);
request.setFlags(createMode.toFlag());
- request.setPath(path);
+ request.setPath(serverPath);
if (acl != null && acl.size() == 0) {
throw new KeeperException.InvalidACLException();
}
@@ -520,9 +565,13 @@
ReplyHeader r = cnxn.submitRequest(h, request, response, null);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
+ }
+ if (cnxn.chrootPath == null) {
+ return response.getPath();
+ } else {
+ return response.getPath().substring(cnxn.chrootPath.length());
}
- return response.getPath();
}
/**
@@ -532,11 +581,13 @@
* @see #create(String, byte[], List, CreateMode)
*/
- public void create(String path, byte data[], List<ACL> acl,
+ public void create(final String path, byte data[], List<ACL> acl,
CreateMode createMode, StringCallback cb, Object ctx)
{
- // also handle the case where server will append name suffix
- PathUtils.validatePath(path, createMode.isSequential());
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath, createMode.isSequential());
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.create);
@@ -545,9 +596,10 @@
ReplyHeader r = new ReplyHeader();
request.setData(data);
request.setFlags(createMode.toFlag());
- request.setPath(path);
+ request.setPath(serverPath);
request.setAcl(acl);
- cnxn.queuePacket(h, r, request, response, cb, path, ctx, null);
+ cnxn.queuePacket(h, r, request, response, cb, clientPath,
+ serverPath, ctx, null);
}
/**
@@ -573,22 +625,38 @@
* @param version
* the expected node version.
* @throws InterruptedException IF the server transaction is interrupted
- * @throws KeeperException If the server signals an error with a non-zero return code.
+ * @throws KeeperException If the server signals an error with a non-zero
+ * return code.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public void delete(String path, int version) throws
- InterruptedException, KeeperException {
- PathUtils.validatePath(path);
+ public void delete(final String path, int version)
+ throws InterruptedException, KeeperException
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath;
+
+ // maintain semantics even in chroot case
+ // specifically - root cannot be deleted
+ // I think this makes sense even in chroot case.
+ if (clientPath.equals("/")) {
+ // a bit of a hack, but delete(/) will never succeed and ensures
+ // that the same semantics are maintained
+ serverPath = clientPath;
+ } else {
+ serverPath = prependChroot(clientPath);
+ }
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.delete);
DeleteRequest request = new DeleteRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setVersion(version);
ReplyHeader r = cnxn.submitRequest(h, request, null, null);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
}
@@ -598,15 +666,32 @@
*
* @see #delete(String, int)
*/
- public void delete(String path, int version, VoidCallback cb, Object ctx) {
- PathUtils.validatePath(path);
+ public void delete(final String path, int version, VoidCallback cb,
+ Object ctx)
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath;
+
+ // maintain semantics even in chroot case
+ // specifically - root cannot be deleted
+ // I think this makes sense even in chroot case.
+ if (clientPath.equals("/")) {
+ // a bit of a hack, but delete(/) will never succeed and ensures
+ // that the same semantics are maintained
+ serverPath = clientPath;
+ } else {
+ serverPath = prependChroot(clientPath);
+ }
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.delete);
DeleteRequest request = new DeleteRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setVersion(version);
- cnxn.queuePacket(h, new ReplyHeader(), request, null, cb, path, ctx, null);
+ cnxn.queuePacket(h, new ReplyHeader(), request, null, cb, clientPath,
+ serverPath, ctx, null);
}
/**
@@ -626,28 +711,33 @@
* @throws InterruptedException If the server transaction is interrupted.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public Stat exists(String path, Watcher watcher) throws KeeperException,
- InterruptedException
+ public Stat exists(final String path, Watcher watcher)
+ throws KeeperException, InterruptedException
{
- PathUtils.validatePath(path);
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ // the watch contains the un-chroot path
+ WatchRegistration wcb = null;
+ if (watcher != null) {
+ wcb = new ExistsWatchRegistration(watcher, clientPath);
+ }
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.exists);
ExistsRequest request = new ExistsRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setWatch(watcher != null);
SetDataResponse response = new SetDataResponse();
- WatchRegistration wcb = null;
- if (watcher != null) {
- wcb = new ExistsWatchRegistration(watcher, path);
- }
ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);
if (r.getErr() != 0) {
if (r.getErr() == KeeperException.Code.NONODE.intValue()) {
return null;
}
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
return response.getStat().getCzxid() == -1 ? null : response.getStat();
@@ -683,23 +773,28 @@
*
* @see #exists(String, boolean)
*/
- public void exists(String path, Watcher watcher, StatCallback cb,
- Object ctx)
+ public void exists(final String path, Watcher watcher,
+ StatCallback cb, Object ctx)
{
- PathUtils.validatePath(path);
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ // the watch contains the un-chroot path
+ WatchRegistration wcb = null;
+ if (watcher != null) {
+ wcb = new ExistsWatchRegistration(watcher, clientPath);
+ }
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.exists);
ExistsRequest request = new ExistsRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setWatch(watcher != null);
SetDataResponse response = new SetDataResponse();
- WatchRegistration wcb = null;
- if (watcher != null) {
- wcb = new ExistsWatchRegistration(watcher, path);
- }
- cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, path,
- ctx, wcb);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, wcb);
}
/**
@@ -731,24 +826,30 @@
* @throws InterruptedException If the server transaction is interrupted.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public byte[] getData(String path, Watcher watcher, Stat stat)
- throws KeeperException, InterruptedException {
- PathUtils.validatePath(path);
+ public byte[] getData(final String path, Watcher watcher, Stat stat)
+ throws KeeperException, InterruptedException
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ // the watch contains the un-chroot path
+ WatchRegistration wcb = null;
+ if (watcher != null) {
+ wcb = new DataWatchRegistration(watcher, clientPath);
+ }
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.getData);
GetDataRequest request = new GetDataRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setWatch(watcher != null);
GetDataResponse response = new GetDataResponse();
- WatchRegistration wcb = null;
- if (watcher != null) {
- wcb = new DataWatchRegistration(watcher, path);
- }
ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
if (stat != null) {
DataTree.copyStat(response.getStat(), stat);
@@ -785,21 +886,28 @@
*
* @see #getData(String, Watcher, Stat)
*/
- public void getData(String path, Watcher watcher, DataCallback cb, Object ctx) {
- PathUtils.validatePath(path);
+ public void getData(final String path, Watcher watcher,
+ DataCallback cb, Object ctx)
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ // the watch contains the un-chroot path
+ WatchRegistration wcb = null;
+ if (watcher != null) {
+ wcb = new DataWatchRegistration(watcher, clientPath);
+ }
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.getData);
GetDataRequest request = new GetDataRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setWatch(watcher != null);
GetDataResponse response = new GetDataResponse();
- WatchRegistration wcb = null;
- if (watcher != null) {
- wcb = new DataWatchRegistration(watcher, path);
- }
- cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, path,
- ctx, wcb);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, wcb);
}
/**
@@ -840,21 +948,25 @@
* @throws KeeperException If the server signals an error with a non-zero error code.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public Stat setData(String path, byte data[], int version)
- throws KeeperException, InterruptedException {
- PathUtils.validatePath(path);
+ public Stat setData(final String path, byte data[], int version)
+ throws KeeperException, InterruptedException
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.setData);
SetDataRequest request = new SetDataRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setData(data);
request.setVersion(version);
SetDataResponse response = new SetDataResponse();
ReplyHeader r = cnxn.submitRequest(h, request, response, null);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
return response.getStat();
}
@@ -865,20 +977,23 @@
*
* @see #setData(String, byte[], int)
*/
- public void setData(String path, byte data[], int version, StatCallback cb,
- Object ctx) {
- PathUtils.validatePath(path);
+ public void setData(final String path, byte data[], int version,
+ StatCallback cb, Object ctx)
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.setData);
SetDataRequest request = new SetDataRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setData(data);
request.setVersion(version);
SetDataResponse response = new SetDataResponse();
- cnxn
- .queuePacket(h, new ReplyHeader(), request, response, cb, path,
- ctx, null);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, null);
}
/**
@@ -896,19 +1011,23 @@
* @throws KeeperException If the server signals an error with a non-zero error code.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public List<ACL> getACL(String path, Stat stat)
- throws KeeperException, InterruptedException {
- PathUtils.validatePath(path);
+ public List<ACL> getACL(final String path, Stat stat)
+ throws KeeperException, InterruptedException
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.getACL);
GetACLRequest request = new GetACLRequest();
- request.setPath(path);
+ request.setPath(serverPath);
GetACLResponse response = new GetACLResponse();
ReplyHeader r = cnxn.submitRequest(h, request, response, null);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
DataTree.copyStat(response.getStat(), stat);
return response.getAcl();
@@ -920,17 +1039,21 @@
*
* @see #getACL(String, Stat)
*/
- public void getACL(String path, Stat stat, ACLCallback cb, Object ctx) {
- PathUtils.validatePath(path);
+ public void getACL(final String path, Stat stat, ACLCallback cb,
+ Object ctx)
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.getACL);
GetACLRequest request = new GetACLRequest();
- request.setPath(path);
+ request.setPath(serverPath);
GetACLResponse response = new GetACLResponse();
- cnxn
- .queuePacket(h, new ReplyHeader(), request, response, cb, path,
- ctx, null);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, null);
}
/**
@@ -953,14 +1076,18 @@
* @throws org.apache.zookeeper.KeeperException.InvalidACLException If the acl is invalide.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public Stat setACL(String path, List<ACL> acl, int version)
- throws KeeperException, InterruptedException {
- PathUtils.validatePath(path);
+ public Stat setACL(final String path, List<ACL> acl, int version)
+ throws KeeperException, InterruptedException
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.setACL);
SetACLRequest request = new SetACLRequest();
- request.setPath(path);
+ request.setPath(serverPath);
if (acl != null && acl.size() == 0) {
throw new KeeperException.InvalidACLException();
}
@@ -970,7 +1097,7 @@
ReplyHeader r = cnxn.submitRequest(h, request, response, null);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
return response.getStat();
}
@@ -981,20 +1108,23 @@
*
* @see #setACL(String, List, int)
*/
- public void setACL(String path, List<ACL> acl, int version,
- StatCallback cb, Object ctx) {
- PathUtils.validatePath(path);
+ public void setACL(final String path, List<ACL> acl, int version,
+ StatCallback cb, Object ctx)
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.setACL);
SetACLRequest request = new SetACLRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setAcl(acl);
request.setVersion(version);
SetACLResponse response = new SetACLResponse();
- cnxn
- .queuePacket(h, new ReplyHeader(), request, response, cb, path,
- ctx, null);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, null);
}
/**
@@ -1018,24 +1148,30 @@
* @throws KeeperException If the server signals an error with a non-zero error code.
* @throws IllegalArgumentException if an invalid path is specified
*/
- public List<String> getChildren(String path, Watcher watcher)
- throws KeeperException, InterruptedException {
- PathUtils.validatePath(path);
+ public List<String> getChildren(final String path, Watcher watcher)
+ throws KeeperException, InterruptedException
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ // the watch contains the un-chroot path
+ WatchRegistration wcb = null;
+ if (watcher != null) {
+ wcb = new ChildWatchRegistration(watcher, clientPath);
+ }
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.getChildren);
GetChildrenRequest request = new GetChildrenRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setWatch(watcher != null);
GetChildrenResponse response = new GetChildrenResponse();
- WatchRegistration wcb = null;
- if (watcher != null) {
- wcb = new ChildWatchRegistration(watcher, path);
- }
ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);
if (r.getErr() != 0) {
throw KeeperException.create(KeeperException.Code.get(r.getErr()),
- path);
+ clientPath);
}
return response.getChildren();
}
@@ -1071,22 +1207,28 @@
*
* @see #getChildren(String, Watcher)
*/
- public void getChildren(String path, Watcher watcher, ChildrenCallback cb,
- Object ctx) {
- PathUtils.validatePath(path);
+ public void getChildren(final String path, Watcher watcher,
+ ChildrenCallback cb, Object ctx)
+ {
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ // the watch contains the un-chroot path
+ WatchRegistration wcb = null;
+ if (watcher != null) {
+ wcb = new ChildWatchRegistration(watcher, clientPath);
+ }
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.getChildren);
GetChildrenRequest request = new GetChildrenRequest();
- request.setPath(path);
+ request.setPath(serverPath);
request.setWatch(watcher != null);
GetChildrenResponse response = new GetChildrenResponse();
- WatchRegistration wcb = null;
- if (watcher != null) {
- wcb = new ChildWatchRegistration(watcher, path);
- }
- cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, path,
- ctx, wcb);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, wcb);
}
/**
@@ -1107,16 +1249,19 @@
* @param ctx context to be provided to the callback
* @throws IllegalArgumentException if an invalid path is specified
*/
- public void sync(String path, VoidCallback cb, Object ctx){
- PathUtils.validatePath(path);
+ public void sync(final String path, VoidCallback cb, Object ctx){
+ final String clientPath = path;
+ PathUtils.validatePath(clientPath);
+
+ final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.sync);
SyncRequest request = new SyncRequest();
SyncResponse response = new SyncResponse();
- request.setPath(path);
- cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, path, ctx,
- null);
+ request.setPath(serverPath);
+ cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+ clientPath, serverPath, ctx, null);
}
public States getState() {