1
0
This commit is contained in:
Arpad Ryszka 2026-03-15 17:44:03 +01:00
parent 2866936856
commit c96a21e423

View File

@ -64,174 +64,46 @@ func (a *adaptive) nightshiftTO() time.Duration {
return to return to
} }
// ensure that a single client does not get freed if using it func (a *adaptive) nightshift(s Stats) time.Duration {
// ensure that eventually gets collected if not using it
// ensure that the background job is not running forever
// handle load as well
func (a *adaptive) nightshift(s Stats, now time.Time) time.Duration {
// idle, inactive, uninitialized => not idle, initialize, 0
// idle, inactive, initialized => to
// idle, active, uninitialized => not idle, initialize, 0
// idle, active, initialized => not idle, initialize, 0
// not idle, inactive, uninitialized => not idle, initialize, 0
// not idle, inactive, initialized => idle, new to
// not idle, active, uninitialized => not idle, initialize, 0
// not idle, active, initialized => 0
// idle := a.idle
// active := s.Active > 0
// initialized := !a.activeTime.IsZero()
// if !initialized {
// a.idle = false
// a.activeTime = now
// return 0
// }
// if idle && !active {
// return a.nsTO
// }
// if idle {
// a.idle = false
// a.nsTO = 0
// a.activeTime = now
// return 0
// }
// if active {
// return 0
// }
// a.idle = true
// a.nsTO = nightshiftTO(a.activeTime, now)
// return a.nsTO
// --
// state flags:
// - initialized
// - pempty
// - pactive
// - empty
// - active
// actions:
// - start active
// - call to
// - update prev state on every call
// states:
// X not initialized, not pempty, not pactive, not empty, not active
// X not initialized, not pempty, not pactive, not empty, active
// X not initialized, not pempty, not pactive, empty, not active
// X not initialized, not pempty, not pactive, empty, active
// X not initialized, not pempty, pactive, not empty, not active
// X not initialized, not pempty, pactive, not empty, active
// X not initialized, not pempty, pactive, empty, not active
// X not initialized, not pempty, pactive, empty, active
// * not initialized, pempty, not pactive, not empty, not active => start active, call to
// * not initialized, pempty, not pactive, not empty, active => start active
// X not initialized, pempty, not pactive, empty, not active
// X not initialized, pempty, not pactive, empty, active
// X not initialized, pempty, pactive, not empty, not active
// X not initialized, pempty, pactive, not empty, active
// X not initialized, pempty, pactive, empty, not active
// X not initialized, pempty, pactive, empty, active
// * initialized, not pempty, not pactive, not empty, not active => end active, call to
// * initialized, not pempty, not pactive, not empty, active => start active
// * initialized, not pempty, not pactive, empty, not active => noop
// * initialized, not pempty, not pactive, empty, active => start active
// * initialized, not pempty, pactive, not empty, not active => end active, call to
// * initialized, not pempty, pactive, not empty, active => noop
// * initialized, not pempty, pactive, empty, not active => end active, noop
// * initialized, not pempty, pactive, empty, active => noop
// * initialized, pempty, not pactive, not empty, not active => call to
// * initialized, pempty, not pactive, not empty, active => start active
// * initialized, pempty, not pactive, empty, not active => noop
// * initialized, pempty, not pactive, empty, active => start active
// * initialized, pempty, pactive, not empty, not active => end active, call to
// * initialized, pempty, pactive, not empty, active => noop
// - initialized, pempty, pactive, empty, not active => end active, noop
// * initialized, pempty, pactive, empty, active => noop
pempty := a.prevState.Idle == 0
pactive := a.prevState.Active > 0 pactive := a.prevState.Active > 0
empty := s.Idle == 0 empty := s.Idle == 0
active := s.Active > 0 active := s.Active > 0
a.prevState = s a.prevState = s
// not initialized, pempty, not pactive, not empty, not active => start active, call to // on the first put we need to set an active start time:
if !a.initialized && pempty && !pactive && !empty && !active {
a.initialized = true
a.activeStart = now
return a.nightshiftTO()
}
// not initialized, pempty, not pactive, not empty, active => start active
if !a.initialized && pempty && !pactive && !empty && active {
a.initialized = true
a.activeStart = now
return 0
}
if !a.initialized { if !a.initialized {
a.initialized = true
a.activeStart = a.clock.Now()
if active {
return 0 return 0
} }
// initialized, not pempty, not pactive, not empty, not active => end active, call to
if !pempty && !pactive && !empty && !active {
ns := a.nightshiftTO()
return ns
}
// initialized, not pempty, not pactive, not empty, active => start active
// initialized, not pempty, not pactive, empty, active => start active
if !pempty && !pactive && active {
a.activeStart = now
return 0
}
// initialized, not pempty, pactive, not empty, not active => end active, call to
if !pempty && pactive && !empty && !active {
a.activeEnd = now
ns := a.nightshiftTO()
return ns
}
// initialized, not pempty, pactive, empty, not active => end active, noop
if !pempty && pactive && empty && !active {
a.activeEnd = now
return 0
}
// initialized, pempty, not pactive, not empty, not active => call to
if pempty && !pactive && !empty && !active {
return a.nightshiftTO() return a.nightshiftTO()
} }
// initialized, pempty, not pactive, not empty, active => start active if !pactive && !active && !empty {
// initialized, pempty, not pactive, empty, active => start active
if pempty && !pactive && active {
a.activeStart = now
return 0
}
// initialized, pempty, pactive, not empty, not active => end active, call to
if pempty && pactive && !empty && !active {
a.activeEnd = now
return a.nightshiftTO() return a.nightshiftTO()
} }
// initialized, pempty, pactive, empty, not active => end active, noop if !pactive && active {
if pempty && pactive && empty && !active { a.activeStart = a.clock.Now()
a.activeEnd = now
return 0 return 0
} }
if pactive && !active {
a.activeEnd = a.clock.Now()
if empty {
return 0
}
return a.nightshiftTO()
}
return 0 return 0
} }
func (a *adaptive) Target(s Stats) (int, time.Duration) { func (a *adaptive) Target(s Stats) (int, time.Duration) {
t := a.target(s) // handle when t < 2 t := a.target(s)
// magic number 2: we allow max 2 idle items to be collected only by the nightshift, to provide better // magic number 2: we allow max 2 idle items to be collected only by the nightshift, to provide better
// support for sporadic requests, when it's active or just going inactive: // support for sporadic requests, when it's active or just going inactive:
@ -239,9 +111,7 @@ func (a *adaptive) Target(s Stats) (int, time.Duration) {
t = 2 t = 2
} }
// TODO: optimize, only take the clock when necessary ns := a.nightshift(s)
ns := a.nightshift(s, a.clock.Now())
return t, ns return t, ns
} }
@ -251,5 +121,5 @@ func (a *adaptive) Load(n int) {
a.average += float64(n) a.average += float64(n)
s := a.prevState s := a.prevState
s.Idle += n s.Idle += n
a.nightshift(s, a.clock.Now()) a.nightshift(s)
} }