[CURATOR-499] ZKPaths strips trailing "/" incorrectly when creating sequential nodes
I think this was introduced in CURATOR-166, which changed ZKPaths to strip trailing slashes from child nodes.
This is fine in most cases: it made it so
curatorFramework.create()
.forPath("/path/to/node/", data);
would create a node at /path/to/node.
However, if you want to create a sequential node:
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL)
.forPath("/path/to/node/", data);
In clients after CURATOR-166 (2.7.1 and higher), this will create a node /path/to/node00000001. Before, and if you call the zookeeper cli with the same options, it would create a node /path/to/node/00000001.
This effectively makes it so you cannot use curator to create sequential nodes where the entire node name is the sequence number.
Originally reported by mwang5, imported from: ZKPaths strips trailing "/" incorrectly when creating sequential nodes
- assignee: randgalt
- status: Open
- priority: Minor
- resolution: Unresolved
- imported: 2025-01-21
So the intent is to create a ZNode with "no name" and have ZK append the sequence number? That was never meant to be supported by Curator (I didn't even know ZK supported it). I'd say that this would be a special case and require a special-case API. What's the use-case for this? Why is this needed?
That is correct.
Zookeeper does support this (at least, via zkCli)
[zk: localhost:2181(CONNECTED) 5] create -s /foo/ data Created /foo/0000000000 [zk: localhost:2181(CONNECTED) 6] create -s /foo/ data Created /foo/0000000001
My use case is we are using zookeeper to store data and we're using the sequence number as a globally unique, auto-incrementing id. The schema looks like
/Application/Users/0000000000 /Application/Users/0000000001 /Application/Users/0000000002 ...
where the data for each node is the data for that user. Because of the behavior change in curator 2.7.1, we're unable to upgrade to newer versions of curator without migrating the data in zookeeper.
Dang - we're in a bit of a catch-22 here. It's been in it's current form long enough that to support this behavior we'd have to consider it "new" behavior. I can imagine we'd use some kind of special spelling, maybe forPath("/path/to/node//", data) or something.
Or, another "verb" in the DSL: .withEmptyPath().forPath("/path/to/node/", data)
Yeah, I think .withEmptyPath() seems the safest way to go. We'd appreciate a PR with this change ![]()
Thinking more, maybe add another overload of forPath that takes an encoding type:
public enum PathEncodingType { STANDARD, EMPTY }public interface PathAndBytesable<T> { ... public T forPath(String path, byte[] data, PathEncodingType type) throws Exception; }
Since this only makes sense with sequential creates, as a non-sequential create will just fail with no name, would it make sense to associate this with the CreateMode? Either:
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL, PathEncodingType.ALLOW_EMPTY)
.forPath(path, data);
or just adding two more CreateModes, PERSISTENT_SEQUENTIAL_WITH_EMPTY / EPHEMERAL_SEQUENTIAL_WITH_EMPTY (kind of a mouthful, may not so good)?
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL_WITH_EMPTY)
.forPath(path, data);
GitHub user marquiswang opened a pull request:
https://github.com/apache/curator/pull/300
CURATOR-499 Allow creating sequential nodes with an empty name
Add CreateModable#withMode(CreateMode, PathEncodingType) where
PathEncodingType is an enum with values DEFAULT and ALLOW_EMPTY.
When a node is created with ALLOW_EMPTY, trailing /s will not be
removed from the path.
This should not be used except with sequential CreateModes, as it will
fail with:
java.lang.IllegalArgumentException: Path must not end with / character
Calling the following:
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL, PathEncodingType.ALLOW_EMPTY)
.forPath("/foo/bar/, data);
Will create a node "/foo/bar/000000000X", whereas calling:
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL)
.forPath("/foo/bar/, data);
Will create a node "/foo/bar000000000X".
You can merge this pull request into a Git repository by running:
$ git pull https://github.com/marquiswang/curator master
Alternatively you can review and apply these changes as the patch at:
https://github.com/apache/curator/pull/300.patch
To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:
This closes #300
commit df2ad2a27eeeb21a30dd1a7e9c05416d23b22d2a
Author: Marquis Wong
Date: 2019-01-10T17:20:22Z
CURATOR-499 Allow creating sequential nodes with an empty name
Add CreateModable#withMode(CreateMode, PathEncodingType) where
PathEncodingType is an enum with values DEFAULT and ALLOW_EMPTY.
When a node is created with ALLOW_EMPTY, trailing /s will not be
removed from the path.
This should not be used except with sequential CreateModes, as it will
fail with:
java.lang.IllegalArgumentException: Path must not end with / character
Calling the following:
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL, PathEncodingType.ALLOW_EMPTY)
.forPath("/foo/bar/, data);
Will create a node "/foo/bar/000000000X", whereas calling:
curatorFramework.create()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL)
.forPath("/foo/bar/, data);
Will create a node "/foo/bar000000000X".