github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/show_trace_replica.go (about) 1 // Copyright 2018 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 sql 12 13 import ( 14 "context" 15 "regexp" 16 "strconv" 17 "strings" 18 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 20 "github.com/cockroachdb/errors" 21 ) 22 23 // showTraceReplicaNode is a planNode that wraps another node and uses session 24 // tracing (via SHOW TRACE) to report the replicas of all kv events that occur 25 // during its execution. It is used as the top-level node for SHOW 26 // EXPERIMENTAL_REPLICA TRACE FOR statements. 27 // 28 // TODO(dan): This works by selecting trace lines matching certain event 29 // logs in command execution, which is possibly brittle. A much better 30 // system would be to set the `ReturnRangeInfo` flag on all kv requests and 31 // use the `RangeInfo`s that come back. Unfortunately, we wanted to get 32 // _some_ version of this into 2.0 for partitioning users, but the RangeInfo 33 // plumbing would have sunk the project. It's also possible that the 34 // sovereignty work may require the RangeInfo plumbing and we should revisit 35 // this then. 36 type showTraceReplicaNode struct { 37 optColumnsSlot 38 39 // plan is the wrapped execution plan that will be traced. 40 plan planNode 41 42 run struct { 43 values tree.Datums 44 } 45 } 46 47 func (n *showTraceReplicaNode) startExec(params runParams) error { 48 return nil 49 } 50 51 func (n *showTraceReplicaNode) Next(params runParams) (bool, error) { 52 var timestampD tree.Datum 53 var tag string 54 for { 55 ok, err := n.plan.Next(params) 56 if !ok || err != nil { 57 return ok, err 58 } 59 values := n.plan.Values() 60 // The rows are received from showTraceNode; see ShowTraceColumns. 61 const ( 62 tsCol = 0 63 msgCol = 2 64 tagCol = 3 65 ) 66 if replicaMsgRE.MatchString(string(*values[msgCol].(*tree.DString))) { 67 timestampD = values[tsCol] 68 tag = string(*values[tagCol].(*tree.DString)) 69 break 70 } 71 } 72 73 matches := nodeStoreRangeRE.FindStringSubmatch(tag) 74 if matches == nil { 75 return false, errors.Errorf(`could not extract node, store, range from: %s`, tag) 76 } 77 nodeID, err := strconv.Atoi(matches[1]) 78 if err != nil { 79 return false, err 80 } 81 storeID, err := strconv.Atoi(matches[2]) 82 if err != nil { 83 return false, err 84 } 85 rangeID, err := strconv.Atoi(matches[3]) 86 if err != nil { 87 return false, err 88 } 89 90 n.run.values = append( 91 n.run.values[:0], 92 timestampD, 93 tree.NewDInt(tree.DInt(nodeID)), 94 tree.NewDInt(tree.DInt(storeID)), 95 tree.NewDInt(tree.DInt(rangeID)), 96 ) 97 return true, nil 98 } 99 100 func (n *showTraceReplicaNode) Values() tree.Datums { 101 return n.run.values 102 } 103 104 func (n *showTraceReplicaNode) Close(ctx context.Context) { 105 n.plan.Close(ctx) 106 } 107 108 var nodeStoreRangeRE = regexp.MustCompile(`^\[n(\d+),s(\d+),r(\d+)/`) 109 110 var replicaMsgRE = regexp.MustCompile( 111 strings.Join([]string{ 112 "^read-write path$", 113 "^read-only path$", 114 "^admin path$", 115 }, "|"), 116 )