GrantPSpencer commented on code in PR #2607:
URL: https://github.com/apache/helix/pull/2607#discussion_r1336470794
##########
meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java:
##########
@@ -115,6 +117,67 @@ public void create(String key, Object data,
MetaClientInterface.EntryMode mode)
}
}
+ @Override
+ public void recursiveCreate(String key, T data, EntryMode mode) {
+ // Function named recursiveCreate to match naming scheme, but actual work
is iterative
+ iterativeCreate(key, data, mode, -1);
+ }
+
+ @Override
+ public void recursiveCreateWithTTL(String key, T data, long ttl) {
+ iterativeCreate(key, data, EntryMode.TTL, ttl);
+ }
+
+ private void iterativeCreate(String key, T data, EntryMode mode, long ttl) {
+ List<String> nodePaths = separateIntoUniqueNodePaths(key);
+ int i = 0;
+ // Ephemeral nodes cant have children, so change mode when creating parents
+ EntryMode parentMode = (EntryMode.EPHEMERAL.equals(mode) ?
+ EntryMode.PERSISTENT : mode);
+
+ // Iterate over paths, starting with full key then attempting each
successive parent
+ // Try /a/b/c, if parent /a/b, does not exist, then try to create parent,
etc..
+ while (i < nodePaths.size()) {
+ // If parent exists or there is no parent node, then try to create the
node
+ // and break out of loop on successful create
+ if (i == nodePaths.size() - 1 || _zkClient.exists(nodePaths.get(i+1))) {
+ try {
+ if (EntryMode.TTL.equals(mode)) {
+ createWithTTL(nodePaths.get(i), data, ttl);
+ } else {
+ create(nodePaths.get(i), data, i == 0 ? mode : parentMode);
+ }
+ // Race condition may occur where a node is created by another thread
in between loops.
+ // We should not throw error if this occurs for parent nodes, only for
the full node path.
+ } catch (MetaClientNodeExistsException e) {
+ if (i != 0) {
+ throw e;
+ }
+ }
+ break;
+ // Else try to create parent in next loop iteration
+ } else {
+ i++;
+ }
+ }
+
+ // Reattempt creation of children that failed due to NoNodeException
+ while (--i >= 0) {
Review Comment:
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.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]