github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_query_txn.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  	"bytes"
    15  	"context"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/keys"
    18  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval/result"
    19  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/spanset"
    20  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    21  	"github.com/cockroachdb/cockroach/pkg/storage"
    22  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    23  	"github.com/cockroachdb/errors"
    24  )
    25  
    26  func init() {
    27  	RegisterReadOnlyCommand(roachpb.QueryTxn, declareKeysQueryTransaction, QueryTxn)
    28  }
    29  
    30  func declareKeysQueryTransaction(
    31  	_ *roachpb.RangeDescriptor,
    32  	header roachpb.Header,
    33  	req roachpb.Request,
    34  	latchSpans, _ *spanset.SpanSet,
    35  ) {
    36  	qr := req.(*roachpb.QueryTxnRequest)
    37  	latchSpans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{Key: keys.TransactionKey(qr.Txn.Key, qr.Txn.ID)})
    38  }
    39  
    40  // QueryTxn fetches the current state of a transaction.
    41  // This method is used to continually update the state of a txn
    42  // which is blocked waiting to resolve a conflicting intent. It
    43  // fetches the complete transaction record to determine whether
    44  // priority or status has changed and also fetches a list of
    45  // other txns which are waiting on this transaction in order
    46  // to find dependency cycles.
    47  func QueryTxn(
    48  	ctx context.Context, reader storage.Reader, cArgs CommandArgs, resp roachpb.Response,
    49  ) (result.Result, error) {
    50  	args := cArgs.Args.(*roachpb.QueryTxnRequest)
    51  	h := cArgs.Header
    52  	reply := resp.(*roachpb.QueryTxnResponse)
    53  
    54  	if h.Txn != nil {
    55  		return result.Result{}, ErrTransactionUnsupported
    56  	}
    57  	if h.Timestamp.Less(args.Txn.WriteTimestamp) {
    58  		// This condition must hold for the timestamp cache access to be safe.
    59  		return result.Result{}, errors.Errorf("request timestamp %s less than txn timestamp %s", h.Timestamp, args.Txn.WriteTimestamp)
    60  	}
    61  	if !bytes.Equal(args.Key, args.Txn.Key) {
    62  		return result.Result{}, errors.Errorf("request key %s does not match txn key %s", args.Key, args.Txn.Key)
    63  	}
    64  	key := keys.TransactionKey(args.Txn.Key, args.Txn.ID)
    65  
    66  	// Fetch transaction record; if missing, attempt to synthesize one.
    67  	if ok, err := storage.MVCCGetProto(
    68  		ctx, reader, key, hlc.Timestamp{}, &reply.QueriedTxn, storage.MVCCGetOptions{},
    69  	); err != nil {
    70  		return result.Result{}, err
    71  	} else if !ok {
    72  		// The transaction hasn't written a transaction record yet.
    73  		// Attempt to synthesize it from the provided TxnMeta.
    74  		reply.QueriedTxn = SynthesizeTxnFromMeta(cArgs.EvalCtx, args.Txn)
    75  	}
    76  
    77  	// Get the list of txns waiting on this txn.
    78  	reply.WaitingTxns = cArgs.EvalCtx.GetConcurrencyManager().GetDependents(args.Txn.ID)
    79  	return result.Result{}, nil
    80  }