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 }