You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by an...@apache.org on 2019/07/17 11:42:38 UTC
[zookeeper] branch master updated: ZOOKEEPER-2563: A revisit to
setquota
This is an automated email from the ASF dual-hosted git repository.
andor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git
The following commit(s) were added to refs/heads/master by this push:
new a6c36b6 ZOOKEEPER-2563: A revisit to setquota
a6c36b6 is described below
commit a6c36b69cc72d7d67e392dab5360007d6f737bef
Author: maoling <ma...@sina.com>
AuthorDate: Wed Jul 17 13:42:32 2019 +0200
ZOOKEEPER-2563: A revisit to setquota
- remove some useless methods in the `ZooKeeperMain.java`
- cannot set the quota on the path under` /zookeeper/quota`, because this path is reserved for storing the quota info. if we do something like this:
`setquota -n 5 /zookeeper/quota`
which will let us only have five chances to use the setquota, that violates the quota semantics.
- handle the Exception when users set a quota on the parent/child node.([ZOOKEEPER-2565](https://issues.apache.org/jira/browse/ZOOKEEPER-2565)).
- more detail in the [ZOOKEEPER-2563](https://issues.apache.org/jira/browse/ZOOKEEPER-2563)
Author: maoling <ma...@sina.com>
Reviewers: andor@apache.org
Closes #936 from maoling/ZOOKEEPER-2563 and squashes the following commits:
9d46e862c [maoling] strength the doc,especially for the concept:namespaces
3777359bd [maoling] ZOOKEEPER-2563: A revisit to setquota
---
.../src/main/resources/markdown/zookeeperCLI.md | 4 +-
.../src/main/resources/markdown/zookeeperQuotas.md | 31 ++-
.../java/org/apache/zookeeper/ZooKeeperMain.java | 210 ---------------------
.../org/apache/zookeeper/cli/SetQuotaCommand.java | 65 +++++--
.../org/apache/zookeeper/test/QuorumQuotaTest.java | 3 +-
.../apache/zookeeper/test/ZooKeeperQuotaTest.java | 78 +++++++-
6 files changed, 153 insertions(+), 238 deletions(-)
diff --git a/zookeeper-docs/src/main/resources/markdown/zookeeperCLI.md b/zookeeper-docs/src/main/resources/markdown/zookeeperCLI.md
index 57ab71d..717c4f1 100644
--- a/zookeeper-docs/src/main/resources/markdown/zookeeperCLI.md
+++ b/zookeeper-docs/src/main/resources/markdown/zookeeperCLI.md
@@ -497,7 +497,7 @@ Set the Acl permission for one node.
Set the quota in one path.
```bash
-# -n to limit the number of child nodes(namespaces)
+# -n to limit the number of child nodes(included itself)
[zkshell: 18] setquota -n 2 /quota_test
[zkshell: 19] create /quota_test/child_1
Created /quota_test/child_1
@@ -509,7 +509,7 @@ Set the quota in one path.
2019-03-07 11:22:36,680 [myid:1] - WARN [SyncThread:0:DataTree@374] - Quota exceeded: /quota_test count=3 limit=2
2019-03-07 11:22:41,861 [myid:1] - WARN [SyncThread:0:DataTree@374] - Quota exceeded: /quota_test count=4 limit=2
-# -b to limit the bytes/size of one path
+# -b to limit the bytes(data length) of one path
[zkshell: 22] setquota -b 5 /brokers
[zkshell: 23] set /brokers "I_love_zookeeper"
# Notice:don't have a hard constraint,just log the warning info
diff --git a/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md b/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md
index 7f56a34..11226c3 100644
--- a/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md
+++ b/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md
@@ -31,6 +31,9 @@ ZooKeeper has both namespace and bytes quotas. You can use the ZooKeeperMain cla
ZooKeeper prints _WARN_ messages if users exceed the quota assigned to them. The messages
are printed in the log of the ZooKeeper.
+Notice: What the `namespace` quota means is the count quota which limits the number of children
+under the path(included itself).
+
$ bin/zkCli.sh -server host:port**
The above command gives you a command line option of using quotas.
@@ -39,12 +42,30 @@ The above command gives you a command line option of using quotas.
### Setting Quotas
-You can use _setquota_ to set a quota on a ZooKeeper node. It has an option of setting quota with
-`-n` (for namespace)
-and `-b` (for bytes).
+- You can use `setquota` to set a quota on a ZooKeeper node. It has an option of setting quota with
+`-n` (for namespace/count) and `-b` (for bytes/data length).
+
+- The ZooKeeper quota is stored in ZooKeeper itself in **/zookeeper/quota**. To disable other people from
+changing the quotas, users can set the ACL for **/zookeeper/quota** ,so that only admins are able to read and write to it.
+
+- If the quota doesn't exist in the specified path,create the quota, otherwise update the quota.
+
+- The Scope of the quota users set is all the nodes under the path specified (included itself).
+
+- In order to simplify the calculation of quota in the current directory/hierarchy structure, a complete tree path(from root to leaf node)
+can be set only one quota. In the situation when setting a quota in a path which its parent or child node already has a quota. `setquota` will
+reject and tell the specified parent or child path, users can adjust allocations of quotas(delete/move-up/move-down the quota)
+according to specific circumstances.
+
+- Combined with the Chroot, the quota will have a better isolation effectiveness between different applications.For example:
+
+ ```bash
+ # Chroot is:
+ 192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181/apps/app1
+ setquota -n 100000 /apps/app1
+ ```
-The ZooKeeper quota is stored in ZooKeeper itself in /zookeeper/quota. To disable other people from
-changing the quota's set the ACL for /zookeeper/quota such that only admins are able to read and write to it.
+- Users cannot set the quota on the path under **/zookeeper/quota**
<a name="Listing+Quotas"></a>
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
index ce575b1..8b0caf9 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
@@ -43,8 +43,6 @@ import org.apache.zookeeper.cli.MalformedCommandException;
import org.apache.zookeeper.cli.VersionCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.zookeeper.ZooDefs.Ids;
-import org.apache.zookeeper.data.Stat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -381,214 +379,6 @@ public class ZooKeeperMain {
}
}
- /**
- * trim the quota tree to recover unwanted tree elements
- * in the quota's tree
- * @param zk the zookeeper client
- * @param path the path to start from and go up and see if their
- * is any unwanted parent in the path.
- * @return true if sucessful
- * @throws KeeperException
- * @throws IOException
- * @throws InterruptedException
- */
- private static boolean trimProcQuotas(ZooKeeper zk, String path)
- throws KeeperException, IOException, InterruptedException
- {
- if (Quotas.quotaZookeeper.equals(path)) {
- return true;
- }
- List<String> children = zk.getChildren(path, false);
- if (children.size() == 0) {
- zk.delete(path, -1);
- String parent = path.substring(0, path.lastIndexOf('/'));
- return trimProcQuotas(zk, parent);
- } else {
- return true;
- }
- }
-
- /**
- * this method deletes quota for a node.
- * @param zk the zookeeper client
- * @param path the path to delete quota for
- * @param bytes true if number of bytes needs to
- * be unset
- * @param numNodes true if number of nodes needs
- * to be unset
- * @return true if quota deletion is successful
- * @throws KeeperException
- * @throws IOException
- * @throws InterruptedException
- */
- public static boolean delQuota(ZooKeeper zk, String path,
- boolean bytes, boolean numNodes)
- throws KeeperException, IOException, InterruptedException
- {
- String parentPath = Quotas.quotaZookeeper + path;
- String quotaPath = Quotas.quotaZookeeper + path + "/" + Quotas.limitNode;
- if (zk.exists(quotaPath, false) == null) {
- System.out.println("Quota does not exist for " + path);
- return true;
- }
- byte[] data = null;
- try {
- data = zk.getData(quotaPath, false, new Stat());
- } catch(KeeperException.NoNodeException ne) {
- System.err.println("quota does not exist for " + path);
- return true;
- }
- StatsTrack strack = new StatsTrack(new String(data));
- if (bytes && !numNodes) {
- strack.setBytes(-1L);
- zk.setData(quotaPath, strack.toString().getBytes(), -1);
- } else if (!bytes && numNodes) {
- strack.setCount(-1);
- zk.setData(quotaPath, strack.toString().getBytes(), -1);
- } else if (bytes && numNodes) {
- // delete till you can find a node with more than
- // one child
- List<String> children = zk.getChildren(parentPath, false);
- /// delete the direct children first
- for (String child: children) {
- zk.delete(parentPath + "/" + child, -1);
- }
- // cut the tree till their is more than one child
- trimProcQuotas(zk, parentPath);
- }
- return true;
- }
-
- private static void checkIfParentQuota(ZooKeeper zk, String path)
- throws InterruptedException, KeeperException
- {
- final String[] splits = path.split("/");
- String quotaPath = Quotas.quotaZookeeper;
- for (String str: splits) {
- if (str.length() == 0) {
- // this should only be for the beginning of the path
- // i.e. "/..." - split(path)[0] is empty string before first '/'
- continue;
- }
- quotaPath += "/" + str;
- List<String> children = null;
- try {
- children = zk.getChildren(quotaPath, false);
- } catch(KeeperException.NoNodeException ne) {
- LOG.debug("child removed during quota check", ne);
- return;
- }
- if (children.size() == 0) {
- return;
- }
- for (String child: children) {
- if (Quotas.limitNode.equals(child)) {
- throw new IllegalArgumentException(path + " has a parent "
- + quotaPath + " which has a quota");
- }
- }
- }
- }
-
- /**
- * this method creates a quota node for the path
- * @param zk the ZooKeeper client
- * @param path the path for which quota needs to be created
- * @param bytes the limit of bytes on this path
- * @param numNodes the limit of number of nodes on this path
- * @return true if its successful and false if not.
- */
- public static boolean createQuota(ZooKeeper zk, String path,
- long bytes, int numNodes)
- throws KeeperException, IOException, InterruptedException
- {
- // check if the path exists. We cannot create
- // quota for a path that already exists in zookeeper
- // for now.
- Stat initStat = zk.exists(path, false);
- if (initStat == null) {
- throw new IllegalArgumentException(path + " does not exist.");
- }
- // now check if their is already existing
- // parent or child that has quota
-
- String quotaPath = Quotas.quotaZookeeper;
- // check for more than 2 children --
- // if zookeeper_stats and zookeeper_qutoas
- // are not the children then this path
- // is an ancestor of some path that
- // already has quota
- String realPath = Quotas.quotaZookeeper + path;
- try {
- List<String> children = zk.getChildren(realPath, false);
- for (String child: children) {
- if (!child.startsWith("zookeeper_")) {
- throw new IllegalArgumentException(path + " has child " +
- child + " which has a quota");
- }
- }
- } catch(KeeperException.NoNodeException ne) {
- // this is fine
- }
-
- //check for any parent that has been quota
- checkIfParentQuota(zk, path);
-
- // this is valid node for quota
- // start creating all the parents
- if (zk.exists(quotaPath, false) == null) {
- try {
- zk.create(Quotas.procZookeeper, null, Ids.OPEN_ACL_UNSAFE,
- CreateMode.PERSISTENT);
- zk.create(Quotas.quotaZookeeper, null, Ids.OPEN_ACL_UNSAFE,
- CreateMode.PERSISTENT);
- } catch(KeeperException.NodeExistsException ne) {
- // do nothing
- }
- }
-
- // now create the direct children
- // and the stat and quota nodes
- String[] splits = path.split("/");
- StringBuilder sb = new StringBuilder();
- sb.append(quotaPath);
- for (int i=1; i<splits.length; i++) {
- sb.append("/" + splits[i]);
- quotaPath = sb.toString();
- try {
- zk.create(quotaPath, null, Ids.OPEN_ACL_UNSAFE ,
- CreateMode.PERSISTENT);
- } catch(KeeperException.NodeExistsException ne) {
- //do nothing
- }
- }
- String statPath = quotaPath + "/" + Quotas.statNode;
- quotaPath = quotaPath + "/" + Quotas.limitNode;
- StatsTrack strack = new StatsTrack(null);
- strack.setBytes(bytes);
- strack.setCount(numNodes);
- try {
- zk.create(quotaPath, strack.toString().getBytes(),
- Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- StatsTrack stats = new StatsTrack(null);
- stats.setBytes(0L);
- stats.setCount(0);
- zk.create(statPath, stats.toString().getBytes(),
- Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- } catch(KeeperException.NodeExistsException ne) {
- byte[] data = zk.getData(quotaPath, false , new Stat());
- StatsTrack strackC = new StatsTrack(new String(data));
- if (bytes != -1L) {
- strackC.setBytes(bytes);
- }
- if (numNodes != -1) {
- strackC.setCount(numNodes);
- }
- zk.setData(quotaPath, strackC.toString().getBytes(), -1);
- }
- return true;
- }
-
protected boolean processCmd(MyCommandOptions co) throws CliException, IOException, InterruptedException {
boolean watch = false;
try {
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/SetQuotaCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/SetQuotaCommand.java
index 8119454..38fc638 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/SetQuotaCommand.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/SetQuotaCommand.java
@@ -17,7 +17,7 @@
*/
package org.apache.zookeeper.cli;
-import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import org.apache.commons.cli.*;
import org.apache.zookeeper.*;
@@ -65,13 +65,17 @@ public class SetQuotaCommand extends CliCommand {
public boolean exec() throws CliException {
// get the args
String path = args[1];
+ if (path.startsWith(Quotas.quotaZookeeper)) {
+ err.println("cannot set a quota under the path: " + Quotas.quotaZookeeper);
+ return false;
+ }
if (cl.hasOption("b")) {
// we are setting the bytes quota
long bytes = Long.parseLong(cl.getOptionValue("b"));
try {
createQuota(zk, path, bytes, -1);
- } catch (KeeperException|IOException|InterruptedException ex) {
+ } catch (KeeperException|InterruptedException|IllegalArgumentException ex) {
throw new CliWrapperException(ex);
}
} else if (cl.hasOption("n")) {
@@ -79,7 +83,7 @@ public class SetQuotaCommand extends CliCommand {
int numNodes = Integer.parseInt(cl.getOptionValue("n"));
try {
createQuota(zk, path, -1L, numNodes);
- } catch (KeeperException|IOException|InterruptedException ex) {
+ } catch (KeeperException|InterruptedException|IllegalArgumentException ex) {
throw new CliWrapperException(ex);
}
} else {
@@ -91,7 +95,7 @@ public class SetQuotaCommand extends CliCommand {
public static boolean createQuota(ZooKeeper zk, String path,
long bytes, int numNodes)
- throws KeeperException, IOException, InterruptedException, MalformedPathException {
+ throws KeeperException, InterruptedException, IllegalArgumentException, MalformedPathException {
// check if the path exists. We cannot create
// quota for a path that already exists in zookeeper
// for now.
@@ -113,18 +117,9 @@ public class SetQuotaCommand extends CliCommand {
// are not the children then this path
// is an ancestor of some path that
// already has quota
- String realPath = Quotas.quotaZookeeper + path;
- try {
- List<String> children = zk.getChildren(realPath, false);
- for (String child : children) {
- if (!child.startsWith("zookeeper_")) {
- throw new IllegalArgumentException(path + " has child "
- + child + " which has a quota");
- }
- }
- } catch (KeeperException.NoNodeException ne) {
- // this is fine
- }
+
+ //check if the child node has a quota.
+ checkIfChildQuota(zk, path);
//check for any parent that has been quota
checkIfParentQuota(zk, path);
@@ -184,6 +179,40 @@ public class SetQuotaCommand extends CliCommand {
return true;
}
+ private static void checkIfChildQuota(ZooKeeper zk, String path) throws KeeperException, InterruptedException {
+ String realPath = Quotas.quotaZookeeper + path;
+
+ try {
+ ZKUtil.visitSubTreeDFS(zk, realPath, false, new AsyncCallback.StringCallback() {
+
+ @Override
+ public void processResult(int rc, String quotaPath, Object ctx, String name) {
+ List<String> children = new ArrayList<>();
+ try {
+ children = zk.getChildren(quotaPath, false);
+ } catch (KeeperException.NoNodeException ne) {
+ LOG.debug("child removed during quota check", ne);
+ return;
+ } catch (InterruptedException | KeeperException e) {
+ e.printStackTrace();
+ }
+
+ if (children.size() == 0) {
+ return;
+ }
+ for (String child : children) {
+ if (!quotaPath.equals(Quotas.quotaZookeeper + path) && Quotas.limitNode.equals(child)) {
+ throw new IllegalArgumentException(path + " has a child "
+ + quotaPath.substring(Quotas.quotaZookeeper.length()) + " which has a quota");
+ }
+ }
+ }
+ });
+ } catch (KeeperException.NoNodeException ne) {
+ // this is fine
+ }
+ }
+
private static void checkIfParentQuota(ZooKeeper zk, String path)
throws InterruptedException, KeeperException {
final String[] splits = path.split("/");
@@ -206,9 +235,9 @@ public class SetQuotaCommand extends CliCommand {
return;
}
for (String child : children) {
- if (Quotas.limitNode.equals(child)) {
+ if (!quotaPath.equals(Quotas.quotaZookeeper + path) && Quotas.limitNode.equals(child)) {
throw new IllegalArgumentException(path + " has a parent "
- + quotaPath + " which has a quota");
+ + quotaPath.substring(Quotas.quotaZookeeper.length()) + " which has a quota");
}
}
}
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumQuotaTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumQuotaTest.java
index 415bb7d..4391ce9 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumQuotaTest.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumQuotaTest.java
@@ -24,6 +24,7 @@ import org.apache.zookeeper.StatsTrack;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooKeeperMain;
import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.cli.SetQuotaCommand;
import org.apache.zookeeper.data.Stat;
import org.junit.Assert;
import org.junit.Test;
@@ -41,7 +42,7 @@ public class QuorumQuotaTest extends QuorumBase {
zk.create("/a/" + i, "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
- ZooKeeperMain.createQuota(zk, "/a", 1000L, 5000);
+ SetQuotaCommand.createQuota(zk, "/a", 1000L, 5000);
String statPath = Quotas.quotaZookeeper + "/a"+ "/" + Quotas.statNode;
byte[] data = zk.getData(statPath, false, new Stat());
StatsTrack st = new StatsTrack(new String(data));
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ZooKeeperQuotaTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ZooKeeperQuotaTest.java
index d4d217d..8c18d78 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ZooKeeperQuotaTest.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ZooKeeperQuotaTest.java
@@ -25,8 +25,9 @@ import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Quotas;
import org.apache.zookeeper.StatsTrack;
import org.apache.zookeeper.ZooKeeper;
-import org.apache.zookeeper.ZooKeeperMain;
import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.cli.MalformedPathException;
+import org.apache.zookeeper.cli.SetQuotaCommand;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.ZooKeeperServer;
import org.junit.Assert;
@@ -52,7 +53,7 @@ public class ZooKeeperQuotaTest extends ClientBase {
zk.create("/a/b/v/d", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
- ZooKeeperMain.createQuota(zk, path, 5L, 10);
+ SetQuotaCommand.createQuota(zk, path, 5L, 10);
// see if its set
String absolutePath = Quotas.quotaZookeeper + path + "/" + Quotas.limitNode;
@@ -76,4 +77,77 @@ public class ZooKeeperQuotaTest extends ClientBase {
Assert.assertNotNull("Quota is still set",
server.getZKDatabase().getDataTree().getMaxPrefixWithQuota(path) != null);
}
+
+ @Test
+ public void testSetQuota() throws IOException,
+ InterruptedException, KeeperException, MalformedPathException {
+ final ZooKeeper zk = createClient();
+
+ String path = "/c1";
+ String nodeData = "foo";
+ zk.create(path, nodeData.getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+
+ int count = 10;
+ long bytes = 5L;
+ SetQuotaCommand.createQuota(zk, path, bytes, count);
+
+ //check the limit
+ String absoluteLimitPath = Quotas.quotaZookeeper + path + "/" + Quotas.limitNode;
+ byte[] data = zk.getData(absoluteLimitPath, false, null);
+ StatsTrack st = new StatsTrack(new String(data));
+ Assert.assertEquals(bytes, st.getBytes());
+ Assert.assertEquals(count, st.getCount());
+ //check the stats
+ String absoluteStatPath = Quotas.quotaZookeeper + path + "/" + Quotas.statNode;
+ data = zk.getData(absoluteStatPath, false, null);
+ st = new StatsTrack(new String(data));
+ Assert.assertEquals(nodeData.length(), st.getBytes());
+ Assert.assertEquals(1, st.getCount());
+
+ //create another node
+ String path2 = "/c1/c2";
+ String nodeData2 = "bar";
+ zk.create(path2, nodeData2.getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+
+ absoluteStatPath = Quotas.quotaZookeeper + path + "/" + Quotas.statNode;
+ data = zk.getData(absoluteStatPath, false, null);
+ st = new StatsTrack(new String(data));
+ //check the stats
+ Assert.assertEquals(nodeData.length() + nodeData2.length(), st.getBytes());
+ Assert.assertEquals(2, st.getCount());
+ }
+
+ @Test
+ public void testSetQuotaWhenSetQuotaOnParentOrChildPath() throws IOException,
+ InterruptedException, KeeperException, MalformedPathException {
+ final ZooKeeper zk = createClient();
+
+ zk.create("/c1", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ zk.create("/c1/c2", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ zk.create("/c1/c2/c3", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ zk.create("/c1/c2/c3/c4", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ zk.create("/c1/c2/c3/c4/c5", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+
+ //set the quota on the path:/c1/c2/c3
+ SetQuotaCommand.createQuota(zk, "/c1/c2/c3", 5L, 10);
+
+ try {
+ SetQuotaCommand.createQuota(zk, "/c1", 5L, 10);
+ } catch (IllegalArgumentException e) {
+ Assert.assertEquals("/c1 has a child /c1/c2/c3 which has a quota", e.getMessage());
+ }
+
+ try {
+ SetQuotaCommand.createQuota(zk, "/c1/c2/c3/c4/c5", 5L, 10);
+ } catch (IllegalArgumentException e) {
+ Assert.assertEquals("/c1/c2/c3/c4/c5 has a parent /c1/c2/c3 which has a quota", e.getMessage());
+ }
+ }
}