Merge pull request #10085 from hashicorp/dnephin/ttlcache-never-decrease-expiry

lib/ttlcache: never decrease the expiry on update
This commit is contained in:
Daniel Nephin 2021-04-22 13:06:10 -04:00 committed by GitHub
commit 2619dcd949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 8 deletions

View File

@ -76,8 +76,10 @@ func (h *ExpiryHeap) Add(key string, expiry time.Duration) *Entry {
return entry return entry
} }
// Update the entry that is currently at idx with the new expiry time. The heap // Update the entry that is currently at idx with the new expiry time, if the new
// will be rebalanced after the entry is updated. // expiry time is further into the future. The heap will be rebalanced after the
// entry is updated. If the new expiry time is earlier than the existing expiry
// time than the expiry is not modified.
// //
// Must be synchronized by the caller. // Must be synchronized by the caller.
func (h *ExpiryHeap) Update(idx int, expiry time.Duration) { func (h *ExpiryHeap) Update(idx int, expiry time.Duration) {
@ -86,11 +88,15 @@ func (h *ExpiryHeap) Update(idx int, expiry time.Duration) {
return return
} }
entry := h.entries[idx] entry := h.entries[idx]
entry.expiry = time.Now().Add(expiry) newExpiry := time.Now().Add(expiry)
// Ignore the new expiry if the time is earlier than the existing expiry.
if entry.expiry.After(newExpiry) {
return
}
entry.expiry = newExpiry
heap.Fix((*entryHeap)(h), idx) heap.Fix((*entryHeap)(h), idx)
// If the previous index and current index are both zero then Fix did not
// swap the entry, and notify must be called here.
if idx == 0 || entry.heapIndex == 0 { if idx == 0 || entry.heapIndex == 0 {
h.notify() h.notify()
} }

View File

@ -47,8 +47,8 @@ func TestExpiryHeap(t *testing.T) {
testNoMessage(t, ch) testNoMessage(t, ch)
}) })
runStep(t, "update entry3 to expire first", func(t *testing.T) { runStep(t, "update so that entry3 expires first", func(t *testing.T) {
h.Update(entry3.heapIndex, 10*time.Millisecond) h.Update(entry.heapIndex, 2000*time.Millisecond)
assert.Equal(t, 1, entry.heapIndex) assert.Equal(t, 1, entry.heapIndex)
assert.Equal(t, 0, entry3.heapIndex) assert.Equal(t, 0, entry3.heapIndex)
testMessage(t, ch) testMessage(t, ch)
@ -56,12 +56,19 @@ func TestExpiryHeap(t *testing.T) {
}) })
runStep(t, "0th element change triggers a notify", func(t *testing.T) { runStep(t, "0th element change triggers a notify", func(t *testing.T) {
h.Update(entry3.heapIndex, 20) h.Update(entry3.heapIndex, 1500*time.Millisecond)
assert.Equal(t, 1, entry.heapIndex) // no move assert.Equal(t, 1, entry.heapIndex) // no move
assert.Equal(t, 0, entry3.heapIndex) assert.Equal(t, 0, entry3.heapIndex)
testMessage(t, ch) testMessage(t, ch)
testNoMessage(t, ch) // one message testNoMessage(t, ch) // one message
}) })
runStep(t, "update can not decrease expiry time", func(t *testing.T) {
h.Update(entry.heapIndex, 100*time.Millisecond)
assert.Equal(t, 1, entry.heapIndex) // no move
assert.Equal(t, 0, entry3.heapIndex)
testNoMessage(t, ch) // no notify, because no change in the heap
})
} }
func testNoMessage(t *testing.T, ch <-chan struct{}) { func testNoMessage(t *testing.T, ch <-chan struct{}) {