github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/compiler.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package interlock
    15  
    16  import (
    17  	"context"
    18  
    19  	"github.com/opentracing/opentracing-go"
    20  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    21  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    22  	"github.com/whtcorpsinc/milevadb/causet"
    23  	causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded"
    24  	"github.com/whtcorpsinc/milevadb/config"
    25  	"github.com/whtcorpsinc/milevadb/metrics"
    26  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    27  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    28  )
    29  
    30  var (
    31  	stmtNodeCounterUse       = metrics.StmtNodeCounter.WithLabelValues("Use")
    32  	stmtNodeCounterShow      = metrics.StmtNodeCounter.WithLabelValues("Show")
    33  	stmtNodeCounterBegin     = metrics.StmtNodeCounter.WithLabelValues("Begin")
    34  	stmtNodeCounterCommit    = metrics.StmtNodeCounter.WithLabelValues("Commit")
    35  	stmtNodeCounterRollback  = metrics.StmtNodeCounter.WithLabelValues("Rollback")
    36  	stmtNodeCounterInsert    = metrics.StmtNodeCounter.WithLabelValues("Insert")
    37  	stmtNodeCounterReplace   = metrics.StmtNodeCounter.WithLabelValues("Replace")
    38  	stmtNodeCounterDelete    = metrics.StmtNodeCounter.WithLabelValues("Delete")
    39  	stmtNodeCounterUFIDelate = metrics.StmtNodeCounter.WithLabelValues("UFIDelate")
    40  	stmtNodeCounterSelect    = metrics.StmtNodeCounter.WithLabelValues("Select")
    41  )
    42  
    43  // Compiler compiles an ast.StmtNode to a physical plan.
    44  type Compiler struct {
    45  	Ctx stochastikctx.Context
    46  }
    47  
    48  // Compile compiles an ast.StmtNode to a physical plan.
    49  func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (*InterDircStmt, error) {
    50  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
    51  		span1 := span.Tracer().StartSpan("interlock.Compile", opentracing.ChildOf(span.Context()))
    52  		defer span1.Finish()
    53  		ctx = opentracing.ContextWithSpan(ctx, span1)
    54  	}
    55  
    56  	schemaReplicant := schemareplicant.GetSchemaReplicant(c.Ctx)
    57  	if err := causetembedded.Preprocess(c.Ctx, stmtNode, schemaReplicant); err != nil {
    58  		return nil, err
    59  	}
    60  	stmtNode = causetembedded.TryAddExtraLimit(c.Ctx, stmtNode)
    61  
    62  	finalCauset, names, err := causet.Optimize(ctx, c.Ctx, stmtNode, schemaReplicant)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	CountStmtNode(stmtNode, c.Ctx.GetStochastikVars().InRestrictedALLEGROSQL)
    68  	var lowerPriority bool
    69  	if c.Ctx.GetStochastikVars().StmtCtx.Priority == allegrosql.NoPriority {
    70  		lowerPriority = needLowerPriority(finalCauset)
    71  	}
    72  	return &InterDircStmt{
    73  		GoCtx:           ctx,
    74  		SchemaReplicant: schemaReplicant,
    75  		Causet:          finalCauset,
    76  		LowerPriority:   lowerPriority,
    77  		Text:            stmtNode.Text(),
    78  		StmtNode:        stmtNode,
    79  		Ctx:             c.Ctx,
    80  		OutputNames:     names,
    81  	}, nil
    82  }
    83  
    84  // needLowerPriority checks whether it's needed to lower the execution priority
    85  // of a query.
    86  // If the estimated output event count of any operator in the physical plan tree
    87  // is greater than the specific threshold, we'll set it to lowPriority when
    88  // sending it to the interlock.
    89  func needLowerPriority(p causetembedded.Causet) bool {
    90  	switch x := p.(type) {
    91  	case causetembedded.PhysicalCauset:
    92  		return isPhysicalCausetNeedLowerPriority(x)
    93  	case *causetembedded.InterDircute:
    94  		return needLowerPriority(x.Causet)
    95  	case *causetembedded.Insert:
    96  		if x.SelectCauset != nil {
    97  			return isPhysicalCausetNeedLowerPriority(x.SelectCauset)
    98  		}
    99  	case *causetembedded.Delete:
   100  		if x.SelectCauset != nil {
   101  			return isPhysicalCausetNeedLowerPriority(x.SelectCauset)
   102  		}
   103  	case *causetembedded.UFIDelate:
   104  		if x.SelectCauset != nil {
   105  			return isPhysicalCausetNeedLowerPriority(x.SelectCauset)
   106  		}
   107  	}
   108  	return false
   109  }
   110  
   111  func isPhysicalCausetNeedLowerPriority(p causetembedded.PhysicalCauset) bool {
   112  	expensiveThreshold := int64(config.GetGlobalConfig().Log.ExpensiveThreshold)
   113  	if int64(p.StatsCount()) > expensiveThreshold {
   114  		return true
   115  	}
   116  
   117  	for _, child := range p.Children() {
   118  		if isPhysicalCausetNeedLowerPriority(child) {
   119  			return true
   120  		}
   121  	}
   122  
   123  	return false
   124  }
   125  
   126  // CountStmtNode records the number of memexs with the same type.
   127  func CountStmtNode(stmtNode ast.StmtNode, inRestrictedALLEGROSQL bool) {
   128  	if inRestrictedALLEGROSQL {
   129  		return
   130  	}
   131  
   132  	typeLabel := GetStmtLabel(stmtNode)
   133  	switch typeLabel {
   134  	case "Use":
   135  		stmtNodeCounterUse.Inc()
   136  	case "Show":
   137  		stmtNodeCounterShow.Inc()
   138  	case "Begin":
   139  		stmtNodeCounterBegin.Inc()
   140  	case "Commit":
   141  		stmtNodeCounterCommit.Inc()
   142  	case "Rollback":
   143  		stmtNodeCounterRollback.Inc()
   144  	case "Insert":
   145  		stmtNodeCounterInsert.Inc()
   146  	case "Replace":
   147  		stmtNodeCounterReplace.Inc()
   148  	case "Delete":
   149  		stmtNodeCounterDelete.Inc()
   150  	case "UFIDelate":
   151  		stmtNodeCounterUFIDelate.Inc()
   152  	case "Select":
   153  		stmtNodeCounterSelect.Inc()
   154  	default:
   155  		metrics.StmtNodeCounter.WithLabelValues(typeLabel).Inc()
   156  	}
   157  
   158  	if !config.GetGlobalConfig().Status.RecordQPSbyDB {
   159  		return
   160  	}
   161  
   162  	dbLabels := getStmtDbLabel(stmtNode)
   163  	for dbLabel := range dbLabels {
   164  		metrics.DbStmtNodeCounter.WithLabelValues(dbLabel, typeLabel).Inc()
   165  	}
   166  }
   167  
   168  func getStmtDbLabel(stmtNode ast.StmtNode) map[string]struct{} {
   169  	dbLabelSet := make(map[string]struct{})
   170  
   171  	switch x := stmtNode.(type) {
   172  	case *ast.AlterBlockStmt:
   173  		dbLabel := x.Block.Schema.O
   174  		dbLabelSet[dbLabel] = struct{}{}
   175  	case *ast.CreateIndexStmt:
   176  		dbLabel := x.Block.Schema.O
   177  		dbLabelSet[dbLabel] = struct{}{}
   178  	case *ast.CreateBlockStmt:
   179  		dbLabel := x.Block.Schema.O
   180  		dbLabelSet[dbLabel] = struct{}{}
   181  	case *ast.InsertStmt:
   182  		dbLabels := getDbFromResultNode(x.Block.BlockRefs)
   183  		for _, EDB := range dbLabels {
   184  			dbLabelSet[EDB] = struct{}{}
   185  		}
   186  		dbLabels = getDbFromResultNode(x.Select)
   187  		for _, EDB := range dbLabels {
   188  			dbLabelSet[EDB] = struct{}{}
   189  		}
   190  	case *ast.DropIndexStmt:
   191  		dbLabel := x.Block.Schema.O
   192  		dbLabelSet[dbLabel] = struct{}{}
   193  	case *ast.DropBlockStmt:
   194  		blocks := x.Blocks
   195  		for _, causet := range blocks {
   196  			dbLabel := causet.Schema.O
   197  			if _, ok := dbLabelSet[dbLabel]; !ok {
   198  				dbLabelSet[dbLabel] = struct{}{}
   199  			}
   200  		}
   201  	case *ast.SelectStmt:
   202  		dbLabels := getDbFromResultNode(x)
   203  		for _, EDB := range dbLabels {
   204  			dbLabelSet[EDB] = struct{}{}
   205  		}
   206  	case *ast.UFIDelateStmt:
   207  		if x.BlockRefs != nil {
   208  			dbLabels := getDbFromResultNode(x.BlockRefs.BlockRefs)
   209  			for _, EDB := range dbLabels {
   210  				dbLabelSet[EDB] = struct{}{}
   211  			}
   212  		}
   213  	case *ast.DeleteStmt:
   214  		if x.BlockRefs != nil {
   215  			dbLabels := getDbFromResultNode(x.BlockRefs.BlockRefs)
   216  			for _, EDB := range dbLabels {
   217  				dbLabelSet[EDB] = struct{}{}
   218  			}
   219  		}
   220  	case *ast.CreateBindingStmt:
   221  		if x.OriginSel != nil {
   222  			originSelect := x.OriginSel.(*ast.SelectStmt)
   223  			dbLabels := getDbFromResultNode(originSelect.From.BlockRefs)
   224  			for _, EDB := range dbLabels {
   225  				dbLabelSet[EDB] = struct{}{}
   226  			}
   227  		}
   228  
   229  		if len(dbLabelSet) == 0 && x.HintedSel != nil {
   230  			hintedSelect := x.HintedSel.(*ast.SelectStmt)
   231  			dbLabels := getDbFromResultNode(hintedSelect.From.BlockRefs)
   232  			for _, EDB := range dbLabels {
   233  				dbLabelSet[EDB] = struct{}{}
   234  			}
   235  		}
   236  	}
   237  
   238  	return dbLabelSet
   239  }
   240  
   241  func getDbFromResultNode(resultNode ast.ResultSetNode) []string { //may have duplicate EDB name
   242  	var dbLabels []string
   243  
   244  	if resultNode == nil {
   245  		return dbLabels
   246  	}
   247  
   248  	switch x := resultNode.(type) {
   249  	case *ast.BlockSource:
   250  		return getDbFromResultNode(x.Source)
   251  	case *ast.SelectStmt:
   252  		if x.From != nil {
   253  			return getDbFromResultNode(x.From.BlockRefs)
   254  		}
   255  	case *ast.BlockName:
   256  		dbLabels = append(dbLabels, x.DBInfo.Name.O)
   257  	case *ast.Join:
   258  		if x.Left != nil {
   259  			dbs := getDbFromResultNode(x.Left)
   260  			if dbs != nil {
   261  				dbLabels = append(dbLabels, dbs...)
   262  			}
   263  		}
   264  
   265  		if x.Right != nil {
   266  			dbs := getDbFromResultNode(x.Right)
   267  			if dbs != nil {
   268  				dbLabels = append(dbLabels, dbs...)
   269  			}
   270  		}
   271  	}
   272  
   273  	return dbLabels
   274  }
   275  
   276  // GetStmtLabel generates a label for a memex.
   277  func GetStmtLabel(stmtNode ast.StmtNode) string {
   278  	switch x := stmtNode.(type) {
   279  	case *ast.AlterBlockStmt:
   280  		return "AlterBlock"
   281  	case *ast.AnalyzeBlockStmt:
   282  		return "AnalyzeBlock"
   283  	case *ast.BeginStmt:
   284  		return "Begin"
   285  	case *ast.ChangeStmt:
   286  		return "Change"
   287  	case *ast.CommitStmt:
   288  		return "Commit"
   289  	case *ast.CreateDatabaseStmt:
   290  		return "CreateDatabase"
   291  	case *ast.CreateIndexStmt:
   292  		return "CreateIndex"
   293  	case *ast.CreateBlockStmt:
   294  		return "CreateBlock"
   295  	case *ast.CreateViewStmt:
   296  		return "CreateView"
   297  	case *ast.CreateUserStmt:
   298  		return "CreateUser"
   299  	case *ast.DeleteStmt:
   300  		return "Delete"
   301  	case *ast.DroFIDelatabaseStmt:
   302  		return "DroFIDelatabase"
   303  	case *ast.DropIndexStmt:
   304  		return "DropIndex"
   305  	case *ast.DropBlockStmt:
   306  		return "DropBlock"
   307  	case *ast.ExplainStmt:
   308  		return "Explain"
   309  	case *ast.InsertStmt:
   310  		if x.IsReplace {
   311  			return "Replace"
   312  		}
   313  		return "Insert"
   314  	case *ast.LoadDataStmt:
   315  		return "LoadData"
   316  	case *ast.RollbackStmt:
   317  		return "RollBack"
   318  	case *ast.SelectStmt:
   319  		return "Select"
   320  	case *ast.SetStmt, *ast.SetPwdStmt:
   321  		return "Set"
   322  	case *ast.ShowStmt:
   323  		return "Show"
   324  	case *ast.TruncateBlockStmt:
   325  		return "TruncateBlock"
   326  	case *ast.UFIDelateStmt:
   327  		return "UFIDelate"
   328  	case *ast.GrantStmt:
   329  		return "Grant"
   330  	case *ast.RevokeStmt:
   331  		return "Revoke"
   332  	case *ast.DeallocateStmt:
   333  		return "Deallocate"
   334  	case *ast.InterDircuteStmt:
   335  		return "InterDircute"
   336  	case *ast.PrepareStmt:
   337  		return "Prepare"
   338  	case *ast.UseStmt:
   339  		return "Use"
   340  	case *ast.CreateBindingStmt:
   341  		return "CreateBinding"
   342  	case *ast.IndexAdviseStmt:
   343  		return "IndexAdvise"
   344  	}
   345  	return "other"
   346  }