blob: 6f609c84c02060053ef4db709f461e8230ce4918 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fetch
import (
"sync"
)
type loadShedder struct {
// The maximum size of requests that can be processed at once. If an
// incoming request would cause sizeInFlight to exceed this value, it won't
// be processed.
maxSizeInFlight uint64
// Protects the variables below, and also serializes shedding decisions so
// multiple simultaneous requests are handled properly.
mu sync.Mutex
sizeInFlight uint64 // size of requests currently in progress.
requestsInFlight int // number of request currently in progress
requestsTotal int // total fetch requests ever seen
requestsShed int // number of requests that were shedded
}
// shouldShed reports whether a request of size should be shed (not processed).
// Its second return value is a function that should be deferred by the caller.
func (ls *loadShedder) shouldShed(size uint64) (_ bool, deferFunc func()) {
ls.mu.Lock()
defer ls.mu.Unlock()
ls.requestsTotal++
// Shed if size exceeds our limit--except that if nothing is being
// processed, accept this request to avoid starving it forever.
if ls.sizeInFlight > 0 && ls.sizeInFlight+size > ls.maxSizeInFlight {
ls.requestsShed++
return true, func() {}
}
ls.sizeInFlight += size
ls.requestsInFlight++
return false, func() {
ls.mu.Lock()
defer ls.mu.Unlock()
ls.sizeInFlight -= size
ls.requestsInFlight--
}
}
// LoadShedStats holds statistics about load shedding.
type LoadShedStats struct {
SizeInFlight uint64
MaxSizeInFlight uint64
RequestsInFlight int
RequestsShed int
RequestsTotal int
}
func (ls *loadShedder) stats() LoadShedStats {
ls.mu.Lock()
defer ls.mu.Unlock()
return LoadShedStats{
RequestsInFlight: ls.requestsInFlight,
SizeInFlight: ls.sizeInFlight,
MaxSizeInFlight: ls.maxSizeInFlight,
RequestsShed: ls.requestsShed,
RequestsTotal: ls.requestsTotal,
}
}