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

     1  // Copyright 2014 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  	"context"
    15  	"reflect"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/clusterversion"
    20  	"github.com/cockroachdb/cockroach/pkg/gossip"
    21  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    22  	"github.com/cockroachdb/cockroach/pkg/storage"
    23  	"github.com/cockroachdb/cockroach/pkg/testutils"
    24  	"github.com/cockroachdb/cockroach/pkg/util"
    25  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    26  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    27  	"github.com/cockroachdb/cockroach/pkg/util/log"
    28  	"github.com/cockroachdb/cockroach/pkg/util/stop"
    29  	"github.com/cockroachdb/cockroach/pkg/util/tracing"
    30  	"github.com/cockroachdb/errors"
    31  )
    32  
    33  func newStores(ambientCtx log.AmbientContext, clock *hlc.Clock) *Stores {
    34  	return NewStores(ambientCtx, clock)
    35  }
    36  
    37  func TestStoresAddStore(t *testing.T) {
    38  	defer leaktest.AfterTest(t)()
    39  	ls := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, hlc.NewClock(hlc.UnixNano, time.Nanosecond))
    40  	store := Store{
    41  		Ident: &roachpb.StoreIdent{StoreID: 123},
    42  	}
    43  	ls.AddStore(&store)
    44  	if !ls.HasStore(store.Ident.StoreID) {
    45  		t.Errorf("expected local sender to contain storeID=%d", store.Ident.StoreID)
    46  	}
    47  	if ls.HasStore(store.Ident.StoreID + 1) {
    48  		t.Errorf("expected local sender to not contain storeID=%d", store.Ident.StoreID+1)
    49  	}
    50  }
    51  
    52  func TestStoresRemoveStore(t *testing.T) {
    53  	defer leaktest.AfterTest(t)()
    54  	ls := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, hlc.NewClock(hlc.UnixNano, time.Nanosecond))
    55  
    56  	storeID := roachpb.StoreID(89)
    57  
    58  	ls.AddStore(&Store{Ident: &roachpb.StoreIdent{StoreID: storeID}})
    59  
    60  	ls.RemoveStore(&Store{Ident: &roachpb.StoreIdent{StoreID: storeID}})
    61  
    62  	if ls.HasStore(storeID) {
    63  		t.Errorf("expted local sender to remove storeID=%d", storeID)
    64  	}
    65  }
    66  
    67  func TestStoresGetStoreCount(t *testing.T) {
    68  	defer leaktest.AfterTest(t)()
    69  	ls := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, hlc.NewClock(hlc.UnixNano, time.Nanosecond))
    70  	if ls.GetStoreCount() != 0 {
    71  		t.Errorf("expected 0 stores in new local sender")
    72  	}
    73  
    74  	expectedCount := 10
    75  	for i := 0; i < expectedCount; i++ {
    76  		ls.AddStore(&Store{Ident: &roachpb.StoreIdent{StoreID: roachpb.StoreID(i)}})
    77  	}
    78  	if count := ls.GetStoreCount(); count != expectedCount {
    79  		t.Errorf("expected store count to be %d but was %d", expectedCount, count)
    80  	}
    81  }
    82  
    83  func TestStoresVisitStores(t *testing.T) {
    84  	defer leaktest.AfterTest(t)()
    85  	ls := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, hlc.NewClock(hlc.UnixNano, time.Nanosecond))
    86  	numStores := 10
    87  	for i := 0; i < numStores; i++ {
    88  		ls.AddStore(&Store{Ident: &roachpb.StoreIdent{StoreID: roachpb.StoreID(i)}})
    89  	}
    90  
    91  	visit := make([]bool, numStores)
    92  	err := ls.VisitStores(func(s *Store) error { visit[s.Ident.StoreID] = true; return nil })
    93  	if err != nil {
    94  		t.Errorf("unexpected error on visit: %s", err.Error())
    95  	}
    96  
    97  	for i, visited := range visit {
    98  		if !visited {
    99  			t.Errorf("store %d was not visited", i)
   100  		}
   101  	}
   102  
   103  	errBoom := errors.New("boom")
   104  	if err := ls.VisitStores(func(s *Store) error {
   105  		return errBoom
   106  	}); !errors.Is(err, errBoom) {
   107  		t.Errorf("got unexpected error %v", err)
   108  	}
   109  }
   110  
   111  func TestStoresGetReplicaForRangeID(t *testing.T) {
   112  	defer leaktest.AfterTest(t)()
   113  	ctx := context.Background()
   114  	stopper := stop.NewStopper()
   115  	defer stopper.Stop(ctx)
   116  
   117  	clock := hlc.NewClock(hlc.UnixNano, time.Nanosecond)
   118  
   119  	ls := newStores(log.AmbientContext{}, clock)
   120  	numStores := 10
   121  	for i := 1; i <= numStores; i++ {
   122  		storeID := roachpb.StoreID(i)
   123  		rangeID := roachpb.RangeID(i)
   124  		replicaID := roachpb.ReplicaID(1)
   125  
   126  		memEngine := storage.NewDefaultInMem()
   127  		stopper.AddCloser(memEngine)
   128  
   129  		cfg := TestStoreConfig(clock)
   130  		cfg.Transport = NewDummyRaftTransport(cfg.Settings)
   131  
   132  		store := NewStore(ctx, cfg, memEngine, &roachpb.NodeDescriptor{NodeID: 1})
   133  		// Fake-set an ident. This is usually read from the engine on store.Start()
   134  		// which we're not even going to call.
   135  		store.Ident = &roachpb.StoreIdent{StoreID: storeID}
   136  		ls.AddStore(store)
   137  
   138  		desc := &roachpb.RangeDescriptor{
   139  			RangeID:  rangeID,
   140  			StartKey: roachpb.RKey("a"),
   141  			EndKey:   roachpb.RKey("b"),
   142  			InternalReplicas: []roachpb.ReplicaDescriptor{
   143  				{
   144  					StoreID:   storeID,
   145  					ReplicaID: replicaID,
   146  					NodeID:    1,
   147  				},
   148  			},
   149  		}
   150  
   151  		replica, err := newReplica(ctx, desc, store, replicaID)
   152  		if err != nil {
   153  			t.Fatalf("unexpected error when creating replica: %+v", err)
   154  		}
   155  		err2 := store.AddReplica(replica)
   156  		if err2 != nil {
   157  			t.Fatalf("unexpected error when adding replica: %v", err2)
   158  		}
   159  	}
   160  
   161  	// Test the case where the replica we're looking for exists.
   162  	rangeID1 := roachpb.RangeID(5)
   163  	replica1, _, err1 := ls.GetReplicaForRangeID(rangeID1)
   164  	if replica1 == nil {
   165  		t.Fatal("expected replica to be found; was nil")
   166  	}
   167  	if err1 != nil {
   168  		t.Fatalf("expected err to be nil; was %v", err1)
   169  	}
   170  	if replica1.RangeID != rangeID1 {
   171  		t.Fatalf("expected replica's range id to be %v; got %v", rangeID1, replica1.RangeID)
   172  	}
   173  
   174  	// Test the case where the replica we're looking for doesn't exist.
   175  	rangeID2 := roachpb.RangeID(1000)
   176  	replica2, _, err2 := ls.GetReplicaForRangeID(rangeID2)
   177  	if replica2 != nil {
   178  		t.Fatalf("expected replica to be nil; was %v", replica2)
   179  	}
   180  	expectedError := roachpb.NewRangeNotFoundError(rangeID2, 0)
   181  	if err2.Error() != expectedError.Error() {
   182  		t.Fatalf("expected err to be %v; was %v", expectedError, err2)
   183  	}
   184  }
   185  
   186  func TestStoresGetStore(t *testing.T) {
   187  	defer leaktest.AfterTest(t)()
   188  	ls := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, hlc.NewClock(hlc.UnixNano, time.Nanosecond))
   189  	store := Store{Ident: &roachpb.StoreIdent{StoreID: 1}}
   190  	replica := roachpb.ReplicaDescriptor{StoreID: store.Ident.StoreID}
   191  	s, pErr := ls.GetStore(replica.StoreID)
   192  	if s != nil || pErr == nil {
   193  		t.Errorf("expected no stores in new local sender")
   194  	}
   195  
   196  	ls.AddStore(&store)
   197  	s, pErr = ls.GetStore(replica.StoreID)
   198  	if s == nil {
   199  		t.Errorf("expected store")
   200  	} else if s.Ident.StoreID != store.Ident.StoreID {
   201  		t.Errorf("expected storeID to be %d but was %d",
   202  			s.Ident.StoreID, store.Ident.StoreID)
   203  	} else if pErr != nil {
   204  		t.Errorf("expected no error, instead had err=%s", pErr)
   205  	}
   206  }
   207  
   208  var storeIDAlloc roachpb.StoreID
   209  
   210  // createStores creates a slice of count stores.
   211  func createStores(count int, t *testing.T) (*hlc.ManualClock, []*Store, *Stores, *stop.Stopper) {
   212  	stopper := stop.NewStopper()
   213  	manual := hlc.NewManualClock(123)
   214  	cfg := TestStoreConfig(hlc.NewClock(manual.UnixNano, time.Nanosecond))
   215  	ls := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, cfg.Clock)
   216  
   217  	// Create two stores with ranges we care about.
   218  	stores := []*Store{}
   219  	for i := 0; i < count; i++ {
   220  		cfg.Transport = NewDummyRaftTransport(cfg.Settings)
   221  		eng := storage.NewDefaultInMem()
   222  		stopper.AddCloser(eng)
   223  		s := NewStore(context.Background(), cfg, eng, &roachpb.NodeDescriptor{NodeID: 1})
   224  		storeIDAlloc++
   225  		s.Ident = &roachpb.StoreIdent{StoreID: storeIDAlloc}
   226  		stores = append(stores, s)
   227  	}
   228  
   229  	return manual, stores, ls, stopper
   230  }
   231  
   232  // TestStoresGossipStorage verifies reading and writing of bootstrap info.
   233  func TestStoresGossipStorage(t *testing.T) {
   234  	defer leaktest.AfterTest(t)()
   235  	manual, stores, ls, stopper := createStores(2, t)
   236  	defer stopper.Stop(context.Background())
   237  	ls.AddStore(stores[0])
   238  
   239  	// Verify initial read is empty.
   240  	var bi gossip.BootstrapInfo
   241  	if err := ls.ReadBootstrapInfo(&bi); err != nil {
   242  		t.Fatal(err)
   243  	}
   244  	if len(bi.Addresses) != 0 {
   245  		t.Errorf("expected empty bootstrap info: %+v", bi)
   246  	}
   247  
   248  	// Add a fake address and write.
   249  	manual.Increment(1)
   250  	bi.Addresses = append(bi.Addresses, util.MakeUnresolvedAddr("tcp", "127.0.0.1:8001"))
   251  	if err := ls.WriteBootstrapInfo(&bi); err != nil {
   252  		t.Fatal(err)
   253  	}
   254  
   255  	// Verify on read.
   256  	manual.Increment(1)
   257  	var newBI gossip.BootstrapInfo
   258  	if err := ls.ReadBootstrapInfo(&newBI); err != nil {
   259  		t.Fatal(err)
   260  	}
   261  	if len(newBI.Addresses) != 1 {
   262  		t.Errorf("expected single bootstrap info address: %+v", newBI)
   263  	}
   264  
   265  	// Add another store and verify it has bootstrap info written.
   266  	ls.AddStore(stores[1])
   267  
   268  	// Create a new stores object to verify read.
   269  	ls2 := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, ls.clock)
   270  	ls2.AddStore(stores[1])
   271  	var verifyBI gossip.BootstrapInfo
   272  	if err := ls2.ReadBootstrapInfo(&verifyBI); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	if !reflect.DeepEqual(bi, verifyBI) {
   276  		t.Errorf("bootstrap info %+v not equal to expected %+v", verifyBI, bi)
   277  	}
   278  }
   279  
   280  // TestStoresGossipStorageReadLatest verifies that the latest
   281  // bootstrap info from multiple stores is returned on Read.
   282  func TestStoresGossipStorageReadLatest(t *testing.T) {
   283  	defer leaktest.AfterTest(t)()
   284  	manual, stores, ls, stopper := createStores(2, t)
   285  	defer stopper.Stop(context.Background())
   286  	ls.AddStore(stores[0])
   287  
   288  	// Add a fake address and write.
   289  	var bi gossip.BootstrapInfo
   290  	bi.Addresses = append(bi.Addresses, util.MakeUnresolvedAddr("tcp", "127.0.0.1:8001"))
   291  	if err := ls.WriteBootstrapInfo(&bi); err != nil {
   292  		t.Fatal(err)
   293  	}
   294  
   295  	// Now remove store 0 and add store 1.
   296  	ls.RemoveStore(stores[0])
   297  	ls.AddStore(stores[1])
   298  
   299  	// Increment clock, add another address and write.
   300  	manual.Increment(1)
   301  	bi.Addresses = append(bi.Addresses, util.MakeUnresolvedAddr("tcp", "127.0.0.1:8002"))
   302  	if err := ls.WriteBootstrapInfo(&bi); err != nil {
   303  		t.Fatal(err)
   304  	}
   305  
   306  	// Create a new stores object to freshly read. Should get latest
   307  	// version from store 1.
   308  	manual.Increment(1)
   309  	ls2 := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, ls.clock)
   310  	ls2.AddStore(stores[0])
   311  	ls2.AddStore(stores[1])
   312  	var verifyBI gossip.BootstrapInfo
   313  	if err := ls2.ReadBootstrapInfo(&verifyBI); err != nil {
   314  		t.Fatal(err)
   315  	}
   316  	if !reflect.DeepEqual(bi, verifyBI) {
   317  		t.Errorf("bootstrap info %+v not equal to expected %+v", verifyBI, bi)
   318  	}
   319  
   320  	// Verify that stores[0], which had old info, was updated with
   321  	// latest bootstrap info during the read.
   322  	ls3 := newStores(log.AmbientContext{Tracer: tracing.NewTracer()}, ls.clock)
   323  	ls3.AddStore(stores[0])
   324  	verifyBI.Reset()
   325  	if err := ls3.ReadBootstrapInfo(&verifyBI); err != nil {
   326  		t.Fatal(err)
   327  	}
   328  	if !reflect.DeepEqual(bi, verifyBI) {
   329  		t.Errorf("bootstrap info %+v not equal to expected %+v", verifyBI, bi)
   330  	}
   331  }
   332  
   333  // TestStoresClusterVersionWriteSynthesize verifies that the cluster version is
   334  // written to all stores and that missing versions are filled in appropriately.
   335  func TestClusterVersionWriteSynthesize(t *testing.T) {
   336  	defer leaktest.AfterTest(t)()
   337  	_, stores, _, stopper := createStores(3, t)
   338  	ctx := context.Background()
   339  	defer stopper.Stop(ctx)
   340  
   341  	v1_0 := roachpb.Version{Major: 1}
   342  	// Hard-code binaryVersion of 1.1 for this test.
   343  	// Hard-code binaryMinSupportedVersion of 1.0 for this test.
   344  	binV := roachpb.Version{Major: 1, Minor: 1}
   345  	minV := v1_0
   346  
   347  	makeStores := func() *Stores {
   348  		ls := NewStores(log.AmbientContext{}, stores[0].Clock())
   349  		return ls
   350  	}
   351  
   352  	ls0 := makeStores()
   353  
   354  	// If there are no stores, default to binaryMinSupportedVersion
   355  	// (v1_0 in this test)
   356  	if initialCV, err := SynthesizeClusterVersionFromEngines(ctx, ls0.engines(), binV, minV); err != nil {
   357  		t.Fatal(err)
   358  	} else {
   359  		expCV := clusterversion.ClusterVersion{
   360  			Version: v1_0,
   361  		}
   362  		if !reflect.DeepEqual(initialCV, expCV) {
   363  			t.Fatalf("expected %+v; got %+v", expCV, initialCV)
   364  		}
   365  	}
   366  
   367  	ls0.AddStore(stores[0])
   368  
   369  	versionA := roachpb.Version{Major: 1, Minor: 0, Unstable: 1} // 1.0-1
   370  	versionB := roachpb.Version{Major: 1, Minor: 0, Unstable: 2} // 1.0-2
   371  
   372  	// Verify that the initial read of an empty store synthesizes v1.0-0. This
   373  	// is the code path that runs after starting the 1.1 binary for the first
   374  	// time after the rolling upgrade from 1.0.
   375  	if initialCV, err := SynthesizeClusterVersionFromEngines(ctx, ls0.engines(), binV, minV); err != nil {
   376  		t.Fatal(err)
   377  	} else {
   378  		expCV := clusterversion.ClusterVersion{
   379  			Version: v1_0,
   380  		}
   381  		if !reflect.DeepEqual(initialCV, expCV) {
   382  			t.Fatalf("expected %+v; got %+v", expCV, initialCV)
   383  		}
   384  	}
   385  
   386  	// Bump a version to something more modern (but supported by this binary).
   387  	// Note that there's still only one store.
   388  	{
   389  		cv := clusterversion.ClusterVersion{
   390  			Version: versionB,
   391  		}
   392  		if err := WriteClusterVersionToEngines(ctx, ls0.engines(), cv); err != nil {
   393  			t.Fatal(err)
   394  		}
   395  
   396  		// Verify the same thing comes back on read.
   397  		if newCV, err := SynthesizeClusterVersionFromEngines(ctx, ls0.engines(), binV, minV); err != nil {
   398  			t.Fatal(err)
   399  		} else {
   400  			expCV := cv
   401  			if !reflect.DeepEqual(newCV, cv) {
   402  				t.Fatalf("expected %+v; got %+v", expCV, newCV)
   403  			}
   404  		}
   405  	}
   406  
   407  	// Make a stores with store0 and store1. It reads as v1.0 because store1 has
   408  	// no entry, lowering the use version to v1.0 (but not the min version).
   409  	{
   410  		ls01 := makeStores()
   411  		ls01.AddStore(stores[0])
   412  		ls01.AddStore(stores[1])
   413  
   414  		expCV := clusterversion.ClusterVersion{
   415  			Version: v1_0,
   416  		}
   417  		if cv, err := SynthesizeClusterVersionFromEngines(ctx, ls01.engines(), binV, minV); err != nil {
   418  			t.Fatal(err)
   419  		} else if !reflect.DeepEqual(cv, expCV) {
   420  			t.Fatalf("expected %+v, got %+v", expCV, cv)
   421  		}
   422  
   423  		// Write an updated Version to both stores.
   424  		cv := clusterversion.ClusterVersion{
   425  			Version: versionB,
   426  		}
   427  		if err := WriteClusterVersionToEngines(ctx, ls01.engines(), cv); err != nil {
   428  			t.Fatal(err)
   429  		}
   430  	}
   431  
   432  	// Third node comes along, for now it's alone. It has a lower use version.
   433  	cv := clusterversion.ClusterVersion{
   434  		Version: versionA,
   435  	}
   436  
   437  	{
   438  		ls3 := makeStores()
   439  		ls3.AddStore(stores[2])
   440  		if err := WriteClusterVersionToEngines(ctx, ls3.engines(), cv); err != nil {
   441  			t.Fatal(err)
   442  		}
   443  	}
   444  
   445  	ls012 := makeStores()
   446  	for _, store := range stores {
   447  		ls012.AddStore(store)
   448  	}
   449  
   450  	// Reading across all stores, we expect to pick up the lowest useVersion both
   451  	// from the third store.
   452  	expCV := clusterversion.ClusterVersion{
   453  		Version: versionA,
   454  	}
   455  	if cv, err := SynthesizeClusterVersionFromEngines(ctx, ls012.engines(), binV, minV); err != nil {
   456  		t.Fatal(err)
   457  	} else if !reflect.DeepEqual(cv, expCV) {
   458  		t.Fatalf("expected %+v, got %+v", expCV, cv)
   459  	}
   460  }
   461  
   462  // TestStoresClusterVersionIncompatible verifies an error occurs when
   463  // setting up the cluster version from stores that are incompatible with the
   464  // running binary.
   465  func TestStoresClusterVersionIncompatible(t *testing.T) {
   466  	defer leaktest.AfterTest(t)()
   467  
   468  	ctx := context.Background()
   469  
   470  	vOneDashOne := roachpb.Version{Major: 1, Unstable: 1}
   471  	vOne := roachpb.Version{Major: 1}
   472  
   473  	type testCase struct {
   474  		binV, minV roachpb.Version // binary version and min supported version
   475  		engV       roachpb.Version // version found on engine in test
   476  		expErr     string
   477  	}
   478  	for name, tc := range map[string]testCase{
   479  		"StoreTooNew": {
   480  			// This is what the node is running.
   481  			binV: vOneDashOne,
   482  			// This is what the running node requires from its stores.
   483  			minV: vOne,
   484  			// Version is way too high for this node.
   485  			engV:   roachpb.Version{Major: 9},
   486  			expErr: `cockroach version v1\.0-1 is incompatible with data in store <no-attributes>=<in-mem>; use version v9\.0 or later`,
   487  		},
   488  		"StoreTooOldVersion": {
   489  			// This is what the node is running.
   490  			binV: roachpb.Version{Major: 9},
   491  			// This is what the running node requires from its stores.
   492  			minV: roachpb.Version{Major: 5},
   493  			// Version is way too low.
   494  			engV:   roachpb.Version{Major: 4},
   495  			expErr: `store <no-attributes>=<in-mem>, last used with cockroach version v4\.0, is too old for running version v9\.0 \(which requires data from v5\.0 or later\)`,
   496  		},
   497  		"StoreTooOldMinVersion": {
   498  			// Like the previous test case, but this time cv.MinimumVersion is the culprit.
   499  			binV:   roachpb.Version{Major: 9},
   500  			minV:   roachpb.Version{Major: 5},
   501  			engV:   roachpb.Version{Major: 4},
   502  			expErr: `store <no-attributes>=<in-mem>, last used with cockroach version v4\.0, is too old for running version v9\.0 \(which requires data from v5\.0 or later\)`,
   503  		},
   504  	} {
   505  		t.Run(name, func(t *testing.T) {
   506  			engs := []storage.Engine{storage.NewDefaultInMem()}
   507  			defer engs[0].Close()
   508  			// Configure versions and write.
   509  			cv := clusterversion.ClusterVersion{Version: tc.engV}
   510  			if err := WriteClusterVersionToEngines(ctx, engs, cv); err != nil {
   511  				t.Fatal(err)
   512  			}
   513  			if cv, err := SynthesizeClusterVersionFromEngines(
   514  				ctx, engs, tc.binV, tc.minV,
   515  			); !testutils.IsError(err, tc.expErr) {
   516  				t.Fatalf("unexpected error: %+v, got version %v", err, cv)
   517  			}
   518  		})
   519  	}
   520  }