Upgrade k8s package verison (#5358)
* upgrade k8s package version Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> * Script upgrade and code formatting. Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
This commit is contained in:
213
vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_controller.go
generated
vendored
213
vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_controller.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
@@ -28,14 +29,12 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
apitypes "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
@@ -47,13 +46,15 @@ import (
|
||||
fq "k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing"
|
||||
fcfmt "k8s.io/apiserver/pkg/util/flowcontrol/format"
|
||||
"k8s.io/apiserver/pkg/util/flowcontrol/metrics"
|
||||
fcrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
flowcontrol "k8s.io/api/flowcontrol/v1beta1"
|
||||
flowcontrolclient "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1"
|
||||
flowcontrollister "k8s.io/client-go/listers/flowcontrol/v1beta1"
|
||||
flowcontrol "k8s.io/api/flowcontrol/v1beta2"
|
||||
flowcontrolclient "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2"
|
||||
flowcontrollister "k8s.io/client-go/listers/flowcontrol/v1beta2"
|
||||
)
|
||||
|
||||
const timeFmt = "2006-01-02T15:04:05.999"
|
||||
@@ -67,6 +68,14 @@ const timeFmt = "2006-01-02T15:04:05.999"
|
||||
// undesired becomes completely unused, all the config objects are
|
||||
// read and processed as a whole.
|
||||
|
||||
// The funcs in this package follow the naming convention that the suffix
|
||||
// "Locked" means the relevant mutex must be locked at the start of each
|
||||
// call and will be locked upon return. For a configController, the
|
||||
// suffix "ReadLocked" stipulates a read lock while just "Locked"
|
||||
// stipulates a full lock. Absence of either suffix means that either
|
||||
// (a) the lock must NOT be held at call time and will not be held
|
||||
// upon return or (b) locking is irrelevant.
|
||||
|
||||
// StartFunction begins the process of handling a request. If the
|
||||
// request gets queued then this function uses the given hashValue as
|
||||
// the source of entropy as it shuffle-shards the request into a
|
||||
@@ -90,10 +99,11 @@ type RequestDigest struct {
|
||||
// this type and cfgMeal follow the convention that the suffix
|
||||
// "Locked" means that the caller must hold the configController lock.
|
||||
type configController struct {
|
||||
name string // varies in tests of fighting controllers
|
||||
clock clock.PassiveClock
|
||||
queueSetFactory fq.QueueSetFactory
|
||||
obsPairGenerator metrics.TimedObserverPairGenerator
|
||||
name string // varies in tests of fighting controllers
|
||||
clock clock.PassiveClock
|
||||
queueSetFactory fq.QueueSetFactory
|
||||
reqsGaugeVec metrics.RatioedGaugeVec
|
||||
execSeatsGaugeVec metrics.RatioedGaugeVec
|
||||
|
||||
// How this controller appears in an ObjectMeta ManagedFieldsEntry.Manager
|
||||
asFieldManager string
|
||||
@@ -113,7 +123,7 @@ type configController struct {
|
||||
fsLister flowcontrollister.FlowSchemaLister
|
||||
fsInformerSynced cache.InformerSynced
|
||||
|
||||
flowcontrolClient flowcontrolclient.FlowcontrolV1beta1Interface
|
||||
flowcontrolClient flowcontrolclient.FlowcontrolV1beta2Interface
|
||||
|
||||
// serverConcurrencyLimit is the limit on the server's total
|
||||
// number of non-exempt requests being served at once. This comes
|
||||
@@ -123,10 +133,25 @@ type configController struct {
|
||||
// requestWaitLimit comes from server configuration.
|
||||
requestWaitLimit time.Duration
|
||||
|
||||
// This must be locked while accessing flowSchemas or
|
||||
// priorityLevelStates. It is the lock involved in
|
||||
// LockingWriteMultiple.
|
||||
lock sync.Mutex
|
||||
// watchTracker implements the necessary WatchTracker interface.
|
||||
WatchTracker
|
||||
|
||||
// the most recent update attempts, ordered by increasing age.
|
||||
// Consumer trims to keep only the last minute's worth of entries.
|
||||
// The controller uses this to limit itself to at most six updates
|
||||
// to a given FlowSchema in any minute.
|
||||
// This may only be accessed from the one and only worker goroutine.
|
||||
mostRecentUpdates []updateAttempt
|
||||
|
||||
// This must be locked while accessing the later fields.
|
||||
// A lock for writing is needed
|
||||
// for writing to any of the following:
|
||||
// - the flowSchemas field
|
||||
// - the slice held in the flowSchemas field
|
||||
// - the priorityLevelStates field
|
||||
// - the map held in the priorityLevelStates field
|
||||
// - any field of a priorityLevelState held in that map
|
||||
lock sync.RWMutex
|
||||
|
||||
// flowSchemas holds the flow schema objects, sorted by increasing
|
||||
// numerical (decreasing logical) matching precedence. Every
|
||||
@@ -137,13 +162,6 @@ type configController struct {
|
||||
// name to the state for that level. Every name referenced from a
|
||||
// member of `flowSchemas` has an entry here.
|
||||
priorityLevelStates map[string]*priorityLevelState
|
||||
|
||||
// the most recent update attempts, ordered by increasing age.
|
||||
// Consumer trims to keep only the last minute's worth of entries.
|
||||
// The controller uses this to limit itself to at most six updates
|
||||
// to a given FlowSchema in any minute.
|
||||
// This may only be accessed from the one and only worker goroutine.
|
||||
mostRecentUpdates []updateAttempt
|
||||
}
|
||||
|
||||
type updateAttempt struct {
|
||||
@@ -174,8 +192,11 @@ type priorityLevelState struct {
|
||||
// returned StartFunction
|
||||
numPending int
|
||||
|
||||
// Observers tracking number waiting, executing
|
||||
obsPair metrics.TimedObserverPair
|
||||
// Observers tracking number of requests waiting, executing
|
||||
reqsGaugePair metrics.RatioedGaugePair
|
||||
|
||||
// Observer of number of seats occupied throughout execution
|
||||
execSeatsObs metrics.RatioedGauge
|
||||
}
|
||||
|
||||
// NewTestableController is extra flexible to facilitate testing
|
||||
@@ -184,13 +205,15 @@ func newTestableController(config TestableConfig) *configController {
|
||||
name: config.Name,
|
||||
clock: config.Clock,
|
||||
queueSetFactory: config.QueueSetFactory,
|
||||
obsPairGenerator: config.ObsPairGenerator,
|
||||
reqsGaugeVec: config.ReqsGaugeVec,
|
||||
execSeatsGaugeVec: config.ExecSeatsGaugeVec,
|
||||
asFieldManager: config.AsFieldManager,
|
||||
foundToDangling: config.FoundToDangling,
|
||||
serverConcurrencyLimit: config.ServerConcurrencyLimit,
|
||||
requestWaitLimit: config.RequestWaitLimit,
|
||||
flowcontrolClient: config.FlowcontrolClient,
|
||||
priorityLevelStates: make(map[string]*priorityLevelState),
|
||||
WatchTracker: NewWatchTracker(),
|
||||
}
|
||||
klog.V(2).Infof("NewTestableController %q with serverConcurrencyLimit=%d, requestWaitLimit=%s, name=%s, asFieldManager=%q", cfgCtlr.name, cfgCtlr.serverConcurrencyLimit, cfgCtlr.requestWaitLimit, cfgCtlr.name, cfgCtlr.asFieldManager)
|
||||
// Start with longish delay because conflicts will be between
|
||||
@@ -198,7 +221,7 @@ func newTestableController(config TestableConfig) *configController {
|
||||
cfgCtlr.configQueue = workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(200*time.Millisecond, 8*time.Hour), "priority_and_fairness_config_queue")
|
||||
// ensure the data structure reflects the mandatory config
|
||||
cfgCtlr.lockAndDigestConfigObjects(nil, nil)
|
||||
fci := config.InformerFactory.Flowcontrol().V1beta1()
|
||||
fci := config.InformerFactory.Flowcontrol().V1beta2()
|
||||
pli := fci.PriorityLevelConfigurations()
|
||||
fsi := fci.FlowSchemas()
|
||||
cfgCtlr.plLister = pli.Lister()
|
||||
@@ -268,23 +291,6 @@ func newTestableController(config TestableConfig) *configController {
|
||||
return cfgCtlr
|
||||
}
|
||||
|
||||
// MaintainObservations keeps the observers from
|
||||
// metrics.PriorityLevelConcurrencyObserverPairGenerator from falling
|
||||
// too far behind
|
||||
func (cfgCtlr *configController) MaintainObservations(stopCh <-chan struct{}) {
|
||||
wait.Until(cfgCtlr.updateObservations, 10*time.Second, stopCh)
|
||||
}
|
||||
|
||||
func (cfgCtlr *configController) updateObservations() {
|
||||
cfgCtlr.lock.Lock()
|
||||
defer cfgCtlr.lock.Unlock()
|
||||
for _, plc := range cfgCtlr.priorityLevelStates {
|
||||
if plc.queues != nil {
|
||||
plc.queues.UpdateObservations()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cfgCtlr *configController) Run(stopCh <-chan struct{}) error {
|
||||
defer utilruntime.HandleCrash()
|
||||
|
||||
@@ -322,7 +328,7 @@ func (cfgCtlr *configController) processNextWorkItem() bool {
|
||||
|
||||
func(obj interface{}) {
|
||||
defer cfgCtlr.configQueue.Done(obj)
|
||||
specificDelay, err := cfgCtlr.syncOne(map[string]string{})
|
||||
specificDelay, err := cfgCtlr.syncOne()
|
||||
switch {
|
||||
case err != nil:
|
||||
klog.Error(err)
|
||||
@@ -341,7 +347,7 @@ func (cfgCtlr *configController) processNextWorkItem() bool {
|
||||
// objects that configure API Priority and Fairness and updates the
|
||||
// local configController accordingly.
|
||||
// Only invoke this in the one and only worker goroutine
|
||||
func (cfgCtlr *configController) syncOne(flowSchemaRVs map[string]string) (specificDelay time.Duration, err error) {
|
||||
func (cfgCtlr *configController) syncOne() (specificDelay time.Duration, err error) {
|
||||
klog.V(5).Infof("%s syncOne at %s", cfgCtlr.name, cfgCtlr.clock.Now().Format(timeFmt))
|
||||
all := labels.Everything()
|
||||
newPLs, err := cfgCtlr.plLister.List(all)
|
||||
@@ -352,7 +358,7 @@ func (cfgCtlr *configController) syncOne(flowSchemaRVs map[string]string) (speci
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to list FlowSchema objects: %w", err)
|
||||
}
|
||||
return cfgCtlr.digestConfigObjects(newPLs, newFSs, flowSchemaRVs)
|
||||
return cfgCtlr.digestConfigObjects(newPLs, newFSs)
|
||||
}
|
||||
|
||||
// cfgMeal is the data involved in the process of digesting the API
|
||||
@@ -381,6 +387,8 @@ type cfgMeal struct {
|
||||
// provoking a call into this controller while the lock held
|
||||
// waiting on that request to complete.
|
||||
fsStatusUpdates []fsStatusUpdate
|
||||
|
||||
maxWaitingRequests, maxExecutingRequests int
|
||||
}
|
||||
|
||||
// A buffered set of status updates for FlowSchemas
|
||||
@@ -393,7 +401,7 @@ type fsStatusUpdate struct {
|
||||
// digestConfigObjects is given all the API objects that configure
|
||||
// cfgCtlr and writes its consequent new configState.
|
||||
// Only invoke this in the one and only worker goroutine
|
||||
func (cfgCtlr *configController) digestConfigObjects(newPLs []*flowcontrol.PriorityLevelConfiguration, newFSs []*flowcontrol.FlowSchema, flowSchemaRVs map[string]string) (time.Duration, error) {
|
||||
func (cfgCtlr *configController) digestConfigObjects(newPLs []*flowcontrol.PriorityLevelConfiguration, newFSs []*flowcontrol.FlowSchema) (time.Duration, error) {
|
||||
fsStatusUpdates := cfgCtlr.lockAndDigestConfigObjects(newPLs, newFSs)
|
||||
var errs []error
|
||||
currResult := updateAttempt{
|
||||
@@ -412,26 +420,26 @@ func (cfgCtlr *configController) digestConfigObjects(newPLs []*flowcontrol.Prior
|
||||
|
||||
// if we are going to issue an update, be sure we track every name we update so we know if we update it too often.
|
||||
currResult.updatedItems.Insert(fsu.flowSchema.Name)
|
||||
|
||||
enc, err := json.Marshal(fsu.condition)
|
||||
patchBytes, err := makeFlowSchemaConditionPatch(fsu.condition)
|
||||
if err != nil {
|
||||
// should never happen because these conditions are created here and well formed
|
||||
panic(fmt.Sprintf("Failed to json.Marshall(%#+v): %s", fsu.condition, err.Error()))
|
||||
}
|
||||
klog.V(4).Infof("%s writing Condition %s to FlowSchema %s, which had ResourceVersion=%s, because its previous value was %s", cfgCtlr.name, string(enc), fsu.flowSchema.Name, fsu.flowSchema.ResourceVersion, fcfmt.Fmt(fsu.oldValue))
|
||||
if klogV := klog.V(4); klogV.Enabled() {
|
||||
klogV.Infof("%s writing Condition %s to FlowSchema %s, which had ResourceVersion=%s, because its previous value was %s, diff: %s",
|
||||
cfgCtlr.name, fsu.condition, fsu.flowSchema.Name, fsu.flowSchema.ResourceVersion, fcfmt.Fmt(fsu.oldValue), cmp.Diff(fsu.oldValue, fsu.condition))
|
||||
}
|
||||
fsIfc := cfgCtlr.flowcontrolClient.FlowSchemas()
|
||||
patchBytes := []byte(fmt.Sprintf(`{"status": {"conditions": [ %s ] } }`, string(enc)))
|
||||
patchOptions := metav1.PatchOptions{FieldManager: cfgCtlr.asFieldManager}
|
||||
patchedFlowSchema, err := fsIfc.Patch(context.TODO(), fsu.flowSchema.Name, apitypes.StrategicMergePatchType, patchBytes, patchOptions, "status")
|
||||
if err == nil {
|
||||
key, _ := cache.MetaNamespaceKeyFunc(patchedFlowSchema)
|
||||
flowSchemaRVs[key] = patchedFlowSchema.ResourceVersion
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
// This object has been deleted. A notification is coming
|
||||
// and nothing more needs to be done here.
|
||||
klog.V(5).Infof("%s at %s: attempted update of concurrently deleted FlowSchema %s; nothing more needs to be done", cfgCtlr.name, cfgCtlr.clock.Now().Format(timeFmt), fsu.flowSchema.Name)
|
||||
} else {
|
||||
errs = append(errs, errors.Wrap(err, fmt.Sprintf("failed to set a status.condition for FlowSchema %s", fsu.flowSchema.Name)))
|
||||
_, err = fsIfc.Patch(context.TODO(), fsu.flowSchema.Name, apitypes.StrategicMergePatchType, patchBytes, patchOptions, "status")
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
// This object has been deleted. A notification is coming
|
||||
// and nothing more needs to be done here.
|
||||
klog.V(5).Infof("%s at %s: attempted update of concurrently deleted FlowSchema %s; nothing more needs to be done", cfgCtlr.name, cfgCtlr.clock.Now().Format(timeFmt), fsu.flowSchema.Name)
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("failed to set a status.condition for FlowSchema %s: %w", fsu.flowSchema.Name, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
cfgCtlr.addUpdateResult(currResult)
|
||||
@@ -439,6 +447,20 @@ func (cfgCtlr *configController) digestConfigObjects(newPLs []*flowcontrol.Prior
|
||||
return suggestedDelay, utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// makeFlowSchemaConditionPatch takes in a condition and returns the patch status as a json.
|
||||
func makeFlowSchemaConditionPatch(condition flowcontrol.FlowSchemaCondition) ([]byte, error) {
|
||||
o := struct {
|
||||
Status flowcontrol.FlowSchemaStatus `json:"status"`
|
||||
}{
|
||||
Status: flowcontrol.FlowSchemaStatus{
|
||||
Conditions: []flowcontrol.FlowSchemaCondition{
|
||||
condition,
|
||||
},
|
||||
},
|
||||
}
|
||||
return json.Marshal(o)
|
||||
}
|
||||
|
||||
// shouldDelayUpdate checks to see if a flowschema has been updated too often and returns true if a delay is needed.
|
||||
// Only invoke this in the one and only worker goroutine
|
||||
func (cfgCtlr *configController) shouldDelayUpdate(flowSchemaName string) bool {
|
||||
@@ -491,7 +513,13 @@ func (cfgCtlr *configController) lockAndDigestConfigObjects(newPLs []*flowcontro
|
||||
|
||||
// The new config has been constructed
|
||||
cfgCtlr.priorityLevelStates = meal.newPLStates
|
||||
klog.V(5).Infof("Switched to new API Priority and Fairness configuration")
|
||||
klog.V(5).InfoS("Switched to new API Priority and Fairness configuration", "maxWaitingRequests", meal.maxWaitingRequests, "maxExecutinRequests", meal.maxExecutingRequests)
|
||||
|
||||
metrics.GetWaitingReadonlyConcurrency().SetDenominator(float64(meal.maxWaitingRequests))
|
||||
metrics.GetWaitingMutatingConcurrency().SetDenominator(float64(meal.maxWaitingRequests))
|
||||
metrics.GetExecutingReadonlyConcurrency().SetDenominator(float64(meal.maxExecutingRequests))
|
||||
metrics.GetExecutingMutatingConcurrency().SetDenominator(float64(meal.maxExecutingRequests))
|
||||
|
||||
return meal.fsStatusUpdates
|
||||
}
|
||||
|
||||
@@ -501,9 +529,10 @@ func (meal *cfgMeal) digestNewPLsLocked(newPLs []*flowcontrol.PriorityLevelConfi
|
||||
for _, pl := range newPLs {
|
||||
state := meal.cfgCtlr.priorityLevelStates[pl.Name]
|
||||
if state == nil {
|
||||
state = &priorityLevelState{obsPair: meal.cfgCtlr.obsPairGenerator.Generate(1, 1, []string{pl.Name})}
|
||||
labelValues := []string{pl.Name}
|
||||
state = &priorityLevelState{reqsGaugePair: metrics.RatioedGaugeVecPhasedElementPair(meal.cfgCtlr.reqsGaugeVec, 1, 1, labelValues), execSeatsObs: meal.cfgCtlr.execSeatsGaugeVec.NewForLabelValuesSafe(0, 1, labelValues)}
|
||||
}
|
||||
qsCompleter, err := queueSetCompleterForPL(meal.cfgCtlr.queueSetFactory, state.queues, pl, meal.cfgCtlr.requestWaitLimit, state.obsPair)
|
||||
qsCompleter, err := queueSetCompleterForPL(meal.cfgCtlr.queueSetFactory, state.queues, pl, meal.cfgCtlr.requestWaitLimit, state.reqsGaugePair, state.execSeatsObs)
|
||||
if err != nil {
|
||||
klog.Warningf("Ignoring PriorityLevelConfiguration object %s because its spec (%s) is broken: %s", pl.Name, fcfmt.Fmt(pl.Spec), err)
|
||||
continue
|
||||
@@ -570,9 +599,10 @@ func (meal *cfgMeal) digestFlowSchemasLocked(newFSs []*flowcontrol.FlowSchema) {
|
||||
}
|
||||
|
||||
meal.cfgCtlr.flowSchemas = fsSeq
|
||||
if klog.V(5).Enabled() {
|
||||
klogV := klog.V(5)
|
||||
if klogV.Enabled() {
|
||||
for _, fs := range fsSeq {
|
||||
klog.Infof("Using FlowSchema %s", fcfmt.Fmt(fs))
|
||||
klogV.Infof("Using FlowSchema %s", fcfmt.Fmt(fs))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -606,7 +636,7 @@ func (meal *cfgMeal) processOldPLsLocked() {
|
||||
}
|
||||
}
|
||||
var err error
|
||||
plState.qsCompleter, err = queueSetCompleterForPL(meal.cfgCtlr.queueSetFactory, plState.queues, plState.pl, meal.cfgCtlr.requestWaitLimit, plState.obsPair)
|
||||
plState.qsCompleter, err = queueSetCompleterForPL(meal.cfgCtlr.queueSetFactory, plState.queues, plState.pl, meal.cfgCtlr.requestWaitLimit, plState.reqsGaugePair, plState.execSeatsObs)
|
||||
if err != nil {
|
||||
// This can not happen because queueSetCompleterForPL already approved this config
|
||||
panic(fmt.Sprintf("%s from name=%q spec=%s", err, plName, fcfmt.Fmt(plState.pl.Spec)))
|
||||
@@ -641,6 +671,12 @@ func (meal *cfgMeal) finishQueueSetReconfigsLocked() {
|
||||
// difference will be negligible.
|
||||
concurrencyLimit := int(math.Ceil(float64(meal.cfgCtlr.serverConcurrencyLimit) * float64(plState.pl.Spec.Limited.AssuredConcurrencyShares) / meal.shareSum))
|
||||
metrics.UpdateSharedConcurrencyLimit(plName, concurrencyLimit)
|
||||
meal.maxExecutingRequests += concurrencyLimit
|
||||
var waitLimit int
|
||||
if qCfg := plState.pl.Spec.Limited.LimitResponse.Queuing; qCfg != nil {
|
||||
waitLimit = int(qCfg.Queues * qCfg.QueueLengthLimit)
|
||||
}
|
||||
meal.maxWaitingRequests += waitLimit
|
||||
|
||||
if plState.queues == nil {
|
||||
klog.V(5).Infof("Introducing queues for priority level %q: config=%s, concurrencyLimit=%d, quiescing=%v (shares=%v, shareSum=%v)", plName, fcfmt.Fmt(plState.pl.Spec), concurrencyLimit, plState.quiescing, plState.pl.Spec.Limited.AssuredConcurrencyShares, meal.shareSum)
|
||||
@@ -655,7 +691,7 @@ func (meal *cfgMeal) finishQueueSetReconfigsLocked() {
|
||||
// given priority level configuration. Returns nil if that config
|
||||
// does not call for limiting. Returns nil and an error if the given
|
||||
// object is malformed in a way that is a problem for this package.
|
||||
func queueSetCompleterForPL(qsf fq.QueueSetFactory, queues fq.QueueSet, pl *flowcontrol.PriorityLevelConfiguration, requestWaitLimit time.Duration, intPair metrics.TimedObserverPair) (fq.QueueSetCompleter, error) {
|
||||
func queueSetCompleterForPL(qsf fq.QueueSetFactory, queues fq.QueueSet, pl *flowcontrol.PriorityLevelConfiguration, requestWaitLimit time.Duration, reqsIntPair metrics.RatioedGaugePair, execSeatsObs metrics.RatioedGauge) (fq.QueueSetCompleter, error) {
|
||||
if (pl.Spec.Type == flowcontrol.PriorityLevelEnablementExempt) != (pl.Spec.Limited == nil) {
|
||||
return nil, errors.New("broken union structure at the top")
|
||||
}
|
||||
@@ -684,10 +720,10 @@ func queueSetCompleterForPL(qsf fq.QueueSetFactory, queues fq.QueueSet, pl *flow
|
||||
if queues != nil {
|
||||
qsc, err = queues.BeginConfigChange(qcQS)
|
||||
} else {
|
||||
qsc, err = qsf.BeginConstruction(qcQS, intPair)
|
||||
qsc, err = qsf.BeginConstruction(qcQS, reqsIntPair, execSeatsObs)
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("priority level %q has QueuingConfiguration %#+v, which is invalid", pl.Name, qcAPI))
|
||||
err = fmt.Errorf("priority level %q has QueuingConfiguration %#+v, which is invalid: %w", pl.Name, qcAPI, err)
|
||||
}
|
||||
return qsc, err
|
||||
}
|
||||
@@ -729,17 +765,20 @@ func (meal *cfgMeal) presyncFlowSchemaStatus(fs *flowcontrol.FlowSchema, isDangl
|
||||
// that does not actually exist (right now) as a real API object.
|
||||
func (meal *cfgMeal) imaginePL(proto *flowcontrol.PriorityLevelConfiguration, requestWaitLimit time.Duration) {
|
||||
klog.V(3).Infof("No %s PriorityLevelConfiguration found, imagining one", proto.Name)
|
||||
obsPair := meal.cfgCtlr.obsPairGenerator.Generate(1, 1, []string{proto.Name})
|
||||
qsCompleter, err := queueSetCompleterForPL(meal.cfgCtlr.queueSetFactory, nil, proto, requestWaitLimit, obsPair)
|
||||
labelValues := []string{proto.Name}
|
||||
reqsGaugePair := metrics.RatioedGaugeVecPhasedElementPair(meal.cfgCtlr.reqsGaugeVec, 1, 1, labelValues)
|
||||
execSeatsObs := meal.cfgCtlr.execSeatsGaugeVec.NewForLabelValuesSafe(0, 1, labelValues)
|
||||
qsCompleter, err := queueSetCompleterForPL(meal.cfgCtlr.queueSetFactory, nil, proto, requestWaitLimit, reqsGaugePair, execSeatsObs)
|
||||
if err != nil {
|
||||
// This can not happen because proto is one of the mandatory
|
||||
// objects and these are not erroneous
|
||||
panic(err)
|
||||
}
|
||||
meal.newPLStates[proto.Name] = &priorityLevelState{
|
||||
pl: proto,
|
||||
qsCompleter: qsCompleter,
|
||||
obsPair: obsPair,
|
||||
pl: proto,
|
||||
qsCompleter: qsCompleter,
|
||||
reqsGaugePair: reqsGaugePair,
|
||||
execSeatsObs: execSeatsObs,
|
||||
}
|
||||
if proto.Spec.Limited != nil {
|
||||
meal.shareSum += float64(proto.Spec.Limited.AssuredConcurrencyShares)
|
||||
@@ -758,10 +797,13 @@ func (immediateRequest) Finish(execute func()) bool {
|
||||
// The returned bool indicates whether the request is exempt from
|
||||
// limitation. The startWaitingTime is when the request started
|
||||
// waiting in its queue, or `Time{}` if this did not happen.
|
||||
func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDigest, queueNoteFn fq.QueueNoteFn) (fs *flowcontrol.FlowSchema, pl *flowcontrol.PriorityLevelConfiguration, isExempt bool, req fq.Request, startWaitingTime time.Time) {
|
||||
func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDigest,
|
||||
noteFn func(fs *flowcontrol.FlowSchema, pl *flowcontrol.PriorityLevelConfiguration, flowDistinguisher string),
|
||||
workEstimator func() fcrequest.WorkEstimate,
|
||||
queueNoteFn fq.QueueNoteFn) (fs *flowcontrol.FlowSchema, pl *flowcontrol.PriorityLevelConfiguration, isExempt bool, req fq.Request, startWaitingTime time.Time) {
|
||||
klog.V(7).Infof("startRequest(%#+v)", rd)
|
||||
cfgCtlr.lock.Lock()
|
||||
defer cfgCtlr.lock.Unlock()
|
||||
cfgCtlr.lock.RLock()
|
||||
defer cfgCtlr.lock.RUnlock()
|
||||
var selectedFlowSchema, catchAllFlowSchema *flowcontrol.FlowSchema
|
||||
for _, fs := range cfgCtlr.flowSchemas {
|
||||
if matchesFlowSchema(rd, fs) {
|
||||
@@ -789,6 +831,7 @@ func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDig
|
||||
plName := selectedFlowSchema.Spec.PriorityLevelConfiguration.Name
|
||||
plState := cfgCtlr.priorityLevelStates[plName]
|
||||
if plState.pl.Spec.Type == flowcontrol.PriorityLevelEnablementExempt {
|
||||
noteFn(selectedFlowSchema, plState.pl, "")
|
||||
klog.V(7).Infof("startRequest(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, immediate", rd, selectedFlowSchema.Name, selectedFlowSchema.Spec.DistinguisherMethod, plName)
|
||||
return selectedFlowSchema, plState.pl, true, immediateRequest{}, time.Time{}
|
||||
}
|
||||
@@ -802,11 +845,15 @@ func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDig
|
||||
flowDistinguisher = computeFlowDistinguisher(rd, selectedFlowSchema.Spec.DistinguisherMethod)
|
||||
hashValue = hashFlowID(selectedFlowSchema.Name, flowDistinguisher)
|
||||
}
|
||||
|
||||
noteFn(selectedFlowSchema, plState.pl, flowDistinguisher)
|
||||
workEstimate := workEstimator()
|
||||
|
||||
startWaitingTime = time.Now()
|
||||
klog.V(7).Infof("startRequest(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, numQueues=%d", rd, selectedFlowSchema.Name, selectedFlowSchema.Spec.DistinguisherMethod, plName, numQueues)
|
||||
req, idle := plState.queues.StartRequest(ctx, hashValue, flowDistinguisher, selectedFlowSchema.Name, rd.RequestInfo, rd.User, queueNoteFn)
|
||||
req, idle := plState.queues.StartRequest(ctx, &workEstimate, hashValue, flowDistinguisher, selectedFlowSchema.Name, rd.RequestInfo, rd.User, queueNoteFn)
|
||||
if idle {
|
||||
cfgCtlr.maybeReapLocked(plName, plState)
|
||||
cfgCtlr.maybeReapReadLocked(plName, plState)
|
||||
}
|
||||
return selectedFlowSchema, plState.pl, false, req, startWaitingTime
|
||||
}
|
||||
@@ -815,8 +862,8 @@ func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDig
|
||||
// priority level if it has no more use. Call this after getting a
|
||||
// clue that the given priority level is undesired and idle.
|
||||
func (cfgCtlr *configController) maybeReap(plName string) {
|
||||
cfgCtlr.lock.Lock()
|
||||
defer cfgCtlr.lock.Unlock()
|
||||
cfgCtlr.lock.RLock()
|
||||
defer cfgCtlr.lock.RUnlock()
|
||||
plState := cfgCtlr.priorityLevelStates[plName]
|
||||
if plState == nil {
|
||||
klog.V(7).Infof("plName=%s, plState==nil", plName)
|
||||
@@ -838,7 +885,7 @@ func (cfgCtlr *configController) maybeReap(plName string) {
|
||||
// it has no more use. Call this if both (1) plState.queues is
|
||||
// non-nil and reported being idle, and (2) cfgCtlr's lock has not
|
||||
// been released since then.
|
||||
func (cfgCtlr *configController) maybeReapLocked(plName string, plState *priorityLevelState) {
|
||||
func (cfgCtlr *configController) maybeReapReadLocked(plName string, plState *priorityLevelState) {
|
||||
if !(plState.quiescing && plState.numPending == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user