github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cli/debug_check_store_test.go (about) 1 // Copyright 2019 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 cli 12 13 import ( 14 "context" 15 "fmt" 16 "path/filepath" 17 "strings" 18 "testing" 19 "time" 20 21 "github.com/cockroachdb/cockroach/pkg/base" 22 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/stateloader" 23 "github.com/cockroachdb/cockroach/pkg/roachpb" 24 "github.com/cockroachdb/cockroach/pkg/storage" 25 "github.com/cockroachdb/cockroach/pkg/testutils" 26 "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" 27 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestDebugCheckStore(t *testing.T) { 32 defer leaktest.AfterTest(t)() 33 34 ctx := context.Background() 35 36 baseDir, dirCleanupFn := testutils.TempDir(t) 37 defer dirCleanupFn() 38 39 // Number of nodes. Increasing this will make the test flaky as written 40 // because it relies on finding r1 on n1. 41 const n = 3 42 43 clusterArgs := base.TestClusterArgs{ 44 ServerArgsPerNode: map[int]base.TestServerArgs{}, 45 } 46 var storePaths []string 47 for i := 0; i < n; i++ { 48 args := base.TestServerArgs{} 49 args.ScanMaxIdleTime = time.Millisecond 50 args.ScanMaxIdleTime = time.Millisecond 51 storeID := roachpb.StoreID(i + 1) 52 path := filepath.Join(baseDir, fmt.Sprintf("s%d", storeID)) 53 storePaths = append(storePaths, path) 54 args.StoreSpecs = []base.StoreSpec{{Path: path}} 55 clusterArgs.ServerArgsPerNode[i] = args 56 } 57 58 // Start the cluster, wait for full replication, stop the cluster. 59 func() { 60 tc := testcluster.StartTestCluster(t, n, clusterArgs) 61 defer tc.Stopper().Stop(ctx) 62 require.NoError(t, tc.WaitForFullReplication()) 63 }() 64 65 check := func(dir string) (string, error) { 66 var buf strings.Builder 67 err := checkStoreRangeStats(ctx, dir, func(args ...interface{}) { 68 fmt.Fprintln(&buf, args...) 69 }) 70 return buf.String(), err 71 } 72 73 // Should not error out randomly. 74 for _, dir := range storePaths { 75 out, err := check(dir) 76 require.NoError(t, err, dir) 77 require.Contains(t, out, "total stats", dir) 78 } 79 80 // Introduce a stats divergence on s1. 81 func() { 82 eng, err := storage.NewDefaultEngine( 83 10<<20, /* 10mb */ 84 base.StorageConfig{ 85 Dir: storePaths[0], 86 MustExist: true, 87 }) 88 require.NoError(t, err) 89 defer eng.Close() 90 sl := stateloader.Make(1) 91 ms, err := sl.LoadMVCCStats(ctx, eng) 92 require.NoError(t, err) 93 ms.ContainsEstimates = 0 94 ms.LiveBytes++ 95 require.NoError(t, sl.SetMVCCStats(ctx, eng, &ms)) 96 }() 97 98 // The check should now fail on s1. 99 { 100 const s = "stats inconsistency" 101 out, err := check(storePaths[0]) 102 require.Error(t, err) 103 require.Contains(t, out, s) 104 require.Contains(t, out, "total stats") 105 } 106 }