[Bug report] Async cache removal can delete the index entry of a reinserted entity
- Dominant language
- Java
- Stars
- 3.2k
- Forks
- 935
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 298
Description
### Version
main branch
### Describe what is wrong
`CaffeineEntityCache` maintains cached entities in `cacheData` and a hierarchy index in `cacheIndex`. Its removal listener runs asynchronously.
If an old entry is removed and the same key is reinserted before the listener runs, `invalidateExpiredItem()` unconditionally removes the key from `cacheIndex`, even though the new entry still exists in `cacheData`. A subsequent parent-level invalidation cannot discover the child through the index, so the child remains cached.
This race predates #13099 and was identified while reviewing that PR.
### Error message and/or stacktrace
No exception is produced. The failure manifests as divergence between `cacheData` and `cacheIndex`.
### How to reproduce
1. Insert a child entity into the cache.
2. Trigger expiration or eviction of that entry.
3. Reinsert the same key before its asynchronous removal listener executes.
4. Allow the old removal callback to run.
5. Invalidate the parent entity.
6. Observe that the reinserted child remains in `cacheData` because its index entry was removed.
### Additional context
The listener should remove the index entry only when the key is no longer present in `cacheData`, while holding the corresponding segmented lock.
A deterministic regression test should simulate a delayed removal callback followed by reinsertion.
Related: #12377, #13099.
Contributor guide
Research direction
Start by reading CaffeineEntityCache, especially cacheData, cacheIndex, and invalidateExpiredItem(), then locate the existing cache tests. Add a deterministic regression test that delays the removal callback, reinserts the same key, and invalidates its parent; done means the reinserted child is still discoverable and removed by parent invalidation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100