github-actions[bot] commented on code in PR #68196:
URL: https://github.com/apache/doris/pull/68196#discussion_r4045802732
##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalMetaCacheMgr.java:
##########
@@ -484,14 +489,30 @@ public void removeCatalogByEngine(long catalogId, String
engine) {
}
public void invalidateDb(long catalogId, String dbName) {
- routeCatalogEngines(catalogId, cache -> safeInvalidate(
- cache, catalogId, "invalidateDb", () ->
cache.invalidateDb(catalogId, dbName)));
+ try {
+ routeCatalogEngines(catalogId, cache -> safeInvalidate(
+ cache, catalogId, "invalidateDb", () ->
cache.invalidateDb(catalogId, dbName)));
+ } finally {
+ CatalogIf<?> catalog = getCatalog(catalogId);
+ if (catalog != null) {
+ rowCountCache.invalidateDb(catalogId,
Util.genIdByName(catalog.getName(), dbName));
+ }
+ }
}
public void invalidateTable(long catalogId, String dbName, String
tableName) {
- routeCatalogEngines(catalogId, cache -> safeInvalidate(
- cache, catalogId, "invalidateTable",
- () -> cache.invalidateTable(catalogId, dbName, tableName)));
+ try {
+ routeCatalogEngines(catalogId, cache -> safeInvalidate(
+ cache, catalogId, "invalidateTable",
+ () -> cache.invalidateTable(catalogId, dbName,
tableName)));
+ } finally {
+ CatalogIf<?> catalog = getCatalog(catalogId);
+ if (catalog != null) {
+ rowCountCache.invalidateTable(catalogId,
Review Comment:
[P1] Do not make point eviction depend on a resident `ExternalTable`. The
table-object cache defaults to 1,000 entries while this cache retains 100,000,
so the row count can outlive its object. In that state an HMS DROP/RENAME event
cannot rebuild the already-removed table and returns from
`unregisterExternalTable`; cold `replayRefreshTable` similarly returns before
reaching this call. A later same-name CREATE regenerates the same table ID and
reuses the stale future. Please carry/canonicalize the identity so event and
replay paths evict even when the metadata object is absent (or conservatively
evict the DB scope).
##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalMetaCacheMgr.java:
##########
@@ -379,9 +380,13 @@ private Map<String, String>
runtimeEffectiveCacheProperties(
}
public void invalidateCatalog(long catalogId) {
- routeCatalogEngines(catalogId, cache -> safeInvalidate(
- cache, catalogId, "invalidateCatalog",
- () -> cache.invalidateCatalogEntries(catalogId)));
+ try {
+ routeCatalogEngines(catalogId, cache -> safeInvalidate(
+ cache, catalogId, "invalidateCatalog",
+ () -> cache.invalidateCatalogEntries(catalogId)));
+ } finally {
+ rowCountCache.invalidateCatalog(catalogId);
Review Comment:
[P1] Invalidate row counts on every whole-catalog retirement. This call is
only reached by `invalidateCatalog`, while DROP/replay use
`removeCatalogPermanently` and rename uses `removeCatalog`; neither clears
`rowCountCache`. Because external table IDs are deterministic from names and
`RowCountKey.equals` compares only `tableId`, recreating the same catalog name
can return the dropped catalog's future (and rename-back has the same reuse).
Please add a final catalog-scope row-count barrier to those retirement paths.
##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalMetaCacheMgr.java:
##########
@@ -484,14 +489,30 @@ public void removeCatalogByEngine(long catalogId, String
engine) {
}
public void invalidateDb(long catalogId, String dbName) {
- routeCatalogEngines(catalogId, cache -> safeInvalidate(
- cache, catalogId, "invalidateDb", () ->
cache.invalidateDb(catalogId, dbName)));
+ try {
+ routeCatalogEngines(catalogId, cache -> safeInvalidate(
+ cache, catalogId, "invalidateDb", () ->
cache.invalidateDb(catalogId, dbName)));
+ } finally {
+ CatalogIf<?> catalog = getCatalog(catalogId);
+ if (catalog != null) {
+ rowCountCache.invalidateDb(catalogId,
Util.genIdByName(catalog.getName(), dbName));
+ }
+ }
}
public void invalidateTable(long catalogId, String dbName, String
tableName) {
- routeCatalogEngines(catalogId, cache -> safeInvalidate(
- cache, catalogId, "invalidateTable",
- () -> cache.invalidateTable(catalogId, dbName, tableName)));
+ try {
+ routeCatalogEngines(catalogId, cache -> safeInvalidate(
+ cache, catalogId, "invalidateTable",
+ () -> cache.invalidateTable(catalogId, dbName,
tableName)));
+ } finally {
+ CatalogIf<?> catalog = getCatalog(catalogId);
+ if (catalog != null) {
+ rowCountCache.invalidateTable(catalogId,
+ Util.genIdByName(catalog.getName(), dbName),
+ Util.genIdByName(catalog.getName(), dbName,
tableName));
Review Comment:
[P1] Also evict the table row count after partition-scoped mutations. A
partitioned Hive insert refreshes only affected partition caches, and HMS
add/drop/alter-partition events likewise call only partition helpers, so none
reaches this new table eviction. `HMSExternalTable` can derive its row count
from the partition/file list, which means a successful commit or event
continues serving the pre-mutation cached count. Please add a final table
row-count fence to the partition mutation and replay paths.
##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalRowCountCache.java:
##########
@@ -122,10 +126,16 @@ static Optional<Long> loadRowCount(RowCountKey
rowCountKey, boolean fillMetaCach
public long getCachedRowCount(long catalogId, long dbId, long tableId,
boolean fillMetaCache) {
RowCountKey key = new RowCountKey(catalogId, dbId, tableId);
try {
- CompletableFuture<Optional<Long>> f = fillMetaCache
- ? rowCountCache.get(key, (rowCountKey, executor) ->
CompletableFuture.supplyAsync(
- () -> loadRowCount(rowCountKey, true), executor))
- : rowCountCache.get(key);
+ CompletableFuture<Optional<Long>> f;
+ publicationLock.readLock().lock();
+ try {
+ f = fillMetaCache
+ ? rowCountCache.get(key, (rowCountKey, executor) ->
CompletableFuture.supplyAsync(
+ () -> loadRowCount(rowCountKey, true),
executor))
+ : rowCountCache.get(key);
+ } finally {
+ publicationLock.readLock().unlock();
Review Comment:
[P1] Fence refresh completion, not only refresh start. This cache enables
`refreshAfterWrite`, and [Caffeine 2.9.3's
`refreshIfNeeded`](https://github.com/ben-manes/caffeine/blob/v2.9.3/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java#L1112-L1165)
completes with `compute(key, ...)` and returns the refreshed value when
`currentValue == null`. Therefore an expired read can start refresh under this
lock, unlock here, be invalidated under the write lock, and then have the
pre-invalidation refresh reinsert the key. Please add an invalidation
generation/epoch (or another completion-time ownership check) and a
deterministic refresh-start -> invalidate -> refresh-complete test.
##########
fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalMetaCacheMgr.java:
##########
@@ -484,14 +489,30 @@ public void removeCatalogByEngine(long catalogId, String
engine) {
}
public void invalidateDb(long catalogId, String dbName) {
- routeCatalogEngines(catalogId, cache -> safeInvalidate(
- cache, catalogId, "invalidateDb", () ->
cache.invalidateDb(catalogId, dbName)));
+ try {
+ routeCatalogEngines(catalogId, cache -> safeInvalidate(
+ cache, catalogId, "invalidateDb", () ->
cache.invalidateDb(catalogId, dbName)));
+ } finally {
+ CatalogIf<?> catalog = getCatalog(catalogId);
+ if (catalog != null) {
+ rowCountCache.invalidateDb(catalogId,
Util.genIdByName(catalog.getName(), dbName));
Review Comment:
[P1] Derive this ID from the resolved database, not the caller's spelling.
With `lower_case_database_names=1/2`, DROP DATABASE can resolve a canonical DB
and then pass the original DDL spelling through `afterDropDb`/replay to this
line; in mode 2, HMS events also lowercase a mixed-case stored name. The
resulting hash differs from the DB ID carried by row-count keys, so the scan
removes nothing and a same-name recreation reuses stale counts. Please
capture/pass the canonical numeric identity before removal and cover both
case-insensitive DDL/replay and a mixed-case mode-2 event.
--
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]