@@ -33,6 +33,11 @@ import (
33
33
const (
34
34
bytesPerSeat = 100_000
35
35
cacheWithStreamingMaxMemoryUsage = 1_000_000
36
+ // 1.5MB is the recommended client request size in byte
37
+ // the etcd server should accept. See
38
+ // https://github.com/etcd-io/etcd/blob/release-3.4/embed/config.go#L56.
39
+ maxObjectSize = 1_500_000
40
+ infiniteObjectCount = 1_000_000_000
36
41
)
37
42
38
43
func newListWorkEstimator (countFn statsGetterFunc ,config * WorkEstimatorConfig ,maxSeatsFn maxSeatsFunc )* listWorkEstimator {
@@ -89,21 +94,24 @@ func (e *listWorkEstimator) estimate(r *http.Request, flowSchemaName, priorityLe
89
94
}
90
95
}
91
96
// TODO: Check whether watchcache is enabled.
97
+ var listFromStorage bool
92
98
result ,err := delegator .ShouldDelegateListMeta (& listOptions , delegator.CacheWithoutSnapshots {})
93
99
if err != nil {
94
- return WorkEstimate {InitialSeats :maxSeats }
100
+ // Assume worse case where we need to reach to etcd.
101
+ listFromStorage = true
102
+ }else {
103
+ listFromStorage = result .ShouldDelegate
95
104
}
96
- listFromStorage := result .ShouldDelegate
97
105
isListFromCache := requestInfo .Verb == "watch" || ! listFromStorage
98
106
99
107
stats ,err := e .statsGetterFn (key (requestInfo ))
100
108
switch {
101
109
case err == ObjectCountStaleErr :
102
110
// object count going stale is indicative of degradation, so we should
103
- // be conservative here andallocate maximumseats to this list request .
111
+ // be conservative here andreturn maximumobject count and size .
104
112
// NOTE: if a CRD is removed, its count will go stale first and then the
105
113
// pruner will eventually remove the CRD from the cache.
106
- return WorkEstimate { InitialSeats : maxSeats }
114
+ stats = storage. Stats { ObjectCount : infiniteObjectCount , EstimatedAverageObjectSizeBytes : maxObjectSize }
107
115
case err == ObjectCountNotFoundErr :
108
116
// there are multiple scenarios in which we can see this error:
109
117
// a. the type is truly unknown, a typo on the caller's part.
@@ -120,9 +128,9 @@ func (e *listWorkEstimator) estimate(r *http.Request, flowSchemaName, priorityLe
120
128
return WorkEstimate {InitialSeats :minSeats }
121
129
case err != nil :
122
130
// we should never be here since Get returns either ObjectCountStaleErr or
123
- // ObjectCountNotFoundErr, returnmaximumSeats to be on the safe side .
131
+ // ObjectCountNotFoundErr, returnmaximum object count and size .
124
132
klog .ErrorS (err ,"Unexpected error from object count tracker" )
125
- return WorkEstimate { InitialSeats : maxSeats }
133
+ stats = storage. Stats { ObjectCount : infiniteObjectCount , EstimatedAverageObjectSizeBytes : maxObjectSize }
126
134
}
127
135
128
136
var seats uint64
@@ -172,9 +180,8 @@ func (e *listWorkEstimator) seatsBasedOnObjectCount(stats storage.Stats, listOpt
172
180
}
173
181
174
182
func (e * listWorkEstimator )seatsBasedOnObjectSize (stats storage.Stats ,listOptions metav1.ListOptions ,isListFromCache bool ,matchesSingle bool )uint64 {
175
- // Size not available, fallback to count based estimate
176
183
if stats .EstimatedAverageObjectSizeBytes <= 0 && stats .ObjectCount != 0 {
177
- return e . seatsBasedOnObjectCount ( stats , listOptions , isListFromCache , matchesSingle )
184
+ stats . EstimatedAverageObjectSizeBytes = maxObjectSize
178
185
}
179
186
limited := stats .ObjectCount
180
187
if listOptions .Limit > 0 && listOptions .Limit < limited {