github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvclient/kvcoord/split_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 kvcoord
    12  
    13  import (
    14  	"context"
    15  	"math/rand"
    16  	"sync"
    17  	"sync/atomic"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/cockroachdb/cockroach/pkg/config"
    22  	"github.com/cockroachdb/cockroach/pkg/config/zonepb"
    23  	"github.com/cockroachdb/cockroach/pkg/keys"
    24  	"github.com/cockroachdb/cockroach/pkg/kv"
    25  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver"
    26  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    27  	"github.com/cockroachdb/cockroach/pkg/storage"
    28  	"github.com/cockroachdb/cockroach/pkg/testutils"
    29  	"github.com/cockroachdb/cockroach/pkg/testutils/localtestcluster"
    30  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    31  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    32  	"github.com/cockroachdb/cockroach/pkg/util/log"
    33  	"github.com/cockroachdb/cockroach/pkg/util/randutil"
    34  	"github.com/cockroachdb/errors"
    35  	"github.com/gogo/protobuf/proto"
    36  )
    37  
    38  // startTestWriter creates a writer which initiates a sequence of
    39  // transactions, each which writes up to 10 times to random keys with
    40  // random values. If not nil, txnChannel is written to non-blockingly
    41  // every time a new transaction starts.
    42  func startTestWriter(
    43  	db *kv.DB,
    44  	i int64,
    45  	valBytes int32,
    46  	wg *sync.WaitGroup,
    47  	retries *int32,
    48  	txnChannel chan struct{},
    49  	done <-chan struct{},
    50  	t *testing.T,
    51  ) {
    52  	src := rand.New(rand.NewSource(i))
    53  	defer func() {
    54  		if wg != nil {
    55  			wg.Done()
    56  		}
    57  	}()
    58  
    59  	for j := 0; ; j++ {
    60  		select {
    61  		case <-done:
    62  			return
    63  		default:
    64  			first := true
    65  			err := db.Txn(context.Background(), func(ctx context.Context, txn *kv.Txn) error {
    66  				if first && txnChannel != nil {
    67  					select {
    68  					case txnChannel <- struct{}{}:
    69  					default:
    70  					}
    71  				} else if !first && retries != nil {
    72  					atomic.AddInt32(retries, 1)
    73  				}
    74  				first = false
    75  				for j := 0; j <= int(src.Int31n(10)); j++ {
    76  					key := randutil.RandBytes(src, 10)
    77  					val := randutil.RandBytes(src, int(src.Int31n(valBytes)))
    78  					if err := txn.Put(ctx, key, val); err != nil {
    79  						log.Infof(ctx, "experienced an error in routine %d: %s", i, err)
    80  						return err
    81  					}
    82  				}
    83  				return nil
    84  			})
    85  			if err != nil {
    86  				t.Error(err)
    87  			} else {
    88  				time.Sleep(1 * time.Millisecond)
    89  			}
    90  		}
    91  	}
    92  }
    93  
    94  // TestRangeSplitMeta executes various splits (including at meta addressing)
    95  // and checks that all created intents are resolved. This includes both intents
    96  // which are resolved synchronously with EndTxn and via RPC.
    97  func TestRangeSplitMeta(t *testing.T) {
    98  	defer leaktest.AfterTest(t)()
    99  	s := createTestDB(t)
   100  	defer s.Stop()
   101  
   102  	ctx := context.Background()
   103  
   104  	splitKeys := []roachpb.RKey{roachpb.RKey("G"), keys.RangeMetaKey(roachpb.RKey("F")),
   105  		keys.RangeMetaKey(roachpb.RKey("K")), keys.RangeMetaKey(roachpb.RKey("H"))}
   106  
   107  	// Execute the consecutive splits.
   108  	for _, splitRKey := range splitKeys {
   109  		splitKey := roachpb.Key(splitRKey)
   110  		log.Infof(ctx, "starting split at key %q...", splitKey)
   111  		if err := s.DB.AdminSplit(ctx, splitKey, splitKey, hlc.MaxTimestamp /* expirationTime */); err != nil {
   112  			t.Fatal(err)
   113  		}
   114  		log.Infof(ctx, "split at key %q complete", splitKey)
   115  	}
   116  
   117  	testutils.SucceedsSoon(t, func() error {
   118  		if _, err := storage.MVCCScan(ctx, s.Eng, keys.LocalMax, roachpb.KeyMax, hlc.MaxTimestamp, storage.MVCCScanOptions{}); err != nil {
   119  			return errors.Errorf("failed to verify no dangling intents: %s", err)
   120  		}
   121  		return nil
   122  	})
   123  }
   124  
   125  // TestRangeSplitsWithConcurrentTxns does 5 consecutive splits while
   126  // 10 concurrent goroutines are each running successive transactions
   127  // composed of a random mix of puts.
   128  func TestRangeSplitsWithConcurrentTxns(t *testing.T) {
   129  	defer leaktest.AfterTest(t)()
   130  	s := createTestDB(t)
   131  	defer s.Stop()
   132  
   133  	// This channel shuts the whole apparatus down.
   134  	done := make(chan struct{})
   135  	txnChannel := make(chan struct{}, 1000)
   136  
   137  	// Set five split keys, about evenly spaced along the range of random keys.
   138  	splitKeys := []roachpb.Key{roachpb.Key("G"), roachpb.Key("R"), roachpb.Key("a"), roachpb.Key("l"), roachpb.Key("s")}
   139  
   140  	// Start up the concurrent goroutines which run transactions.
   141  	const concurrency = 10
   142  	var retries int32
   143  	var wg sync.WaitGroup
   144  	wg.Add(concurrency)
   145  	for i := 0; i < concurrency; i++ {
   146  		go startTestWriter(s.DB, int64(i), 1<<7, &wg, &retries, txnChannel, done, t)
   147  	}
   148  
   149  	ctx := context.Background()
   150  	// Execute the consecutive splits.
   151  	for _, splitKey := range splitKeys {
   152  		// Allow txns to start before initiating split.
   153  		for i := 0; i < concurrency; i++ {
   154  			<-txnChannel
   155  		}
   156  		log.Infof(ctx, "starting split at key %q...", splitKey)
   157  		if pErr := s.DB.AdminSplit(context.Background(), splitKey, splitKey, hlc.MaxTimestamp /* expirationTime */); pErr != nil {
   158  			t.Error(pErr)
   159  		}
   160  		log.Infof(ctx, "split at key %q complete", splitKey)
   161  	}
   162  
   163  	close(done)
   164  	wg.Wait()
   165  
   166  	if retries != 0 {
   167  		t.Errorf("expected no retries splitting a range with concurrent writes, "+
   168  			"as range splits do not cause conflicts; got %d", retries)
   169  	}
   170  }
   171  
   172  // TestRangeSplitsWithWritePressure sets the zone config max bytes for
   173  // a range to 256K and writes data until there are five ranges.
   174  func TestRangeSplitsWithWritePressure(t *testing.T) {
   175  	defer leaktest.AfterTest(t)()
   176  	// Override default zone config.
   177  	cfg := zonepb.DefaultZoneConfigRef()
   178  	cfg.RangeMaxBytes = proto.Int64(1 << 18)
   179  
   180  	// Manually create the local test cluster so that the split queue
   181  	// is not disabled (LocalTestCluster disables it by default).
   182  	s := &localtestcluster.LocalTestCluster{
   183  		Cfg: kvserver.StoreConfig{
   184  			DefaultZoneConfig: cfg,
   185  		},
   186  		StoreTestingKnobs: &kvserver.StoreTestingKnobs{
   187  			DisableScanner: true,
   188  		},
   189  	}
   190  	s.Start(t, testutils.NewNodeTestBaseContext(), InitFactoryForLocalTestCluster)
   191  
   192  	// This is purely to silence log spam.
   193  	config.TestingSetupZoneConfigHook(s.Stopper)
   194  	defer s.Stop()
   195  
   196  	// Start test writer write about a 32K/key so there aren't too many
   197  	// writes necessary to split 5 ranges.
   198  	done := make(chan struct{})
   199  	var wg sync.WaitGroup
   200  	wg.Add(1)
   201  	go startTestWriter(s.DB, int64(0), 1<<15, &wg, nil, nil, done, t)
   202  
   203  	ctx := context.Background()
   204  
   205  	// Check that we split 5 times in allotted time.
   206  	testutils.SucceedsSoon(t, func() error {
   207  		// Scan the txn records.
   208  		rows, err := s.DB.Scan(ctx, keys.Meta2Prefix, keys.MetaMax, 0)
   209  		if err != nil {
   210  			return errors.Errorf("failed to scan meta2 keys: %s", err)
   211  		}
   212  		if lr := len(rows); lr < 5 {
   213  			return errors.Errorf("expected >= 5 scans; got %d", lr)
   214  		}
   215  		return nil
   216  	})
   217  	close(done)
   218  	wg.Wait()
   219  
   220  	// This write pressure test often causes splits while resolve
   221  	// intents are in flight, causing them to fail with range key
   222  	// mismatch errors. However, LocalSender should retry in these
   223  	// cases. Check here via MVCC scan that there are no dangling write
   224  	// intents. We do this using a SucceedsSoon construct to account
   225  	// for timing of finishing the test writer and a possibly-ongoing
   226  	// asynchronous split.
   227  	testutils.SucceedsSoon(t, func() error {
   228  		if _, err := storage.MVCCScan(ctx, s.Eng, keys.LocalMax, roachpb.KeyMax, hlc.MaxTimestamp, storage.MVCCScanOptions{}); err != nil {
   229  			return errors.Errorf("failed to verify no dangling intents: %s", err)
   230  		}
   231  		return nil
   232  	})
   233  }
   234  
   235  // TestRangeSplitsWithSameKeyTwice check that second range split
   236  // on the same splitKey succeeds.
   237  func TestRangeSplitsWithSameKeyTwice(t *testing.T) {
   238  	defer leaktest.AfterTest(t)()
   239  	s := createTestDBWithContextAndKnobs(t, kv.DefaultDBContext(), &kvserver.StoreTestingKnobs{
   240  		DisableScanner:    true,
   241  		DisableSplitQueue: true,
   242  		DisableMergeQueue: true,
   243  	})
   244  	defer s.Stop()
   245  
   246  	ctx := context.Background()
   247  
   248  	splitKey := roachpb.Key("aa")
   249  	log.Infof(ctx, "starting split at key %q...", splitKey)
   250  	if err := s.DB.AdminSplit(ctx, splitKey, splitKey, hlc.MaxTimestamp /* expirationTime */); err != nil {
   251  		t.Fatal(err)
   252  	}
   253  	log.Infof(ctx, "split at key %q first time complete", splitKey)
   254  	if err := s.DB.AdminSplit(ctx, splitKey, splitKey, hlc.MaxTimestamp /* expirationTime */); err != nil {
   255  		t.Fatal(err)
   256  	}
   257  }
   258  
   259  // TestSplitStickyBit checks that the sticky bit is set when performing a manual
   260  // split. There are two cases to consider:
   261  // 1. Range is split so sticky bit is updated on RHS.
   262  // 2. Range is already split and split key is the start key of a range, so update
   263  //    the sticky bit of that range, but no range is split.
   264  func TestRangeSplitsStickyBit(t *testing.T) {
   265  	defer leaktest.AfterTest(t)()
   266  	s := createTestDBWithContextAndKnobs(t, kv.DefaultDBContext(), &kvserver.StoreTestingKnobs{
   267  		DisableScanner:    true,
   268  		DisableSplitQueue: true,
   269  		DisableMergeQueue: true,
   270  	})
   271  	defer s.Stop()
   272  
   273  	ctx := context.Background()
   274  	splitKey := roachpb.RKey("aa")
   275  	descKey := keys.RangeDescriptorKey(splitKey)
   276  
   277  	// Splitting range.
   278  	if err := s.DB.AdminSplit(ctx, splitKey.AsRawKey(), splitKey.AsRawKey(), hlc.MaxTimestamp /* expirationTime */); err != nil {
   279  		t.Fatal(err)
   280  	}
   281  
   282  	// Checking sticky bit.
   283  	var desc roachpb.RangeDescriptor
   284  	err := s.DB.GetProto(ctx, descKey, &desc)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  	if (desc.GetStickyBit() == hlc.Timestamp{}) {
   289  		t.Fatal("Sticky bit not set after splitting")
   290  	}
   291  
   292  	// Removing sticky bit.
   293  	if err := s.DB.AdminUnsplit(ctx, splitKey.AsRawKey()); err != nil {
   294  		t.Fatal(err)
   295  	}
   296  
   297  	// Splitting range.
   298  	if err := s.DB.AdminSplit(ctx, splitKey.AsRawKey(), splitKey.AsRawKey(), hlc.MaxTimestamp /* expirationTime */); err != nil {
   299  		t.Fatal(err)
   300  	}
   301  
   302  	// Checking sticky bit.
   303  	err = s.DB.GetProto(ctx, descKey, &desc)
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  	if (desc.GetStickyBit() == hlc.Timestamp{}) {
   308  		t.Fatal("Sticky bit not set after splitting")
   309  	}
   310  }