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