-
Notifications
You must be signed in to change notification settings - Fork 229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add method to create full key path if it does not exist #2607
Conversation
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
3593218
to
17ac48b
Compare
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java
Outdated
Show resolved
Hide resolved
while (--i >= 0) { | ||
if (EntryMode.TTL.equals(mode)) { | ||
createWithTTL(nodePaths.get(i), data, ttl); | ||
} else { | ||
create(nodePaths.get(i), data, i == 0 ? mode : parentMode); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This require try catch that if two threads parallel creation the children at the same time. Also I would imagine this should be same path as previous one.
@xyuanlu could you please help @GrantPSpencer walk through the idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I fully understand this race condition yet. I'll sync up with @xyuanlu to get more info
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to ignore when NodeExistsException thrown when we try to create the parents, only throw when we try to create the full node path. This means we don't throw an error if another thread has already created the parents we are trying to create.
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java
Outdated
Show resolved
Hide resolved
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java
Show resolved
Hide resolved
} | ||
} | ||
|
||
// Reattempt creation of children that failed due to NoNodeException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update this comment.
} | ||
|
||
// Reattempt creation of children that failed due to NoNodeException | ||
while (--i >= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this i ++ or --I? We should start with 0, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My approach is to use the same counter that we used in the previous loop. I'll walk through it below:
Lets say customer calls recursiveCreate("/first/second/third")
ZK only has "/first" node
This gets split into three separate nodes comprising the chain -->
nodePaths = ["/first/second/third", "/first/second", "/first"]
The first while loop we start with i=0 and increment up (i++) if we don't create it
- i=0, Check if parent of nodePaths.get(i) -> "/first/second/third" exists, it does not so i++
- i=1, Check if parent of nodePaths.get(i) -> "/first/second" exists, it exists so create "/first/second" and exit loop
The second while loop then goes back through the list of nodes and attempts to create the ones we missed
- pre-decrement i, so i=0, create nodePaths.get(i)->"/first/second/third"
This approach of starting from the final child node is my attempt at optimizing over starting from the root node and then working down to the final child node. Unfortunately, my code has bloated quite a bite as a result :/
Also, we could have this as one loop, but I separated it into two as I did not want a possibility where a thread is stuck in an endless loop of incrementing/decrementing due to some unexpected behavior.
if (i != 0) { | ||
throw e; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes the API complicated behavior. I would suggest to consider if there is exist nodes, then we just stop disregard it is root race condition or not.
Otherwise, the API behavior would be a little bit complicate. We can just let user to retry create it recursively if it is root race condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Metaclient's normal create behavior is to throw error when creation fails due to NodeExistsException. So should we likewise just let this error be thrown and not catch it? For context, this change was to address your comments here regarding two threads creating children at same time:
#2607 (comment)
Pull request approved by @junkaixue |
Co-authored-by: Grant Palau Spencer <[email protected]>
* MetaClientCache Part 1 - API's, configs, and builders (#2612) MetaClientCache Part 1 - API's, configs, and builders --------- Co-authored-by: mapeng <[email protected]> * Skip one time listener re-register for exists for ZkClient - MetaClient usage. (#2637) * Lattice cache - caching just data implementation (#2619) Lattice cache - caching just data implementation --------- Co-authored-by: mapeng <[email protected]> * Add recursiveCreate functionality to metaclient (#2607) Co-authored-by: Grant Palau Spencer <[email protected]> * Lattice Children Cache Implementation(#2623) Co-authored-by: mapeng <[email protected]> --------- Co-authored-by: Marcos Rico Peng <[email protected]> Co-authored-by: mapeng <[email protected]> Co-authored-by: Grant Paláu Spencer <[email protected]> Co-authored-by: Grant Palau Spencer <[email protected]>
Issues
Metaclient currently does not offer the functionality of attempting to create a key's parents if they do not exist.
I'd like to expose a method that does the following:
Assume no nodes have been created
createFullPath("/a/b/c/d", data)
This would then create nodes /a, /b, and /c with null values and lastly create node /d with the data passed in.
Description
Add functionality to create the full path to a key if the path does not already exist.
Tests
Added unit tests to both TestStressZkClient.Java and TestZkMetaClient.java
Changes that Break Backward Compatibility (Optional)
None. Only new method
Documentation (Optional)
No documentation added
Commits
Code Quality
(helix-style-intellij.xml if IntelliJ IDE is used)