github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvnemesis/operations.go (about)

     1  // Copyright 2020 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 kvnemesis
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"strings"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    19  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    20  	"github.com/cockroachdb/errors"
    21  )
    22  
    23  // Result returns the Result field of the given Operation.
    24  func (op Operation) Result() *Result {
    25  	switch o := op.GetValue().(type) {
    26  	case *GetOperation:
    27  		return &o.Result
    28  	case *PutOperation:
    29  		return &o.Result
    30  	case *SplitOperation:
    31  		return &o.Result
    32  	case *MergeOperation:
    33  		return &o.Result
    34  	case *BatchOperation:
    35  		return &o.Result
    36  	case *ClosureTxnOperation:
    37  		return &o.Result
    38  	default:
    39  		panic(errors.AssertionFailedf(`unknown operation: %T %v`, o, o))
    40  	}
    41  }
    42  
    43  type steps []Step
    44  
    45  func (s steps) After() hlc.Timestamp {
    46  	var ts hlc.Timestamp
    47  	for _, step := range s {
    48  		ts.Forward(step.After)
    49  	}
    50  	return ts
    51  }
    52  
    53  func (s Step) String() string {
    54  	var fctx formatCtx
    55  	var buf strings.Builder
    56  	s.format(&buf, fctx)
    57  	return buf.String()
    58  }
    59  
    60  type formatCtx struct {
    61  	receiver string
    62  	indent   string
    63  	// TODO(dan): error handling.
    64  }
    65  
    66  func (s Step) format(w *strings.Builder, fctx formatCtx) {
    67  	if fctx.receiver != `` {
    68  		panic(`cannot specify receiver in Step.format fctx`)
    69  	}
    70  	fctx.receiver = fmt.Sprintf(`db%d`, s.DBID)
    71  	w.WriteString("\n")
    72  	w.WriteString(fctx.indent)
    73  	s.Op.format(w, fctx)
    74  }
    75  
    76  func formatOps(w *strings.Builder, fctx formatCtx, ops []Operation) {
    77  	for _, op := range ops {
    78  		w.WriteString("\n")
    79  		w.WriteString(fctx.indent)
    80  		op.format(w, fctx)
    81  	}
    82  }
    83  
    84  func (op Operation) String() string {
    85  	fctx := formatCtx{receiver: `x`, indent: ``}
    86  	var buf strings.Builder
    87  	op.format(&buf, fctx)
    88  	return buf.String()
    89  }
    90  
    91  func (op Operation) format(w *strings.Builder, fctx formatCtx) {
    92  	switch o := op.GetValue().(type) {
    93  	case *GetOperation:
    94  		o.format(w, fctx)
    95  	case *PutOperation:
    96  		o.format(w, fctx)
    97  	case *SplitOperation:
    98  		o.format(w, fctx)
    99  	case *MergeOperation:
   100  		o.format(w, fctx)
   101  	case *ChangeReplicasOperation:
   102  		o.format(w, fctx)
   103  	case *BatchOperation:
   104  		newFctx := fctx
   105  		newFctx.indent = fctx.indent + `  `
   106  		newFctx.receiver = `b`
   107  		w.WriteString(`{`)
   108  		o.format(w, newFctx)
   109  		w.WriteString("\n")
   110  		w.WriteString(newFctx.indent)
   111  		w.WriteString(fctx.receiver)
   112  		w.WriteString(`.Run(ctx, b)`)
   113  		o.Result.format(w)
   114  		w.WriteString("\n")
   115  		w.WriteString(fctx.indent)
   116  		w.WriteString(`}`)
   117  	case *ClosureTxnOperation:
   118  		txnName := `txn` + o.TxnID
   119  		newFctx := fctx
   120  		newFctx.indent = fctx.indent + `  `
   121  		newFctx.receiver = txnName
   122  		w.WriteString(fctx.receiver)
   123  		fmt.Fprintf(w, `.Txn(ctx, func(ctx context.Context, %s *kv.Txn) error {`, txnName)
   124  		formatOps(w, newFctx, o.Ops)
   125  		if o.CommitInBatch != nil {
   126  			newFctx.receiver = `b`
   127  			o.CommitInBatch.format(w, newFctx)
   128  			newFctx.receiver = txnName
   129  			w.WriteString("\n")
   130  			w.WriteString(newFctx.indent)
   131  			w.WriteString(newFctx.receiver)
   132  			w.WriteString(`.CommitInBatch(ctx, b)`)
   133  			o.CommitInBatch.Result.format(w)
   134  		}
   135  		w.WriteString("\n")
   136  		w.WriteString(newFctx.indent)
   137  		switch o.Type {
   138  		case ClosureTxnType_Commit:
   139  			w.WriteString(`return nil`)
   140  		case ClosureTxnType_Rollback:
   141  			w.WriteString(`return errors.New("rollback")`)
   142  		default:
   143  			panic(errors.AssertionFailedf(`unknown closure txn type: %s`, o.Type))
   144  		}
   145  		w.WriteString("\n")
   146  		w.WriteString(fctx.indent)
   147  		w.WriteString(`})`)
   148  		o.Result.format(w)
   149  		if o.Txn != nil {
   150  			fmt.Fprintf(w, ` txnpb:(%s)`, o.Txn)
   151  		}
   152  	default:
   153  		fmt.Fprintf(w, "%v", op.GetValue())
   154  	}
   155  }
   156  
   157  func (op GetOperation) format(w *strings.Builder, fctx formatCtx) {
   158  	fmt.Fprintf(w, `%s.Get(ctx, %s)`, fctx.receiver, roachpb.Key(op.Key))
   159  	switch op.Result.Type {
   160  	case ResultType_Error:
   161  		err := errors.DecodeError(context.TODO(), *op.Result.Err)
   162  		fmt.Fprintf(w, ` // (nil, %s)`, err.Error())
   163  	case ResultType_Value:
   164  		v := `nil`
   165  		if len(op.Result.Value) > 0 {
   166  			value, err := roachpb.Value{RawBytes: op.Result.Value}.GetBytes()
   167  			if err != nil {
   168  				v = fmt.Sprintf(`<err:%s>`, err.Error())
   169  			} else {
   170  				v = `"` + string(value) + `"`
   171  			}
   172  		}
   173  		fmt.Fprintf(w, ` // (%s, nil)`, v)
   174  	}
   175  }
   176  
   177  func (op PutOperation) format(w *strings.Builder, fctx formatCtx) {
   178  	fmt.Fprintf(w, `%s.Put(ctx, %s, %s)`, fctx.receiver, roachpb.Key(op.Key), op.Value)
   179  	op.Result.format(w)
   180  }
   181  
   182  func (op SplitOperation) format(w *strings.Builder, fctx formatCtx) {
   183  	fmt.Fprintf(w, `%s.AdminSplit(ctx, %s)`, fctx.receiver, roachpb.Key(op.Key))
   184  	op.Result.format(w)
   185  }
   186  
   187  func (op MergeOperation) format(w *strings.Builder, fctx formatCtx) {
   188  	fmt.Fprintf(w, `%s.AdminMerge(ctx, %s)`, fctx.receiver, roachpb.Key(op.Key))
   189  	op.Result.format(w)
   190  }
   191  
   192  func (op BatchOperation) format(w *strings.Builder, fctx formatCtx) {
   193  	w.WriteString("\n")
   194  	w.WriteString(fctx.indent)
   195  	w.WriteString(`b := &Batch{}`)
   196  	formatOps(w, fctx, op.Ops)
   197  }
   198  
   199  func (op ChangeReplicasOperation) format(w *strings.Builder, fctx formatCtx) {
   200  	fmt.Fprintf(w, `%s.AdminChangeReplicas(ctx, %s, %s)`, fctx.receiver, roachpb.Key(op.Key), op.Changes)
   201  	op.Result.format(w)
   202  }
   203  
   204  func (r Result) format(w *strings.Builder) {
   205  	switch r.Type {
   206  	case ResultType_NoError:
   207  		fmt.Fprintf(w, ` // nil`)
   208  	case ResultType_Error:
   209  		err := errors.DecodeError(context.TODO(), *r.Err)
   210  		fmt.Fprintf(w, ` // %s`, err.Error())
   211  	}
   212  }