This is an automated email from the ASF dual-hosted git repository.

kturner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new 9812f05f4e Removed table name lock in Manager (#5801)
9812f05f4e is described below

commit 9812f05f4e4e71fc91f3d26ac9d232d6dcb8dbcf
Author: Imirie Billey <[email protected]>
AuthorDate: Tue Aug 19 13:29:59 2025 -0400

    Removed table name lock in Manager (#5801)
    
    Created `testDefendAgainstThreadsCreateSameTableNameConcurrently()` in 
TableOperationsIT to ensure that Zookeeper can defend against concurrent create 
table operations that try to create a table with the same table name. Verified 
it worked and removed the lock in the call method in the PopulateZookeeper file.
---
 .../manager/tableOps/create/PopulateZookeeper.java | 36 ++++++--------
 .../apache/accumulo/test/TableOperationsIT.java    | 55 ++++++++++++++++++++++
 2 files changed, 70 insertions(+), 21 deletions(-)

diff --git 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/create/PopulateZookeeper.java
 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/create/PopulateZookeeper.java
index 0517e7c8ea..4e7b01e09c 100644
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/create/PopulateZookeeper.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/create/PopulateZookeeper.java
@@ -51,30 +51,24 @@ class PopulateZookeeper extends ManagerRepo {
   public Repo<Manager> call(FateId fateId, Manager manager) throws Exception {
     // reserve the table name in zookeeper or fail
 
-    Utils.getTableNameLock().lock();
-    try {
-      var context = manager.getContext();
-      // write tableName & tableId, first to Table Mapping and then to 
Zookeeper
-      
context.getTableMapping(tableInfo.getNamespaceId()).put(tableInfo.getTableId(),
-          tableInfo.getTableName(), TableOperation.CREATE);
-      manager.getTableManager().addTable(tableInfo.getTableId(), 
tableInfo.getNamespaceId(),
-          tableInfo.getTableName());
-
-      try {
-        PropUtil.setProperties(context, 
TablePropKey.of(tableInfo.getTableId()), tableInfo.props);
-      } catch (IllegalStateException ex) {
-        throw new ThriftTableOperationException(null, tableInfo.getTableName(),
-            TableOperation.CREATE, TableOperationExceptionType.OTHER,
-            "Property or value not valid for create " + 
tableInfo.getTableName() + " in "
-                + tableInfo.props);
-      }
+    var context = manager.getContext();
+    // write tableName & tableId, first to Table Mapping and then to Zookeeper
+    
context.getTableMapping(tableInfo.getNamespaceId()).put(tableInfo.getTableId(),
+        tableInfo.getTableName(), TableOperation.CREATE);
+    manager.getTableManager().addTable(tableInfo.getTableId(), 
tableInfo.getNamespaceId(),
+        tableInfo.getTableName());
 
-      context.clearTableListCache();
-      return new ChooseDir(tableInfo);
-    } finally {
-      Utils.getTableNameLock().unlock();
+    try {
+      PropUtil.setProperties(context, TablePropKey.of(tableInfo.getTableId()), 
tableInfo.props);
+    } catch (IllegalStateException ex) {
+      throw new ThriftTableOperationException(null, tableInfo.getTableName(), 
TableOperation.CREATE,
+          TableOperationExceptionType.OTHER, "Property or value not valid for 
create "
+              + tableInfo.getTableName() + " in " + tableInfo.props);
     }
 
+    context.clearTableListCache();
+    return new ChooseDir(tableInfo);
+
   }
 
   @Override
diff --git a/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java 
b/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java
index 2b9fae4677..75730ed8b1 100644
--- a/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java
@@ -39,10 +39,12 @@ import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 import org.apache.accumulo.core.client.Accumulo;
@@ -79,6 +81,7 @@ import org.apache.accumulo.harness.AccumuloClusterHarness;
 import org.apache.accumulo.manager.tableOps.Utils;
 import org.apache.accumulo.test.functional.BadIterator;
 import org.apache.accumulo.test.functional.FunctionalTestUtils;
+import org.apache.accumulo.test.util.Wait;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hadoop.io.Text;
 import org.junit.jupiter.api.AfterEach;
@@ -202,6 +205,58 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
     accumuloClient.tableOperations().delete(tableName);
   }
 
+  @Test
+  public void testDefendAgainstThreadsCreateSameTableNameConcurrently()
+      throws ExecutionException, InterruptedException {
+    final int initialTableSize = 
accumuloClient.tableOperations().list().size();
+    final int numTasks = 10;
+    ExecutorService pool = Executors.newFixedThreadPool(numTasks);
+
+    for (String tablename : getUniqueNames(30)) {
+      CountDownLatch startSignal = new CountDownLatch(1);
+      AtomicInteger numTasksRunning = new AtomicInteger(0);
+
+      List<Future<Boolean>> futureList = new ArrayList<>();
+
+      for (int j = 0; j < numTasks; j++) {
+        Future<Boolean> future = pool.submit(() -> {
+          boolean result;
+          try {
+            numTasksRunning.incrementAndGet();
+            startSignal.await();
+            accumuloClient.tableOperations().create(tablename);
+            result = true;
+          } catch (TableExistsException e) {
+            result = false;
+          }
+          return result;
+        });
+        futureList.add(future);
+      }
+
+      Wait.waitFor(() -> numTasksRunning.get() == numTasks);
+
+      startSignal.countDown();
+
+      int taskSucceeded = 0;
+      int taskFailed = 0;
+      for (Future<Boolean> result : futureList) {
+        if (result.get() == true) {
+          taskSucceeded++;
+        } else {
+          taskFailed++;
+        }
+      }
+
+      assertEquals(1, taskSucceeded);
+      assertEquals(9, taskFailed);
+    }
+
+    assertEquals(30, accumuloClient.tableOperations().list().size() - 
initialTableSize);
+
+    pool.shutdown();
+  }
+
   @Test
   public void createTableWithSystemUser() throws TableExistsException, 
AccumuloException,
       AccumuloSecurityException, TableNotFoundException {

Reply via email to