blob: 9140b4ca95efd01c49c1542fd4ce709e1a772506 [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 (
"context"
"math"
"os"
"strconv"
"sync"
"golang.org/x/pkgsite/internal/log"
)
var (
// The maximum size of zips being processed. If an incoming module would
// cause zipSizeInFlight to exceed this value, it won't be processed.
maxZipSizeInFlight uint64 = math.MaxUint64
// Protects the variables below, and also serializes shedding decisions so
// multiple simultaneous requests are handled properly.
shedmu sync.Mutex
// The total size of all zips currently being processed. We treat zip size
// as a proxy for the total memory consumed by processing a module, and use
// it to decide whether we can currently afford to process a module.
zipSizeInFlight uint64
fetchesInFlight int // number of fetches currently in progress
totalRequests int // total fetch requests
sheddedRequests int // number of requests that were shedded
)
func init() {
ctx := context.Background()
m := os.Getenv("GO_DISCOVERY_MAX_IN_FLIGHT_ZIP_MI")
if m != "" {
mebis, err := strconv.ParseUint(m, 10, 64)
if err != nil {
log.Errorf(ctx, "could not parse GO_DISCOVERY_MAX_IN_FLIGHT_ZIP_MI value %q", m)
} else if mebis == 0 {
log.Errorf(ctx, "bad value for GO_DISCOVERY_MAX_IN_FLIGHT_ZIP_MI: %d. Must be >= 1.", mebis)
} else {
log.Infof(ctx, "shedding load over %dMi", mebis)
maxZipSizeInFlight = mebis * mib
}
}
}
// decideToShed reports whether a module whose zip file is zipSize bytes should
// be shed (not processed). Its second return value is a function that should be
// deferred by the caller.
func decideToShed(zipSize uint64) (shouldShed bool, deferFunc func()) {
shedmu.Lock()
defer shedmu.Unlock()
totalRequests++
if zipSizeInFlight+zipSize > maxZipSizeInFlight {
sheddedRequests++
return true, func() {}
}
zipSizeInFlight += zipSize
fetchesInFlight++
return false, func() {
shedmu.Lock()
defer shedmu.Unlock()
zipSizeInFlight -= zipSize
fetchesInFlight--
}
}
// LoadShedStats holds statistics about load shedding.
type LoadShedStats struct {
FetchesInFlight int
ZipBytesInFlight uint64
MaxZipBytesInFlight uint64
SheddedRequests int
TotalRequests int
}
// GetLoadShedStats returns a snapshot of the current LoadShedStats.
func GetLoadShedStats() LoadShedStats {
shedmu.Lock()
defer shedmu.Unlock()
return LoadShedStats{
FetchesInFlight: fetchesInFlight,
ZipBytesInFlight: zipSizeInFlight,
MaxZipBytesInFlight: maxZipSizeInFlight,
SheddedRequests: sheddedRequests,
TotalRequests: totalRequests,
}
}