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

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


The following commit(s) were added to refs/heads/main by this push:
     new e8241a967 [#6044] improve(lock): optimization tree lock when drop and 
load Table/Schema (#6063)
e8241a967 is described below

commit e8241a96701a2e135db31a94474e3758464f4427
Author: Xun <[email protected]>
AuthorDate: Fri Jan 3 15:58:20 2025 +0800

    [#6044] improve(lock): optimization tree lock when drop and load 
Table/Schema (#6063)
    
    ### What changes were proposed in this pull request?
    
    Modify Schema and Table RESTful interface lock operations.
    
    ### Why are the changes needed?
    
    Fix: #6044
    
    ### Does this PR introduce _any_ user-facing change?
    
    N/A
    
    ### How was this patch tested?
    
    CI Passed.
---
 .../catalog/SchemaOperationDispatcher.java         |  64 +++++-----
 .../catalog/TableOperationDispatcher.java          | 131 ++++++++++++---------
 .../apache/gravitino/utils/NameIdentifierUtil.java |  31 ++++-
 .../server/web/rest/SchemaOperations.java          |   6 +-
 .../gravitino/server/web/rest/TableOperations.java |   6 +-
 5 files changed, 139 insertions(+), 99 deletions(-)

diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java
 
b/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java
index 789e5e471..8f36ce0d9 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java
@@ -277,36 +277,40 @@ public class SchemaOperationDispatcher extends 
OperationDispatcher implements Sc
   @Override
   public boolean dropSchema(NameIdentifier ident, boolean cascade) throws 
NonEmptySchemaException {
     NameIdentifier catalogIdent = getCatalogIdentifier(ident);
-    boolean droppedFromCatalog =
-        doWithCatalog(
-            catalogIdent,
-            c -> c.doWithSchemaOps(s -> s.dropSchema(ident, cascade)),
-            NonEmptySchemaException.class,
-            RuntimeException.class);
-
-    // For managed schema, we don't need to drop the schema from the store 
again.
-    boolean isManagedSchema = isManagedEntity(catalogIdent, 
Capability.Scope.SCHEMA);
-    if (isManagedSchema) {
-      return droppedFromCatalog;
-    }
-
-    // For unmanaged schema, it could happen that the schema:
-    // 1. Is not found in the catalog (dropped directly from underlying 
sources)
-    // 2. Is found in the catalog but not in the store (not managed by 
Gravitino)
-    // 3. Is found in the catalog and the store (managed by Gravitino)
-    // 4. Neither found in the catalog nor in the store.
-    // In all situations, we try to delete the schema from the store, but we 
don't take the
-    // return value of the store operation into account. We only take the 
return value of the
-    // catalog into account.
-    try {
-      store.delete(ident, SCHEMA, cascade);
-    } catch (NoSuchEntityException e) {
-      LOG.warn("The schema to be dropped does not exist in the store: {}", 
ident, e);
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-
-    return droppedFromCatalog;
+    return TreeLockUtils.doWithTreeLock(
+        catalogIdent,
+        LockType.WRITE,
+        () -> {
+          boolean droppedFromCatalog =
+              doWithCatalog(
+                  catalogIdent,
+                  c -> c.doWithSchemaOps(s -> s.dropSchema(ident, cascade)),
+                  NonEmptySchemaException.class,
+                  RuntimeException.class);
+
+          // For managed schema, we don't need to drop the schema from the 
store again.
+          boolean isManagedSchema = isManagedEntity(catalogIdent, 
Capability.Scope.SCHEMA);
+          if (isManagedSchema) {
+            return droppedFromCatalog;
+          }
+
+          // For unmanaged schema, it could happen that the schema:
+          // 1. Is not found in the catalog (dropped directly from underlying 
sources)
+          // 2. Is found in the catalog but not in the store (not managed by 
Gravitino)
+          // 3. Is found in the catalog and the store (managed by Gravitino)
+          // 4. Neither found in the catalog nor in the store.
+          // In all situations, we try to delete the schema from the store, 
but we don't take the
+          // return value of the store operation into account. We only take 
the return value of the
+          // catalog into account.
+          try {
+            store.delete(ident, SCHEMA, cascade);
+          } catch (NoSuchEntityException e) {
+            LOG.warn("The schema to be dropped does not exist in the store: 
{}", ident, e);
+          } catch (Exception e) {
+            throw new RuntimeException(e);
+          }
+          return droppedFromCatalog;
+        });
   }
 
   private void importSchema(NameIdentifier identifier) {
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java 
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
index 7a4c5a565..3e6aa2abb 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
@@ -62,6 +62,7 @@ import 
org.apache.gravitino.rel.expressions.transforms.Transform;
 import org.apache.gravitino.rel.indexes.Index;
 import org.apache.gravitino.rel.indexes.Indexes;
 import org.apache.gravitino.storage.IdGenerator;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.apache.gravitino.utils.PrincipalUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -269,33 +270,41 @@ public class TableOperationDispatcher extends 
OperationDispatcher implements Tab
    */
   @Override
   public boolean dropTable(NameIdentifier ident) {
-    NameIdentifier catalogIdent = getCatalogIdentifier(ident);
-    boolean droppedFromCatalog =
-        doWithCatalog(
-            catalogIdent, c -> c.doWithTableOps(t -> t.dropTable(ident)), 
RuntimeException.class);
-
-    // For unmanaged table, it could happen that the table:
-    // 1. Is not found in the catalog (dropped directly from underlying 
sources)
-    // 2. Is found in the catalog but not in the store (not managed by 
Gravitino)
-    // 3. Is found in the catalog and the store (managed by Gravitino)
-    // 4. Neither found in the catalog nor in the store.
-    // In all situations, we try to delete the schema from the store, but we 
don't take the
-    // return value of the store operation into account. We only take the 
return value of the
-    // catalog into account.
-    //
-    // For managed table, we should take the return value of the store 
operation into account.
-    boolean droppedFromStore = false;
-    try {
-      droppedFromStore = store.delete(ident, TABLE);
-    } catch (NoSuchEntityException e) {
-      LOG.warn("The table to be dropped does not exist in the store: {}", 
ident, e);
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-
-    return isManagedEntity(catalogIdent, Capability.Scope.TABLE)
-        ? droppedFromStore
-        : droppedFromCatalog;
+    NameIdentifier schemaIdentifier = 
NameIdentifierUtil.getSchemaIdentifier(ident);
+    return TreeLockUtils.doWithTreeLock(
+        schemaIdentifier,
+        LockType.WRITE,
+        () -> {
+          NameIdentifier catalogIdent = getCatalogIdentifier(ident);
+          boolean droppedFromCatalog =
+              doWithCatalog(
+                  catalogIdent,
+                  c -> c.doWithTableOps(t -> t.dropTable(ident)),
+                  RuntimeException.class);
+
+          // For unmanaged table, it could happen that the table:
+          // 1. Is not found in the catalog (dropped directly from underlying 
sources)
+          // 2. Is found in the catalog but not in the store (not managed by 
Gravitino)
+          // 3. Is found in the catalog and the store (managed by Gravitino)
+          // 4. Neither found in the catalog nor in the store.
+          // In all situations, we try to delete the schema from the store, 
but we don't take the
+          // return value of the store operation into account. We only take 
the return value of the
+          // catalog into account.
+          //
+          // For managed table, we should take the return value of the store 
operation into account.
+          boolean droppedFromStore = false;
+          try {
+            droppedFromStore = store.delete(ident, TABLE);
+          } catch (NoSuchEntityException e) {
+            LOG.warn("The table to be dropped does not exist in the store: 
{}", ident, e);
+          } catch (Exception e) {
+            throw new RuntimeException(e);
+          }
+
+          return isManagedEntity(catalogIdent, Capability.Scope.TABLE)
+              ? droppedFromStore
+              : droppedFromCatalog;
+        });
   }
 
   /**
@@ -314,37 +323,43 @@ public class TableOperationDispatcher extends 
OperationDispatcher implements Tab
    */
   @Override
   public boolean purgeTable(NameIdentifier ident) throws 
UnsupportedOperationException {
-    NameIdentifier catalogIdent = getCatalogIdentifier(ident);
-    boolean droppedFromCatalog =
-        doWithCatalog(
-            catalogIdent,
-            c -> c.doWithTableOps(t -> t.purgeTable(ident)),
-            RuntimeException.class,
-            UnsupportedOperationException.class);
-
-    // For unmanaged table, it could happen that the table:
-    // 1. Is not found in the catalog (dropped directly from underlying 
sources)
-    // 2. Is found in the catalog but not in the store (not managed by 
Gravitino)
-    // 3. Is found in the catalog and the store (managed by Gravitino)
-    // 4. Neither found in the catalog nor in the store.
-    // In all situations, we try to delete the schema from the store, but we 
don't take the
-    // return value of the store operation into account. We only take the 
return value of the
-    // catalog into account.
-    //
-    // For managed table, we should take the return value of the store 
operation into account.
-    boolean droppedFromStore = false;
-    try {
-      droppedFromStore = store.delete(ident, TABLE);
-    } catch (NoSuchEntityException e) {
-      LOG.warn("The table to be purged does not exist in the store: {}", 
ident, e);
-      return false;
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-
-    return isManagedEntity(catalogIdent, Capability.Scope.TABLE)
-        ? droppedFromStore
-        : droppedFromCatalog;
+    NameIdentifier schemaIdentifier = 
NameIdentifierUtil.getSchemaIdentifier(ident);
+    return TreeLockUtils.doWithTreeLock(
+        schemaIdentifier,
+        LockType.WRITE,
+        () -> {
+          NameIdentifier catalogIdent = getCatalogIdentifier(ident);
+          boolean droppedFromCatalog =
+              doWithCatalog(
+                  catalogIdent,
+                  c -> c.doWithTableOps(t -> t.purgeTable(ident)),
+                  RuntimeException.class,
+                  UnsupportedOperationException.class);
+
+          // For unmanaged table, it could happen that the table:
+          // 1. Is not found in the catalog (dropped directly from underlying 
sources)
+          // 2. Is found in the catalog but not in the store (not managed by 
Gravitino)
+          // 3. Is found in the catalog and the store (managed by Gravitino)
+          // 4. Neither found in the catalog nor in the store.
+          // In all situations, we try to delete the schema from the store, 
but we don't take the
+          // return value of the store operation into account. We only take 
the return value of the
+          // catalog into account.
+          //
+          // For managed table, we should take the return value of the store 
operation into account.
+          boolean droppedFromStore = false;
+          try {
+            droppedFromStore = store.delete(ident, TABLE);
+          } catch (NoSuchEntityException e) {
+            LOG.warn("The table to be purged does not exist in the store: {}", 
ident, e);
+            return false;
+          } catch (Exception e) {
+            throw new RuntimeException(e);
+          }
+
+          return isManagedEntity(catalogIdent, Capability.Scope.TABLE)
+              ? droppedFromStore
+              : droppedFromCatalog;
+        });
   }
 
   private EntityCombinedTable importTable(NameIdentifier identifier) {
diff --git 
a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java 
b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
index b656bfa95..2b7e69ebe 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
@@ -249,7 +249,8 @@ public class NameIdentifierUtil {
   public static NameIdentifier getCatalogIdentifier(NameIdentifier ident)
       throws IllegalNameIdentifierException {
     NameIdentifier.check(
-        ident.name() != null, "The name variable in the NameIdentifier must 
have value.");
+        ident.name() != null && !ident.name().isEmpty(),
+        "The name variable in the NameIdentifier must have value.");
     Namespace.check(
         ident.namespace() != null && !ident.namespace().isEmpty(),
         "Catalog namespace must be non-null and have 1 level, the input 
namespace is %s",
@@ -265,6 +266,34 @@ public class NameIdentifierUtil {
     return NameIdentifier.of(allElems.get(0), allElems.get(1));
   }
 
+  /**
+   * Try to get the schema {@link NameIdentifier} from the given {@link 
NameIdentifier}.
+   *
+   * @param ident The {@link NameIdentifier} to check.
+   * @return The schema {@link NameIdentifier}
+   * @throws IllegalNameIdentifierException If the given {@link 
NameIdentifier} does not include
+   *     schema name
+   */
+  public static NameIdentifier getSchemaIdentifier(NameIdentifier ident)
+      throws IllegalNameIdentifierException {
+    NameIdentifier.check(
+        ident.name() != null && !ident.name().isEmpty(),
+        "The name variable in the NameIdentifier must have value.");
+    Namespace.check(
+        ident.namespace() != null && !ident.namespace().isEmpty() && 
ident.namespace().length() > 1,
+        "Schema namespace must be non-null and at least 1 level, the input 
namespace is %s",
+        ident.namespace());
+
+    List<String> allElems =
+        Stream.concat(Arrays.stream(ident.namespace().levels()), 
Stream.of(ident.name()))
+            .collect(Collectors.toList());
+    if (allElems.size() < 3) {
+      throw new IllegalNameIdentifierException(
+          "Cannot create a schema NameIdentifier less than three elements.");
+    }
+    return NameIdentifier.of(allElems.get(0), allElems.get(1), 
allElems.get(2));
+  }
+
   /**
    * Check the given {@link NameIdentifier} is a metalake identifier. Throw an 
{@link
    * IllegalNameIdentifierException} if it's not.
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
index 8093da7ef..55341627b 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
@@ -210,11 +210,7 @@ public class SchemaOperations {
           httpRequest,
           () -> {
             NameIdentifier ident = NameIdentifierUtil.ofSchema(metalake, 
catalog, schema);
-            boolean dropped =
-                TreeLockUtils.doWithTreeLock(
-                    NameIdentifierUtil.ofCatalog(metalake, catalog),
-                    LockType.WRITE,
-                    () -> dispatcher.dropSchema(ident, cascade));
+            boolean dropped = dispatcher.dropSchema(ident, cascade);
             if (!dropped) {
               LOG.warn("Fail to drop schema {} under namespace {}", schema, 
ident.namespace());
             }
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
index d5cf1ffc7..3d9d863e9 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
@@ -228,11 +228,7 @@ public class TableOperations {
           httpRequest,
           () -> {
             NameIdentifier ident = NameIdentifierUtil.ofTable(metalake, 
catalog, schema, table);
-            boolean dropped =
-                TreeLockUtils.doWithTreeLock(
-                    NameIdentifier.of(metalake, catalog, schema),
-                    LockType.WRITE,
-                    () -> purge ? dispatcher.purgeTable(ident) : 
dispatcher.dropTable(ident));
+            boolean dropped = purge ? dispatcher.purgeTable(ident) : 
dispatcher.dropTable(ident);
             if (!dropped) {
               LOG.warn("Failed to drop table {} under schema {}", table, 
schema);
             }

Reply via email to