fix: correctly notify auto-cleaner when an item's TTL is shortened#206
fix: correctly notify auto-cleaner when an item's TTL is shortened#206PiAreSquared wants to merge 1 commit into
Conversation
Coverage Report for CI Build 24898134592Coverage increased (+0.003%) to 99.738%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
swithek
left a comment
There was a problem hiding this comment.
Thanks for the PR :) I've added a comment that needs to be addressed before merging this.
| c.Stop() | ||
| } | ||
|
|
||
| func Test_Cache_ShortenedTTLNotifiesAutoCleaner(t *testing.T) { |
There was a problem hiding this comment.
Do you think it would be possible to split this test into cases inside Test_Cache_updateExpirations, Test_Cache_set, and Test_Cache_get? We use table-driven tests with map keys as distinct test cases and the name of the test func determines the unit/func that is being tested. Each logic change within the tested funcs should be covered with a dedicated test case.
Also, your test case uses a lot of different cache methods, which means it isn't focused on one specific unit and might fail/succeed because of the side effects of the logic unrelated to your changes. Do you think you could change this to test only the methods you've updated, i.e., updateExpirations(), set(), and get()?
Description
This PR fixes a bug where the background auto-cleaner fails to wake up early if an existing item's TTL is shortened, causing the item to live past its new expiration time. This seems to have been first reported in #204.
Root Cause
When
Set()(orGet()with touch) is called on an existing item, the item's internalexpiresAtis mutated first. Afterwards,updateExpirations()is called to reorder the heap and notify the auto-cleaner's timer channel.Previously,
updateExpirationsattempted to snapshot the old closest expiration time after the item had already been mutated. If the updated item was already at the front of the expiration queue,oldExpiresAtperfectly matched the newly updated time. Because the method didn't detect a change in the root expiration time, it silently returned without notifying thetimerCh, causing the auto-cleaner to oversleep.Fix
updateExpirationssignature to takeoldExpiresAtas a parameterexpQueueinset()andget()before mutating the item viaitem.touch()oritem.update()oldExpiresAtintoupdateExpirationsTesting
I updated the existing
Test_Cache_updateExpirationsto accommodate the signature change and added a new regression test.Test_Cache_ShortenedTTLNotifiesAutoCleanesets an item with a 1-hour TTL, immediately updates it to 10ms, and asserts that the auto-cleaner wakes up and evicts the item on time.Closes #204