Summary
While working on #3011, @dpol1 spotted a potential silent-drop bug in the legacy EventHub cache-notification path. This issue tracks the investigation and fix.
Root Cause
Cache.java defines four string constants:
// present-tense — "command" semantics
String ACTION_INVALID = "invalid";
String ACTION_CLEAR = "clear";
// past-tense — "event happened" semantics
String ACTION_INVALIDED = "invalided";
String ACTION_CLEARED = "cleared";
Producers emit past-tense events:
| File |
Lines |
Emitted action |
CachedGraphTransaction.java |
400, 414, 428 |
ACTION_INVALIDED, ACTION_CLEARED |
CachedSchemaTransaction.java |
182, 224, 233, 286 |
ACTION_INVALIDED, ACTION_CLEARED |
Local listeners only match present-tense events:
| File |
Lines |
Listened action |
CachedGraphTransaction.java |
147, 179 |
ACTION_INVALID, ACTION_CLEAR |
CachedSchemaTransaction.java |
120, 127 |
ACTION_INVALID, ACTION_CLEAR |
CachedSchemaTransactionV2.java |
117, 137 |
ACTION_INVALID, ACTION_CLEAR |
How the Current Bridge Works
StandardHugeGraph.AbstractCacheNotifier (StandardHugeGraph.java:1397) listens for "invalided"/"cleared" and converts them into RPC calls to remote nodes. Remote nodes then call AbstractCacheNotifier.invalid/clear(), which emits "invalid"/"clear" on their local hubs — which local listeners do catch.
Local transaction commits
→ notifyChanges("invalided") on local schemaEventHub
→ AbstractCacheNotifier.listener catches "invalided"
→ proxy.invalid(type, id) ← RPC call to remote nodes only
→ Remote node: AbstractCacheNotifier.invalid() emits "invalid" on remote hub
→ Remote CachedSchemaTransaction.listener catches "invalid" ✓
Where Events Are Silently Dropped
The bridge only routes to remote nodes via RPC. The local node never re-emits "invalid" after "invalided" is published, which means:
-
Single-node / no-RPC deployments: proxy is a no-op; "invalided" events from CachedSchemaTransaction/CachedGraphTransaction are consumed by AbstractCacheNotifier and go nowhere. Local consistency is currently maintained by direct updateCache() calls inside each transaction, but any secondary consumer that relies solely on the EventHub would miss these events.
-
If the RPC proxy is misconfigured or unavailable: The "invalided" event is silently swallowed — no error, no fallback.
-
Concurrent local transactions: Due to the containsListener guard (only one listener per hub/event), if a second transaction instance needs to be notified via EventHub it will not be — a latent hazard in scenarios where multiple transactions share the same EventHub.
Suggested Fix
Align the action constants: either
- Have producers emit present-tense (
ACTION_INVALID / ACTION_CLEAR) and remove the past-tense constants, or
- Have
AbstractCacheNotifier also re-publish "invalid"/"clear" locally after forwarding the RPC, so local listeners are always notified.
The safer approach is option 1: unify on present-tense ACTION_INVALID / ACTION_CLEAR throughout, since RaftContext (RaftContext.java:287,313) already uses the present-tense constants correctly.
Related
Summary
While working on #3011, @dpol1 spotted a potential silent-drop bug in the legacy
EventHubcache-notification path. This issue tracks the investigation and fix.Root Cause
Cache.javadefines four string constants:Producers emit past-tense events:
CachedGraphTransaction.javaACTION_INVALIDED,ACTION_CLEAREDCachedSchemaTransaction.javaACTION_INVALIDED,ACTION_CLEAREDLocal listeners only match present-tense events:
CachedGraphTransaction.javaACTION_INVALID,ACTION_CLEARCachedSchemaTransaction.javaACTION_INVALID,ACTION_CLEARCachedSchemaTransactionV2.javaACTION_INVALID,ACTION_CLEARHow the Current Bridge Works
StandardHugeGraph.AbstractCacheNotifier(StandardHugeGraph.java:1397) listens for"invalided"/"cleared"and converts them into RPC calls to remote nodes. Remote nodes then callAbstractCacheNotifier.invalid/clear(), which emits"invalid"/"clear"on their local hubs — which local listeners do catch.Where Events Are Silently Dropped
The bridge only routes to remote nodes via RPC. The local node never re-emits
"invalid"after"invalided"is published, which means:Single-node / no-RPC deployments:
proxyis a no-op;"invalided"events fromCachedSchemaTransaction/CachedGraphTransactionare consumed byAbstractCacheNotifierand go nowhere. Local consistency is currently maintained by directupdateCache()calls inside each transaction, but any secondary consumer that relies solely on the EventHub would miss these events.If the RPC proxy is misconfigured or unavailable: The
"invalided"event is silently swallowed — no error, no fallback.Concurrent local transactions: Due to the
containsListenerguard (only one listener per hub/event), if a second transaction instance needs to be notified via EventHub it will not be — a latent hazard in scenarios where multiple transactions share the same EventHub.Suggested Fix
Align the action constants: either
ACTION_INVALID/ACTION_CLEAR) and remove the past-tense constants, orAbstractCacheNotifieralso re-publish"invalid"/"clear"locally after forwarding the RPC, so local listeners are always notified.The safer approach is option 1: unify on present-tense
ACTION_INVALID/ACTION_CLEARthroughout, since RaftContext (RaftContext.java:287,313) already uses the present-tense constants correctly.Related
CachedSchemaTransactionV2fix that surfaced this)