You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Several paths write to shared caches, or run external effects, while a transaction is still open. After a rollback, what they wrote or did stays. These were found while fixing the nested hard delete ordering (#33981) and are not fixed there.
Findings
Reads inside an open transaction fill shared caches. A read inside a transaction sees that transaction's uncommitted rows. On a cache miss, the following write what they saw straight into shared caches:
the Guava L1 loader, and the Redis L2 putBase it calls;
the "not found" markers written by find and findByName when the database has no row;
the read-bundle puts.
After a rollback those entries stay: up to 3600 s in L2, and 30 s for the markers. The loader's write-epoch check does not catch this case, because the epoch moved before the load started.
Subclass postDelete overrides run external effects before the outer commit. When the delete is nested:
WorkflowDefinitionRepository.postDelete deletes the Flowable definition;
TableRepository.postDelete starts the async profiler purge (its javadoc says it runs after the commit);
ingestion pipeline deletes call the pipeline service.
Peer nodes delete a fresh "not found" marker. A delete publishes a cache invalidation, and every other node's NotFoundCache.invalidate deletes the shared marker just after the deleting node set it. This weakens fix(cache): seal hard-delete stale-read window via NotFoundCache marker #28197 on multi-node deployments.
Redis round trips inside a transaction.cleanupFlushBody calls invalidate() inside the delete transaction, contrary to flushInOneTransaction's javadoc. Fixes 33860: evict Redis L2 after commit, not inside the write transaction #33866 made the L2 half wait for the commit; the in-process half and the pub/sub are still inline.
Wrong javadoc.executeInTransaction says a boundary opened on Entity.getJdbi() does not bind the on-demand DAOs. jdbi 3.37 does bind them, through threadHandleSupplier.
Reindex still queries the negative cache.EntityCacheBypass does not cover NotFoundCache, so a reindex still pays a Redis GET per lookup.
Suggested direction
Writes to shared caches made while a unit of work is open should either wait for its commit (PostCommitActionQueue) or be skipped. External effects in delete hooks should be queued the same way.
Summary
Several paths write to shared caches, or run external effects, while a transaction is still open. After a rollback, what they wrote or did stays. These were found while fixing the nested hard delete ordering (#33981) and are not fixed there.
Findings
Reads inside an open transaction fill shared caches. A read inside a transaction sees that transaction's uncommitted rows. On a cache miss, the following write what they saw straight into shared caches:
putBaseit calls;findandfindByNamewhen the database has no row;After a rollback those entries stay: up to 3600 s in L2, and 30 s for the markers. The loader's write-epoch check does not catch this case, because the epoch moved before the load started.
Subclass
postDeleteoverrides run external effects before the outer commit. When the delete is nested:WorkflowDefinitionRepository.postDeletedeletes the Flowable definition;TableRepository.postDeletestarts the async profiler purge (its javadoc says it runs after the commit);Peer nodes delete a fresh "not found" marker. A delete publishes a cache invalidation, and every other node's
NotFoundCache.invalidatedeletes the shared marker just after the deleting node set it. This weakens fix(cache): seal hard-delete stale-read window via NotFoundCache marker #28197 on multi-node deployments.Redis round trips inside a transaction.
cleanupFlushBodycallsinvalidate()inside the delete transaction, contrary toflushInOneTransaction's javadoc. Fixes 33860: evict Redis L2 after commit, not inside the write transaction #33866 made the L2 half wait for the commit; the in-process half and the pub/sub are still inline.Wrong javadoc.
executeInTransactionsays a boundary opened onEntity.getJdbi()does not bind the on-demand DAOs. jdbi 3.37 does bind them, throughthreadHandleSupplier.Reindex still queries the negative cache.
EntityCacheBypassdoes not coverNotFoundCache, so a reindex still pays a Redis GET per lookup.Suggested direction
Writes to shared caches made while a unit of work is open should either wait for its commit (
PostCommitActionQueue) or be skipped. External effects in delete hooks should be queued the same way.