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

yuqi1129 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 735918739d [#14279] docs(core): Document the load/alter column race 
that can drop column tags (#14280)
735918739d is described below

commit 735918739d56a26b7ec7d73939ba38441eb66a8e
Author: Qi Yu <[email protected]>
AuthorDate: Wed Oct 28 19:34:02 2026 +0800

    [#14279] docs(core): Document the load/alter column race that can drop 
column tags (#14280)
    
    ### What changes were proposed in this pull request?
    
    Document the load/alter column race; the code is not changed:
    - `TableOperationDispatcher`: comments in `alterTable` and
    `updateColumnsIfNecessaryWhenLoad` explain why the race is still open
    across servers and what the full fix needs.
    - `docs/manage-tags-in-gravitino.md`: a note that a column rename that
    runs concurrently with a load or alter of the same external-backed table
    can drop the column's tags.
    
    ### Why are the changes needed?
    
    A fix that only takes a stronger tree lock would close the race on one
    server but not across servers, so it is not worth shipping on its own.
    The full fix needs a new EntityStore API (#13621) and is tracked in
    #14279.
    
    Part of #14279
    
    ### Does this PR introduce _any_ user-facing change?
    
    Documentation only.
    
    ### How was this patch tested?
    
    Comments and docs only. `./gradlew :core:spotlessCheck` passes.
---
 .../gravitino/catalog/TableOperationDispatcher.java      | 16 ++++++++++++++--
 docs/manage-tags-in-gravitino.md                         |  8 ++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

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 507b3c76c5..4e50f44aa4 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
@@ -280,6 +280,11 @@ public class TableOperationDispatcher extends 
OperationDispatcher implements Tab
     // at the same time.
     // 2. if the TableChange.RenameTable only change the table name, we need 
to acquire write lock
     // to on the schema.
+    //
+    // The read lock on the table does not order this alter against a 
concurrent load or another
+    // alter of the same table, and no tree lock orders them across servers. 
Either of them can
+    // write a stale column list over this alter and turn a column rename into 
a drop plus an add,
+    // which removes the renamed column's tags. See 
updateColumnsIfNecessaryWhenLoad and #14279.
     NameIdentifier nameIdentifierForLock = ident;
     String schemaName = ident.namespace().level(2);
     
Arrays.stream(changes).forEach(TableOperationDispatcher::validateColumnChange);
@@ -1096,8 +1101,15 @@ public class TableOperationDispatcher extends 
OperationDispatcher implements Tab
     // stored columns since, e.g. renamed a column while keeping its id. So 
the columns are matched
     // again against the entity being updated, which is the latest stored one. 
This narrows the
     // load/alter race but does not close it: if this load read the catalog 
before a concurrent
-    // alter and the store after it, the catalog snapshot is the stale side. 
Closing that needs
-    // alterTable and loadTable to exclude each other, which is tracked 
separately.
+    // alter and the store after it, the catalog snapshot is the stale side, 
and a column that the
+    // alter renamed is stored as dropped plus added, so it loses its id and 
its tags.
+    //
+    // A tree lock cannot close this, because tree locks are local to one 
server. Closing it needs
+    // the alter to record in the store that it is in progress before it calls 
the catalog, and
+    // the load to read the stored version, operation epoch and in-progress 
mark before it reads
+    // the catalog, skipping the store write while the mark is set. The load 
may write only if the
+    // version and epoch are unchanged and no in-progress mark is set. That 
needs a new EntityStore
+    // API and is tracked in #14279.
     Table tableFromCatalog = combinedTable.tableFromCatalog();
     return TreeLockUtils.doWithTreeLock(
         tableIdent,
diff --git a/docs/manage-tags-in-gravitino.md b/docs/manage-tags-in-gravitino.md
index e99d8c5196..1d23f832c2 100644
--- a/docs/manage-tags-in-gravitino.md
+++ b/docs/manage-tags-in-gravitino.md
@@ -292,6 +292,14 @@ raw_events.supports_tags().associate_tags(["pii"], None)
 </TabItem>
 </Tabs>
 
+:::note
+Column tags follow the column's internal id. For tables whose metadata is kept 
by an external
+catalog, such as Hive, Iceberg or JDBC catalogs, a column rename that runs 
concurrently with a load
+or another alter of the same table, on any Gravitino server, can be stored as 
a dropped column plus
+a new one. The renamed column then loses its tags. Avoid loading or altering a 
table while one of
+its columns is being renamed, and check the column's tags after the rename.
+:::
+
 ### Assign and Remove Tag Values
 
 Tag values are updated as pairs of tag name and value. Adding a pair preserves 
the tag's other

Reply via email to