Skip to content

Commit 8034bc5

Browse files
committed
kvserver: add scheduler re-add test
1 parent f150d45 commit 8034bc5

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

pkg/kv/kvserver/scheduler.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvflowcontrol/rac2"
1515
"github.com/cockroachdb/cockroach/pkg/roachpb"
1616
"github.com/cockroachdb/cockroach/pkg/util"
17+
"github.com/cockroachdb/cockroach/pkg/util/buildutil"
1718
"github.com/cockroachdb/cockroach/pkg/util/log"
1819
"github.com/cockroachdb/cockroach/pkg/util/stop"
1920
"github.com/cockroachdb/cockroach/pkg/util/syncutil"
@@ -22,6 +23,12 @@ import (
2223

2324
const rangeIDChunkSize = 1000
2425

26+
type testProcessorI interface {
27+
processTestEvent(
28+
context.Context, roachpb.RangeID, *raftSchedulerShard, raftScheduleState,
29+
)
30+
}
31+
2532
type rangeIDChunk struct {
2633
// Valid contents are buf[rd:wr], read at buf[rd], write at buf[wr].
2734
buf [rangeIDChunkSize]roachpb.RangeID
@@ -134,6 +141,7 @@ const (
134141
stateRaftTick
135142
stateRACv2PiggybackedAdmitted
136143
stateRACv2RangeController
144+
stateTestIntercept // used for testing, CrdbTestBuild only
137145
)
138146

139147
type raftScheduleState struct {
@@ -424,6 +432,9 @@ func (ss *raftSchedulerShard) worker(
424432
if state.flags&stateRACv2RangeController != 0 {
425433
processor.processRACv2RangeController(ctx, id)
426434
}
435+
if buildutil.CrdbTestBuild && state.flags&stateTestIntercept != 0 {
436+
processor.(testProcessorI).processTestEvent(ctx, id, ss, state)
437+
}
427438

428439
ss.Lock()
429440
state = ss.state[id]

pkg/kv/kvserver/scheduler_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/cockroachdb/cockroach/pkg/util/stop"
2727
"github.com/cockroachdb/cockroach/pkg/util/syncutil"
2828
"github.com/cockroachdb/errors"
29+
"github.com/stretchr/testify/assert"
2930
"github.com/stretchr/testify/require"
3031
)
3132

@@ -135,15 +136,19 @@ type testProcessor struct {
135136
rac2RangeController map[roachpb.RangeID]int
136137
ready func(roachpb.RangeID)
137138
}
139+
testEventCh chan func(roachpb.RangeID, *raftSchedulerShard, raftScheduleState)
138140
}
139141

142+
var _ testProcessorI = (*testProcessor)(nil)
143+
140144
func newTestProcessor() *testProcessor {
141145
p := &testProcessor{}
142146
p.mu.raftReady = make(map[roachpb.RangeID]int)
143147
p.mu.raftRequest = make(map[roachpb.RangeID]int)
144148
p.mu.raftTick = make(map[roachpb.RangeID]int)
145149
p.mu.rac2PiggybackedAdmitted = make(map[roachpb.RangeID]int)
146150
p.mu.rac2RangeController = make(map[roachpb.RangeID]int)
151+
p.testEventCh = make(chan func(roachpb.RangeID, *raftSchedulerShard, raftScheduleState), 10)
147152
return p
148153
}
149154

@@ -192,6 +197,16 @@ func (p *testProcessor) processRACv2RangeController(_ context.Context, rangeID r
192197
p.mu.Unlock()
193198
}
194199

200+
func (p *testProcessor) processTestEvent(
201+
ctx context.Context, id roachpb.RangeID, ss *raftSchedulerShard, ev raftScheduleState,
202+
) {
203+
select {
204+
case fn := <-p.testEventCh:
205+
fn(id, ss, ev)
206+
default:
207+
}
208+
}
209+
195210
func (p *testProcessor) readyCount(rangeID roachpb.RangeID) int {
196211
p.mu.Lock()
197212
defer p.mu.Unlock()
@@ -352,6 +367,75 @@ func TestSchedulerBuffering(t *testing.T) {
352367
}
353368
}
354369

370+
func TestSchedulerEnqueueWhileProcessing(t *testing.T) {
371+
defer leaktest.AfterTest(t)()
372+
defer log.Scope(t).Close(t)
373+
skip.UnderNonTestBuild(t) // stateTestIntercept needs crdb test build
374+
375+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
376+
defer cancel()
377+
378+
stopper := stop.NewStopper()
379+
defer stopper.Stop(ctx)
380+
381+
m := newStoreMetrics(metric.TestSampleInterval)
382+
p := newTestProcessor()
383+
s := newRaftScheduler(log.MakeTestingAmbientContext(stopper.Tracer()), m, p, 1, 1, 1, 5)
384+
s.Start(stopper)
385+
386+
done := make(chan struct{})
387+
388+
// Inject code into the "middle" of event processing - after having consumed
389+
// from the queue, but before re-checking of overlapping enqueue calls.
390+
p.testEventCh <- func(id roachpb.RangeID, ss *raftSchedulerShard, ev raftScheduleState) {
391+
// First call into this method.
392+
//
393+
// The event calling into us must have `ev.begin` set; it was set when
394+
// enqueuing.
395+
assert.NotZero(t, ev.begin)
396+
397+
// Even though our event is currently being processed, there is a queued
398+
// and otherwise blank event in the scheduler state (which is how we have
399+
// concurrent enqueue calls coalesce onto the still pending processing of
400+
// the current event).
401+
ss.Lock()
402+
statePre := ss.state[id]
403+
ss.Unlock()
404+
405+
assert.Zero(t, statePre.begin)
406+
assert.Equal(t, stateQueued, statePre.flags)
407+
408+
// Simulate a concurrent actor that enqueues the same range again.
409+
// This will not trigger the interceptor again, since the done channel
410+
// is closed by that time.
411+
s.enqueue1(stateTestIntercept, 1)
412+
413+
// Seeing that there is an existing "queued" event, the enqueue call below
414+
// should not populate `begin`. Instead, this will be the job of our
415+
// caller when it *actually* pushes into the queue again after fully
416+
// having handled `ev`.
417+
ss.Lock()
418+
statePost := ss.state[id]
419+
ss.Unlock()
420+
421+
// TODO(tbg): enable in follow-up commit.
422+
// assert.Zero(t, statePost.begin)
423+
assert.Equal(t, stateQueued|stateTestIntercept, statePost.flags)
424+
close(done)
425+
}
426+
p.testEventCh <- func(id roachpb.RangeID, shard *raftSchedulerShard, ev raftScheduleState) {
427+
// Second call into this method, i.e. the overlappingly-enqeued event is
428+
// being processed. Check that `begin` is now set.
429+
assert.NotZero(t, ev.begin)
430+
}
431+
s.enqueue1(stateTestIntercept, 1) // will become 'ev' in the intercept
432+
select {
433+
case <-done:
434+
case <-ctx.Done():
435+
t.Fatal(ctx.Err())
436+
}
437+
}
438+
355439
func TestNewSchedulerShards(t *testing.T) {
356440
defer leaktest.AfterTest(t)()
357441
defer log.Scope(t).Close(t)

0 commit comments

Comments
 (0)