github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/log_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_test
    12  
    13  import (
    14  	"context"
    15  	gosql "database/sql"
    16  	"encoding/json"
    17  	"net/url"
    18  	"testing"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/base"
    21  	"github.com/cockroachdb/cockroach/pkg/keys"
    22  	"github.com/cockroachdb/cockroach/pkg/kv"
    23  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver"
    24  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb"
    25  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    26  	"github.com/cockroachdb/cockroach/pkg/security"
    27  	"github.com/cockroachdb/cockroach/pkg/server"
    28  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    29  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    30  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    31  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    32  	_ "github.com/lib/pq"
    33  )
    34  
    35  func TestLogSplits(t *testing.T) {
    36  	defer leaktest.AfterTest(t)()
    37  	s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
    38  	ts := s.(*server.TestServer)
    39  	ctx := context.Background()
    40  	defer s.Stopper().Stop(ctx)
    41  
    42  	countSplits := func() int {
    43  		var count int
    44  		err := db.QueryRowContext(ctx,
    45  			`SELECT count(*) FROM system.rangelog WHERE "eventType" = $1`,
    46  			kvserverpb.RangeLogEventType_split.String()).Scan(&count)
    47  		if err != nil {
    48  			t.Fatal(err)
    49  		}
    50  		return count
    51  	}
    52  
    53  	// Count the number of split events.
    54  	initialSplits := countSplits()
    55  
    56  	// Generate an explicit split event.
    57  	if err := kvDB.AdminSplit(ctx, "splitkey", "splitkey", hlc.MaxTimestamp /* expirationTime */); err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	// Verify that the count has increased by at least one. Realistically it's
    62  	// almost always by exactly one, but if there are any other splits they
    63  	// might race in after the previous call to countSplits().
    64  	if now := countSplits(); now <= initialSplits {
    65  		t.Fatalf("expected >= %d splits, found %d", initialSplits, now)
    66  	}
    67  
    68  	// verify that RangeID always increases (a good way to see that the splits
    69  	// are logged correctly)
    70  	rows, err := db.QueryContext(ctx,
    71  		`SELECT "rangeID", "otherRangeID", info FROM system.rangelog WHERE "eventType" = $1`,
    72  		kvserverpb.RangeLogEventType_split.String(),
    73  	)
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	for rows.Next() {
    78  		var rangeID int64
    79  		var otherRangeID gosql.NullInt64
    80  		var infoStr gosql.NullString
    81  		if err := rows.Scan(&rangeID, &otherRangeID, &infoStr); err != nil {
    82  			t.Fatal(err)
    83  		}
    84  
    85  		if !otherRangeID.Valid {
    86  			t.Errorf("otherRangeID not recorded for split of range %d", rangeID)
    87  		}
    88  		if otherRangeID.Int64 <= rangeID {
    89  			t.Errorf("otherRangeID %d is not greater than rangeID %d", otherRangeID.Int64, rangeID)
    90  		}
    91  		// Verify that info returns a json struct.
    92  		if !infoStr.Valid {
    93  			t.Errorf("info not recorded for split of range %d", rangeID)
    94  		}
    95  		var info kvserverpb.RangeLogEvent_Info
    96  		if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil {
    97  			t.Errorf("error unmarshalling info string for split of range %d: %+v", rangeID, err)
    98  			continue
    99  		}
   100  		if int64(info.UpdatedDesc.RangeID) != rangeID {
   101  			t.Errorf("recorded wrong updated descriptor %s for split of range %d", info.UpdatedDesc, rangeID)
   102  		}
   103  		if int64(info.NewDesc.RangeID) != otherRangeID.Int64 {
   104  			t.Errorf("recorded wrong new descriptor %s for split of range %d", info.NewDesc, rangeID)
   105  		}
   106  	}
   107  	if rows.Err() != nil {
   108  		t.Fatal(rows.Err())
   109  	}
   110  
   111  	store, pErr := ts.Stores().GetStore(ts.GetFirstStoreID())
   112  	if pErr != nil {
   113  		t.Fatal(pErr)
   114  	}
   115  	minSplits := int64(initialSplits + 1)
   116  	// Verify that the minimum number of splits has occurred. This is a min
   117  	// instead of an exact number, because the number of splits seems to vary
   118  	// between different runs of this test.
   119  	if a := store.Metrics().RangeSplits.Count(); a < minSplits {
   120  		t.Errorf("splits = %d < min %d", a, minSplits)
   121  	}
   122  
   123  	{
   124  		// Verify that the uniqueIDs have non-zero node IDs. The "& 0x7fff" is
   125  		// using internal knowledge of the structure of uniqueIDs that the node ID
   126  		// is embedded in the lower 15 bits. See #17560.
   127  		var count int
   128  		err := db.QueryRowContext(ctx,
   129  			`SELECT count(*) FROM system.rangelog WHERE ("uniqueID" & 0x7fff) = 0`).Scan(&count)
   130  		if err != nil {
   131  			t.Fatal(err)
   132  		}
   133  		if count != 0 {
   134  			t.Fatalf("found %d uniqueIDs with a zero node ID", count)
   135  		}
   136  	}
   137  }
   138  
   139  func TestLogMerges(t *testing.T) {
   140  	defer leaktest.AfterTest(t)()
   141  
   142  	ctx := context.Background()
   143  	s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{
   144  		Knobs: base.TestingKnobs{
   145  			Store: &kvserver.StoreTestingKnobs{
   146  				DisableMergeQueue: true,
   147  			},
   148  		},
   149  	})
   150  	defer s.Stopper().Stop(ctx)
   151  
   152  	ts := s.(*server.TestServer)
   153  	store, pErr := ts.Stores().GetStore(ts.GetFirstStoreID())
   154  	if pErr != nil {
   155  		t.Fatal(pErr)
   156  	}
   157  
   158  	countRangeLogMerges := func() int {
   159  		var count int
   160  		err := db.QueryRowContext(ctx,
   161  			`SELECT count(*) FROM system.rangelog WHERE "eventType" = $1`,
   162  			kvserverpb.RangeLogEventType_merge.String()).Scan(&count)
   163  		if err != nil {
   164  			t.Fatal(err)
   165  		}
   166  		return count
   167  	}
   168  
   169  	// No ranges should have merged immediately after startup.
   170  	if n := countRangeLogMerges(); n != 0 {
   171  		t.Fatalf("expected 0 initial merges, but got %d", n)
   172  	}
   173  	if n := store.Metrics().RangeMerges.Count(); n != 0 {
   174  		t.Errorf("expected 0 initial merges, but got %d", n)
   175  	}
   176  
   177  	// Create two ranges, then merge them.
   178  	if err := kvDB.AdminSplit(ctx, "a", "a", hlc.MaxTimestamp /* expirationTime */); err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	if err := kvDB.AdminSplit(ctx, "b", "b", hlc.MaxTimestamp /* expirationTime */); err != nil {
   182  		t.Fatal(err)
   183  	}
   184  	if err := kvDB.AdminMerge(ctx, "a"); err != nil {
   185  		t.Fatal(err)
   186  	}
   187  
   188  	if n := countRangeLogMerges(); n != 1 {
   189  		t.Fatalf("expected 1 merge, but got %d", n)
   190  	}
   191  	if n := store.Metrics().RangeMerges.Count(); n != 1 {
   192  		t.Errorf("expected 1 merge, but got %d", n)
   193  	}
   194  
   195  	rows, err := db.QueryContext(ctx,
   196  		`SELECT "rangeID", "otherRangeID", info FROM system.rangelog WHERE "eventType" = $1`,
   197  		kvserverpb.RangeLogEventType_merge.String(),
   198  	)
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  	for rows.Next() {
   203  		var rangeID int64
   204  		var otherRangeID gosql.NullInt64
   205  		var infoStr gosql.NullString
   206  		if err := rows.Scan(&rangeID, &otherRangeID, &infoStr); err != nil {
   207  			t.Fatal(err)
   208  		}
   209  
   210  		if !otherRangeID.Valid {
   211  			t.Errorf("otherRangeID not recorded for merge of range %d", rangeID)
   212  		}
   213  		if otherRangeID.Int64 <= rangeID {
   214  			t.Errorf("otherRangeID %d is not greater than rangeID %d", otherRangeID.Int64, rangeID)
   215  		}
   216  		if !infoStr.Valid {
   217  			t.Errorf("info not recorded for merge of range %d", rangeID)
   218  		}
   219  		var info kvserverpb.RangeLogEvent_Info
   220  		if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil {
   221  			t.Errorf("error unmarshalling info string for merge of range %d: %+v", rangeID, err)
   222  			continue
   223  		}
   224  		if int64(info.UpdatedDesc.RangeID) != rangeID {
   225  			t.Errorf("recorded wrong updated descriptor %s for merge of range %d", info.UpdatedDesc, rangeID)
   226  		}
   227  		if int64(info.RemovedDesc.RangeID) != otherRangeID.Int64 {
   228  			t.Errorf("recorded wrong new descriptor %s for merge of range %d", info.RemovedDesc, rangeID)
   229  		}
   230  	}
   231  	if rows.Err() != nil {
   232  		t.Fatal(rows.Err())
   233  	}
   234  }
   235  
   236  func TestLogRebalances(t *testing.T) {
   237  	defer leaktest.AfterTest(t)()
   238  	s, _, db := serverutils.StartServer(t, base.TestServerArgs{})
   239  	ctx := context.Background()
   240  	defer s.Stopper().Stop(ctx)
   241  
   242  	// Use a client to get the RangeDescriptor for the first range. We will use
   243  	// this range's information to log fake rebalance events.
   244  	desc := &roachpb.RangeDescriptor{}
   245  	if err := db.GetProto(ctx, keys.RangeDescriptorKey(roachpb.RKeyMin), desc); err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	// This code assumes that there is only one TestServer, and thus that
   250  	// StoreID 1 is present on the testserver. If this assumption changes in the
   251  	// future, *any* store will work, but a new method will need to be added to
   252  	// Stores (or a creative usage of VisitStores could suffice).
   253  	store, err := s.(*server.TestServer).Stores().GetStore(roachpb.StoreID(1))
   254  	if err != nil {
   255  		t.Fatal(err)
   256  	}
   257  
   258  	// Log several fake events using the store.
   259  	const details = "test"
   260  	logEvent := func(changeType roachpb.ReplicaChangeType, reason kvserverpb.RangeLogEventReason) {
   261  		if err := db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
   262  			return store.LogReplicaChangeTest(ctx, txn, changeType, desc.InternalReplicas[0], *desc, reason, details)
   263  		}); err != nil {
   264  			t.Fatal(err)
   265  		}
   266  	}
   267  	checkMetrics := func(expAdds, expRemoves int64) {
   268  		if a, e := store.Metrics().RangeAdds.Count(), expAdds; a != e {
   269  			t.Errorf("range adds %d != expected %d", a, e)
   270  		}
   271  		if a, e := store.Metrics().RangeRemoves.Count(), expRemoves; a != e {
   272  			t.Errorf("range removes %d != expected %d", a, e)
   273  		}
   274  	}
   275  	logEvent(roachpb.ADD_REPLICA, kvserverpb.ReasonRangeUnderReplicated)
   276  	checkMetrics(1 /*add*/, 0 /*remove*/)
   277  	logEvent(roachpb.ADD_REPLICA, kvserverpb.ReasonRangeUnderReplicated)
   278  	checkMetrics(2 /*adds*/, 0 /*remove*/)
   279  	logEvent(roachpb.REMOVE_REPLICA, kvserverpb.ReasonRangeOverReplicated)
   280  	checkMetrics(2 /*adds*/, 1 /*remove*/)
   281  
   282  	// Open a SQL connection to verify that the events have been logged.
   283  	pgURL, cleanupFn := sqlutils.PGUrl(t, s.ServingSQLAddr(), "TestLogRebalances", url.User(security.RootUser))
   284  	defer cleanupFn()
   285  
   286  	sqlDB, err := gosql.Open("postgres", pgURL.String())
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	defer sqlDB.Close()
   291  
   292  	// verify that two add replica events have been logged.
   293  	rows, err := sqlDB.QueryContext(ctx,
   294  		`SELECT "rangeID", info FROM system.rangelog WHERE "eventType" = $1`,
   295  		kvserverpb.RangeLogEventType_add.String(),
   296  	)
   297  	if err != nil {
   298  		t.Fatal(err)
   299  	}
   300  	var count int
   301  	for rows.Next() {
   302  		count++
   303  		var rangeID int64
   304  		var infoStr gosql.NullString
   305  		if err := rows.Scan(&rangeID, &infoStr); err != nil {
   306  			t.Fatal(err)
   307  		}
   308  
   309  		if a, e := roachpb.RangeID(rangeID), desc.RangeID; a != e {
   310  			t.Errorf("wrong rangeID %d recorded for add event, expected %d", a, e)
   311  		}
   312  		// Verify that info returns a json struct.
   313  		if !infoStr.Valid {
   314  			t.Errorf("info not recorded for add replica of range %d", rangeID)
   315  		}
   316  		var info kvserverpb.RangeLogEvent_Info
   317  		if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil {
   318  			t.Errorf("error unmarshalling info string for add replica %d: %+v", rangeID, err)
   319  			continue
   320  		}
   321  		if int64(info.UpdatedDesc.RangeID) != rangeID {
   322  			t.Errorf("recorded wrong updated descriptor %s for add replica of range %d", info.UpdatedDesc, rangeID)
   323  		}
   324  		if a, e := *info.AddedReplica, desc.InternalReplicas[0]; a != e {
   325  			t.Errorf("recorded wrong updated replica %s for add replica of range %d, expected %s",
   326  				a, rangeID, e)
   327  		}
   328  		if a, e := info.Reason, kvserverpb.ReasonRangeUnderReplicated; a != e {
   329  			t.Errorf("recorded wrong reason %s for add replica of range %d, expected %s",
   330  				a, rangeID, e)
   331  		}
   332  		if a, e := info.Details, details; a != e {
   333  			t.Errorf("recorded wrong details %s for add replica of range %d, expected %s",
   334  				a, rangeID, e)
   335  		}
   336  	}
   337  	if rows.Err() != nil {
   338  		t.Fatal(rows.Err())
   339  	}
   340  	if a, e := count, 2; a != e {
   341  		t.Errorf("expected %d AddReplica events logged, found %d", e, a)
   342  	}
   343  
   344  	// verify that one remove replica event was logged.
   345  	rows, err = sqlDB.QueryContext(ctx,
   346  		`SELECT "rangeID", info FROM system.rangelog WHERE "eventType" = $1`,
   347  		kvserverpb.RangeLogEventType_remove.String(),
   348  	)
   349  	if err != nil {
   350  		t.Fatal(err)
   351  	}
   352  	count = 0
   353  	for rows.Next() {
   354  		count++
   355  		var rangeID int64
   356  		var infoStr gosql.NullString
   357  		if err := rows.Scan(&rangeID, &infoStr); err != nil {
   358  			t.Fatal(err)
   359  		}
   360  
   361  		if a, e := roachpb.RangeID(rangeID), desc.RangeID; a != e {
   362  			t.Errorf("wrong rangeID %d recorded for remove event, expected %d", a, e)
   363  		}
   364  		// Verify that info returns a json struct.
   365  		if !infoStr.Valid {
   366  			t.Errorf("info not recorded for remove replica of range %d", rangeID)
   367  		}
   368  		var info kvserverpb.RangeLogEvent_Info
   369  		if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil {
   370  			t.Errorf("error unmarshalling info string for remove replica %d: %+v", rangeID, err)
   371  			continue
   372  		}
   373  		if int64(info.UpdatedDesc.RangeID) != rangeID {
   374  			t.Errorf("recorded wrong updated descriptor %s for remove replica of range %d", info.UpdatedDesc, rangeID)
   375  		}
   376  		if a, e := *info.RemovedReplica, desc.InternalReplicas[0]; a != e {
   377  			t.Errorf("recorded wrong updated replica %s for remove replica of range %d, expected %s",
   378  				a, rangeID, e)
   379  		}
   380  		if a, e := info.Reason, kvserverpb.ReasonRangeOverReplicated; a != e {
   381  			t.Errorf("recorded wrong reason %s for add replica of range %d, expected %s",
   382  				a, rangeID, e)
   383  		}
   384  		if a, e := info.Details, details; a != e {
   385  			t.Errorf("recorded wrong details %s for add replica of range %d, expected %s",
   386  				a, rangeID, e)
   387  		}
   388  	}
   389  	if rows.Err() != nil {
   390  		t.Fatal(rows.Err())
   391  	}
   392  	if a, e := count, 1; a != e {
   393  		t.Errorf("expected %d RemoveReplica events logged, found %d", e, a)
   394  	}
   395  }