github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/scheduler_test.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package kvserver
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  	"sort"
    18  	"testing"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    21  	"github.com/cockroachdb/cockroach/pkg/testutils"
    22  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    23  	"github.com/cockroachdb/cockroach/pkg/util/stop"
    24  	"github.com/cockroachdb/cockroach/pkg/util/syncutil"
    25  	"github.com/cockroachdb/errors"
    26  )
    27  
    28  func TestRangeIDChunk(t *testing.T) {
    29  	defer leaktest.AfterTest(t)()
    30  
    31  	var c rangeIDChunk
    32  	if c.Len() != 0 {
    33  		t.Fatalf("expected empty chunk, but found %d", c.Len())
    34  	}
    35  	if c.WriteCap() != rangeIDChunkSize {
    36  		t.Fatalf("expected %d, but found %d", rangeIDChunkSize, c.WriteCap())
    37  	}
    38  	if _, ok := c.PopFront(); ok {
    39  		t.Fatalf("successfully popped from empty chunk")
    40  	}
    41  
    42  	for i := 1; i <= rangeIDChunkSize; i++ {
    43  		if !c.PushBack(roachpb.RangeID(i)) {
    44  			t.Fatalf("%d: failed to push", i)
    45  		}
    46  		if e := i; e != c.Len() {
    47  			t.Fatalf("expected %d, but found %d", e, c.Len())
    48  		}
    49  		if e := rangeIDChunkSize - i; e != c.WriteCap() {
    50  			t.Fatalf("expected %d, but found %d", e, c.WriteCap())
    51  		}
    52  	}
    53  	if c.PushBack(0) {
    54  		t.Fatalf("successfully pushed to full chunk")
    55  	}
    56  
    57  	for i := 1; i <= rangeIDChunkSize; i++ {
    58  		id, ok := c.PopFront()
    59  		if !ok {
    60  			t.Fatalf("%d: failed to pop", i)
    61  		}
    62  		if roachpb.RangeID(i) != id {
    63  			t.Fatalf("expected %d, but found %d", i, id)
    64  		}
    65  		if e := rangeIDChunkSize - i; e != c.Len() {
    66  			t.Fatalf("expected %d, but found %d", e, c.Len())
    67  		}
    68  		if c.WriteCap() != 0 {
    69  			t.Fatalf("expected full chunk, but found %d", c.WriteCap())
    70  		}
    71  	}
    72  	if c.Len() != 0 {
    73  		t.Fatalf("expected empty chunk, but found %d", c.Len())
    74  	}
    75  	if c.WriteCap() != 0 {
    76  		t.Fatalf("expected full chunk, but found %d", c.WriteCap())
    77  	}
    78  	if _, ok := c.PopFront(); ok {
    79  		t.Fatalf("successfully popped from empty chunk")
    80  	}
    81  }
    82  
    83  func TestRangeIDQueue(t *testing.T) {
    84  	defer leaktest.AfterTest(t)()
    85  
    86  	var q rangeIDQueue
    87  	if q.Len() != 0 {
    88  		t.Fatalf("expected empty queue, but found %d", q.Len())
    89  	}
    90  	if _, ok := q.PopFront(); ok {
    91  		t.Fatalf("successfully popped from empty queue")
    92  	}
    93  
    94  	const count = 3 * rangeIDChunkSize
    95  	for i := 1; i <= count; i++ {
    96  		q.PushBack(roachpb.RangeID(i))
    97  		if e := i; e != q.Len() {
    98  			t.Fatalf("expected %d, but found %d", e, q.Len())
    99  		}
   100  	}
   101  
   102  	for i := 1; i <= count; i++ {
   103  		id, ok := q.PopFront()
   104  		if !ok {
   105  			t.Fatalf("%d: failed to pop", i)
   106  		}
   107  		if roachpb.RangeID(i) != id {
   108  			t.Fatalf("expected %d, but found %d", i, id)
   109  		}
   110  		if e := count - i; e != q.Len() {
   111  			t.Fatalf("expected %d, but found %d", e, q.Len())
   112  		}
   113  	}
   114  	if q.Len() != 0 {
   115  		t.Fatalf("expected empty queue, but found %d", q.Len())
   116  	}
   117  	if _, ok := q.PopFront(); ok {
   118  		t.Fatalf("successfully popped from empty queue")
   119  	}
   120  }
   121  
   122  type testProcessor struct {
   123  	mu struct {
   124  		syncutil.Mutex
   125  		raftReady   map[roachpb.RangeID]int
   126  		raftRequest map[roachpb.RangeID]int
   127  		raftTick    map[roachpb.RangeID]int
   128  	}
   129  }
   130  
   131  func newTestProcessor() *testProcessor {
   132  	p := &testProcessor{}
   133  	p.mu.raftReady = make(map[roachpb.RangeID]int)
   134  	p.mu.raftRequest = make(map[roachpb.RangeID]int)
   135  	p.mu.raftTick = make(map[roachpb.RangeID]int)
   136  	return p
   137  }
   138  
   139  func (p *testProcessor) processReady(_ context.Context, rangeID roachpb.RangeID) {
   140  	p.mu.Lock()
   141  	p.mu.raftReady[rangeID]++
   142  	p.mu.Unlock()
   143  }
   144  
   145  func (p *testProcessor) processRequestQueue(_ context.Context, rangeID roachpb.RangeID) bool {
   146  	p.mu.Lock()
   147  	p.mu.raftRequest[rangeID]++
   148  	p.mu.Unlock()
   149  	return false
   150  }
   151  
   152  func (p *testProcessor) processTick(_ context.Context, rangeID roachpb.RangeID) bool {
   153  	p.mu.Lock()
   154  	p.mu.raftTick[rangeID]++
   155  	p.mu.Unlock()
   156  	return false
   157  }
   158  
   159  func (p *testProcessor) countsLocked(m map[roachpb.RangeID]int) string {
   160  	var ids roachpb.RangeIDSlice
   161  	for id := range m {
   162  		ids = append(ids, id)
   163  	}
   164  	sort.Sort(ids)
   165  	var buf bytes.Buffer
   166  	fmt.Fprintf(&buf, "[")
   167  	for i, id := range ids {
   168  		if i > 0 {
   169  			fmt.Fprintf(&buf, ",")
   170  		}
   171  		fmt.Fprintf(&buf, "%d:%d", id, m[id])
   172  	}
   173  	fmt.Fprintf(&buf, "]")
   174  	return buf.String()
   175  }
   176  
   177  func (p *testProcessor) String() string {
   178  	p.mu.Lock()
   179  	defer p.mu.Unlock()
   180  	return fmt.Sprintf("ready=%s request=%s tick=%s",
   181  		p.countsLocked(p.mu.raftReady),
   182  		p.countsLocked(p.mu.raftRequest),
   183  		p.countsLocked(p.mu.raftTick))
   184  }
   185  
   186  // Verify that enqueuing more ranges than the number of workers correctly
   187  // processes all of the ranges. This exercises a code path that was buggy
   188  // during development.
   189  func TestSchedulerLoop(t *testing.T) {
   190  	defer leaktest.AfterTest(t)()
   191  
   192  	p := newTestProcessor()
   193  	s := newRaftScheduler(nil, p, 1)
   194  	stopper := stop.NewStopper()
   195  	ctx := context.Background()
   196  	defer stopper.Stop(ctx)
   197  	s.Start(ctx, stopper)
   198  	s.EnqueueRaftTick(1, 2, 3)
   199  
   200  	testutils.SucceedsSoon(t, func() error {
   201  		const expected = "ready=[] request=[] tick=[1:1,2:1,3:1]"
   202  		if s := p.String(); expected != s {
   203  			return errors.Errorf("expected %s, but got %s", expected, s)
   204  		}
   205  		return nil
   206  	})
   207  }
   208  
   209  // Verify that when we enqueue the same range multiple times for the same
   210  // reason, it is only processed once.
   211  func TestSchedulerBuffering(t *testing.T) {
   212  	defer leaktest.AfterTest(t)()
   213  
   214  	p := newTestProcessor()
   215  	s := newRaftScheduler(nil, p, 1)
   216  	stopper := stop.NewStopper()
   217  	ctx := context.Background()
   218  	defer stopper.Stop(ctx)
   219  	s.Start(ctx, stopper)
   220  
   221  	testCases := []struct {
   222  		state    raftScheduleState
   223  		expected string
   224  	}{
   225  		{stateRaftReady, "ready=[1:1] request=[] tick=[]"},
   226  		{stateRaftRequest, "ready=[1:1] request=[1:1] tick=[]"},
   227  		{stateRaftTick, "ready=[1:1] request=[1:1] tick=[1:1]"},
   228  		{stateRaftReady | stateRaftRequest | stateRaftTick, "ready=[1:2] request=[1:2] tick=[1:2]"},
   229  	}
   230  
   231  	for _, c := range testCases {
   232  		s.signal(s.enqueueN(c.state, 1, 1, 1, 1, 1))
   233  
   234  		testutils.SucceedsSoon(t, func() error {
   235  			if s := p.String(); c.expected != s {
   236  				return errors.Errorf("expected %s, but got %s", c.expected, s)
   237  			}
   238  			return nil
   239  		})
   240  	}
   241  }