github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/index_advise.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 "strings" 19 20 "github.com/whtcorpsinc/errors" 21 "github.com/whtcorpsinc/BerolinaSQL" 22 "github.com/whtcorpsinc/BerolinaSQL/ast" 23 "github.com/whtcorpsinc/milevadb/stochastikctx" 24 "github.com/whtcorpsinc/milevadb/soliton" 25 "github.com/whtcorpsinc/milevadb/soliton/chunk" 26 ) 27 28 // IndexAdviseInterDirc represents a index advise interlock. 29 type IndexAdviseInterDirc struct { 30 baseInterlockingDirectorate 31 32 IsLocal bool 33 indexAdviseInfo *IndexAdviseInfo 34 } 35 36 // Next implements the InterlockingDirectorate Next interface. 37 func (e *IndexAdviseInterDirc) Next(ctx context.Context, req *chunk.Chunk) error { 38 if !e.IsLocal { 39 return errors.New("Index Advise: don't support load file without local field") 40 } 41 if e.indexAdviseInfo.Path == "" { 42 return errors.New("Index Advise: infile path is empty") 43 } 44 if len(e.indexAdviseInfo.LinesInfo.Terminated) == 0 { 45 return errors.New("Index Advise: don't support advise index for ALLEGROALLEGROSQL terminated by nil") 46 } 47 48 if val := e.ctx.Value(IndexAdviseVarKey); val != nil { 49 e.ctx.SetValue(IndexAdviseVarKey, nil) 50 return errors.New("Index Advise: previous index advise option isn't closed normally") 51 } 52 e.ctx.SetValue(IndexAdviseVarKey, e.indexAdviseInfo) 53 return nil 54 } 55 56 // Close implements the InterlockingDirectorate Close interface. 57 func (e *IndexAdviseInterDirc) Close() error { 58 return nil 59 } 60 61 // Open implements the InterlockingDirectorate Open interface. 62 func (e *IndexAdviseInterDirc) Open(ctx context.Context) error { 63 return nil 64 } 65 66 // IndexAdviseInfo saves the information of index advise operation. 67 type IndexAdviseInfo struct { 68 Path string 69 MaxMinutes uint64 70 MaxIndexNum *ast.MaxIndexNumClause 71 LinesInfo *ast.LinesClause 72 Ctx stochastikctx.Context 73 StmtNodes [][]ast.StmtNode 74 Result *IndexAdvice 75 } 76 77 func (e *IndexAdviseInfo) getStmtNodes(data []byte) error { 78 str := string(data) 79 sqls := strings.Split(str, e.LinesInfo.Terminated) 80 81 j := 0 82 for i, allegrosql := range sqls { 83 if allegrosql != "\n" && allegrosql != "" && strings.HasPrefix(allegrosql, e.LinesInfo.Starting) { 84 sqls[j] = sqls[i] 85 j++ 86 } 87 } 88 sqls = sqls[:j] 89 90 sv := e.Ctx.GetStochastikVars() 91 e.StmtNodes = make([][]ast.StmtNode, len(sqls)) 92 sqlBerolinaSQL := BerolinaSQL.New() 93 for i, allegrosql := range sqls { 94 stmtNodes, warns, err := sqlBerolinaSQL.Parse(allegrosql, "", "") 95 if err != nil { 96 return err 97 } 98 for _, warn := range warns { 99 sv.StmtCtx.AppendWarning(soliton.SyntaxWarn(warn)) 100 } 101 curStmtNodes := make([]ast.StmtNode, len(stmtNodes)) 102 copy(curStmtNodes, stmtNodes) 103 e.StmtNodes[i] = curStmtNodes 104 } 105 return nil 106 } 107 108 func (e *IndexAdviseInfo) prepareInfo(data []byte) error { 109 if e.MaxMinutes == 0 { 110 return errors.New("Index Advise: the maximum execution time limit should be greater than 0") 111 } 112 if e.MaxIndexNum != nil { 113 if e.MaxIndexNum.PerBlock == 0 || e.MaxIndexNum.PerDB == 0 { 114 return errors.New("Index Advise: the maximum number of indexes should be greater than 0") 115 } 116 } 117 return e.getStmtNodes(data) 118 } 119 120 // GetIndexAdvice gets the index advice by workload file. 121 func (e *IndexAdviseInfo) GetIndexAdvice(ctx context.Context, data []byte) error { 122 if err := e.prepareInfo(data); err != nil { 123 return err 124 } 125 // TODO: Finish the index advise process. It will be done in another PR. 126 return nil 127 } 128 129 // IndexAdvice represents the index advice. 130 type IndexAdvice struct { 131 // TODO: Define index advice data structure and implements the ResultSet interface. It will be done in another PR 132 } 133 134 // IndexAdviseVarKeyType is a dummy type to avoid naming defCauslision in context. 135 type IndexAdviseVarKeyType int 136 137 // String defines a Stringer function for debugging and pretty printing. 138 func (k IndexAdviseVarKeyType) String() string { 139 return "index_advise_var" 140 } 141 142 // IndexAdviseVarKey is a variable key for index advise. 143 const IndexAdviseVarKey IndexAdviseVarKeyType = 0