github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_resolve_intent.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 batcheval 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/keys" 17 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval/result" 18 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/spanset" 19 "github.com/cockroachdb/cockroach/pkg/roachpb" 20 "github.com/cockroachdb/cockroach/pkg/storage" 21 "github.com/cockroachdb/cockroach/pkg/util/hlc" 22 "github.com/cockroachdb/cockroach/pkg/util/uuid" 23 ) 24 25 func init() { 26 RegisterReadWriteCommand(roachpb.ResolveIntent, declareKeysResolveIntent, ResolveIntent) 27 } 28 29 func declareKeysResolveIntentCombined( 30 header roachpb.Header, req roachpb.Request, latchSpans *spanset.SpanSet, 31 ) { 32 var status roachpb.TransactionStatus 33 var txnID uuid.UUID 34 var minTxnTS hlc.Timestamp 35 switch t := req.(type) { 36 case *roachpb.ResolveIntentRequest: 37 status = t.Status 38 txnID = t.IntentTxn.ID 39 minTxnTS = t.IntentTxn.MinTimestamp 40 case *roachpb.ResolveIntentRangeRequest: 41 status = t.Status 42 txnID = t.IntentTxn.ID 43 minTxnTS = t.IntentTxn.MinTimestamp 44 } 45 latchSpans.AddMVCC(spanset.SpanReadWrite, req.Header().Span(), minTxnTS) 46 if status == roachpb.ABORTED { 47 // We don't always write to the abort span when resolving an ABORTED 48 // intent, but we can't tell whether we will or not ahead of time. 49 latchSpans.AddNonMVCC(spanset.SpanReadWrite, roachpb.Span{Key: keys.AbortSpanKey(header.RangeID, txnID)}) 50 } 51 } 52 53 func declareKeysResolveIntent( 54 _ *roachpb.RangeDescriptor, 55 header roachpb.Header, 56 req roachpb.Request, 57 latchSpans, _ *spanset.SpanSet, 58 ) { 59 declareKeysResolveIntentCombined(header, req, latchSpans) 60 } 61 62 func resolveToMetricType(status roachpb.TransactionStatus, poison bool) *result.Metrics { 63 var typ result.Metrics 64 if status == roachpb.ABORTED { 65 if poison { 66 typ.ResolvePoison = 1 67 } else { 68 typ.ResolveAbort = 1 69 } 70 } else { 71 typ.ResolveCommit = 1 72 } 73 return &typ 74 } 75 76 // ResolveIntent resolves a write intent from the specified key 77 // according to the status of the transaction which created it. 78 func ResolveIntent( 79 ctx context.Context, readWriter storage.ReadWriter, cArgs CommandArgs, resp roachpb.Response, 80 ) (result.Result, error) { 81 args := cArgs.Args.(*roachpb.ResolveIntentRequest) 82 h := cArgs.Header 83 ms := cArgs.Stats 84 85 if h.Txn != nil { 86 return result.Result{}, ErrTransactionUnsupported 87 } 88 89 update := args.AsLockUpdate() 90 ok, err := storage.MVCCResolveWriteIntent(ctx, readWriter, ms, update) 91 if err != nil { 92 return result.Result{}, err 93 } 94 95 var res result.Result 96 res.Local.ResolvedLocks = []roachpb.LockUpdate{update} 97 res.Local.Metrics = resolveToMetricType(args.Status, args.Poison) 98 99 if WriteAbortSpanOnResolve(args.Status, args.Poison, ok) { 100 if err := UpdateAbortSpan(ctx, cArgs.EvalCtx, readWriter, ms, args.IntentTxn, args.Poison); err != nil { 101 return result.Result{}, err 102 } 103 } 104 return res, nil 105 }