vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/plan.go (about)

     1  /*
     2  Copyright 2022 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package engine
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"sync/atomic"
    23  	"time"
    24  
    25  	"vitess.io/vitess/go/vt/proto/query"
    26  	"vitess.io/vitess/go/vt/sqlparser"
    27  )
    28  
    29  // Plan represents the execution strategy for a given query.
    30  // For now it's a simple wrapper around the real instructions.
    31  // An instruction (aka Primitive) is typically a tree where
    32  // each node does its part by combining the results of the
    33  // sub-nodes.
    34  type Plan struct {
    35  	Type         sqlparser.StatementType // The type of query we have
    36  	Original     string                  // Original is the original query.
    37  	Instructions Primitive               // Instructions contains the instructions needed to fulfil the query.
    38  	BindVarNeeds *sqlparser.BindVarNeeds // Stores BindVars needed to be provided as part of expression rewriting
    39  	Warnings     []*query.QueryWarning   // Warnings that need to be yielded every time this query runs
    40  	TablesUsed   []string                // TablesUsed is the list of tables that this plan will query
    41  
    42  	ExecCount    uint64 // Count of times this plan was executed
    43  	ExecTime     uint64 // Total execution time
    44  	ShardQueries uint64 // Total number of shard queries
    45  	RowsReturned uint64 // Total number of rows
    46  	RowsAffected uint64 // Total number of rows
    47  	Errors       uint64 // Total number of errors
    48  }
    49  
    50  // AddStats updates the plan execution statistics
    51  func (p *Plan) AddStats(execCount uint64, execTime time.Duration, shardQueries, rowsAffected, rowsReturned, errors uint64) {
    52  	atomic.AddUint64(&p.ExecCount, execCount)
    53  	atomic.AddUint64(&p.ExecTime, uint64(execTime))
    54  	atomic.AddUint64(&p.ShardQueries, shardQueries)
    55  	atomic.AddUint64(&p.RowsAffected, rowsAffected)
    56  	atomic.AddUint64(&p.RowsReturned, rowsReturned)
    57  	atomic.AddUint64(&p.Errors, errors)
    58  }
    59  
    60  // Stats returns a copy of the plan execution statistics
    61  func (p *Plan) Stats() (execCount uint64, execTime time.Duration, shardQueries, rowsAffected, rowsReturned, errors uint64) {
    62  	execCount = atomic.LoadUint64(&p.ExecCount)
    63  	execTime = time.Duration(atomic.LoadUint64(&p.ExecTime))
    64  	shardQueries = atomic.LoadUint64(&p.ShardQueries)
    65  	rowsAffected = atomic.LoadUint64(&p.RowsAffected)
    66  	rowsReturned = atomic.LoadUint64(&p.RowsReturned)
    67  	errors = atomic.LoadUint64(&p.Errors)
    68  	return
    69  }
    70  
    71  // MarshalJSON serializes the plan into a JSON representation.
    72  func (p *Plan) MarshalJSON() ([]byte, error) {
    73  	var instructions *PrimitiveDescription
    74  	if p.Instructions != nil {
    75  		description := PrimitiveToPlanDescription(p.Instructions)
    76  		instructions = &description
    77  	}
    78  
    79  	marshalPlan := struct {
    80  		QueryType    string
    81  		Original     string                `json:",omitempty"`
    82  		Instructions *PrimitiveDescription `json:",omitempty"`
    83  		ExecCount    uint64                `json:",omitempty"`
    84  		ExecTime     time.Duration         `json:",omitempty"`
    85  		ShardQueries uint64                `json:",omitempty"`
    86  		RowsAffected uint64                `json:",omitempty"`
    87  		RowsReturned uint64                `json:",omitempty"`
    88  		Errors       uint64                `json:",omitempty"`
    89  		TablesUsed   []string              `json:",omitempty"`
    90  	}{
    91  		QueryType:    p.Type.String(),
    92  		Original:     p.Original,
    93  		Instructions: instructions,
    94  		ExecCount:    atomic.LoadUint64(&p.ExecCount),
    95  		ExecTime:     time.Duration(atomic.LoadUint64(&p.ExecTime)),
    96  		ShardQueries: atomic.LoadUint64(&p.ShardQueries),
    97  		RowsAffected: atomic.LoadUint64(&p.RowsAffected),
    98  		RowsReturned: atomic.LoadUint64(&p.RowsReturned),
    99  		Errors:       atomic.LoadUint64(&p.Errors),
   100  		TablesUsed:   p.TablesUsed,
   101  	}
   102  
   103  	b := new(bytes.Buffer)
   104  	enc := json.NewEncoder(b)
   105  	enc.SetEscapeHTML(false)
   106  	err := enc.Encode(marshalPlan)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	return b.Bytes(), nil
   112  }