Skip to content

Commit 1c43745

Browse files
craig[bot]kev-caosumeerbholayuzefovich
committed
153588: restore: set correct number of link workers r=msbutler a=kev-cao #153065 contains a typo that ensures the number of link workers is always 0 or 1. This patch fixes the bug. Epic: None Release note: None 153592: admission: add getterQualification to granter/requester interfaces r=joshimhoff a=sumeerbhola This is in preparation for the CPU time token scheme, where the WorkQueue will distinguish between burstable and non-burstable tenants. This is just an interface change, with no behavioral change. Informs #153591 Epic: none Release note: None 153593: sql: clarify recent change around soft limits r=yuzefovich a=yuzefovich AI review spotted a "bug" in a recent change around soft limits when that limit is negative. This is impossible by construction, so this commit clarifies the code a bit by switching to `uint64` in non-proto code. We also have "hard limit" that still remains `int64` due to one special case (I was being lazy so only left a TODO to clean this up). Epic: None Release note: None Co-authored-by: Kevin Cao <[email protected]> Co-authored-by: sumeerbhola <[email protected]> Co-authored-by: Yahor Yuzefovich <[email protected]>
4 parents 7dd49da + a6ae71e + 314400c + 6c3b66a commit 1c43745

17 files changed

+77
-51
lines changed

pkg/backup/restore_online.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,6 @@ func getNumOnlineRestoreLinkWorkers(ctx context.Context, execCtx sql.JobExecCont
10611061
if err != nil {
10621062
return 0, err
10631063
}
1064-
numNodes := min(len(sqlInstanceIDs), 1)
1064+
numNodes := max(len(sqlInstanceIDs), 1)
10651065
return defaultLinkWorkersPerNode * numNodes, nil
10661066
}

pkg/sql/distsql_physical_planner.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ func checkSupportForPlanNode(
726726
var suffix string
727727
estimate := n.estimatedRowCount
728728
if n.softLimit != 0 && sd.UseSoftLimitForDistributeScan {
729-
estimate = uint64(n.softLimit)
729+
estimate = n.softLimit
730730
suffix = " (using soft limit)"
731731
}
732732
if estimate >= sd.DistributeScanRowCountThreshold {
@@ -2205,8 +2205,8 @@ func initTableReaderSpecTemplate(
22052205
var post execinfrapb.PostProcessSpec
22062206
if n.hardLimit != 0 {
22072207
post.Limit = uint64(n.hardLimit)
2208-
} else if n.softLimit != 0 {
2209-
s.LimitHint = n.softLimit
2208+
} else if softLimit := int64(n.softLimit); softLimit > 0 {
2209+
s.LimitHint = softLimit
22102210
}
22112211
return s, post, nil
22122212
}

pkg/sql/distsql_spec_exec_factory.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,8 @@ func (e *distSQLSpecExecFactory) ConstructScan(
337337
post := execinfrapb.PostProcessSpec{}
338338
if params.HardLimit != 0 {
339339
post.Limit = uint64(params.HardLimit)
340-
} else if params.SoftLimit != 0 {
341-
trSpec.LimitHint = params.SoftLimit
340+
} else if softLimit := int64(params.SoftLimit); softLimit > 0 {
341+
trSpec.LimitHint = softLimit
342342
}
343343

344344
err = e.dsp.planTableReaders(

pkg/sql/opt/exec/execbuilder/relational.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ func (b *Builder) scanParams(
737737
sqltelemetry.IncrementPartitioningCounter(sqltelemetry.PartitionConstrainedScan)
738738
}
739739

740-
softLimit := reqProps.LimitHintInt64()
740+
softLimit := uint64(reqProps.LimitHintInt64())
741741
hardLimit := scan.HardLimit.RowCount()
742742
maxResults, maxResultsOk := b.indexConstraintMaxResults(scan, relProps)
743743

pkg/sql/opt/exec/explain/emit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1319,7 +1319,7 @@ func (e *emitter) spansStr(table cat.Table, index cat.Index, scanParams exec.Sca
13191319
if scanParams.HardLimit != 0 {
13201320
return "LIMITED SCAN"
13211321
}
1322-
if scanParams.SoftLimit > 0 {
1322+
if scanParams.SoftLimit != 0 {
13231323
return "FULL SCAN (SOFT LIMIT)"
13241324
}
13251325
return "FULL SCAN"

pkg/sql/opt/exec/factory.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,17 @@ type ScanParams struct {
118118
InvertedConstraint inverted.Spans
119119

120120
// If non-zero, the scan returns this many rows.
121+
//
122+
// Additionally, in plan-gist decoding path, this will be set to -1 to
123+
// indicate presence of a limit, regardless of its value.
124+
// TODO(yuzefovich): we could refactor this special case by adding an
125+
// additional boolean that would allow us to switch to using uint64.
121126
HardLimit int64
122127

123128
// If non-zero, the scan may still be required to return up to all its rows
124129
// (or up to the HardLimit if it is set, but can be optimized under the
125130
// assumption that only SoftLimit rows will be needed.
126-
SoftLimit int64
131+
SoftLimit uint64
127132

128133
Reverse bool
129134

pkg/sql/scan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type scanNode struct {
5252
// if non-zero, softLimit is an estimation that only this many rows might be
5353
// needed. It is a (potentially optimistic) "hint". If hardLimit is set
5454
// (non-zero), softLimit must be unset (zero).
55-
softLimit int64
55+
softLimit uint64
5656

5757
// See exec.Factory.ConstructScan.
5858
parallelize bool

pkg/util/admission/admission.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,28 @@ import (
129129
"github.com/cockroachdb/pebble"
130130
)
131131

132+
// burstQualification is an optional behavior of certain WorkQueues (which
133+
// implement requester), that differentiate between tenants that are qualified
134+
// to burst (in their token consumption) and those that are not. This is a
135+
// dynamic attribute of a tenant, based on token consumption history
136+
// maintained in the WorkQueue. The ordering of tenants is also affected in
137+
// that burstable tenants are ordered before non-burstable tenants.
138+
type burstQualification uint8
139+
140+
const (
141+
canBurst burstQualification = iota
142+
noBurst
143+
numBurstQualifications
144+
)
145+
132146
// requester is an interface implemented by an object that orders admission
133147
// work for a particular WorkKind. See WorkQueue for the implementation of
134148
// requester.
135149
type requester interface {
136150
// hasWaitingRequests returns whether there are any waiting/queued requests
137-
// of this WorkKind.
138-
hasWaitingRequests() bool
151+
// of this WorkKind, and when true, the qualification of the highest
152+
// importance getter.
153+
hasWaitingRequests() (bool, burstQualification)
139154
// granted is called by a granter to grant admission to a single queued
140155
// request. It returns > 0 if the grant was accepted, else returns 0. A
141156
// grant may not be accepted if the grant raced with request cancellation
@@ -155,12 +170,15 @@ type granter interface {
155170
grantKind() grantKind
156171
// tryGet is used by a requester to get slots/tokens for a piece of work
157172
// that has encountered no waiting/queued work. This is the fast path that
158-
// avoids queueing in the requester.
173+
// avoids queueing in the requester. The optional parameter
174+
// burstQualification identifies the qualification of the getter, which is
175+
// useful for certain granters.
159176
//
160177
// REQUIRES: count > 0. count == 1 for slots.
161-
tryGet(count int64) (granted bool)
178+
tryGet(getterQual burstQualification, count int64) (granted bool)
162179
// returnGrant is called for:
163180
// - returning slots after use.
181+
// - returning tokens after use, if all the granted tokens were not used.
164182
// - returning either slots or tokens when the grant raced with the work
165183
// being canceled, and the grantee did not end up doing any work.
166184
//
@@ -197,7 +215,9 @@ type granter interface {
197215
// the grantee after its goroutine runs and notices that it has been granted
198216
// a slot/tokens. This provides a natural throttling that reduces grant
199217
// bursts by taking into immediate account the capability of the goroutine
200-
// scheduler to schedule such work.
218+
// scheduler to schedule such work. Grant chains are only used for the CPU
219+
// resource in the hybrid slot/token scheme, where slots are used for KVWork
220+
// and tokens for SQLKVResponseWork and SQLSQLResponseWork.
201221
//
202222
// In an experiment, using such grant chains reduced burstiness of grants by
203223
// 5x and shifted ~2s of latency (at p99) from the scheduler into admission

pkg/util/admission/elastic_cpu_granter.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (e *elasticCPUGranter) grantKind() grantKind {
146146
}
147147

148148
// tryGet implements granter.
149-
func (e *elasticCPUGranter) tryGet(count int64) (granted bool) {
149+
func (e *elasticCPUGranter) tryGet(_ burstQualification, count int64) (granted bool) {
150150
e.mu.Lock()
151151
defer e.mu.Unlock()
152152

@@ -182,7 +182,7 @@ func (e *elasticCPUGranter) continueGrantChain(grantChainID) {
182182

183183
// tryGrant is used to attempt to grant to waiting requests.
184184
func (e *elasticCPUGranter) tryGrant() {
185-
for e.requester.hasWaitingRequests() && e.tryGet(1) {
185+
for e.hasWaitingRequests() && e.tryGet(canBurst /*arbitrary*/, 1) {
186186
tokens := e.requester.granted(noGrantChain)
187187
if tokens == 0 {
188188
e.returnGrantWithoutGrantingElsewhere(1)
@@ -235,7 +235,8 @@ func (e *elasticCPUGranter) getUtilizationLimit() float64 {
235235

236236
// hasWaitingRequests is part of the elasticCPULimiter interface.
237237
func (e *elasticCPUGranter) hasWaitingRequests() bool {
238-
return e.requester.hasWaitingRequests()
238+
hasWaiting, _ := e.requester.hasWaitingRequests()
239+
return hasWaiting
239240
}
240241

241242
// computeUtilizationMetric is part of the elasticCPULimiter interface.

pkg/util/admission/elastic_cpu_granter_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func TestElasticCPUGranter(t *testing.T) {
152152
return ""
153153

154154
case "try-get":
155-
granted := elasticCPUGranter.tryGet(duration.Nanoseconds())
155+
granted := elasticCPUGranter.tryGet(canBurst /*arbitrary*/, duration.Nanoseconds())
156156
return fmt.Sprintf("granted: %t\n", granted)
157157

158158
case "return-grant":
@@ -189,13 +189,13 @@ type testElasticCPURequester struct {
189189

190190
var _ requester = &testElasticCPURequester{}
191191

192-
func (t *testElasticCPURequester) hasWaitingRequests() bool {
192+
func (t *testElasticCPURequester) hasWaitingRequests() (bool, burstQualification) {
193193
var padding string
194194
if t.buf.Len() > 0 {
195195
padding = " "
196196
}
197197
t.buf.WriteString(fmt.Sprintf("%shas-waiting=%t ", padding, t.numWaitingRequests > 0))
198-
return t.numWaitingRequests > 0
198+
return t.numWaitingRequests > 0, canBurst /*arbitrary*/
199199
}
200200

201201
func (t *testElasticCPURequester) granted(grantChainID grantChainID) int64 {

0 commit comments

Comments
 (0)