common/prque: refactor LazyQueue (#21236)

This commit is contained in:
Daniel Liu 2024-12-16 18:52:16 +08:00
parent d3a943d0b3
commit cf0c5c8cd2

View file

@ -29,6 +29,7 @@ import (
// - priority evaluates the actual priority of an item // - priority evaluates the actual priority of an item
// - maxPriority gives an upper estimate for the priority in any moment between // - maxPriority gives an upper estimate for the priority in any moment between
// now and the given absolute time // now and the given absolute time
//
// If the upper estimate is exceeded then Update should be called for that item. // If the upper estimate is exceeded then Update should be called for that item.
// A global Refresh function should also be called periodically. // A global Refresh function should also be called periodically.
type LazyQueue struct { type LazyQueue struct {
@ -44,6 +45,7 @@ type LazyQueue struct {
setIndex SetIndexCallback setIndex SetIndexCallback
priority PriorityCallback priority PriorityCallback
maxPriority MaxPriorityCallback maxPriority MaxPriorityCallback
lastRefresh1, lastRefresh2 mclock.AbsTime
} }
type ( type (
@ -59,9 +61,12 @@ func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPrior
priority: priority, priority: priority,
maxPriority: maxPriority, maxPriority: maxPriority,
clock: clock, clock: clock,
period: refreshPeriod} period: refreshPeriod,
lastRefresh1: clock.Now(),
lastRefresh2: clock.Now(),
}
q.Reset() q.Reset()
q.Refresh() q.refresh(clock.Now())
return q return q
} }
@ -71,9 +76,19 @@ func (q *LazyQueue) Reset() {
q.queue[1] = newSstack(q.setIndex1) q.queue[1] = newSstack(q.setIndex1)
} }
// Refresh should be called at least with the frequency specified by the refreshPeriod parameter // Refresh performs queue re-evaluation if necessary
func (q *LazyQueue) Refresh() { func (q *LazyQueue) Refresh() {
q.maxUntil = q.clock.Now() + mclock.AbsTime(q.period) now := q.clock.Now()
for time.Duration(now-q.lastRefresh2) >= q.period*2 {
q.refresh(now)
q.lastRefresh2 = q.lastRefresh1
q.lastRefresh1 = now
}
}
// refresh re-evaluates items in the older queue and swaps the two queues
func (q *LazyQueue) refresh(now mclock.AbsTime) {
q.maxUntil = now + mclock.AbsTime(q.period)
for q.queue[0].Len() != 0 { for q.queue[0].Len() != 0 {
q.Push(heap.Pop(q.queue[0]).(*item).value) q.Push(heap.Pop(q.queue[0]).(*item).value)
} }
@ -139,6 +154,7 @@ func (q *LazyQueue) MultiPop(callback func(data interface{}, priority int64) boo
} }
return return
} }
nextIndex = q.peekIndex() // re-check because callback is allowed to push items back
} }
} }
} }