github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_refresh_range.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 16 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval/result" 17 "github.com/cockroachdb/cockroach/pkg/roachpb" 18 "github.com/cockroachdb/cockroach/pkg/storage" 19 "github.com/cockroachdb/cockroach/pkg/util/log" 20 "github.com/cockroachdb/errors" 21 ) 22 23 func init() { 24 RegisterReadOnlyCommand(roachpb.RefreshRange, DefaultDeclareKeys, RefreshRange) 25 } 26 27 // RefreshRange checks whether the key range specified has any values written in 28 // the interval [args.RefreshFrom, header.Timestamp]. 29 func RefreshRange( 30 ctx context.Context, reader storage.Reader, cArgs CommandArgs, resp roachpb.Response, 31 ) (result.Result, error) { 32 args := cArgs.Args.(*roachpb.RefreshRangeRequest) 33 h := cArgs.Header 34 35 if h.Txn == nil { 36 return result.Result{}, errors.Errorf("no transaction specified to %s", args.Method()) 37 } 38 39 // We're going to refresh up to the transaction's read timestamp. 40 if h.Timestamp != h.Txn.WriteTimestamp { 41 // We're expecting the read and write timestamp to have converged before the 42 // Refresh request was sent. 43 log.Fatalf(ctx, "expected provisional commit ts %s == read ts %s. txn: %s", h.Timestamp, 44 h.Txn.WriteTimestamp, h.Txn) 45 } 46 refreshTo := h.Timestamp 47 48 refreshFrom := args.RefreshFrom 49 if refreshFrom.IsEmpty() { 50 // Compatibility with 19.2 nodes, which didn't set the args.RefreshFrom field. 51 refreshFrom = h.Txn.DeprecatedOrigTimestamp 52 } 53 54 // Iterate over values until we discover any value written at or after the 55 // original timestamp, but before or at the current timestamp. Note that we 56 // iterate inconsistently, meaning that intents - including our own - are 57 // collected separately and the callback is only invoked on the latest 58 // committed version. Note also that we include tombstones, which must be 59 // considered as updates on refresh. 60 log.VEventf(ctx, 2, "refresh %s @[%s-%s]", args.Span(), refreshFrom, refreshTo) 61 intents, err := storage.MVCCIterate( 62 ctx, reader, args.Key, args.EndKey, refreshTo, 63 storage.MVCCScanOptions{ 64 Inconsistent: true, 65 Tombstones: true, 66 }, 67 func(kv roachpb.KeyValue) (bool, error) { 68 if ts := kv.Value.Timestamp; refreshFrom.LessEq(ts) { 69 return true, errors.Errorf("encountered recently written key %s @%s", kv.Key, ts) 70 } 71 return false, nil 72 }) 73 if err != nil { 74 return result.Result{}, err 75 } 76 77 // Check if any intents which are not owned by this transaction were written 78 // at or beneath the refresh timestamp. 79 for _, i := range intents { 80 // Ignore our own intents. 81 if i.Txn.ID == h.Txn.ID { 82 continue 83 } 84 // Return an error if an intent was written to the span. 85 return result.Result{}, errors.Errorf("encountered recently written intent %s @%s", 86 i.Key, i.Txn.WriteTimestamp) 87 } 88 89 return result.Result{}, nil 90 }