@@ -22,10 +22,11 @@ import (
22
22
// testLoadSplitConfig implements the LoadSplitConfig interface and may be used
23
23
// in testing.
24
24
type testLoadSplitConfig struct {
25
- randSource RandSource
26
- useWeighted bool
27
- statRetention time.Duration
28
- statThreshold float64
25
+ randSource RandSource
26
+ useWeighted bool
27
+ statRetention time.Duration
28
+ statThreshold float64
29
+ sampleResetDuration time.Duration
29
30
}
30
31
31
32
// NewLoadBasedSplitter returns a new LoadBasedSplitter that may be used to
@@ -50,6 +51,12 @@ func (t *testLoadSplitConfig) StatThreshold(_ SplitObjective) float64 {
50
51
return t .statThreshold
51
52
}
52
53
54
+ // SampleResetDuration returns the duration that any sampling structure should
55
+ // retain data for before resetting.
56
+ func (t * testLoadSplitConfig ) SampleResetDuration () time.Duration {
57
+ return t .sampleResetDuration
58
+ }
59
+
53
60
func ld (n int ) func (SplitObjective ) int {
54
61
return func (_ SplitObjective ) int {
55
62
return n
@@ -561,3 +568,66 @@ func TestDeciderMetrics(t *testing.T) {
561
568
assert .Equal (t , dAllInsufficientCounters .loadSplitterMetrics .ClearDirectionCount .Count (), int64 (0 ))
562
569
563
570
}
571
+
572
+ // TestDeciderSampleReset tests the sample reset functionality of the decider,
573
+ // when the sample reset duration is non-zero, the split finder should be reset
574
+ // after the given duration. When the sample reset duration is zero, the split
575
+ // finder should not be reset.
576
+ func TestDeciderSampleReset (t * testing.T ) {
577
+ defer leaktest .AfterTest (t )()
578
+
579
+ rng := rand .New (rand .NewPCG (12 , 12 ))
580
+ loadSplitConfig := testLoadSplitConfig {
581
+ randSource : rng ,
582
+ useWeighted : false ,
583
+ statRetention : 2 * time .Second ,
584
+ statThreshold : 1 ,
585
+ sampleResetDuration : 10 * time .Second ,
586
+ }
587
+ ctx := context .Background ()
588
+ tick := 0
589
+
590
+ var d Decider
591
+ Init (& d , & loadSplitConfig , newSplitterMetrics (), SplitQPS )
592
+
593
+ require .Nil (t , d .mu .splitFinder )
594
+ d .Record (ctx , ms (tick ), ld (100 ), func () roachpb.Span {
595
+ return roachpb.Span {Key : keys .SystemSQLCodec .TablePrefix (uint32 (0 ))}
596
+ })
597
+ // The split finder should be created as the second sample is recorded and
598
+ // the stat remains above the threshold (1) each tick.
599
+ for i := 0 ; i < 10 ; i ++ {
600
+ tick += 1000
601
+ d .Record (ctx , ms (tick ), ld (100 ), func () roachpb.Span {
602
+ return roachpb.Span {Key : keys .SystemSQLCodec .TablePrefix (uint32 (0 ))}
603
+ })
604
+ require .NotNil (t , d .mu .splitFinder , (* lockedDecider )(& d ))
605
+ }
606
+
607
+ // Tick one more time, now the sample reset duration (10s) has passed and the
608
+ // split finder should be reset.
609
+ tick += 1000
610
+ d .Record (ctx , ms (tick ), ld (100 ), func () roachpb.Span {
611
+ return roachpb.Span {Key : keys .SystemSQLCodec .TablePrefix (uint32 (0 ))}
612
+ })
613
+ require .Nil (t , d .mu .splitFinder , (* lockedDecider )(& d ))
614
+
615
+ // Immediately following the last tick where the splitFinder was reset, it
616
+ // should be recreated as the stat is still above the threshold.
617
+ for i := 0 ; i < 10 ; i ++ {
618
+ tick += 1000
619
+ d .Record (ctx , ms (tick ), ld (100 ), func () roachpb.Span {
620
+ return roachpb.Span {Key : keys .SystemSQLCodec .TablePrefix (uint32 (0 ))}
621
+ })
622
+ require .NotNil (t , d .mu .splitFinder , (* lockedDecider )(& d ))
623
+ }
624
+ // Set the sample reset duration to 0, which should cause the split finder to
625
+ // not be reset in the next tick, unlike before when the sample reset
626
+ // duration was 10s.
627
+ loadSplitConfig .sampleResetDuration = 0
628
+ tick += 1000
629
+ d .Record (ctx , ms (tick ), ld (100 ), func () roachpb.Span {
630
+ return roachpb.Span {Key : keys .SystemSQLCodec .TablePrefix (uint32 (0 ))}
631
+ })
632
+ require .NotNil (t , d .mu .splitFinder , (* lockedDecider )(& d ))
633
+ }
0 commit comments