Skip to content

Commit a149750

Browse files
committed
HADOOP-18922. Race condition in ZKDelegationTokenSecretManager creating znode (#6150). Contributed by Kevin Risden.
Signed-off-by: He Xiaoqiao <[email protected]>
1 parent 7540fb1 commit a149750

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/ZKDelegationTokenSecretManager.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import org.apache.zookeeper.client.ZKClientConfig;
6060
import org.apache.zookeeper.data.ACL;
6161
import org.apache.zookeeper.data.Id;
62-
import org.apache.zookeeper.data.Stat;
6362
import org.slf4j.Logger;
6463
import org.slf4j.LoggerFactory;
6564

@@ -268,10 +267,9 @@ public void startThreads() throws IOException {
268267
CuratorFramework nullNsFw = zkClient.usingNamespace(null);
269268
try {
270269
String nameSpace = "/" + zkClient.getNamespace();
271-
Stat stat = nullNsFw.checkExists().forPath(nameSpace);
272-
if (stat == null) {
273-
nullNsFw.create().creatingParentContainersIfNeeded().forPath(nameSpace);
274-
}
270+
nullNsFw.create().creatingParentContainersIfNeeded().forPath(nameSpace);
271+
} catch (KeeperException.NodeExistsException ignore) {
272+
// We don't care if the znode already exists
275273
} catch (Exception e) {
276274
throw new IOException("Could not create namespace", e);
277275
}

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/TestZKDelegationTokenSecretManager.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@
2020

2121
import java.io.IOException;
2222
import java.util.ArrayList;
23+
import java.util.Arrays;
2324
import java.util.List;
2425

26+
import java.util.concurrent.Callable;
27+
import java.util.concurrent.ExecutorService;
28+
import java.util.concurrent.Executors;
29+
import java.util.concurrent.Future;
30+
import java.util.concurrent.TimeUnit;
2531
import java.util.function.Supplier;
2632
import org.apache.curator.RetryPolicy;
2733
import org.apache.curator.framework.CuratorFramework;
@@ -572,4 +578,53 @@ public void testCreateNameSpaceRepeatedly() throws Exception {
572578
"KeeperErrorCode = NodeExists for "+workingPath,
573579
() -> createModeStat.forPath(workingPath));
574580
}
581+
582+
@Test
583+
public void testMultipleInit() throws Exception {
584+
585+
String connectString = zkServer.getConnectString();
586+
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
587+
Configuration conf = getSecretConf(connectString);
588+
CuratorFramework curatorFramework =
589+
CuratorFrameworkFactory.builder()
590+
.connectString(connectString)
591+
.retryPolicy(retryPolicy)
592+
.build();
593+
curatorFramework.start();
594+
ZKDelegationTokenSecretManager.setCurator(curatorFramework);
595+
596+
DelegationTokenManager tm1 = new DelegationTokenManager(conf, new Text("foo"));
597+
DelegationTokenManager tm2 = new DelegationTokenManager(conf, new Text("bar"));
598+
// When the init method is called,
599+
// the ZKDelegationTokenSecretManager#startThread method will be called,
600+
// and the creatingParentContainersIfNeeded will be called to create the nameSpace.
601+
ExecutorService executorService = Executors.newFixedThreadPool(2);
602+
603+
Callable<Boolean> tm1Callable = () -> {
604+
tm1.init();
605+
return true;
606+
};
607+
Callable<Boolean> tm2Callable = () -> {
608+
tm2.init();
609+
return true;
610+
};
611+
List<Future<Boolean>> futures = executorService.invokeAll(
612+
Arrays.asList(tm1Callable, tm2Callable));
613+
for(Future<Boolean> future : futures) {
614+
Assert.assertTrue(future.get());
615+
}
616+
executorService.shutdownNow();
617+
Assert.assertTrue(executorService.awaitTermination(1, TimeUnit.SECONDS));
618+
tm1.destroy();
619+
tm2.destroy();
620+
621+
String workingPath = "/" + conf.get(ZKDelegationTokenSecretManager.ZK_DTSM_ZNODE_WORKING_PATH,
622+
ZKDelegationTokenSecretManager.ZK_DTSM_ZNODE_WORKING_PATH_DEAFULT) + "/ZKDTSMRoot";
623+
624+
// Check if the created NameSpace exists.
625+
Stat stat = curatorFramework.checkExists().forPath(workingPath);
626+
Assert.assertNotNull(stat);
627+
628+
curatorFramework.close();
629+
}
575630
}

0 commit comments

Comments
 (0)