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

     1  // Copyright 2020 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 batcheval
    12  
    13  import (
    14  	"context"
    15  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    18  	"github.com/cockroachdb/cockroach/pkg/storage"
    19  	"github.com/cockroachdb/cockroach/pkg/testutils"
    20  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    21  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  // instrumentedEngine wraps a storage.Engine and allows for various methods in
    26  // the interface to be instrumented for testing purposes.
    27  type instrumentedEngine struct {
    28  	storage.Engine
    29  
    30  	onNewIterator func(storage.IterOptions)
    31  	// ... can be extended ...
    32  }
    33  
    34  func (ie *instrumentedEngine) NewIterator(opts storage.IterOptions) storage.Iterator {
    35  	if ie.onNewIterator != nil {
    36  		ie.onNewIterator(opts)
    37  	}
    38  	return ie.Engine.NewIterator(opts)
    39  }
    40  
    41  // TestCollectIntentsUsesSameIterator tests that all uses of CollectIntents
    42  // (currently only by READ_UNCOMMITTED Gets, Scans, and ReverseScans) use the
    43  // same cached iterator (prefix or non-prefix) for their initial read and their
    44  // provisional value collection for any intents they find.
    45  func TestCollectIntentsUsesSameIterator(t *testing.T) {
    46  	defer leaktest.AfterTest(t)()
    47  
    48  	ctx := context.Background()
    49  	key := roachpb.Key("key")
    50  	ts := hlc.Timestamp{WallTime: 123}
    51  	header := roachpb.Header{
    52  		Timestamp:       ts,
    53  		ReadConsistency: roachpb.READ_UNCOMMITTED,
    54  	}
    55  
    56  	testCases := []struct {
    57  		name              string
    58  		run               func(*testing.T, storage.ReadWriter) (intents []roachpb.KeyValue, _ error)
    59  		expPrefixIters    int
    60  		expNonPrefixIters int
    61  	}{
    62  		{
    63  			name: "get",
    64  			run: func(t *testing.T, db storage.ReadWriter) ([]roachpb.KeyValue, error) {
    65  				req := &roachpb.GetRequest{
    66  					RequestHeader: roachpb.RequestHeader{Key: key},
    67  				}
    68  				var resp roachpb.GetResponse
    69  				if _, err := Get(ctx, db, CommandArgs{Args: req, Header: header}, &resp); err != nil {
    70  					return nil, err
    71  				}
    72  				if resp.IntentValue == nil {
    73  					return nil, nil
    74  				}
    75  				return []roachpb.KeyValue{{Key: key, Value: *resp.IntentValue}}, nil
    76  			},
    77  			expPrefixIters:    2,
    78  			expNonPrefixIters: 0,
    79  		},
    80  		{
    81  			name: "scan",
    82  			run: func(t *testing.T, db storage.ReadWriter) ([]roachpb.KeyValue, error) {
    83  				req := &roachpb.ScanRequest{
    84  					RequestHeader: roachpb.RequestHeader{Key: key, EndKey: key.Next()},
    85  				}
    86  				var resp roachpb.ScanResponse
    87  				if _, err := Scan(ctx, db, CommandArgs{Args: req, Header: header}, &resp); err != nil {
    88  					return nil, err
    89  				}
    90  				return resp.IntentRows, nil
    91  			},
    92  			expPrefixIters:    0,
    93  			expNonPrefixIters: 2,
    94  		},
    95  		{
    96  			name: "reverse scan",
    97  			run: func(t *testing.T, db storage.ReadWriter) ([]roachpb.KeyValue, error) {
    98  				req := &roachpb.ReverseScanRequest{
    99  					RequestHeader: roachpb.RequestHeader{Key: key, EndKey: key.Next()},
   100  				}
   101  				var resp roachpb.ReverseScanResponse
   102  				if _, err := ReverseScan(ctx, db, CommandArgs{Args: req, Header: header}, &resp); err != nil {
   103  					return nil, err
   104  				}
   105  				return resp.IntentRows, nil
   106  			},
   107  			expPrefixIters:    0,
   108  			expNonPrefixIters: 2,
   109  		},
   110  	}
   111  	for _, c := range testCases {
   112  		t.Run(c.name, func(t *testing.T) {
   113  			// Test with and without deletion intents. If a READ_UNCOMMITTED request
   114  			// encounters an intent whose provisional value is a deletion tombstone,
   115  			// the request should ignore the intent and should not return any
   116  			// corresponding intent row.
   117  			testutils.RunTrueAndFalse(t, "deletion intent", func(t *testing.T, delete bool) {
   118  				db := &instrumentedEngine{Engine: storage.NewDefaultInMem()}
   119  				defer db.Close()
   120  
   121  				// Write an intent.
   122  				val := roachpb.MakeValueFromBytes([]byte("val"))
   123  				txn := roachpb.MakeTransaction("test", key, roachpb.NormalUserPriority, ts, 0)
   124  				var err error
   125  				if delete {
   126  					err = storage.MVCCDelete(ctx, db, nil, key, ts, &txn)
   127  				} else {
   128  					err = storage.MVCCPut(ctx, db, nil, key, ts, val, &txn)
   129  				}
   130  				require.NoError(t, err)
   131  
   132  				// Instrument iterator creation, count prefix vs. non-prefix iters.
   133  				var prefixIters, nonPrefixIters int
   134  				db.onNewIterator = func(opts storage.IterOptions) {
   135  					if opts.Prefix {
   136  						prefixIters++
   137  					} else {
   138  						nonPrefixIters++
   139  					}
   140  				}
   141  
   142  				intents, err := c.run(t, db)
   143  				require.NoError(t, err)
   144  
   145  				// Assert proper intent values.
   146  				if delete {
   147  					require.Len(t, intents, 0)
   148  				} else {
   149  					expIntentVal := val
   150  					expIntentVal.Timestamp = ts
   151  					expIntentKeyVal := roachpb.KeyValue{Key: key, Value: expIntentVal}
   152  					require.Len(t, intents, 1)
   153  					require.Equal(t, expIntentKeyVal, intents[0])
   154  				}
   155  
   156  				// Assert proper iterator use.
   157  				require.Equal(t, c.expPrefixIters, prefixIters)
   158  				require.Equal(t, c.expNonPrefixIters, nonPrefixIters)
   159  				require.Equal(t, c.expNonPrefixIters, nonPrefixIters)
   160  			})
   161  		})
   162  	}
   163  }