jerryshao commented on code in PR #12445:
URL: https://github.com/apache/gravitino/pull/12445#discussion_r3783417758


##########
core/src/main/java/org/apache/gravitino/storage/relational/EntityChangeLogPoller.java:
##########
@@ -410,39 +307,29 @@ private List<EntityChangeLogListener> 
notifyListeners(BatchDelivery delivery) {
             delivery.firstChangeId(),
             delivery.lastChangeId);
       } catch (Exception e) {

Review Comment:
   `catch (Exception e)` here (and in `pollChanges()` at line 176) only catches 
`Exception`, not `Error`. `scheduleWithFixedDelay`'s contract is that any 
uncaught `Throwable` from a periodic task silently and permanently cancels all 
future executions. Notably, `CatalogChangeLogListener`'s javadoc in this same 
PR names `NoClassDefFoundError` as an accepted failure mode of its 
whole-cache-clear fallback (the #11739 failure mode) — so a listener can throw 
an `Error` under exactly the recovery path this PR introduces, which would kill 
the poller thread for *every* listener, not just the failing one. That 
contradicts the "self-healing" contract this class's own javadoc asserts 
(listener failures are always logged and the cursor always advances). Worth 
catching `Throwable` here, or documenting why `Error` is intentionally out of 
scope?



##########
core/src/main/java/org/apache/gravitino/catalog/CatalogChangeLogListener.java:
##########
@@ -59,51 +72,87 @@ public CatalogChangeLogListener(CatalogManager 
catalogManager) {
 
   @Override
   public void onEntityChange(List<EntityChangeRecord> changes) {
+    List<CatalogInvalidation> remoteInvalidations = new ArrayList<>();
     for (EntityChangeRecord change : changes) {
+      if (!isCatalogChange(change)) {
+        continue;
+      }
+
+      Optional<NameIdentifier> identOpt = catalogIdentifier(change);

Review Comment:
   `catalogIdentifier(change)` is called here with no enclosing try/catch. The 
old code wrapped identifier resolution + `consumeLocalMutation` + `invalidate` 
for a record in one `catch (RuntimeException)`, isolating any unexpected 
failure to a single row. Today this is safe because `catalogIdentifier()` only 
catches `IllegalArgumentException` internally, but that safety now depends 
entirely on an implementation detail of `decode()`/`NameIdentifier.of()` two 
calls down, with no defensive boundary at this call site. If a future change to 
that codec throws a different unchecked exception, `onEntityChange()` would 
abort for the whole batch — skipping the self-heal cache-clear for every 
already-collected `remoteInvalidations` — rather than being isolated to one bad 
row, as the class javadoc claims ("a malformed row is skipped ... and leaves 
nothing stale"). Worth wrapping this call (or the loop body) defensively?



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