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  }