mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
fn: hot container timer improvements (#751)
* fn: hot container timer improvements With this change, now we are allocating the timers when the container starts and managing them via stop/clear as needed, which should not only be more efficient, but also easier to follow. For example, previously, if eject time out was set to 10 secs, this could have delayed idle timeout up to 10 secs as well. It is also not necessary to do any math for elapsed time. Now consumers avoid any requeuing when startDequeuer() is cancelled. This was triggering additional dequeue/requeue causing containers to wake up spuriously. Also in startDequeuer(), we no longer remove the item from the actual queue and leave this to acquire/eject, which side steps issues related with item landing in the channel, not consumed, etc.
This commit is contained in:
@@ -70,25 +70,15 @@ func NewSlotQueue(key string) *slotQueue {
|
||||
return obj
|
||||
}
|
||||
|
||||
func (a *slotToken) acquireSlot() bool {
|
||||
// let's get the lock
|
||||
if !atomic.CompareAndSwapUint32(&a.isBusy, 0, 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
// now we have the lock, push the trigger
|
||||
close(a.trigger)
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *slotQueue) ejectSlot(ctx context.Context, s *slotToken) bool {
|
||||
func (a *slotQueue) acquireSlot(s *slotToken) bool {
|
||||
// let's get the lock
|
||||
if !atomic.CompareAndSwapUint32(&s.isBusy, 0, 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
a.cond.L.Lock()
|
||||
for i := 0; i < len(a.slots); i++ {
|
||||
// common case: acquired slots are usually at the end
|
||||
for i := len(a.slots) - 1; i >= 0; i-- {
|
||||
if a.slots[i].id == s.id {
|
||||
a.slots = append(a.slots[:i], a.slots[i+1:]...)
|
||||
break
|
||||
@@ -96,7 +86,6 @@ func (a *slotQueue) ejectSlot(ctx context.Context, s *slotToken) bool {
|
||||
}
|
||||
a.cond.L.Unlock()
|
||||
|
||||
s.slot.Close(ctx)
|
||||
// now we have the lock, push the trigger
|
||||
close(s.trigger)
|
||||
return true
|
||||
@@ -131,19 +120,13 @@ func (a *slotQueue) startDequeuer(ctx context.Context) chan *slotToken {
|
||||
return
|
||||
}
|
||||
|
||||
// pop
|
||||
item := a.slots[len(a.slots)-1]
|
||||
a.slots = a.slots[:len(a.slots)-1]
|
||||
a.cond.L.Unlock()
|
||||
|
||||
select {
|
||||
case output <- item: // good case (dequeued)
|
||||
case <-item.trigger: // ejected (eject handles cleanup)
|
||||
case <-ctx.Done(): // time out or cancel from caller
|
||||
// consume slot, we let the hot container queue the slot again
|
||||
if item.acquireSlot() {
|
||||
item.slot.Close(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user