github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/declare.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/spanset" 18 "github.com/cockroachdb/cockroach/pkg/roachpb" 19 "github.com/cockroachdb/cockroach/pkg/storage/enginepb" 20 ) 21 22 // DefaultDeclareKeys is the default implementation of Command.DeclareKeys. 23 func DefaultDeclareKeys( 24 _ *roachpb.RangeDescriptor, 25 header roachpb.Header, 26 req roachpb.Request, 27 latchSpans, _ *spanset.SpanSet, 28 ) { 29 access := spanset.SpanReadWrite 30 if roachpb.IsReadOnly(req) && !roachpb.IsLocking(req) { 31 access = spanset.SpanReadOnly 32 } 33 latchSpans.AddMVCC(access, req.Header().Span(), header.Timestamp) 34 } 35 36 // DefaultDeclareIsolatedKeys is similar to DefaultDeclareKeys, but it declares 37 // both lock spans in addition to latch spans. When used, commands will wait on 38 // locks and wait-queues owned by other transactions before evaluating. This 39 // ensures that the commands are fully isolated from conflicting transactions 40 // when it evaluated. 41 func DefaultDeclareIsolatedKeys( 42 _ *roachpb.RangeDescriptor, 43 header roachpb.Header, 44 req roachpb.Request, 45 latchSpans, lockSpans *spanset.SpanSet, 46 ) { 47 access := spanset.SpanReadWrite 48 timestamp := header.Timestamp 49 if roachpb.IsReadOnly(req) && !roachpb.IsLocking(req) { 50 access = spanset.SpanReadOnly 51 if header.Txn != nil { 52 // For transactional reads, acquire read latches all the way up to 53 // the transaction's MaxTimestamp, because reads may observe locks 54 // all the way up to this timestamp. 55 // 56 // TODO(nvanbenschoten): this parallels similar logic in 57 // concurrency.Request.readConflictTimestamp, which indicates that 58 // there is almost certainly a better way to structure this. There 59 // are actually two issues here that lead to this duplication: 60 // 61 // 1. latch spans and lock spans are declared separately. While these 62 // concepts are not identical, it appears that lock spans are always 63 // a subset of latch spans, which means that we can probably unify 64 // the concepts more closely than we have thus far. This would 65 // probably also have positive performance implications, as the 66 // duplication mandates extra memory allocations. 67 // 68 // 2. latch spans can each be assigned unique MVCC timestamps but lock 69 // spans inherit the timestamp of their request's transaction (see 70 // lockTable and concurrency.Request.{read,write}ConflictTimestamp). 71 // This difference is strange and confusing. It's not clear that the 72 // generality of latches each being declared at their own timestamp 73 // is useful. There may be an emergent pattern that arises here when 74 // we unify latch and lock spans (see part 1) where latches that are 75 // in the lock span subset can inherit their request's transaction's 76 // timestamp and latches that are not are non-MVCC latches. 77 // 78 // Note that addressing these issues does not necessarily need to 79 // lead to the timestamp that MVCC spans are interpretted at being 80 // the same for the purposes of the latch manager and lock-table. 81 // For instance, once the lock-table is segregated and all logic 82 // relating to "lock discovery" is removed, we no longer need to 83 // acquire read latches up to a txn's max timestamp, just to its 84 // read timestamp. However, we will still need to search the 85 // lock-table up to a txn's max timestamp. 86 timestamp.Forward(header.Txn.MaxTimestamp) 87 } 88 } 89 latchSpans.AddMVCC(access, req.Header().Span(), timestamp) 90 lockSpans.AddNonMVCC(access, req.Header().Span()) 91 } 92 93 // DeclareKeysForBatch adds all keys that the batch with the provided header 94 // touches to the given SpanSet. This does not include keys touched during the 95 // processing of the batch's individual commands. 96 func DeclareKeysForBatch( 97 desc *roachpb.RangeDescriptor, header roachpb.Header, latchSpans *spanset.SpanSet, 98 ) { 99 if header.Txn != nil { 100 header.Txn.AssertInitialized(context.TODO()) 101 latchSpans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{ 102 Key: keys.AbortSpanKey(header.RangeID, header.Txn.ID), 103 }) 104 } 105 if header.ReturnRangeInfo { 106 latchSpans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{Key: keys.RangeLeaseKey(header.RangeID)}) 107 latchSpans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{Key: keys.RangeDescriptorKey(desc.StartKey)}) 108 } 109 } 110 111 // CommandArgs contains all the arguments to a command. 112 // TODO(bdarnell): consider merging with kvserverbase.FilterArgs (which 113 // would probably require removing the EvalCtx field due to import order 114 // constraints). 115 type CommandArgs struct { 116 EvalCtx EvalContext 117 Header roachpb.Header 118 Args roachpb.Request 119 // *Stats should be mutated to reflect any writes made by the command. 120 Stats *enginepb.MVCCStats 121 }