jerryshao commented on code in PR #14641:
URL: https://github.com/apache/gravitino/pull/14641#discussion_r4479840647


##########
core/src/main/java/org/apache/gravitino/meta/ColumnEntity.java:
##########
@@ -163,13 +164,33 @@ public static Builder builder() {
     return new Builder();
   }
 
+  /**
+   * Projects a source column comment into the portable entity-store 
representation. The full source
+   * comment remains available from the connector table.
+   *
+   * @param comment the source comment
+   * @return a NUL-free comment bounded by the storage capacity
+   */
+  @Nullable
+  public static String commentForStorage(@Nullable String comment) {
+    if (comment == null) {
+      return null;
+    }
+    String safe = comment.replace("\0", "");
+    int end = Math.min(safe.length(), 
EntityFieldLimits.MAX_COLUMN_COMMENT_LENGTH);

Review Comment:
   **major:** `commentForStorage` caps UTF-16 units, while 
`ColumnEntity.COMMENT.validate` / `EntityFieldLimits.checkMaxLength` cap 
Unicode code points (MySQL utf8mb4 and PostgreSQL `VARCHAR(4096)` count an 
emoji as one character).
   
   `"a".repeat(4095) + "😀"` is 4096 code points, so CREATE/ALTER accept it, and 
then `toColumnEntity` stores it without the emoji. `TestColumnEntity` asserts 
that drop. As a result, managed create returns a shorter comment than the 
caller sent. Managed alter stores the raw comment in 
`ManagedTableOperations.updateColumnEntity`, so create and alter disagree. On 
external tables, `isSameColumn` compares projections, so two different in-limit 
comments can skip the store update.
   
   Could you truncate imports with `offsetByCodePoints` (which also keeps 
surrogate pairs intact) and avoid projecting a comment that request validation 
already accepted? If H2 really limits UTF-16 units, please reject that case in 
`validateColumnComment` before source DDL. It would also be good to add 
round-trip tests for 4096 emoji and for 4095 BMP chars plus one emoji, and to 
apply the same rule on the managed alter path.



##########
core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java:
##########
@@ -861,7 +861,7 @@ public Catalog createCatalog(
             .build();
 
     return TreeLockUtils.doWithTreeLock(
-        metalakeIdent,
+        ident,

Review Comment:
   **major:** Narrowing `createCatalog` to the catalog write lock lets 
`listCatalogs` (which takes the metalake read lock) run during backend 
verification. However, `store.put` still happens before 
`createAndCacheCatalogLease`. If init then fails, the row is deleted, so 
`listCatalogs` can return a catalog that then disappears. `listCatalogsInfo` 
loads through `acquireCatalogLease`, which does not take this catalog lock, so 
it can start a second `validateOnCreate` and cache a wrapper alongside the 
creator.
   
   Could you probe the backend before `store.put`, still under the same catalog 
write lock, and only persist the entity after init succeeds? Sibling catalogs 
would stay unblocked, and a failed create would never be published.



##########
core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java:
##########
@@ -447,42 +447,47 @@ public Table alterTable(NameIdentifier ident, 
TableChange... changes)
   @Override
   public boolean dropTable(NameIdentifier ident) {
     NameIdentifier schemaIdentifier = 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);
-
-          boolean isManagedTable = isManagedEntity(catalogIdent, 
Capability.Scope.TABLE);
-          if (isManagedTable) {
-            return droppedFromCatalog;
-          }
-
-          // A false result is ambiguous: the external table may have been 
renamed or dropped out of
-          // band. Preserve the registration because deleting it after a 
rename would lose
-          // Gravitino-only metadata. A true out-of-band drop can therefore 
leave a stale
-          // registration that requires separate cleanup.
-          if (droppedFromCatalog) {
-            try {
-              store.delete(ident, TABLE);
-            } catch (OptimisticLockException e) {
-              throw e;
-            } 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);
-            }
-          }
-          // Run unconditionally: an out-of-band drop may have left orphaned 
schema entities. The
-          // cleanup is best-effort and stops as soon as a schema still exists.
-          OrphanedSchemaCleanup.cleanUp(this, catalogIdent, schemaIdentifier);
-          return droppedFromCatalog;
-        });
+    Pair<Boolean, Boolean> result =
+        TreeLockUtils.doWithTreeLock(
+            ident,

Review Comment:
   **minor:** `dropTable` no longer holds the schema write lock across source 
DDL, but `purgeTable` (around L513) and `ViewOperationDispatcher#dropView` 
still do. A blocked purge or view drop will therefore still stall sibling 
list/load operations in that schema. Could you apply the same table-lock plus 
read-probe cleanup to those paths, or call out the remaining schema-wide stall 
in the PR description?



##########
trino-connector/integration-test/src/test/java/org/apache/gravitino/trino/connector/integration/test/TrinoQueryIT.java:
##########
@@ -502,6 +534,7 @@ void executeSqlFileWithGenOutput(
       firstLine = false;
 
       String sql = resolveParameters(sqlMatcher.group(1));
+      sql = sql.replaceFirst("^<RETRY_UNTIL_MATCH>\\s*", "");

Review Comment:
   **minor:** `executeSqlFileWithCheckResult` honors `<RETRY_UNTIL_MATCH>`, but 
`executeSqlFileWithGenOutput` strips the flag and runs `SHOW` once. 
Regenerating the PostgreSQL datatype golden file can then capture the staging 
table, and the retry would match that dirty output immediately, so it would no 
longer catch the leak. Could you generate that result through `executeQuery` 
with the same timeout?



##########
core/src/main/java/org/apache/gravitino/lock/TreeLock.java:
##########
@@ -39,22 +39,22 @@
  *   /metalake                            readLock
  *   /metalake/catalog                    readLock
  *   /metalake/catalog/db1                readLock
- *   /metalake/catalog/db/table1          readLock
+ *   /metalake/catalog/db1/table1          readLock
  * </pre>
  *
- * If we need to alter a table `metalake.catalog.db1.table1` (without changing 
the name of it), the
- * lock manager will lock the following:
+ * If we need to drop or alter a table `metalake.catalog.db1.table1` (without 
renaming it), the lock

Review Comment:
   **nit:** This example says a non-rename alter write-locks the table. 
`dropTable` does, but `alterTable` still takes a read lock on the table unless 
it renames (see `TableOperationDispatcher`, which locks READ when the lock 
ident is the table). The preformatted rows also have an extra space before 
`readLock`/`writeLock`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to