curator icon indicating copy to clipboard operation
curator copied to clipboard

[CURATOR-499] ZKPaths strips trailing "/" incorrectly when creating sequential nodes

Open jira-importer opened this issue 7 years ago • 9 comments

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

jira-importer avatar Jan 01 '19 00:01 jira-importer

randgalt:

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?

jira-importer avatar Jan 08 '19 12:01 jira-importer

mwang5:

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.

jira-importer avatar Jan 08 '19 19:01 jira-importer

randgalt:

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)

jira-importer avatar Jan 08 '19 19:01 jira-importer

mwang5:

I'm okay using a special-case api for this.

jira-importer avatar Jan 08 '19 19:01 jira-importer

randgalt:

Yeah, I think .withEmptyPath() seems the safest way to go. We'd appreciate a PR with this change

jira-importer avatar Jan 08 '19 19:01 jira-importer

randgalt:

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; }

jira-importer avatar Jan 08 '19 19:01 jira-importer

mwang5:

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);

jira-importer avatar Jan 08 '19 19:01 jira-importer

randgalt:

Yeah, that'd be good

jira-importer avatar Jan 08 '19 19:01 jira-importer

githubbot:

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".


jira-importer avatar Jan 10 '19 17:01 jira-importer