From d2c4492f29e978836329ec50320b3006ec778871 Mon Sep 17 00:00:00 2001 From: Grant Palau Spencer Date: Mon, 25 Sep 2023 14:58:10 -0700 Subject: [PATCH] catch create parent race condition exception --- .../metaclient/impl/zk/ZkMetaClient.java | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java index 14a0a1a53f..5ab60a36eb 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java @@ -41,6 +41,7 @@ import org.apache.helix.metaclient.api.OpResult; import org.apache.helix.metaclient.exception.MetaClientException; import org.apache.helix.metaclient.exception.MetaClientNoNodeException; +import org.apache.helix.metaclient.exception.MetaClientNodeExistsException; import org.apache.helix.metaclient.impl.zk.adapter.ChildListenerAdapter; import org.apache.helix.metaclient.impl.zk.adapter.DataListenerAdapter; import org.apache.helix.metaclient.impl.zk.adapter.DirectChildListenerAdapter; @@ -137,12 +138,21 @@ private void iterativeCreate(String key, T data, EntryMode mode, long ttl) { // 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 then create and exit loop - if (i == nodePaths.size() -1 || _zkClient.exists(nodePaths.get(i+1))) { - if (EntryMode.TTL.equals(mode)) { - createWithTTL(nodePaths.get(i), data, ttl); - } else { - create(nodePaths.get(i), data, i == 0 ? mode : parentMode); + // 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 @@ -153,10 +163,17 @@ private void iterativeCreate(String key, T data, EntryMode mode, long ttl) { // Reattempt creation of children that failed due to NoNodeException while (--i >= 0) { - if (EntryMode.TTL.equals(mode)) { - createWithTTL(nodePaths.get(i), data, ttl); - } else { - create(nodePaths.get(i), data, i == 0 ? mode : parentMode); + try { + if (EntryMode.TTL.equals(mode)) { + createWithTTL(nodePaths.get(i), data, ttl); + } else { + create(nodePaths.get(i), data, i == 0 ? mode : parentMode); + } + // Catch same race condition as above + } catch (MetaClientNodeExistsException e) { + if (i != 0) { + throw e; + } } } }