Skip to content

Replay DatabaseCache commit work as one pruned task per transaction - #8193

Merged
labkey-jeckels merged 10 commits into
developfrom
fb_collapse_cache_commit_tasks
Oct 20, 2026
Merged

labkey-jeckels merged 10 commits into
developfrom
fb_collapse_cache_commit_tasks

Conversation

@labkey-jeckels

@labkey-jeckels labkey-jeckels commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Rationale

Big transactions spend seconds after commit reloading cache entries they've already invalidated; this replays each transaction's DatabaseCache work as one task and skips what a later removal or clear undoes. A container delete measured 1,194 post-commit reloads taking 2-17 s, nearly all for ontology caches that the same delete clears. Also adds a DEBUG summary of large commit task queues, since the throttled repeated-task warning can't show what fills one.

Related Pull Requests

Changes

  • Replay a transaction's cache removals, clears, and reloads after commit from a single commit task, in the order they happened
  • Skip reloads that a later removal of the same key, or clear of the same cache, would discard
  • Log the most common task classes and their run times for large commit task queues at DEBUG

Tasks

  • Claude Code Review
  • Manual Testing @labkey-martyp
    • Delete container with lots of sample types and datasets (perf)
    • Stale data check across sessions
    • Transaction rollback doesn't update cache
    • Batched cache clears (ClearMaterialSourceCacheTask)
    • Warning for unbatched cache clears (datasets)
  • Test Automation

A transaction touching many caches queued one commit task per cache and key, tripping the repeated commit task warning.
The repeated task warning is throttled per call site, so it can't explain what fills a large queue.
@labkey-jeckels labkey-jeckels self-assigned this Oct 16, 2026
…it task warnings

Container deletes queued a cache clear per sample type; the warning now names the registering call site, trims plumbing frames, and requires more distinct keys before flagging value-equal tasks.
@labkey-jeckels
labkey-jeckels marked this pull request as ready for review October 16, 2026 22:43
@labkey-jeckels

Copy link
Copy Markdown
Contributor Author

@labkey-adam @labkey-martyp this is the change that tries to improve the cache reloading behavior within transactions and CommitTasks

@labkey-tchad labkey-tchad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Claude suggested some additional test cases: #8208

## Rationale
Filling some testing gaps found by Claude:

1. **No end-to-end test of pruning through DatabaseCache.** The whole
design depends on BlockingDatabaseCache.load() and TransactionCache
passing the same _databaseCache object as the Op.cache key. They do
today: TransactionCache
is built with this. But only the string-keyed unit tests exercise
pruning. If either side started passing getCache() or the wrapper
instead, every removal would stop dropping reloads, and no test would
fail. Suggested test
in DatabaseCache.TestCase, using a BlockingDatabaseCache with a counting
loader:
- Inside a transaction, call get("a") (miss), remove("a"), get("b"),
then clear(), then get("c"), and commit.
- Assert that the replay task holds only the clear and the reload of c.
- Assert that after commit the shared cache holds only c, and the loader
ran exactly once more after commit.
2. **Reloads are never shown to run after commit.**
testDatabaseCacheTransactionLimit commits but checks nothing afterwards.
Nothing proves the () -> get(key, argument, loader) lambda runs or fills
the shared cache. This was also
untested before the PR, but this PR rewrites that path. Two asserts
after transaction.commit() would cover it: the shared cache has maxSize
keys, and the loader call count is right.
3. **No automated rollback test.** The PR lists "Transaction rollback
doesn't update cache" as manually tested. A test that loads and removes
inside a transaction, closes it without committing, and asserts the
shared cache is
     unchanged would lock that in.
4. **Remove → reload → remove of one key isn't tested.** The second
remove drops the reload in between, and its own add is a duplicate, so
the first REMOVE keeps its earlier position. The result is correct, but
this exact path in
remove() has no test. It would take three lines in
CacheReplayCommitTask.TestCase.
5. **Nothing tests registering an operation while the replay runs.** The
comment in run() says operations can be registered during replay when
commitAndKeepConnection() runs on an outer transaction. A unit test
where one operation
calls task.reload(...) on the same task would pin the copy that prevents
a ConcurrentModificationException. Without it, a later "simplification"
that drops the copy would pass every test.
@labkey-jeckels
labkey-jeckels merged commit 1e906d1 into develop Oct 20, 2026
7 of 8 checks passed
@labkey-jeckels
labkey-jeckels deleted the fb_collapse_cache_commit_tasks branch October 20, 2026 22:42
labkey-jeckels added a commit that referenced this pull request Oct 22, 2026
## Rationale
Fix stale ObjectIds after ontology objects are deleted by SQL:
recreating a deleted LSID reused its old ObjectId and failed the
`objectproperty` foreign key. This path never invalidated the ObjectId
cache; #8193's more accurate post-commit cache replay now leaves those
ObjectIds cached, which broke `MixtureBatchUpgradeTest` when a batch
edit removes and re-adds its material inputs ([TeamCity
failure](https://teamcity.labkey.org/buildConfiguration/LabKey_Trunk_Internal_Upgrade_UpgradeSetupPostgres/4227772)).

## Related Pull Requests
- #8193

## Changes
- Deleting ontology objects by SQL now invalidates the ObjectId and
property-map caches, like the other delete paths
- The SQL delete runs as one statement that reports exactly which
objects it removed, so only those cache entries are evicted; very large
deletes fall back to clearing the affected containers
- All ontology delete paths share one cache-invalidation helper
- New integration tests cover recreating objects after a SQL delete,
inside and outside a transaction, across containers, and past the
targeted-eviction limit

Tested locally: the new tests fail without the fix and pass with it, and
`OntologyManager`, `CacheReplayCommitTask`, and `DatabaseCache` tests
pass.

## Tasks
- [x] Claude Code Review
- [x] Manual Testing - N/A
- [x] Test Automation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants