github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_refresh.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.Refresh, DefaultDeclareKeys, Refresh) 25 } 26 27 // Refresh checks whether the key has any values written in the interval 28 // [args.RefreshFrom, header.Timestamp]. 29 func Refresh( 30 ctx context.Context, reader storage.Reader, cArgs CommandArgs, resp roachpb.Response, 31 ) (result.Result, error) { 32 args := cArgs.Args.(*roachpb.RefreshRequest) 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 // Get the most recent committed value and return any intent by 55 // specifying consistent=false. Note that we include tombstones, 56 // which must be considered as updates on refresh. 57 log.VEventf(ctx, 2, "refresh %s @[%s-%s]", args.Span(), refreshFrom, refreshTo) 58 val, intent, err := storage.MVCCGet(ctx, reader, args.Key, refreshTo, storage.MVCCGetOptions{ 59 Inconsistent: true, 60 Tombstones: true, 61 }) 62 63 if err != nil { 64 return result.Result{}, err 65 } else if val != nil { 66 if ts := val.Timestamp; refreshFrom.LessEq(ts) { 67 return result.Result{}, errors.Errorf("encountered recently written key %s @%s", args.Key, ts) 68 } 69 } 70 71 // Check if an intent which is not owned by this transaction was written 72 // at or beneath the refresh timestamp. 73 if intent != nil && intent.Txn.ID != h.Txn.ID { 74 return result.Result{}, errors.Errorf("encountered recently written intent %s @%s", 75 intent.Key, intent.Txn.WriteTimestamp) 76 } 77 78 return result.Result{}, nil 79 }