github-actions[bot] commented on code in PR #68196:
URL: https://github.com/apache/doris/pull/68196#discussion_r4128907357


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalMetaCacheMgr.java:
##########
@@ -691,15 +792,70 @@ public void invalidateTableCache(ExternalTable 
dorisTable) {
         long catalogId = dorisTable.getCatalog().getId();
         // Typed table invalidation bypasses the name-based invalidateTable() 
entry point, so the
         // Lance access-cache retirement that used to happen there has to be 
repeated here.
-        invalidateLanceTableAccess(catalogId);
-        routeCatalogEngines(catalogId, cache -> safeInvalidate(
-                cache, catalogId, "invalidateTable", () -> 
cache.invalidateTable(dorisTable)));
+        try {
+            invalidateLanceTableAccess(catalogId);
+            routeCatalogEngines(catalogId, cache -> safeInvalidate(
+                    cache, catalogId, "invalidateTable", () -> 
cache.invalidateTable(dorisTable)));
+        } finally {
+            invalidateRowCountCache(dorisTable);

Review Comment:
   [P1] Fence the held table before full REFRESH TABLE resets it. 
`RefreshManager.refreshTableInternal` calls `unsetObjectCreated()` before 
entering this typed invalidation, so a concurrent query can reload the new HMS 
metadata while `routeCatalogEngines` is still running and read the old 
completed row-count future; this `finally` fence cannot retract that plan. 
Explicit REFRESH TABLE and full-table follower replay lack the opening fence 
used by the event and post-commit paths. Publish a table row-count fence before 
`unsetObjectCreated()`, keep this completion fence, and latch a query between 
the reset and routed invalidation. This is separate from the previously 
threaded selective partition refresh.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java:
##########
@@ -619,15 +640,36 @@ public boolean unregisterTableForReplay(String tableName) 
{
         // Check whether the table still exists in the local replay cache.
         ExternalTable dorisTable = getTableForReplay(tableName).orElse(null);
         if (dorisTable == null) {
+            // A mode-2 table-name mapping can disappear while the old object 
stays resident in
+            // MetaCache.metaObjCache; getTableForReplay then misses only 
because the mapping is
+            // absent. Retire the hidden table-object generation so a 
same-name recreation cannot
+            // reuse the prior incarnation, then widen the engine and 
row-count fence.
+            if (!hasLocalTableName(tableName)) {
+                retireAllTableObjectsWithoutEngineInvalidation();
+            }
+            // The table object cache is much smaller than the row-count and 
Hive engine caches. A drop
+            // or rename must still retire stale entries when the table object 
was evicted, and the
+            // event carries the caller spelling, so widen to the canonical 
scope.
+            Env.getCurrentEnv().getExtMetaCacheMgr()
+                    .invalidateTableByNameOrWider(extCatalog.getId(), 
getFullName(), tableName);

Review Comment:
   [P1] Open a DB row-count fence before this known-name cold-table route. 
Ordinary table-object eviction can make `getTableForReplay` miss while 
`hasLocalTableName` remains true, so the pre-fenced retirement at line 648 is 
skipped. On delayed follower DROP after a remote same-name recreation, 
`invalidateTableByNameOrWider` routes DB engine invalidation before its final 
row-count fence. A concurrent query can load the replacement under its 
deterministic table ID during that work and use the old completed count. This 
differs from the existing missing-name object-retirement thread at this line. 
Fence the DB counts before entering the cold route, retain the completion 
fence, and latch the known-name/evicted-object replay case.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java:
##########
@@ -1247,10 +1273,48 @@ public void unregisterDatabase(String dbName) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("unregister database [{}]", dbName);
         }
-        if (isInitialized()) {
-            metaCache.invalidate(dbName, Util.genIdByName(name, dbName));
+        if (!isInitialized()) {
+            Env.getCurrentEnv().getExtMetaCacheMgr().invalidateDb(getId(), 
dbName);
+            return;
+        }
+        String localDbName = getLocalDatabaseName(dbName, true);

Review Comment:
   [P1] Keep the historical DROP target when a mode-2 name map rebounds. If 
remote `Foo` is dropped and case-only replacement `FOO` is created, a names 
refresh can rebind `foo -> FOO` while the old `Foo` DB object remains cached. A 
delayed `unregisterDatabase("Foo")` now resolves `FOO` here, so the following 
object, engine, and row-count invalidations retire the replacement and leave 
old `Foo` reusable if that spelling returns. The existing missing-map thread 
does not cover this present-but-rebound mapping. The new cold replay identity 
helper repeats the historical-name lookup. Preserve the pre-drop canonical 
key/ID where available, or widen retirement when the mapping has changed; test 
a delayed case-only drop/recreate.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalMetaCacheMgr.java:
##########
@@ -691,15 +792,70 @@ public void invalidateTableCache(ExternalTable 
dorisTable) {
         long catalogId = dorisTable.getCatalog().getId();
         // Typed table invalidation bypasses the name-based invalidateTable() 
entry point, so the
         // Lance access-cache retirement that used to happen there has to be 
repeated here.
-        invalidateLanceTableAccess(catalogId);
-        routeCatalogEngines(catalogId, cache -> safeInvalidate(
-                cache, catalogId, "invalidateTable", () -> 
cache.invalidateTable(dorisTable)));
+        try {
+            invalidateLanceTableAccess(catalogId);
+            routeCatalogEngines(catalogId, cache -> safeInvalidate(

Review Comment:
   [P1] Fence the typed table row count before evicting its engine entries. 
Iceberg `SET CURRENT SNAPSHOT` commits a new snapshot and calls this method 
without an opening fence. `routeCatalogEngines` removes Iceberg table/snapshot 
entries here; a concurrent query can reload the new snapshot and still get the 
old completed count until the `finally` at line 800. Iceberg snapshot/rewrite 
actions share this path. Open the table row-count fence at manager entry, 
retain the completion fence, and test a query paused after Iceberg entry 
removal. This is distinct from full REFRESH TABLE, whose held-object reset 
occurs before this method is entered.



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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to