github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_gc.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/batcheval/result" 18 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb" 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 ) 24 25 func init() { 26 RegisterReadWriteCommand(roachpb.GC, declareKeysGC, GC) 27 } 28 29 func declareKeysGC( 30 desc *roachpb.RangeDescriptor, 31 header roachpb.Header, 32 req roachpb.Request, 33 latchSpans, _ *spanset.SpanSet, 34 ) { 35 // Intentionally don't call DefaultDeclareKeys: the key range in the header 36 // is usually the whole range (pending resolution of #7880). 37 gcr := req.(*roachpb.GCRequest) 38 for _, key := range gcr.Keys { 39 if keys.IsLocal(key.Key) { 40 latchSpans.AddNonMVCC(spanset.SpanReadWrite, roachpb.Span{Key: key.Key}) 41 } else { 42 latchSpans.AddMVCC(spanset.SpanReadWrite, roachpb.Span{Key: key.Key}, header.Timestamp) 43 } 44 } 45 // Be smart here about blocking on the threshold keys. The GC queue can send an empty 46 // request first to bump the thresholds, and then another one that actually does work 47 // but can avoid declaring these keys below. 48 if gcr.Threshold != (hlc.Timestamp{}) { 49 latchSpans.AddNonMVCC(spanset.SpanReadWrite, roachpb.Span{Key: keys.RangeLastGCKey(header.RangeID)}) 50 } 51 latchSpans.AddNonMVCC(spanset.SpanReadOnly, roachpb.Span{Key: keys.RangeDescriptorKey(desc.StartKey)}) 52 } 53 54 // GC iterates through the list of keys to garbage collect 55 // specified in the arguments. MVCCGarbageCollect is invoked on each 56 // listed key along with the expiration timestamp. The GC metadata 57 // specified in the args is persisted after GC. 58 func GC( 59 ctx context.Context, readWriter storage.ReadWriter, cArgs CommandArgs, resp roachpb.Response, 60 ) (result.Result, error) { 61 args := cArgs.Args.(*roachpb.GCRequest) 62 h := cArgs.Header 63 64 // All keys must be inside the current replica range. Keys outside 65 // of this range in the GC request are dropped silently, which is 66 // safe because they can simply be re-collected later on the correct 67 // replica. Discrepancies here can arise from race conditions during 68 // range splitting. 69 keys := make([]roachpb.GCRequest_GCKey, 0, len(args.Keys)) 70 for _, k := range args.Keys { 71 if cArgs.EvalCtx.ContainsKey(k.Key) { 72 keys = append(keys, k) 73 } 74 } 75 76 // Garbage collect the specified keys by expiration timestamps. 77 if err := storage.MVCCGarbageCollect( 78 ctx, readWriter, cArgs.Stats, keys, h.Timestamp, 79 ); err != nil { 80 return result.Result{}, err 81 } 82 83 // Protect against multiple GC requests arriving out of order; we track 84 // the maximum timestamps. 85 86 var newThreshold hlc.Timestamp 87 if args.Threshold != (hlc.Timestamp{}) { 88 oldThreshold := cArgs.EvalCtx.GetGCThreshold() 89 newThreshold = oldThreshold 90 newThreshold.Forward(args.Threshold) 91 } 92 93 var pd result.Result 94 stateLoader := MakeStateLoader(cArgs.EvalCtx) 95 96 // Don't write these keys unless we have to. We also don't declare these 97 // keys unless we have to (to allow the GC queue to batch requests more 98 // efficiently), and we must honor what we declare. 99 100 var replState kvserverpb.ReplicaState 101 if newThreshold != (hlc.Timestamp{}) { 102 replState.GCThreshold = &newThreshold 103 if err := stateLoader.SetGCThreshold(ctx, readWriter, cArgs.Stats, &newThreshold); err != nil { 104 return result.Result{}, err 105 } 106 } 107 108 // Only set ReplicatedEvalResult.ReplicaState if at least one of the GC keys 109 // was written. Leaving the field nil to signify that no changes to the 110 // Replica state occurred allows replicas to perform less work beneath Raft. 111 if replState != (kvserverpb.ReplicaState{}) { 112 pd.Replicated.State = &replState 113 } 114 return pd, nil 115 }