Skip to content

Commit 9fec634

Browse files
split: add SplitStatistics function to Decider
So that external callers can be aware of the internal statistics on the load based splitters, this PR adds a fairly straightforward "SplitStatistics" function to the replica split deciders. Fixes: #138760 Epic: CRDB-43150 Release note: None
1 parent 6e53270 commit 9fec634

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

pkg/kv/kvserver/split/decider.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ type PopularKey struct {
2828
Frequency float64
2929
}
3030

31+
type SplitStatistics struct {
32+
AccessDirection float64
33+
PopularKey PopularKey
34+
}
35+
3136
type LoadBasedSplitter interface {
3237
redact.SafeFormatter
3338
// Record informs the LoadBasedSplitter about where the span lies with regard
@@ -359,6 +364,21 @@ func (d *Decider) MaybeSplitKey(ctx context.Context, now time.Time) roachpb.Key
359364
return key
360365
}
361366

367+
// SplitStatistics gets the split stats of the current replica if load-based
368+
// splitting has been engaged.
369+
func (d *Decider) SplitStatistics() *SplitStatistics {
370+
d.mu.Lock()
371+
defer d.mu.Unlock()
372+
373+
if d.mu.splitFinder != nil {
374+
return &SplitStatistics{
375+
AccessDirection: d.mu.splitFinder.AccessDirection(),
376+
PopularKey: d.mu.splitFinder.PopularKey(),
377+
}
378+
}
379+
return nil
380+
}
381+
362382
// Reset deactivates any current attempt at determining a split key. The method
363383
// also discards any historical stat tracking information.
364384
func (d *Decider) Reset(now time.Time) {

pkg/kv/kvserver/split/decider_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,110 @@ func TestMaxStatTracker(t *testing.T) {
374374
require.Equal(t, 1, mt.curIdx)
375375
}
376376

377+
func TestSplitStatisticsGeneral(t *testing.T) {
378+
defer leaktest.AfterTest(t)()
379+
for _, test := range []struct {
380+
name string
381+
useWeighted bool
382+
expected *SplitStatistics
383+
}{
384+
{"unweighted", false, &SplitStatistics{
385+
AccessDirection: 0.4945791444904396,
386+
PopularKey: PopularKey{
387+
Key: keys.SystemSQLCodec.TablePrefix(uint32(52)),
388+
Frequency: 0.05,
389+
},
390+
}},
391+
{"weighted", true, &SplitStatistics{
392+
AccessDirection: 0.3885786802030457,
393+
PopularKey: PopularKey{
394+
Key: keys.SystemSQLCodec.TablePrefix(uint32(111)),
395+
Frequency: 0.05,
396+
},
397+
}},
398+
} {
399+
t.Run(test.name, func(t *testing.T) {
400+
rand := rand.New(rand.NewPCG(11, 11))
401+
timeStart := 1000
402+
403+
var decider Decider
404+
loadSplitConfig := testLoadSplitConfig{
405+
randSource: rand,
406+
useWeighted: test.useWeighted,
407+
statRetention: time.Second,
408+
statThreshold: 1,
409+
}
410+
411+
Init(&decider, &loadSplitConfig, &LoadSplitterMetrics{
412+
PopularKeyCount: metric.NewCounter(metric.Metadata{}),
413+
NoSplitKeyCount: metric.NewCounter(metric.Metadata{}),
414+
}, SplitCPU)
415+
416+
for i := 1; i <= 1000; i++ {
417+
k := i
418+
if i > 500 {
419+
k = 500 - i
420+
}
421+
decider.Record(context.Background(), ms(timeStart+i*50), ld(1), func() roachpb.Span {
422+
return roachpb.Span{Key: keys.SystemSQLCodec.TablePrefix(uint32(k))}
423+
})
424+
}
425+
426+
assert.Equal(t, decider.SplitStatistics(), test.expected)
427+
})
428+
}
429+
}
430+
431+
func TestSplitStatisticsPopularKey(t *testing.T) {
432+
defer leaktest.AfterTest(t)()
433+
for _, test := range []struct {
434+
name string
435+
useWeighted bool
436+
expected *SplitStatistics
437+
}{
438+
{"unweighted", false, &SplitStatistics{
439+
AccessDirection: 1,
440+
PopularKey: PopularKey{
441+
Key: keys.SystemSQLCodec.TablePrefix(uint32(100)),
442+
Frequency: 1,
443+
},
444+
}},
445+
{"weighted", true, &SplitStatistics{
446+
AccessDirection: 1,
447+
PopularKey: PopularKey{
448+
Key: keys.SystemSQLCodec.TablePrefix(uint32(100)),
449+
Frequency: 1,
450+
},
451+
}},
452+
} {
453+
t.Run(test.name, func(t *testing.T) {
454+
rand := rand.New(rand.NewPCG(11, 11))
455+
timeStart := 1000
456+
457+
var decider Decider
458+
loadSplitConfig := testLoadSplitConfig{
459+
randSource: rand,
460+
useWeighted: test.useWeighted,
461+
statRetention: time.Second,
462+
statThreshold: 1,
463+
}
464+
465+
Init(&decider, &loadSplitConfig, &LoadSplitterMetrics{
466+
PopularKeyCount: metric.NewCounter(metric.Metadata{}),
467+
NoSplitKeyCount: metric.NewCounter(metric.Metadata{}),
468+
}, SplitCPU)
469+
470+
for i := 1; i <= 1000; i++ {
471+
decider.Record(context.Background(), ms(timeStart+i*50), ld(1), func() roachpb.Span {
472+
return roachpb.Span{Key: keys.SystemSQLCodec.TablePrefix(uint32(100))}
473+
})
474+
}
475+
476+
assert.Equal(t, decider.SplitStatistics(), test.expected)
477+
})
478+
}
479+
}
480+
377481
func TestDeciderMetrics(t *testing.T) {
378482
defer leaktest.AfterTest(t)()
379483
rng := rand.New(rand.NewPCG(11, 11))

0 commit comments

Comments
 (0)