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

     1  // Copyright 2015 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 rditer
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/spanset"
    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/hlc"
    25  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    26  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    27  )
    28  
    29  func fakePrevKey(k []byte) roachpb.Key {
    30  	const maxLen = 100
    31  	length := len(k)
    32  
    33  	// When the byte array is empty.
    34  	if length == 0 {
    35  		panic("cannot get the prev key of an empty key")
    36  	}
    37  	if length > maxLen {
    38  		panic(fmt.Sprintf("test does not support key longer than %d characters: %q", maxLen, k))
    39  	}
    40  
    41  	// If the last byte is a 0, then drop it.
    42  	if k[length-1] == 0 {
    43  		return k[0 : length-1]
    44  	}
    45  
    46  	// If the last byte isn't 0, subtract one from it and append "\xff"s
    47  	// until the end of the key space.
    48  	return bytes.Join([][]byte{
    49  		k[0 : length-1],
    50  		{k[length-1] - 1},
    51  		bytes.Repeat([]byte{0xff}, maxLen-length),
    52  	}, nil)
    53  }
    54  
    55  func uuidFromString(input string) uuid.UUID {
    56  	u, err := uuid.FromString(input)
    57  	if err != nil {
    58  		panic(err)
    59  	}
    60  	return u
    61  }
    62  
    63  // createRangeData creates sample range data in all possible areas of
    64  // the key space. Returns a slice of the encoded keys of all created
    65  // data.
    66  func createRangeData(
    67  	t *testing.T, eng storage.Engine, desc roachpb.RangeDescriptor,
    68  ) []storage.MVCCKey {
    69  	testTxnID := uuidFromString("0ce61c17-5eb4-4587-8c36-dcf4062ada4c")
    70  	testTxnID2 := uuidFromString("9855a1ef-8eb9-4c06-a106-cab1dda78a2b")
    71  
    72  	ts0 := hlc.Timestamp{}
    73  	ts := hlc.Timestamp{WallTime: 1}
    74  	keyTSs := []struct {
    75  		key roachpb.Key
    76  		ts  hlc.Timestamp
    77  	}{
    78  		{keys.AbortSpanKey(desc.RangeID, testTxnID), ts0},
    79  		{keys.AbortSpanKey(desc.RangeID, testTxnID2), ts0},
    80  		{keys.RangeLastGCKey(desc.RangeID), ts0},
    81  		{keys.RangeAppliedStateKey(desc.RangeID), ts0},
    82  		{keys.RaftAppliedIndexLegacyKey(desc.RangeID), ts0},
    83  		{keys.RaftTruncatedStateLegacyKey(desc.RangeID), ts0},
    84  		{keys.RangeLeaseKey(desc.RangeID), ts0},
    85  		{keys.LeaseAppliedIndexLegacyKey(desc.RangeID), ts0},
    86  		{keys.RangeStatsLegacyKey(desc.RangeID), ts0},
    87  		{keys.RangeTombstoneKey(desc.RangeID), ts0},
    88  		{keys.RaftHardStateKey(desc.RangeID), ts0},
    89  		{keys.RaftLogKey(desc.RangeID, 1), ts0},
    90  		{keys.RaftLogKey(desc.RangeID, 2), ts0},
    91  		{keys.RangeLastReplicaGCTimestampKey(desc.RangeID), ts0},
    92  		{keys.RangeDescriptorKey(desc.StartKey), ts},
    93  		{keys.TransactionKey(roachpb.Key(desc.StartKey), uuid.MakeV4()), ts0},
    94  		{keys.TransactionKey(roachpb.Key(desc.StartKey.Next()), uuid.MakeV4()), ts0},
    95  		{keys.TransactionKey(fakePrevKey(desc.EndKey), uuid.MakeV4()), ts0},
    96  		// TODO(bdarnell): KeyMin.Next() results in a key in the reserved system-local space.
    97  		// Once we have resolved https://github.com/cockroachdb/cockroach/issues/437,
    98  		// replace this with something that reliably generates the first valid key in the range.
    99  		//{r.Desc().StartKey.Next(), ts},
   100  		// The following line is similar to StartKey.Next() but adds more to the key to
   101  		// avoid falling into the system-local space.
   102  		{append(append([]byte{}, desc.StartKey...), '\x02'), ts},
   103  		{fakePrevKey(desc.EndKey), ts},
   104  	}
   105  
   106  	keys := []storage.MVCCKey{}
   107  	for _, keyTS := range keyTSs {
   108  		if err := storage.MVCCPut(context.Background(), eng, nil, keyTS.key, keyTS.ts, roachpb.MakeValueFromString("value"), nil); err != nil {
   109  			t.Fatal(err)
   110  		}
   111  		keys = append(keys, storage.MVCCKey{Key: keyTS.key, Timestamp: keyTS.ts})
   112  	}
   113  	return keys
   114  }
   115  
   116  func verifyRDIter(
   117  	t *testing.T,
   118  	desc *roachpb.RangeDescriptor,
   119  	readWriter storage.ReadWriter,
   120  	replicatedOnly bool,
   121  	expectedKeys []storage.MVCCKey,
   122  ) {
   123  	t.Helper()
   124  	verify := func(t *testing.T, useSpanSet, reverse bool) {
   125  		if useSpanSet {
   126  			var spans spanset.SpanSet
   127  			spans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{
   128  				Key:    keys.MakeRangeIDPrefix(desc.RangeID),
   129  				EndKey: keys.MakeRangeIDPrefix(desc.RangeID).PrefixEnd(),
   130  			})
   131  			spans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{
   132  				Key:    keys.MakeRangeKeyPrefix(desc.StartKey),
   133  				EndKey: keys.MakeRangeKeyPrefix(desc.EndKey),
   134  			})
   135  			spans.AddMVCC(spanset.SpanReadOnly, roachpb.Span{
   136  				Key:    desc.StartKey.AsRawKey(),
   137  				EndKey: desc.EndKey.AsRawKey(),
   138  			}, hlc.Timestamp{WallTime: 42})
   139  			readWriter = spanset.NewReadWriterAt(readWriter, &spans, hlc.Timestamp{WallTime: 42})
   140  		}
   141  		iter := NewReplicaDataIterator(desc, readWriter, replicatedOnly, reverse /* seekEnd */)
   142  		defer iter.Close()
   143  		i := 0
   144  		if reverse {
   145  			i = len(expectedKeys) - 1
   146  		}
   147  		for {
   148  			if ok, err := iter.Valid(); err != nil {
   149  				t.Fatal(err)
   150  			} else if !ok {
   151  				break
   152  			}
   153  			if !reverse && i >= len(expectedKeys) {
   154  				t.Fatal("there are more keys in the iteration than expected")
   155  			}
   156  			if reverse && i < 0 {
   157  				t.Fatal("there are more keys in the iteration than expected")
   158  			}
   159  			if key := iter.Key(); !key.Equal(expectedKeys[i]) {
   160  				k1, ts1 := key.Key, key.Timestamp
   161  				k2, ts2 := expectedKeys[i].Key, expectedKeys[i].Timestamp
   162  				t.Errorf("%d: expected %q(%d); got %q(%d)", i, k2, ts2, k1, ts1)
   163  			}
   164  			if reverse {
   165  				i--
   166  				iter.Prev()
   167  			} else {
   168  				i++
   169  				iter.Next()
   170  			}
   171  		}
   172  		if (reverse && i >= 0) || (!reverse && i != len(expectedKeys)) {
   173  			t.Fatal("there are fewer keys in the iteration than expected")
   174  		}
   175  	}
   176  	testutils.RunTrueAndFalse(t, "reverse", func(t *testing.T, reverse bool) {
   177  		testutils.RunTrueAndFalse(t, "spanset", func(t *testing.T, useSpanSet bool) {
   178  			verify(t, useSpanSet, reverse)
   179  		})
   180  	})
   181  }
   182  
   183  // TestReplicaDataIterator verifies correct operation of iterator if
   184  // a range contains no data and never has.
   185  func TestReplicaDataIteratorEmptyRange(t *testing.T) {
   186  	defer leaktest.AfterTest(t)()
   187  
   188  	eng := storage.NewDefaultInMem()
   189  	defer eng.Close()
   190  
   191  	desc := &roachpb.RangeDescriptor{
   192  		RangeID:  12345,
   193  		StartKey: roachpb.RKey("a"),
   194  		EndKey:   roachpb.RKey("z"),
   195  	}
   196  
   197  	verifyRDIter(t, desc, eng, false /* replicatedOnly */, []storage.MVCCKey{})
   198  }
   199  
   200  // TestReplicaDataIterator creates three ranges {"a"-"b" (pre), "b"-"c"
   201  // (main test range), "c"-"d" (post)} and fills each with data. It
   202  // first verifies the contents of the "b"-"c" range. Next, it makes sure
   203  // a replicated-only iterator does not show any unreplicated keys from
   204  // the range. Then, it deletes the range and verifies it's empty. Finally,
   205  // it verifies the pre and post ranges still contain the expected data.
   206  func TestReplicaDataIterator(t *testing.T) {
   207  	defer leaktest.AfterTest(t)()
   208  
   209  	eng := storage.NewDefaultInMem()
   210  	defer eng.Close()
   211  
   212  	descPre := roachpb.RangeDescriptor{
   213  		RangeID:  1,
   214  		StartKey: roachpb.RKeyMin,
   215  		EndKey:   roachpb.RKey("b"),
   216  	}
   217  	desc := roachpb.RangeDescriptor{
   218  		RangeID:  2,
   219  		StartKey: roachpb.RKey("b"),
   220  		EndKey:   roachpb.RKey("c"),
   221  	}
   222  	descPost := roachpb.RangeDescriptor{
   223  		RangeID:  3,
   224  		StartKey: roachpb.RKey("c"),
   225  		EndKey:   roachpb.RKeyMax,
   226  	}
   227  
   228  	// Create range data for all three ranges.
   229  	preKeys := createRangeData(t, eng, descPre)
   230  	curKeys := createRangeData(t, eng, desc)
   231  	postKeys := createRangeData(t, eng, descPost)
   232  
   233  	// Verify the contents of the "b"-"c" range.
   234  	t.Run("cur", func(t *testing.T) {
   235  		verifyRDIter(t, &desc, eng, false /* replicatedOnly */, curKeys)
   236  	})
   237  
   238  	// Verify that the replicated-only iterator ignores unreplicated keys.
   239  	unreplicatedPrefix := keys.MakeRangeIDUnreplicatedPrefix(desc.RangeID)
   240  	iter := NewReplicaDataIterator(&desc, eng,
   241  		true /* replicatedOnly */, false /* seekEnd */)
   242  	defer iter.Close()
   243  	for ; ; iter.Next() {
   244  		if ok, err := iter.Valid(); err != nil {
   245  			t.Fatal(err)
   246  		} else if !ok {
   247  			break
   248  		}
   249  		if bytes.HasPrefix(iter.Key().Key, unreplicatedPrefix) {
   250  			t.Fatalf("unexpected unreplicated key: %s", iter.Key().Key)
   251  		}
   252  	}
   253  
   254  	// Verify the keys in pre & post ranges.
   255  	for _, test := range []struct {
   256  		name string
   257  		desc *roachpb.RangeDescriptor
   258  		keys []storage.MVCCKey
   259  	}{
   260  		{"pre", &descPre, preKeys},
   261  		{"post", &descPost, postKeys},
   262  	} {
   263  		t.Run(test.name, func(t *testing.T) {
   264  			verifyRDIter(t, test.desc, eng, false /* replicatedOnly */, test.keys)
   265  		})
   266  	}
   267  }