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

     1  // Copyright 2017 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  	"fmt"
    16  	"strings"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/abortspan"
    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/storage/enginepb"
    24  	"github.com/cockroachdb/cockroach/pkg/testutils"
    25  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    26  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    27  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestDeclareKeysResolveIntent(t *testing.T) {
    32  	defer leaktest.AfterTest(t)()
    33  
    34  	const id = "f90b99de-6bd2-48a3-873c-12fdb9867a3c"
    35  	txnMeta := enginepb.TxnMeta{}
    36  	{
    37  		var err error
    38  		txnMeta.ID, err = uuid.FromString(id)
    39  		if err != nil {
    40  			t.Fatal(err)
    41  		}
    42  	}
    43  	abortSpanKey := fmt.Sprintf(`write local: /Local/RangeID/99/r/AbortSpan/"%s"`, id)
    44  	desc := roachpb.RangeDescriptor{
    45  		RangeID:  99,
    46  		StartKey: roachpb.RKey("a"),
    47  		EndKey:   roachpb.RKey("a"),
    48  	}
    49  	tests := []struct {
    50  		status      roachpb.TransactionStatus
    51  		poison      bool
    52  		expDeclares bool
    53  	}{
    54  		{
    55  			status:      roachpb.ABORTED,
    56  			poison:      true,
    57  			expDeclares: true,
    58  		},
    59  		{
    60  			status:      roachpb.ABORTED,
    61  			poison:      false,
    62  			expDeclares: true,
    63  		},
    64  		{
    65  			status:      roachpb.COMMITTED,
    66  			poison:      true,
    67  			expDeclares: false,
    68  		},
    69  		{
    70  			status:      roachpb.COMMITTED,
    71  			poison:      false,
    72  			expDeclares: false,
    73  		},
    74  	}
    75  	ctx := context.Background()
    76  	engine := storage.NewDefaultInMem()
    77  	defer engine.Close()
    78  	testutils.RunTrueAndFalse(t, "ranged", func(t *testing.T, ranged bool) {
    79  		for _, test := range tests {
    80  			t.Run("", func(t *testing.T) {
    81  				ri := roachpb.ResolveIntentRequest{
    82  					IntentTxn: txnMeta,
    83  					Status:    test.status,
    84  					Poison:    test.poison,
    85  				}
    86  				ri.Key = roachpb.Key("b")
    87  				rir := roachpb.ResolveIntentRangeRequest{
    88  					IntentTxn: ri.IntentTxn,
    89  					Status:    ri.Status,
    90  					Poison:    ri.Poison,
    91  				}
    92  				rir.Key = ri.Key
    93  				rir.EndKey = roachpb.Key("c")
    94  
    95  				as := abortspan.New(desc.RangeID)
    96  
    97  				var latchSpans, lockSpans spanset.SpanSet
    98  				batch := engine.NewBatch()
    99  				batch = spanset.NewBatch(batch, &latchSpans)
   100  				defer batch.Close()
   101  
   102  				var h roachpb.Header
   103  				h.RangeID = desc.RangeID
   104  
   105  				cArgs := CommandArgs{Header: h}
   106  				cArgs.EvalCtx = (&MockEvalCtx{AbortSpan: as}).EvalContext()
   107  
   108  				if !ranged {
   109  					cArgs.Args = &ri
   110  					declareKeysResolveIntent(&desc, h, &ri, &latchSpans, &lockSpans)
   111  					if _, err := ResolveIntent(ctx, batch, cArgs, &roachpb.ResolveIntentResponse{}); err != nil {
   112  						t.Fatal(err)
   113  					}
   114  				} else {
   115  					cArgs.Args = &rir
   116  					declareKeysResolveIntentRange(&desc, h, &rir, &latchSpans, &lockSpans)
   117  					if _, err := ResolveIntentRange(ctx, batch, cArgs, &roachpb.ResolveIntentRangeResponse{}); err != nil {
   118  						t.Fatal(err)
   119  					}
   120  				}
   121  
   122  				if s := latchSpans.String(); strings.Contains(s, abortSpanKey) != test.expDeclares {
   123  					t.Errorf("expected AbortSpan declared: %t, but got spans\n%s", test.expDeclares, s)
   124  				}
   125  				if !lockSpans.Empty() {
   126  					t.Errorf("expected no lock spans declared, but got spans\n%s", lockSpans.String())
   127  				}
   128  			})
   129  		}
   130  	})
   131  }
   132  
   133  // TestResolveIntentAfterPartialRollback checks that the ResolveIntent
   134  // and ResolveIntentRange properly propagate their IgnoredSeqNums
   135  // parameter to the MVCC layer and only commit writes at non-ignored
   136  // seqnums.
   137  func TestResolveIntentAfterPartialRollback(t *testing.T) {
   138  	defer leaktest.AfterTest(t)()
   139  
   140  	ctx := context.Background()
   141  	k := roachpb.Key("a")
   142  	ts := hlc.Timestamp{WallTime: 1}
   143  	ts2 := hlc.Timestamp{WallTime: 2}
   144  	endKey := roachpb.Key("z")
   145  	txn := roachpb.MakeTransaction("test", k, 0, ts, 0)
   146  	desc := roachpb.RangeDescriptor{
   147  		RangeID:  99,
   148  		StartKey: roachpb.RKey(k),
   149  		EndKey:   roachpb.RKey(endKey),
   150  	}
   151  
   152  	testutils.RunTrueAndFalse(t, "ranged", func(t *testing.T, ranged bool) {
   153  		db := storage.NewDefaultInMem()
   154  		defer db.Close()
   155  		batch := db.NewBatch()
   156  		defer batch.Close()
   157  
   158  		var v roachpb.Value
   159  		// Write a first value at key.
   160  		v.SetString("a")
   161  		txn.Sequence = 0
   162  		if err := storage.MVCCPut(ctx, batch, nil, k, ts, v, &txn); err != nil {
   163  			t.Fatal(err)
   164  		}
   165  		// Write another value.
   166  		v.SetString("b")
   167  		txn.Sequence = 1
   168  		if err := storage.MVCCPut(ctx, batch, nil, k, ts, v, &txn); err != nil {
   169  			t.Fatal(err)
   170  		}
   171  		if err := batch.Commit(true); err != nil {
   172  			t.Fatal(err)
   173  		}
   174  
   175  		// Partially revert the 2nd store above.
   176  		ignoredSeqNums := []enginepb.IgnoredSeqNumRange{{Start: 1, End: 1}}
   177  
   178  		h := roachpb.Header{
   179  			RangeID:   desc.RangeID,
   180  			Timestamp: ts,
   181  		}
   182  
   183  		var spans spanset.SpanSet
   184  		rbatch := db.NewBatch()
   185  		rbatch = spanset.NewBatch(rbatch, &spans)
   186  		defer rbatch.Close()
   187  
   188  		if !ranged {
   189  			// Resolve a point intent.
   190  			ri := roachpb.ResolveIntentRequest{
   191  				IntentTxn:      txn.TxnMeta,
   192  				Status:         roachpb.COMMITTED,
   193  				IgnoredSeqNums: ignoredSeqNums,
   194  			}
   195  			ri.Key = k
   196  
   197  			declareKeysResolveIntent(&desc, h, &ri, &spans, nil)
   198  
   199  			if _, err := ResolveIntent(ctx, rbatch,
   200  				CommandArgs{
   201  					Header:  h,
   202  					EvalCtx: (&MockEvalCtx{}).EvalContext(),
   203  					Args:    &ri,
   204  				},
   205  				&roachpb.ResolveIntentResponse{},
   206  			); err != nil {
   207  				t.Fatal(err)
   208  			}
   209  		} else {
   210  			// Resolve an intent range.
   211  			rir := roachpb.ResolveIntentRangeRequest{
   212  				IntentTxn:      txn.TxnMeta,
   213  				Status:         roachpb.COMMITTED,
   214  				IgnoredSeqNums: ignoredSeqNums,
   215  			}
   216  			rir.Key = k
   217  			rir.EndKey = endKey
   218  
   219  			declareKeysResolveIntentRange(&desc, h, &rir, &spans, nil)
   220  
   221  			h.MaxSpanRequestKeys = 10
   222  			if _, err := ResolveIntentRange(ctx, rbatch,
   223  				CommandArgs{
   224  					Header:  h,
   225  					EvalCtx: (&MockEvalCtx{}).EvalContext(),
   226  					Args:    &rir,
   227  				},
   228  				&roachpb.ResolveIntentRangeResponse{},
   229  			); err != nil {
   230  				t.Fatal(err)
   231  			}
   232  		}
   233  
   234  		if err := rbatch.Commit(true); err != nil {
   235  			t.Fatal(err)
   236  		}
   237  
   238  		batch = db.NewBatch()
   239  		defer batch.Close()
   240  
   241  		// The second write has been rolled back; verify that the remaining
   242  		// value is from the first write.
   243  		res, i, err := storage.MVCCGet(ctx, batch, k, ts2, storage.MVCCGetOptions{})
   244  		if err != nil {
   245  			t.Fatal(err)
   246  		}
   247  		if i != nil {
   248  			t.Errorf("%s: found intent, expected none: %+v", k, i)
   249  		}
   250  		if res == nil {
   251  			t.Errorf("%s: no value found, expected one", k)
   252  		} else {
   253  			s, err := res.GetBytes()
   254  			if err != nil {
   255  				t.Fatal(err)
   256  			}
   257  			require.Equal(t, "a", string(s), "at key %s", k)
   258  		}
   259  	})
   260  }