This is an automated email from the ASF dual-hosted git repository.
CRZbulabula pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 6042c4f909f Fix the issue where `list user` throws an error when
executed concurrently with `create user`. (#17583)
6042c4f909f is described below
commit 6042c4f909f2be09fe2ce54412e6aafe1df747d7
Author: wenyanshi-123 <[email protected]>
AuthorDate: Wed May 6 10:54:21 2026 +0800
Fix the issue where `list user` throws an error when executed concurrently
with `create user`. (#17583)
---
.../db/auth/user/LocalFileUserManagerTest.java | 49 ++++++++++++++++++++++
.../iotdb/commons/auth/role/BasicRoleManager.java | 6 +--
2 files changed, 52 insertions(+), 3 deletions(-)
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserManagerTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserManagerTest.java
index 06fc8ae3e02..3043c4a638a 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserManagerTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserManagerTest.java
@@ -32,8 +32,15 @@ import org.junit.Before;
import org.junit.Test;
import java.io.File;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class LocalFileUserManagerTest {
@@ -78,4 +85,46 @@ public class LocalFileUserManagerTest {
User user = manager.getEntity("testRaw");
Assert.assertEquals(user.getPassword(),
AuthUtils.encryptPassword("password1"));
}
+
+ @Test
+ public void testConcurrentListAndCreateDropUser() throws Exception {
+ AtomicReference<Throwable> error = new AtomicReference<>();
+ AtomicBoolean running = new AtomicBoolean(true);
+ CyclicBarrier barrier = new CyclicBarrier(2);
+ ExecutorService pool = Executors.newFixedThreadPool(2);
+
+ pool.submit(
+ () -> {
+ try {
+ barrier.await();
+ while (running.get()) {
+ manager.listAllEntities();
+ manager.listAllEntitiesInfo();
+ }
+ } catch (Throwable t) {
+ error.compareAndSet(null, t);
+ }
+ });
+
+ pool.submit(
+ () -> {
+ try {
+ barrier.await();
+ for (int i = 0; i < 500; i++) {
+ String name = "user_" + i;
+ manager.createUser(name, "password_" + i, false);
+ manager.deleteEntity(name);
+ }
+ } catch (Throwable t) {
+ error.compareAndSet(null, t);
+ } finally {
+ running.set(false);
+ }
+ });
+
+ pool.shutdown();
+ assertTrue(pool.awaitTermination(30, TimeUnit.SECONDS));
+ assertNull(
+ "ConcurrentModificationException during concurrent list/create/drop
user", error.get());
+ }
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
index f6804d3055c..b5fc900c003 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
@@ -36,9 +36,9 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* This class reads roles from local files through LocalFileRoleAccessor and
manages them in a hash
@@ -63,12 +63,12 @@ public abstract class BasicRoleManager implements
IEntityManager, SnapshotProces
}
protected BasicRoleManager() {
- this.entityMap = new HashMap<>();
+ this.entityMap = new ConcurrentHashMap<>();
this.lock = new HashLock();
}
protected BasicRoleManager(IEntityAccessor accessor) {
- this.entityMap = new HashMap<>();
+ this.entityMap = new ConcurrentHashMap<>();
this.accessor = accessor;
this.lock = new HashLock();
this.accessor.reset();