roryqi commented on code in PR #13771:
URL: https://github.com/apache/gravitino/pull/13771#discussion_r4266173765


##########
core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java:
##########
@@ -177,16 +178,27 @@ public Table loadTable(NameIdentifier ident) throws 
NoSuchTableException {
         entityCombinedTable =
             TreeLockUtils.doWithTreeLock(schemaIdent, LockType.WRITE, () -> 
importTable(ident));
       } catch (EntityAlreadyExistsException e) {
-        // HA race: another Gravitino node concurrently imported this table. 
Reload from the
-        // entity store to pick up the entity stored by the winning node.
-        LOG.info(
-            "Table {} was concurrently imported by another node; reloading 
from store.", ident);
+        // A create-only import can conflict either because another Gravitino 
node won an HA race,
+        // or because the external identifier is already stored under another 
Gravitino path.
+        // Reload to distinguish a successful concurrent import from an 
identity conflict.
+        LOG.info("Table {} import conflicted with existing metadata; reloading 
from store.", ident);
         entityCombinedTable =
             TreeLockUtils.doWithTreeLock(ident, LockType.READ, () -> 
internalLoadTable(ident));
         if (!entityCombinedTable.imported()) {
           throw new UnsupportedOperationException(
-              "Table managed by multiple catalogs. This may cause unexpected 
issues such as privilege conflicts. "
-                  + "To resolve: Remove all catalogs managing this table, then 
recreate one catalog to ensure single-catalog management.");
+              "Table "
+                  + ident
+                  + " cannot be imported because its name or external 
identifier is already "
+                  + "managed under a different Gravitino identifier. Gravitino 
does not "
+                  + "automatically reconcile external table renames or stale 
registrations. "
+                  + "Before retrying, manually resolve the conflict: either 
restore the external "
+                  + "table name and identifier to match its Gravitino 
registration, or have an "
+                  + "administrator safely remove the stale Gravitino 
registration and its "
+                  + "privileges, tags, and other relationships. Do not only 
remove "
+                  + "`gravitino.identifier` while the conflicting registration 
remains, because "
+                  + "Gravitino may associate the external table with that 
registration. After the "
+                  + "stale registration is removed, clear 
`gravitino.identifier` from the external "
+                  + "table and load it again.");

Review Comment:
   Addressed in 69495771f8.\n\nThe schema, table, and view conflict messages 
now use a shared helper and no longer prescribe an unavailable object-level 
cleanup operation. They explicitly state that Gravitino has no metadata-only 
unregister for an individual external object and describe the supported 
catalog-wide recovery: force-drop and recreate the containing Gravitino catalog 
registration. The message also warns that this removes every stored 
registration and its privileges, tags, and other relationships, and directs 
operators to the provider-specific guidance before clearing external 
identifiers.\n\nThe Hive, Hudi-HMS, Iceberg, and Paimon catalog docs now 
document the exact recovery sequence and state which external objects and 
physical data are retained. Hudi's guidance is conditional because its 
read-only operations do not write identifiers: an external HMS tool is needed 
only when an affected object actually carries .\n\nThe schema/table/view 
dispatcher tests and 
   > Configure project :
   ------------------ Check Docker environment ---------------------
   Docker server status ............................................ [running]
   Run test cases without `gravitino-docker-test` tag .............. [embedded 
test]
   -----------------------------------------------------------------
   
   > Configure project :catalogs
   Path for java installation '/usr/lib/jvm/openjdk-17' (Common Linux 
Locations) does not contain a java executable
   
   > Configure project :core
   Kotlin DSL property assignment is an incubating feature.
   
   > Task :docs:processResources NO-SOURCE
   > Task :spotlessInternalRegisterDependencies UP-TO-DATE
   > Task :docs:generateMavenLegalFiles UP-TO-DATE
   > Task :docs:spotlessJava UP-TO-DATE
   > Task :docs:spotlessJavaCheck UP-TO-DATE
   > Task :docs:spotlessKotlinGradle UP-TO-DATE
   > Task :docs:spotlessKotlinGradleCheck UP-TO-DATE
   > Task :docs:spotlessCheck UP-TO-DATE
   > Task :docs:compileJava NO-SOURCE
   > Task :docs:classes UP-TO-DATE
   > Task :docs:jar UP-TO-DATE
   > Task :docs:assemble UP-TO-DATE
   > Task :docs:compileTestJava NO-SOURCE
   > Task :docs:processTestResources NO-SOURCE
   > Task :docs:testClasses UP-TO-DATE
   > Task :docs:test NO-SOURCE
   > Task :docs:jacocoTestReport SKIPPED
   > Task :docs:check UP-TO-DATE
   > Task :docs:nodeSetup UP-TO-DATE
   > Task :docs:npmSetup UP-TO-DATE
   
   > Task :docs:lintIdpOpenAPI
   
   > Task :docs:lintOpenAPI
   
   > Task :docs:build
   
   Deprecated Gradle features were used in this build, making it incompatible 
with Gradle 9.0.
   
   You can use '--warning-mode all' to show the individual deprecation warnings 
and determine if they come from your own scripts or plugins.
   
   For more on this, please refer to 
https://docs.gradle.org/8.2/userguide/command_line_interface.html#sec:command_line_warnings
 in the Gradle documentation.
   
   BUILD SUCCESSFUL in 13s
   11 actionable tasks: 2 executed, 9 up-to-date pass. I am leaving this thread 
unresolved for reviewer confirmation.



-- 
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