github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_reverse_scan.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 "fmt" 16 17 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval/result" 18 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/lock" 19 "github.com/cockroachdb/cockroach/pkg/roachpb" 20 "github.com/cockroachdb/cockroach/pkg/storage" 21 ) 22 23 func init() { 24 RegisterReadOnlyCommand(roachpb.ReverseScan, DefaultDeclareIsolatedKeys, ReverseScan) 25 } 26 27 // ReverseScan scans the key range specified by start key through 28 // end key in descending order up to some maximum number of results. 29 // maxKeys stores the number of scan results remaining for this batch 30 // (MaxInt64 for no limit). 31 func ReverseScan( 32 ctx context.Context, reader storage.Reader, cArgs CommandArgs, resp roachpb.Response, 33 ) (result.Result, error) { 34 args := cArgs.Args.(*roachpb.ReverseScanRequest) 35 h := cArgs.Header 36 reply := resp.(*roachpb.ReverseScanResponse) 37 38 var res result.Result 39 var scanRes storage.MVCCScanResult 40 var err error 41 42 opts := storage.MVCCScanOptions{ 43 Inconsistent: h.ReadConsistency != roachpb.CONSISTENT, 44 Txn: h.Txn, 45 MaxKeys: h.MaxSpanRequestKeys, 46 TargetBytes: h.TargetBytes, 47 FailOnMoreRecent: args.KeyLocking != lock.None, 48 Reverse: true, 49 } 50 51 switch args.ScanFormat { 52 case roachpb.BATCH_RESPONSE: 53 scanRes, err = storage.MVCCScanToBytes( 54 ctx, reader, args.Key, args.EndKey, h.Timestamp, opts) 55 if err != nil { 56 return result.Result{}, err 57 } 58 reply.BatchResponses = scanRes.KVData 59 case roachpb.KEY_VALUES: 60 scanRes, err = storage.MVCCScan( 61 ctx, reader, args.Key, args.EndKey, h.Timestamp, opts) 62 if err != nil { 63 return result.Result{}, err 64 } 65 reply.Rows = scanRes.KVs 66 default: 67 panic(fmt.Sprintf("Unknown scanFormat %d", args.ScanFormat)) 68 } 69 70 reply.NumKeys = scanRes.NumKeys 71 reply.NumBytes = scanRes.NumBytes 72 73 if scanRes.ResumeSpan != nil { 74 reply.ResumeSpan = scanRes.ResumeSpan 75 reply.ResumeReason = roachpb.RESUME_KEY_LIMIT 76 } 77 78 if h.ReadConsistency == roachpb.READ_UNCOMMITTED { 79 // NOTE: MVCCScan doesn't use a Prefix iterator, so we don't want to use 80 // one in CollectIntentRows either so that we're guaranteed to use the 81 // same cached iterator and observe a consistent snapshot of the engine. 82 const usePrefixIter = false 83 reply.IntentRows, err = CollectIntentRows(ctx, reader, usePrefixIter, scanRes.Intents) 84 if err != nil { 85 return result.Result{}, err 86 } 87 } 88 89 if args.KeyLocking != lock.None && h.Txn != nil { 90 err = acquireUnreplicatedLocksOnKeys(&res, h.Txn, args.ScanFormat, &scanRes) 91 if err != nil { 92 return result.Result{}, err 93 } 94 } 95 res.Local.EncounteredIntents = scanRes.Intents 96 return res, nil 97 }