mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
rebase: bump k8s.io/kubernetes from 1.26.2 to 1.27.2
Bumps [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes) from 1.26.2 to 1.27.2. - [Release notes](https://github.com/kubernetes/kubernetes/releases) - [Commits](https://github.com/kubernetes/kubernetes/compare/v1.26.2...v1.27.2) --- updated-dependencies: - dependency-name: k8s.io/kubernetes dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
mergify[bot]
parent
0e79135419
commit
07b05616a0
47
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/eventclock/interface.go
generated
vendored
Normal file
47
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/eventclock/interface.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package eventclock
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
baseclock "k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
// EventFunc does some work that needs to be done at or after the
|
||||
// given time.
|
||||
type EventFunc func(time.Time)
|
||||
|
||||
// EventClock is an active clock abstraction for use in code that is
|
||||
// testable with a fake clock that itself determines how time may be
|
||||
// advanced. The timing paradigm is invoking EventFuncs rather than
|
||||
// synchronizing through channels, so that the fake clock has a handle
|
||||
// on when associated activity is done.
|
||||
type Interface interface {
|
||||
baseclock.PassiveClock
|
||||
|
||||
// Sleep returns after the given duration (or more).
|
||||
Sleep(d time.Duration)
|
||||
|
||||
// EventAfterDuration invokes the given EventFunc after the given duration (or more),
|
||||
// passing the time when the invocation was launched.
|
||||
EventAfterDuration(f EventFunc, d time.Duration)
|
||||
|
||||
// EventAfterTime invokes the given EventFunc at the given time or later,
|
||||
// passing the time when the invocation was launched.
|
||||
EventAfterTime(f EventFunc, t time.Time)
|
||||
}
|
44
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/eventclock/real.go
generated
vendored
Normal file
44
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/eventclock/real.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package eventclock
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
// RealEventClock fires event on real world time
|
||||
type Real struct {
|
||||
clock.RealClock
|
||||
}
|
||||
|
||||
var _ Interface = Real{}
|
||||
|
||||
// EventAfterDuration schedules an EventFunc
|
||||
func (Real) EventAfterDuration(f EventFunc, d time.Duration) {
|
||||
ch := time.After(d)
|
||||
go func() {
|
||||
t := <-ch
|
||||
f(t)
|
||||
}()
|
||||
}
|
||||
|
||||
// EventAfterTime schedules an EventFunc
|
||||
func (r Real) EventAfterTime(f EventFunc, t time.Time) {
|
||||
r.EventAfterDuration(f, time.Until(t))
|
||||
}
|
191
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/integrator.go
generated
vendored
Normal file
191
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/integrator.go
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fairqueuing
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
fcmetrics "k8s.io/apiserver/pkg/util/flowcontrol/metrics"
|
||||
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
// Integrator computes the moments of some variable X over time as
|
||||
// read from a particular clock. The integrals start when the
|
||||
// Integrator is created, and ends at the latest operation on the
|
||||
// Integrator.
|
||||
type Integrator interface {
|
||||
fcmetrics.Gauge
|
||||
|
||||
GetResults() IntegratorResults
|
||||
|
||||
// Return the results of integrating to now, and reset integration to start now
|
||||
Reset() IntegratorResults
|
||||
}
|
||||
|
||||
// IntegratorResults holds statistical abstracts of the integration
|
||||
type IntegratorResults struct {
|
||||
Duration float64 //seconds
|
||||
Average float64 //time-weighted
|
||||
Deviation float64 //standard deviation: sqrt(avg((value-avg)^2))
|
||||
Min, Max float64
|
||||
}
|
||||
|
||||
// Equal tests for semantic equality.
|
||||
// This considers all NaN values to be equal to each other.
|
||||
func (x *IntegratorResults) Equal(y *IntegratorResults) bool {
|
||||
return x == y || x != nil && y != nil && x.Duration == y.Duration && x.Min == y.Min && x.Max == y.Max && (x.Average == y.Average || math.IsNaN(x.Average) && math.IsNaN(y.Average)) && (x.Deviation == y.Deviation || math.IsNaN(x.Deviation) && math.IsNaN(y.Deviation))
|
||||
}
|
||||
|
||||
type integrator struct {
|
||||
name string
|
||||
clock clock.PassiveClock
|
||||
sync.Mutex
|
||||
lastTime time.Time
|
||||
x float64
|
||||
moments Moments
|
||||
min, max float64
|
||||
}
|
||||
|
||||
// NewNamedIntegrator makes one that uses the given clock and name
|
||||
func NewNamedIntegrator(clock clock.PassiveClock, name string) Integrator {
|
||||
return &integrator{
|
||||
name: name,
|
||||
clock: clock,
|
||||
lastTime: clock.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (igr *integrator) Set(x float64) {
|
||||
igr.Lock()
|
||||
igr.setLocked(x)
|
||||
igr.Unlock()
|
||||
}
|
||||
|
||||
func (igr *integrator) Add(deltaX float64) {
|
||||
igr.Lock()
|
||||
igr.setLocked(igr.x + deltaX)
|
||||
igr.Unlock()
|
||||
}
|
||||
|
||||
func (igr *integrator) Inc() {
|
||||
igr.Add(1)
|
||||
}
|
||||
|
||||
func (igr *integrator) Dec() {
|
||||
igr.Add(-1)
|
||||
}
|
||||
|
||||
func (igr *integrator) SetToCurrentTime() {
|
||||
igr.Set(float64(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
func (igr *integrator) setLocked(x float64) {
|
||||
igr.updateLocked()
|
||||
igr.x = x
|
||||
if x < igr.min {
|
||||
igr.min = x
|
||||
}
|
||||
if x > igr.max {
|
||||
igr.max = x
|
||||
}
|
||||
}
|
||||
|
||||
func (igr *integrator) updateLocked() {
|
||||
now := igr.clock.Now()
|
||||
dt := now.Sub(igr.lastTime).Seconds()
|
||||
igr.lastTime = now
|
||||
igr.moments = igr.moments.Add(ConstantMoments(dt, igr.x))
|
||||
}
|
||||
|
||||
func (igr *integrator) GetResults() IntegratorResults {
|
||||
igr.Lock()
|
||||
defer igr.Unlock()
|
||||
return igr.getResultsLocked()
|
||||
}
|
||||
|
||||
func (igr *integrator) Reset() IntegratorResults {
|
||||
igr.Lock()
|
||||
defer igr.Unlock()
|
||||
results := igr.getResultsLocked()
|
||||
igr.moments = Moments{}
|
||||
igr.min = igr.x
|
||||
igr.max = igr.x
|
||||
return results
|
||||
}
|
||||
|
||||
func (igr *integrator) getResultsLocked() (results IntegratorResults) {
|
||||
igr.updateLocked()
|
||||
results.Min, results.Max = igr.min, igr.max
|
||||
results.Duration = igr.moments.ElapsedSeconds
|
||||
results.Average, results.Deviation = igr.moments.AvgAndStdDev()
|
||||
return
|
||||
}
|
||||
|
||||
// Moments are the integrals of the 0, 1, and 2 powers of some
|
||||
// variable X over some range of time.
|
||||
type Moments struct {
|
||||
ElapsedSeconds float64 // integral of dt
|
||||
IntegralX float64 // integral of x dt
|
||||
IntegralXX float64 // integral of x*x dt
|
||||
}
|
||||
|
||||
// ConstantMoments is for a constant X
|
||||
func ConstantMoments(dt, x float64) Moments {
|
||||
return Moments{
|
||||
ElapsedSeconds: dt,
|
||||
IntegralX: x * dt,
|
||||
IntegralXX: x * x * dt,
|
||||
}
|
||||
}
|
||||
|
||||
// Add combines over two ranges of time
|
||||
func (igr Moments) Add(ogr Moments) Moments {
|
||||
return Moments{
|
||||
ElapsedSeconds: igr.ElapsedSeconds + ogr.ElapsedSeconds,
|
||||
IntegralX: igr.IntegralX + ogr.IntegralX,
|
||||
IntegralXX: igr.IntegralXX + ogr.IntegralXX,
|
||||
}
|
||||
}
|
||||
|
||||
// Sub finds the difference between a range of time and a subrange
|
||||
func (igr Moments) Sub(ogr Moments) Moments {
|
||||
return Moments{
|
||||
ElapsedSeconds: igr.ElapsedSeconds - ogr.ElapsedSeconds,
|
||||
IntegralX: igr.IntegralX - ogr.IntegralX,
|
||||
IntegralXX: igr.IntegralXX - ogr.IntegralXX,
|
||||
}
|
||||
}
|
||||
|
||||
// AvgAndStdDev returns the average and standard devation
|
||||
func (igr Moments) AvgAndStdDev() (float64, float64) {
|
||||
if igr.ElapsedSeconds <= 0 {
|
||||
return math.NaN(), math.NaN()
|
||||
}
|
||||
avg := igr.IntegralX / igr.ElapsedSeconds
|
||||
// standard deviation is sqrt( average( (x - xbar)^2 ) )
|
||||
// = sqrt( Integral( x^2 + xbar^2 -2*x*xbar dt ) / Duration )
|
||||
// = sqrt( ( Integral( x^2 dt ) + Duration * xbar^2 - 2*xbar*Integral(x dt) ) / Duration)
|
||||
// = sqrt( Integral(x^2 dt)/Duration - xbar^2 )
|
||||
variance := igr.IntegralXX/igr.ElapsedSeconds - avg*avg
|
||||
if variance >= 0 {
|
||||
return avg, math.Sqrt(variance)
|
||||
}
|
||||
return avg, math.NaN()
|
||||
}
|
136
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/interface.go
generated
vendored
Normal file
136
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/interface.go
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fairqueuing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"k8s.io/apiserver/pkg/util/flowcontrol/debug"
|
||||
"k8s.io/apiserver/pkg/util/flowcontrol/metrics"
|
||||
"k8s.io/apiserver/pkg/util/flowcontrol/request"
|
||||
)
|
||||
|
||||
// QueueSetFactory is used to create QueueSet objects. Creation, like
|
||||
// config update, is done in two phases: the first phase consumes the
|
||||
// QueuingConfig and the second consumes the DispatchingConfig. They
|
||||
// are separated so that errors from the first phase can be found
|
||||
// before committing to a concurrency allotment for the second.
|
||||
type QueueSetFactory interface {
|
||||
// BeginConstruction does the first phase of creating a QueueSet.
|
||||
// The RatioedGaugePair observes number of requests,
|
||||
// execution covering just the regular phase.
|
||||
// The RatioedGauge observes number of seats occupied through all phases of execution.
|
||||
// The Gauge observes the seat demand (executing + queued seats).
|
||||
BeginConstruction(QueuingConfig, metrics.RatioedGaugePair, metrics.RatioedGauge, metrics.Gauge) (QueueSetCompleter, error)
|
||||
}
|
||||
|
||||
// QueueSetCompleter finishes the two-step process of creating or
|
||||
// reconfiguring a QueueSet
|
||||
type QueueSetCompleter interface {
|
||||
// Complete returns a QueueSet configured by the given
|
||||
// dispatching configuration.
|
||||
Complete(DispatchingConfig) QueueSet
|
||||
}
|
||||
|
||||
// QueueSet is the abstraction for the queuing and dispatching
|
||||
// functionality of one non-exempt priority level. It covers the
|
||||
// functionality described in the "Assignment to a Queue", "Queuing",
|
||||
// and "Dispatching" sections of
|
||||
// https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/1040-priority-and-fairness/README.md
|
||||
// . Some day we may have connections between priority levels, but
|
||||
// today is not that day.
|
||||
type QueueSet interface {
|
||||
// BeginConfigChange starts the two-step process of updating the
|
||||
// configuration. No change is made until Complete is called. If
|
||||
// `C := X.BeginConstruction(q)` then `C.Complete(d)` returns the
|
||||
// same value `X`. If the QueuingConfig's DesiredNumQueues field
|
||||
// is zero then the other queuing-specific config parameters are
|
||||
// not changed, so that the queues continue draining as before.
|
||||
// In any case, reconfiguration does not discard any queue unless
|
||||
// and until it is undesired and empty.
|
||||
BeginConfigChange(QueuingConfig) (QueueSetCompleter, error)
|
||||
|
||||
// IsIdle returns a bool indicating whether the QueueSet was idle
|
||||
// at the moment of the return. Idle means the QueueSet has zero
|
||||
// requests queued and zero executing. This bit can change only
|
||||
// (1) during a call to StartRequest and (2) during a call to
|
||||
// Request::Finish. In the latter case idleness can only change
|
||||
// from false to true.
|
||||
IsIdle() bool
|
||||
|
||||
// StartRequest begins the process of handling a request. If the
|
||||
// request gets queued and the number of queues is greater than 1
|
||||
// then StartRequest uses the given hashValue as the source of
|
||||
// entropy as it shuffle-shards the request into a queue. The
|
||||
// descr1 and descr2 values play no role in the logic but appear
|
||||
// in log messages. This method always returns quickly (without
|
||||
// waiting for the request to be dequeued). If this method
|
||||
// returns a nil Request value then caller should reject the
|
||||
// request and the returned bool indicates whether the QueueSet
|
||||
// was idle at the moment of the return. Otherwise idle==false
|
||||
// and the client must call the Finish method of the Request
|
||||
// exactly once.
|
||||
StartRequest(ctx context.Context, width *request.WorkEstimate, hashValue uint64, flowDistinguisher, fsName string, descr1, descr2 interface{}, queueNoteFn QueueNoteFn) (req Request, idle bool)
|
||||
|
||||
// Dump saves and returns the instant internal state of the queue-set.
|
||||
// Note that dumping process will stop the queue-set from proceeding
|
||||
// any requests.
|
||||
// For debugging only.
|
||||
Dump(includeRequestDetails bool) debug.QueueSetDump
|
||||
}
|
||||
|
||||
// QueueNoteFn is called when a request enters and leaves a queue
|
||||
type QueueNoteFn func(inQueue bool)
|
||||
|
||||
// Request represents the remainder of the handling of one request
|
||||
type Request interface {
|
||||
// Finish determines whether to execute or reject the request and
|
||||
// invokes `execute` if the decision is to execute the request.
|
||||
// The returned `idle bool` value indicates whether the QueueSet
|
||||
// was idle when the value was calculated, but might no longer be
|
||||
// accurate by the time the client examines that value.
|
||||
Finish(execute func()) (idle bool)
|
||||
}
|
||||
|
||||
// QueuingConfig defines the configuration of the queuing aspect of a QueueSet.
|
||||
type QueuingConfig struct {
|
||||
// Name is used to identify a queue set, allowing for descriptive information about its intended use
|
||||
Name string
|
||||
|
||||
// DesiredNumQueues is the number of queues that the API says
|
||||
// should exist now. This may be zero, in which case
|
||||
// QueueLengthLimit, HandSize, and RequestWaitLimit are ignored.
|
||||
DesiredNumQueues int
|
||||
|
||||
// QueueLengthLimit is the maximum number of requests that may be waiting in a given queue at a time
|
||||
QueueLengthLimit int
|
||||
|
||||
// HandSize is a parameter of shuffle sharding. Upon arrival of a request, a queue is chosen by randomly
|
||||
// dealing a "hand" of this many queues and then picking one of minimum length.
|
||||
HandSize int
|
||||
|
||||
// RequestWaitLimit is the maximum amount of time that a request may wait in a queue.
|
||||
// If, by the end of that time, the request has not been dispatched then it is rejected.
|
||||
RequestWaitLimit time.Duration
|
||||
}
|
||||
|
||||
// DispatchingConfig defines the configuration of the dispatching aspect of a QueueSet.
|
||||
type DispatchingConfig struct {
|
||||
// ConcurrencyLimit is the maximum number of requests of this QueueSet that may be executing at a time
|
||||
ConcurrencyLimit int
|
||||
}
|
34
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/promise/interface.go
generated
vendored
Normal file
34
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/promise/interface.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package promise
|
||||
|
||||
// WriteOnce represents a variable that is initially not set and can
|
||||
// be set once and is readable. This is the common meaning for
|
||||
// "promise".
|
||||
type WriteOnce interface {
|
||||
// Get reads the current value of this variable. If this
|
||||
// variable is not set yet then this call blocks until this
|
||||
// variable gets a value.
|
||||
Get() interface{}
|
||||
|
||||
// Set normally writes a value into this variable, unblocks every
|
||||
// goroutine waiting for this variable to have a value, and
|
||||
// returns true. In the unhappy case that this variable is
|
||||
// already set, this method returns false without modifying the
|
||||
// variable's value.
|
||||
Set(interface{}) bool
|
||||
}
|
70
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/promise/promise.go
generated
vendored
Normal file
70
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/promise/promise.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package promise
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// promise implements the WriteOnce interface.
|
||||
type promise struct {
|
||||
doneCh <-chan struct{}
|
||||
doneVal interface{}
|
||||
setCh chan struct{}
|
||||
onceler sync.Once
|
||||
value interface{}
|
||||
}
|
||||
|
||||
var _ WriteOnce = &promise{}
|
||||
|
||||
// NewWriteOnce makes a new thread-safe WriteOnce.
|
||||
//
|
||||
// If `initial` is non-nil then that value is Set at creation time.
|
||||
//
|
||||
// If a `Get` is waiting soon after `doneCh` becomes selectable (which
|
||||
// never happens for the nil channel) then `Set(doneVal)` effectively
|
||||
// happens at that time.
|
||||
func NewWriteOnce(initial interface{}, doneCh <-chan struct{}, doneVal interface{}) WriteOnce {
|
||||
p := &promise{
|
||||
doneCh: doneCh,
|
||||
doneVal: doneVal,
|
||||
setCh: make(chan struct{}),
|
||||
}
|
||||
if initial != nil {
|
||||
p.Set(initial)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *promise) Get() interface{} {
|
||||
select {
|
||||
case <-p.setCh:
|
||||
case <-p.doneCh:
|
||||
p.Set(p.doneVal)
|
||||
}
|
||||
return p.value
|
||||
}
|
||||
|
||||
func (p *promise) Set(value interface{}) bool {
|
||||
var ans bool
|
||||
p.onceler.Do(func() {
|
||||
p.value = value
|
||||
close(p.setCh)
|
||||
ans = true
|
||||
})
|
||||
return ans
|
||||
}
|
119
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/doc.go
generated
vendored
Normal file
119
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/doc.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package queueset implements a technique called "fair queuing for
|
||||
// server requests". One QueueSet is a set of queues operating
|
||||
// according to this technique.
|
||||
//
|
||||
// Fair queuing for server requests is inspired by the fair queuing
|
||||
// technique from the world of networking. You can find a good paper
|
||||
// on that at https://dl.acm.org/citation.cfm?doid=75247.75248 or
|
||||
// http://people.csail.mit.edu/imcgraw/links/research/pubs/networks/WFQ.pdf
|
||||
// and there is an implementation outline in the Wikipedia article at
|
||||
// https://en.wikipedia.org/wiki/Fair_queuing .
|
||||
//
|
||||
// Fair queuing for server requests differs from traditional fair
|
||||
// queuing in three ways: (1) we are dispatching application layer
|
||||
// requests to a server rather than transmitting packets on a network
|
||||
// link, (2) multiple requests can be executing at once, and (3) the
|
||||
// service time (execution duration) is not known until the execution
|
||||
// completes.
|
||||
//
|
||||
// The first two differences can easily be handled by straightforward
|
||||
// adaptation of the concept called "R(t)" in the original paper and
|
||||
// "virtual time" in the implementation outline. In that
|
||||
// implementation outline, the notation now() is used to mean reading
|
||||
// the virtual clock. In the original paper’s terms, "R(t)" is the
|
||||
// number of "rounds" that have been completed at real time t ---
|
||||
// where a round consists of virtually transmitting one bit from every
|
||||
// non-empty queue in the router (regardless of which queue holds the
|
||||
// packet that is really being transmitted at the moment); in this
|
||||
// conception, a packet is considered to be "in" its queue until the
|
||||
// packet’s transmission is finished. For our problem, we can define a
|
||||
// round to be giving one nanosecond of CPU to every non-empty queue
|
||||
// in the apiserver (where emptiness is judged based on both queued
|
||||
// and executing requests from that queue), and define R(t) = (server
|
||||
// start time) + (1 ns) * (number of rounds since server start). Let
|
||||
// us write NEQ(t) for that number of non-empty queues in the
|
||||
// apiserver at time t. Let us also write C for the concurrency
|
||||
// limit. In the original paper, the partial derivative of R(t) with
|
||||
// respect to t is
|
||||
//
|
||||
// 1 / NEQ(t) .
|
||||
//
|
||||
// To generalize from transmitting one packet at a time to executing C
|
||||
// requests at a time, that derivative becomes
|
||||
//
|
||||
// C / NEQ(t) .
|
||||
//
|
||||
// However, sometimes there are fewer than C requests available to
|
||||
// execute. For a given queue "q", let us also write "reqs(q, t)" for
|
||||
// the number of requests of that queue that are executing at that
|
||||
// time. The total number of requests executing is sum[over q]
|
||||
// reqs(q, t) and if that is less than C then virtual time is not
|
||||
// advancing as fast as it would if all C seats were occupied; in this
|
||||
// case the numerator of the quotient in that derivative should be
|
||||
// adjusted proportionally. Putting it all together for fair queing
|
||||
// for server requests: at a particular time t, the partial derivative
|
||||
// of R(t) with respect to t is
|
||||
//
|
||||
// min( C, sum[over q] reqs(q, t) ) / NEQ(t) .
|
||||
//
|
||||
// In terms of the implementation outline, this is the rate at which
|
||||
// virtual time is advancing at time t (in virtual nanoseconds per
|
||||
// real nanosecond). Where the networking implementation outline adds
|
||||
// packet size to a virtual time, in our version this corresponds to
|
||||
// adding a service time (i.e., duration) to virtual time.
|
||||
//
|
||||
// The third difference is handled by modifying the algorithm to
|
||||
// dispatch based on an initial guess at the request’s service time
|
||||
// (duration) and then make the corresponding adjustments once the
|
||||
// request’s actual service time is known. This is similar, although
|
||||
// not exactly isomorphic, to the original paper’s adjustment by
|
||||
// `$\delta$` for the sake of promptness.
|
||||
//
|
||||
// For implementation simplicity (see below), let us use the same
|
||||
// initial service time guess for every request; call that duration
|
||||
// G. A good choice might be the service time limit (1
|
||||
// minute). Different guesses will give slightly different dynamics,
|
||||
// but any positive number can be used for G without ruining the
|
||||
// long-term behavior.
|
||||
//
|
||||
// As in ordinary fair queuing, there is a bound on divergence from
|
||||
// the ideal. In plain fair queuing the bound is one packet; in our
|
||||
// version it is C requests.
|
||||
//
|
||||
// To support efficiently making the necessary adjustments once a
|
||||
// request’s actual service time is known, the virtual finish time of
|
||||
// a request and the last virtual finish time of a queue are not
|
||||
// represented directly but instead computed from queue length,
|
||||
// request position in the queue, and an alternate state variable that
|
||||
// holds the queue’s virtual start time. While the queue is empty and
|
||||
// has no requests executing: the value of its virtual start time
|
||||
// variable is ignored and its last virtual finish time is considered
|
||||
// to be in the virtual past. When a request arrives to an empty queue
|
||||
// with no requests executing, the queue’s virtual start time is set
|
||||
// to the current virtual time. The virtual finish time of request
|
||||
// number J in the queue (counting from J=1 for the head) is J * G +
|
||||
// (queue's virtual start time). While the queue is non-empty: the
|
||||
// last virtual finish time of the queue is the virtual finish time of
|
||||
// the last request in the queue. While the queue is empty and has a
|
||||
// request executing: the last virtual finish time is the queue’s
|
||||
// virtual start time. When a request is dequeued for service the
|
||||
// queue’s virtual start time is advanced by G. When a request
|
||||
// finishes being served, and the actual service time was S, the
|
||||
// queue’s virtual start time is decremented by G - S.
|
||||
package queueset
|
156
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/fifo_list.go
generated
vendored
Normal file
156
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/fifo_list.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package queueset
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
)
|
||||
|
||||
// removeFromFIFOFunc removes a designated element from the list
|
||||
// if that element is in the list.
|
||||
// The complexity of the runtime cost is O(1).
|
||||
// The returned value is the element removed, if indeed one was removed,
|
||||
// otherwise `nil`.
|
||||
type removeFromFIFOFunc func() *request
|
||||
|
||||
// walkFunc is called for each request in the list in the
|
||||
// oldest -> newest order.
|
||||
// ok: if walkFunc returns false then the iteration stops immediately.
|
||||
// walkFunc may remove the given request from the fifo,
|
||||
// but may not mutate the fifo in any othe way.
|
||||
type walkFunc func(*request) (ok bool)
|
||||
|
||||
// Internal interface to abstract out the implementation details
|
||||
// of the underlying list used to maintain the requests.
|
||||
//
|
||||
// Note that a fifo, including the removeFromFIFOFuncs returned from Enqueue,
|
||||
// is not safe for concurrent use by multiple goroutines.
|
||||
type fifo interface {
|
||||
// Enqueue enqueues the specified request into the list and
|
||||
// returns a removeFromFIFOFunc function that can be used to remove the
|
||||
// request from the list
|
||||
Enqueue(*request) removeFromFIFOFunc
|
||||
|
||||
// Dequeue pulls out the oldest request from the list.
|
||||
Dequeue() (*request, bool)
|
||||
|
||||
// Peek returns the oldest request without removing it.
|
||||
Peek() (*request, bool)
|
||||
|
||||
// Length returns the number of requests in the list.
|
||||
Length() int
|
||||
|
||||
// QueueSum returns the sum of initial seats, final seats, and
|
||||
// additional latency aggregated from all requests in this queue.
|
||||
QueueSum() queueSum
|
||||
|
||||
// Walk iterates through the list in order of oldest -> newest
|
||||
// and executes the specified walkFunc for each request in that order.
|
||||
//
|
||||
// if the specified walkFunc returns false the Walk function
|
||||
// stops the walk an returns immediately.
|
||||
Walk(walkFunc)
|
||||
}
|
||||
|
||||
// the FIFO list implementation is not safe for concurrent use by multiple
|
||||
// goroutines.
|
||||
type requestFIFO struct {
|
||||
*list.List
|
||||
|
||||
sum queueSum
|
||||
}
|
||||
|
||||
func newRequestFIFO() fifo {
|
||||
return &requestFIFO{
|
||||
List: list.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *requestFIFO) Length() int {
|
||||
return l.Len()
|
||||
}
|
||||
|
||||
func (l *requestFIFO) QueueSum() queueSum {
|
||||
return l.sum
|
||||
}
|
||||
|
||||
func (l *requestFIFO) Enqueue(req *request) removeFromFIFOFunc {
|
||||
e := l.PushBack(req)
|
||||
addToQueueSum(&l.sum, req)
|
||||
|
||||
return func() *request {
|
||||
if e.Value == nil {
|
||||
return nil
|
||||
}
|
||||
l.Remove(e)
|
||||
e.Value = nil
|
||||
deductFromQueueSum(&l.sum, req)
|
||||
return req
|
||||
}
|
||||
}
|
||||
|
||||
func (l *requestFIFO) Dequeue() (*request, bool) {
|
||||
return l.getFirst(true)
|
||||
}
|
||||
|
||||
func (l *requestFIFO) Peek() (*request, bool) {
|
||||
return l.getFirst(false)
|
||||
}
|
||||
|
||||
func (l *requestFIFO) getFirst(remove bool) (*request, bool) {
|
||||
e := l.Front()
|
||||
if e == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if remove {
|
||||
defer func() {
|
||||
l.Remove(e)
|
||||
e.Value = nil
|
||||
}()
|
||||
}
|
||||
|
||||
request, ok := e.Value.(*request)
|
||||
if remove && ok {
|
||||
deductFromQueueSum(&l.sum, request)
|
||||
}
|
||||
return request, ok
|
||||
}
|
||||
|
||||
func (l *requestFIFO) Walk(f walkFunc) {
|
||||
var next *list.Element
|
||||
for current := l.Front(); current != nil; current = next {
|
||||
next = current.Next() // f is allowed to remove current
|
||||
if r, ok := current.Value.(*request); ok {
|
||||
if !f(r) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addToQueueSum(sum *queueSum, req *request) {
|
||||
sum.InitialSeatsSum += req.InitialSeats()
|
||||
sum.MaxSeatsSum += req.MaxSeats()
|
||||
sum.TotalWorkSum += req.totalWork()
|
||||
}
|
||||
|
||||
func deductFromQueueSum(sum *queueSum, req *request) {
|
||||
sum.InitialSeatsSum -= req.InitialSeats()
|
||||
sum.MaxSeatsSum -= req.MaxSeats()
|
||||
sum.TotalWorkSum -= req.totalWork()
|
||||
}
|
1046
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/queueset.go
generated
vendored
Normal file
1046
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/queueset.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
183
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/types.go
generated
vendored
Normal file
183
vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/types.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package queueset
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
genericrequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/util/flowcontrol/debug"
|
||||
fq "k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing"
|
||||
"k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/promise"
|
||||
fcrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
|
||||
)
|
||||
|
||||
// request is a temporary container for "requests" with additional
|
||||
// tracking fields required for QueueSet functionality.
|
||||
type request struct {
|
||||
ctx context.Context
|
||||
|
||||
qs *queueSet
|
||||
|
||||
flowDistinguisher string
|
||||
fsName string
|
||||
|
||||
// The relevant queue. Is nil if this request did not go through
|
||||
// a queue.
|
||||
queue *queue
|
||||
|
||||
// estimated amount of work of the request
|
||||
workEstimate completedWorkEstimate
|
||||
|
||||
// decision gets set to a `requestDecision` indicating what to do
|
||||
// with this request. It gets set exactly once, when the request
|
||||
// is removed from its queue. The value will be decisionReject,
|
||||
// decisionCancel, or decisionExecute.
|
||||
//
|
||||
// decision.Set is called with the queueSet locked.
|
||||
// decision.Get is called without the queueSet locked.
|
||||
decision promise.WriteOnce
|
||||
|
||||
// arrivalTime is the real time when the request entered this system
|
||||
arrivalTime time.Time
|
||||
|
||||
// descr1 and descr2 are not used in any logic but they appear in
|
||||
// log messages
|
||||
descr1, descr2 interface{}
|
||||
|
||||
queueNoteFn fq.QueueNoteFn
|
||||
|
||||
// The preceding fields are filled in at creation and not modified since;
|
||||
// the following fields may be modified later and must only be accessed while
|
||||
// holding the queueSet's lock.
|
||||
|
||||
// Removes this request from its queue. If the request is not put into a
|
||||
// a queue it will be nil.
|
||||
removeFromQueueLocked removeFromFIFOFunc
|
||||
|
||||
// arrivalR is R(arrivalTime). R is, confusingly, also called "virtual time".
|
||||
// This field is meaningful only while the request is waiting in the virtual world.
|
||||
arrivalR fcrequest.SeatSeconds
|
||||
|
||||
// startTime is the real time when the request began executing
|
||||
startTime time.Time
|
||||
|
||||
// Indicates whether client has called Request::Wait()
|
||||
waitStarted bool
|
||||
}
|
||||
|
||||
type completedWorkEstimate struct {
|
||||
fcrequest.WorkEstimate
|
||||
totalWork fcrequest.SeatSeconds // initial plus final work
|
||||
finalWork fcrequest.SeatSeconds // only final work
|
||||
}
|
||||
|
||||
// queue is a sequence of requests that have arrived but not yet finished
|
||||
// execution in both the real and virtual worlds.
|
||||
type queue struct {
|
||||
// The requests not yet executing in the real world are stored in a FIFO list.
|
||||
requests fifo
|
||||
|
||||
// nextDispatchR is the R progress meter reading at
|
||||
// which the next request will be dispatched in the virtual world.
|
||||
nextDispatchR fcrequest.SeatSeconds
|
||||
|
||||
// requestsExecuting is the count in the real world.
|
||||
requestsExecuting int
|
||||
|
||||
// index is the position of this queue among those in its queueSet.
|
||||
index int
|
||||
|
||||
// seatsInUse is the total number of "seats" currently occupied
|
||||
// by all the requests that are currently executing in this queue.
|
||||
seatsInUse int
|
||||
}
|
||||
|
||||
// queueSum tracks the sum of initial seats, max seats, and
|
||||
// totalWork from all requests in a given queue
|
||||
type queueSum struct {
|
||||
// InitialSeatsSum is the sum of InitialSeats
|
||||
// associated with all requests in a given queue.
|
||||
InitialSeatsSum int
|
||||
|
||||
// MaxSeatsSum is the sum of MaxSeats
|
||||
// associated with all requests in a given queue.
|
||||
MaxSeatsSum int
|
||||
|
||||
// TotalWorkSum is the sum of totalWork of the waiting requests
|
||||
TotalWorkSum fcrequest.SeatSeconds
|
||||
}
|
||||
|
||||
func (req *request) totalWork() fcrequest.SeatSeconds {
|
||||
return req.workEstimate.totalWork
|
||||
}
|
||||
|
||||
func (qs *queueSet) completeWorkEstimate(we *fcrequest.WorkEstimate) completedWorkEstimate {
|
||||
finalWork := qs.computeFinalWork(we)
|
||||
return completedWorkEstimate{
|
||||
WorkEstimate: *we,
|
||||
totalWork: qs.computeInitialWork(we) + finalWork,
|
||||
finalWork: finalWork,
|
||||
}
|
||||
}
|
||||
|
||||
func (qs *queueSet) computeInitialWork(we *fcrequest.WorkEstimate) fcrequest.SeatSeconds {
|
||||
return fcrequest.SeatsTimesDuration(float64(we.InitialSeats), qs.estimatedServiceDuration)
|
||||
}
|
||||
|
||||
func (qs *queueSet) computeFinalWork(we *fcrequest.WorkEstimate) fcrequest.SeatSeconds {
|
||||
return fcrequest.SeatsTimesDuration(float64(we.FinalSeats), we.AdditionalLatency)
|
||||
}
|
||||
|
||||
func (q *queue) dumpLocked(includeDetails bool) debug.QueueDump {
|
||||
digest := make([]debug.RequestDump, q.requests.Length())
|
||||
i := 0
|
||||
q.requests.Walk(func(r *request) bool {
|
||||
// dump requests.
|
||||
digest[i].MatchedFlowSchema = r.fsName
|
||||
digest[i].FlowDistinguisher = r.flowDistinguisher
|
||||
digest[i].ArriveTime = r.arrivalTime
|
||||
digest[i].StartTime = r.startTime
|
||||
digest[i].WorkEstimate = r.workEstimate.WorkEstimate
|
||||
if includeDetails {
|
||||
userInfo, _ := genericrequest.UserFrom(r.ctx)
|
||||
digest[i].UserName = userInfo.GetName()
|
||||
requestInfo, ok := genericrequest.RequestInfoFrom(r.ctx)
|
||||
if ok {
|
||||
digest[i].RequestInfo = *requestInfo
|
||||
}
|
||||
}
|
||||
i++
|
||||
return true
|
||||
})
|
||||
|
||||
sum := q.requests.QueueSum()
|
||||
queueSum := debug.QueueSum{
|
||||
InitialSeatsSum: sum.InitialSeatsSum,
|
||||
MaxSeatsSum: sum.MaxSeatsSum,
|
||||
TotalWorkSum: sum.TotalWorkSum.String(),
|
||||
}
|
||||
|
||||
return debug.QueueDump{
|
||||
NextDispatchR: q.nextDispatchR.String(),
|
||||
Requests: digest,
|
||||
ExecutingRequests: q.requestsExecuting,
|
||||
SeatsInUse: q.seatsInUse,
|
||||
QueueSum: queueSum,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user