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


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/PaimonMetadataOps.java:
##########
@@ -193,7 +193,13 @@ private void performDropDb(String dbName, boolean 
ifExists, boolean force) throw
 
     @Override
     public void afterDropDb(String dbName) {
+        Optional<ExternalDatabase<? extends ExternalTable>> db = 
dorisCatalog.getDbForReplay(dbName);
         dorisCatalog.unregisterDatabase(dbName);
+        if (db.isPresent()) {
+            Env.getCurrentEnv().getExtMetaCacheMgr().invalidateDb(db.get());
+        } else {
+            invalidatePaimonCatalogForUnresolvedReplay();

Review Comment:
   [P2] Do not turn the `IF EXISTS` early-return path, where no remote drop was 
attempted, into a catalog-wide cache flush. `performDropDb` returns before 
calling `catalog.dropDatabase`, but the default drop wrapper still calls 
`afterDropDb` and `ExternalCatalog.dropDb` still journals the operation. This 
new empty-object fallback therefore invalidates every unrelated cached Paimon 
SDK table handle and Doris Paimon entry on the leader, and replay can repeat 
that full flush on each initialized follower that likewise cannot resolve a 
cached database object. Preserve the conservative catalog fallback for an 
unresolved replay of a real committed drop, but propagate the leader-side 
no-mutation result so it skips this post-hook/log (or otherwise avoids the full 
fallback), with an unrelated warm-table regression. This trigger is distinct 
from the existing catalog-refresh scan thread.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/PaimonExternalCatalog.java:
##########
@@ -125,11 +137,73 @@ public Table getPaimonTable(NameMapping nameMapping) {
     }
 
     public Table getPaimonTable(NameMapping nameMapping, String branch, String 
queryType) {
-        makeSureInitialized();
         Identifier identifier = tableIdentifier(nameMapping, branch, 
queryType);
         return loadPaimonTable(nameMapping, queryType, identifier);
     }
 
+    public synchronized void invalidatePaimonTable(NameMapping nameMapping) 
throws Exception {
+        // Property changes reset and close the SDK catalog before retiring 
Doris cache entries.
+        // Do not recreate that catalog merely to invalidate an already 
retired generation.
+        if (!isInitialized()) {
+            return;
+        }
+        Identifier identifier = tableIdentifier(nameMapping, null, null);
+        withSdkCatalogCacheWriteLock(() -> executionAuthenticator.execute(() 
-> {
+            invalidatePaimonTableEntries(identifier);
+            return null;
+        }));
+    }
+
+    public synchronized void invalidatePaimonDatabase(String remoteDbName) 
throws Exception {
+        if (!isInitialized()) {
+            return;
+        }
+        withSdkCatalogCacheWriteLock(() -> executionAuthenticator.execute(() 
-> {
+            boolean caseSensitive = catalog.caseSensitive();
+            invalidateCachedPaimonTables(identifier -> identifierPartEquals(
+                    identifier.getDatabaseName(), remoteDbName, 
caseSensitive));
+            return null;
+        }));
+    }
+
+    public synchronized void invalidatePaimonCatalog() throws Exception {
+        if (!isInitialized()) {
+            return;
+        }
+        withSdkCatalogCacheWriteLock(() -> executionAuthenticator.execute(() 
-> {
+            invalidateCachedPaimonTables(ignored -> true);
+            return null;
+        }));
+    }
+
+    private void invalidateCachedPaimonTables(Predicate<Identifier> predicate) 
throws Exception {
+        // A property ALTER closes the old SDK catalog before Doris retires 
its cache entries.
+        // The new SDK catalog must remain lazily initialized in that callback.
+        if (!isInitialized()) {
+            return;
+        }
+        CachingCatalog cachingCatalog = findCachingCatalog();
+        if (cachingCatalog == null) {
+            return;
+        }
+        List<Identifier> cachedIdentifiers = new 
ArrayList<>(cachingCatalog.tableCache().asMap().keySet());
+        List<Identifier> matchedIdentifiers = new ArrayList<>();
+        for (Identifier identifier : cachedIdentifiers) {
+            if (predicate.test(identifier)) {
+                matchedIdentifiers.add(identifier);
+            }
+        }
+        if (matchedIdentifiers.isEmpty()) {
+            return;
+        }
+        // Remove all matching branch/system table handles in one pass. 
Calling Paimon's
+        // invalidateTable before this bulk removal would rescan every 
unrelated database key.
+        cachingCatalog.tableCache().invalidateAll(matchedIdentifiers);
+        // Also clear Paimon's partition cache. The table cache is already 
empty, so these calls
+        // do not repeatedly walk unrelated table keys.
+        matchedIdentifiers.forEach(cachingCatalog::invalidateTable);

Review Comment:
   [P2] Avoid re-running Paimon's branch scan once per key that was already 
bulk-removed. `invalidateAll(matchedIdentifiers)` removes only the D 
target-database keys, not the U unrelated keys, and Paimon 1.4.2 
`CachingCatalog.invalidateTable` still iterates the entire remaining 
`tableCache` to find branch variants. Calling it D times here therefore does 
O(D*U) useless key visits while holding the catalog-wide write lock, so a 
direct database refresh can block all fenced SDK table-handle reads for a long 
time. Clear the matched partition keys through a batch/non-scanning path and 
add a many-target/many-unrelated regression. This is distinct from the existing 
catalog-refresh thread: its per-database callback multiplication is suppressed, 
while this amplification occurs inside one database invalidation.



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