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 }