github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/schemareplicant/infoschema.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 schemareplicant
    15  
    16  import (
    17  	"fmt"
    18  	"sort"
    19  	"sync/atomic"
    20  
    21  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    22  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    23  	"github.com/whtcorpsinc/milevadb/causet"
    24  	"github.com/whtcorpsinc/milevadb/ekv"
    25  	"github.com/whtcorpsinc/milevadb/soliton"
    26  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    27  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    28  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    29  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    30  	"go.uber.org/zap"
    31  )
    32  
    33  // SchemaReplicant is the interface used to retrieve the schemaReplicant information.
    34  // It works as a in memory cache and doesn't handle any schemaReplicant change.
    35  // SchemaReplicant is read-only, and the returned value is a copy.
    36  // TODO: add more methods to retrieve blocks and defCausumns.
    37  type SchemaReplicant interface {
    38  	SchemaByName(schemaReplicant perceptron.CIStr) (*perceptron.DBInfo, bool)
    39  	SchemaExists(schemaReplicant perceptron.CIStr) bool
    40  	BlockByName(schemaReplicant, causet perceptron.CIStr) (causet.Block, error)
    41  	BlockExists(schemaReplicant, causet perceptron.CIStr) bool
    42  	SchemaByID(id int64) (*perceptron.DBInfo, bool)
    43  	SchemaByBlock(blockInfo *perceptron.BlockInfo) (*perceptron.DBInfo, bool)
    44  	BlockByID(id int64) (causet.Block, bool)
    45  	AllocByID(id int64) (autoid.SlabPredictors, bool)
    46  	AllSchemaNames() []string
    47  	AllSchemas() []*perceptron.DBInfo
    48  	Clone() (result []*perceptron.DBInfo)
    49  	SchemaBlocks(schemaReplicant perceptron.CIStr) []causet.Block
    50  	SchemaMetaVersion() int64
    51  	// BlockIsView indicates whether the schemaReplicant.causet is a view.
    52  	BlockIsView(schemaReplicant, causet perceptron.CIStr) bool
    53  	// BlockIsSequence indicates whether the schemaReplicant.causet is a sequence.
    54  	BlockIsSequence(schemaReplicant, causet perceptron.CIStr) bool
    55  	FindBlockByPartitionID(partitionID int64) (causet.Block, *perceptron.DBInfo)
    56  }
    57  
    58  type sortedBlocks []causet.Block
    59  
    60  func (s sortedBlocks) Len() int {
    61  	return len(s)
    62  }
    63  
    64  func (s sortedBlocks) Swap(i, j int) {
    65  	s[i], s[j] = s[j], s[i]
    66  }
    67  
    68  func (s sortedBlocks) Less(i, j int) bool {
    69  	return s[i].Meta().ID < s[j].Meta().ID
    70  }
    71  
    72  func (s sortedBlocks) searchBlock(id int64) int {
    73  	idx := sort.Search(len(s), func(i int) bool {
    74  		return s[i].Meta().ID >= id
    75  	})
    76  	if idx == len(s) || s[idx].Meta().ID != id {
    77  		return -1
    78  	}
    79  	return idx
    80  }
    81  
    82  type schemaBlocks struct {
    83  	dbInfo *perceptron.DBInfo
    84  	blocks map[string]causet.Block
    85  }
    86  
    87  const bucketCount = 512
    88  
    89  type schemaReplicant struct {
    90  	schemaMap map[string]*schemaBlocks
    91  
    92  	// sortedBlocksBuckets is a slice of sortedBlocks, a causet's bucket index is (blockID % bucketCount).
    93  	sortedBlocksBuckets []sortedBlocks
    94  
    95  	// schemaMetaVersion is the version of schemaReplicant, and we should check version when change schemaReplicant.
    96  	schemaMetaVersion int64
    97  }
    98  
    99  // MockSchemaReplicant only serves for test.
   100  func MockSchemaReplicant(tbList []*perceptron.BlockInfo) SchemaReplicant {
   101  	result := &schemaReplicant{}
   102  	result.schemaMap = make(map[string]*schemaBlocks)
   103  	result.sortedBlocksBuckets = make([]sortedBlocks, bucketCount)
   104  	dbInfo := &perceptron.DBInfo{ID: 0, Name: perceptron.NewCIStr("test"), Blocks: tbList}
   105  	blockNames := &schemaBlocks{
   106  		dbInfo: dbInfo,
   107  		blocks: make(map[string]causet.Block),
   108  	}
   109  	result.schemaMap["test"] = blockNames
   110  	for _, tb := range tbList {
   111  		tbl := causet.MockBlockFromMeta(tb)
   112  		blockNames.blocks[tb.Name.L] = tbl
   113  		bucketIdx := blockBucketIdx(tb.ID)
   114  		result.sortedBlocksBuckets[bucketIdx] = append(result.sortedBlocksBuckets[bucketIdx], tbl)
   115  	}
   116  	for i := range result.sortedBlocksBuckets {
   117  		sort.Sort(result.sortedBlocksBuckets[i])
   118  	}
   119  	return result
   120  }
   121  
   122  // MockSchemaReplicantWithSchemaVer only serves for test.
   123  func MockSchemaReplicantWithSchemaVer(tbList []*perceptron.BlockInfo, schemaVer int64) SchemaReplicant {
   124  	result := &schemaReplicant{}
   125  	result.schemaMap = make(map[string]*schemaBlocks)
   126  	result.sortedBlocksBuckets = make([]sortedBlocks, bucketCount)
   127  	dbInfo := &perceptron.DBInfo{ID: 0, Name: perceptron.NewCIStr("test"), Blocks: tbList}
   128  	blockNames := &schemaBlocks{
   129  		dbInfo: dbInfo,
   130  		blocks: make(map[string]causet.Block),
   131  	}
   132  	result.schemaMap["test"] = blockNames
   133  	for _, tb := range tbList {
   134  		tbl := causet.MockBlockFromMeta(tb)
   135  		blockNames.blocks[tb.Name.L] = tbl
   136  		bucketIdx := blockBucketIdx(tb.ID)
   137  		result.sortedBlocksBuckets[bucketIdx] = append(result.sortedBlocksBuckets[bucketIdx], tbl)
   138  	}
   139  	for i := range result.sortedBlocksBuckets {
   140  		sort.Sort(result.sortedBlocksBuckets[i])
   141  	}
   142  	result.schemaMetaVersion = schemaVer
   143  	return result
   144  }
   145  
   146  var _ SchemaReplicant = (*schemaReplicant)(nil)
   147  
   148  func (is *schemaReplicant) SchemaByName(schemaReplicant perceptron.CIStr) (val *perceptron.DBInfo, ok bool) {
   149  	blockNames, ok := is.schemaMap[schemaReplicant.L]
   150  	if !ok {
   151  		return
   152  	}
   153  	return blockNames.dbInfo, true
   154  }
   155  
   156  func (is *schemaReplicant) SchemaMetaVersion() int64 {
   157  	return is.schemaMetaVersion
   158  }
   159  
   160  func (is *schemaReplicant) SchemaExists(schemaReplicant perceptron.CIStr) bool {
   161  	_, ok := is.schemaMap[schemaReplicant.L]
   162  	return ok
   163  }
   164  
   165  func (is *schemaReplicant) BlockByName(schemaReplicant, causet perceptron.CIStr) (t causet.Block, err error) {
   166  	if tbNames, ok := is.schemaMap[schemaReplicant.L]; ok {
   167  		if t, ok = tbNames.blocks[causet.L]; ok {
   168  			return
   169  		}
   170  	}
   171  	return nil, ErrBlockNotExists.GenWithStackByArgs(schemaReplicant, causet)
   172  }
   173  
   174  func (is *schemaReplicant) BlockIsView(schemaReplicant, causet perceptron.CIStr) bool {
   175  	if tbNames, ok := is.schemaMap[schemaReplicant.L]; ok {
   176  		if t, ok := tbNames.blocks[causet.L]; ok {
   177  			return t.Meta().IsView()
   178  		}
   179  	}
   180  	return false
   181  }
   182  
   183  func (is *schemaReplicant) BlockIsSequence(schemaReplicant, causet perceptron.CIStr) bool {
   184  	if tbNames, ok := is.schemaMap[schemaReplicant.L]; ok {
   185  		if t, ok := tbNames.blocks[causet.L]; ok {
   186  			return t.Meta().IsSequence()
   187  		}
   188  	}
   189  	return false
   190  }
   191  
   192  func (is *schemaReplicant) BlockExists(schemaReplicant, causet perceptron.CIStr) bool {
   193  	if tbNames, ok := is.schemaMap[schemaReplicant.L]; ok {
   194  		if _, ok = tbNames.blocks[causet.L]; ok {
   195  			return true
   196  		}
   197  	}
   198  	return false
   199  }
   200  
   201  func (is *schemaReplicant) SchemaByID(id int64) (val *perceptron.DBInfo, ok bool) {
   202  	for _, v := range is.schemaMap {
   203  		if v.dbInfo.ID == id {
   204  			return v.dbInfo, true
   205  		}
   206  	}
   207  	return nil, false
   208  }
   209  
   210  func (is *schemaReplicant) SchemaByBlock(blockInfo *perceptron.BlockInfo) (val *perceptron.DBInfo, ok bool) {
   211  	if blockInfo == nil {
   212  		return nil, false
   213  	}
   214  	for _, v := range is.schemaMap {
   215  		if tbl, ok := v.blocks[blockInfo.Name.L]; ok {
   216  			if tbl.Meta().ID == blockInfo.ID {
   217  				return v.dbInfo, true
   218  			}
   219  		}
   220  	}
   221  	return nil, false
   222  }
   223  
   224  func (is *schemaReplicant) BlockByID(id int64) (val causet.Block, ok bool) {
   225  	slice := is.sortedBlocksBuckets[blockBucketIdx(id)]
   226  	idx := slice.searchBlock(id)
   227  	if idx == -1 {
   228  		return nil, false
   229  	}
   230  	return slice[idx], true
   231  }
   232  
   233  func (is *schemaReplicant) AllocByID(id int64) (autoid.SlabPredictors, bool) {
   234  	tbl, ok := is.BlockByID(id)
   235  	if !ok {
   236  		return nil, false
   237  	}
   238  	return tbl.SlabPredictors(nil), true
   239  }
   240  
   241  func (is *schemaReplicant) AllSchemaNames() (names []string) {
   242  	for _, v := range is.schemaMap {
   243  		names = append(names, v.dbInfo.Name.O)
   244  	}
   245  	return
   246  }
   247  
   248  func (is *schemaReplicant) AllSchemas() (schemas []*perceptron.DBInfo) {
   249  	for _, v := range is.schemaMap {
   250  		schemas = append(schemas, v.dbInfo)
   251  	}
   252  	return
   253  }
   254  
   255  func (is *schemaReplicant) SchemaBlocks(schemaReplicant perceptron.CIStr) (blocks []causet.Block) {
   256  	schemaBlocks, ok := is.schemaMap[schemaReplicant.L]
   257  	if !ok {
   258  		return
   259  	}
   260  	for _, tbl := range schemaBlocks.blocks {
   261  		blocks = append(blocks, tbl)
   262  	}
   263  	return
   264  }
   265  
   266  // FindBlockByPartitionID finds the partition-causet info by the partitionID.
   267  // FindBlockByPartitionID will traverse all the blocks to find the partitionID partition in which partition-causet.
   268  func (is *schemaReplicant) FindBlockByPartitionID(partitionID int64) (causet.Block, *perceptron.DBInfo) {
   269  	for _, v := range is.schemaMap {
   270  		for _, tbl := range v.blocks {
   271  			pi := tbl.Meta().GetPartitionInfo()
   272  			if pi == nil {
   273  				continue
   274  			}
   275  			for _, p := range pi.Definitions {
   276  				if p.ID == partitionID {
   277  					return tbl, v.dbInfo
   278  				}
   279  			}
   280  		}
   281  	}
   282  	return nil, nil
   283  }
   284  
   285  func (is *schemaReplicant) Clone() (result []*perceptron.DBInfo) {
   286  	for _, v := range is.schemaMap {
   287  		result = append(result, v.dbInfo.Clone())
   288  	}
   289  	return
   290  }
   291  
   292  // SequenceByName implements the interface of SequenceSchema defined in soliton package.
   293  // It could be used in memex package without import cycle problem.
   294  func (is *schemaReplicant) SequenceByName(schemaReplicant, sequence perceptron.CIStr) (soliton.SequenceBlock, error) {
   295  	tbl, err := is.BlockByName(schemaReplicant, sequence)
   296  	if err != nil {
   297  		return nil, err
   298  	}
   299  	if !tbl.Meta().IsSequence() {
   300  		return nil, ErrWrongObject.GenWithStackByArgs(schemaReplicant, sequence, "SEQUENCE")
   301  	}
   302  	return tbl.(soliton.SequenceBlock), nil
   303  }
   304  
   305  // Handle handles information schemaReplicant, including getting and setting.
   306  type Handle struct {
   307  	value       atomic.Value
   308  	causetstore ekv.CausetStorage
   309  }
   310  
   311  // NewHandle creates a new Handle.
   312  func NewHandle(causetstore ekv.CausetStorage) *Handle {
   313  	h := &Handle{
   314  		causetstore: causetstore,
   315  	}
   316  	return h
   317  }
   318  
   319  // Get gets information schemaReplicant from Handle.
   320  func (h *Handle) Get() SchemaReplicant {
   321  	v := h.value.Load()
   322  	schemaReplicant, _ := v.(SchemaReplicant)
   323  	return schemaReplicant
   324  }
   325  
   326  // IsValid uses to check whether handle value is valid.
   327  func (h *Handle) IsValid() bool {
   328  	return h.value.Load() != nil
   329  }
   330  
   331  // EmptyClone creates a new Handle with the same causetstore and memSchema, but the value is not set.
   332  func (h *Handle) EmptyClone() *Handle {
   333  	newHandle := &Handle{
   334  		causetstore: h.causetstore,
   335  	}
   336  	return newHandle
   337  }
   338  
   339  func init() {
   340  	// Initialize the information shema database and register the driver to `drivers`
   341  	dbID := autoid.InformationSchemaDBID
   342  	schemaReplicantBlocks := make([]*perceptron.BlockInfo, 0, len(blockNameToDeferredCausets))
   343  	for name, defcaus := range blockNameToDeferredCausets {
   344  		blockInfo := buildBlockMeta(name, defcaus)
   345  		schemaReplicantBlocks = append(schemaReplicantBlocks, blockInfo)
   346  		var ok bool
   347  		blockInfo.ID, ok = blockIDMap[blockInfo.Name.O]
   348  		if !ok {
   349  			panic(fmt.Sprintf("get information_schema causet id failed, unknown system causet `%v`", blockInfo.Name.O))
   350  		}
   351  		for i, c := range blockInfo.DeferredCausets {
   352  			c.ID = int64(i) + 1
   353  		}
   354  	}
   355  	schemaReplicantDB := &perceptron.DBInfo{
   356  		ID:          dbID,
   357  		Name:        soliton.InformationSchemaName,
   358  		Charset:     allegrosql.DefaultCharset,
   359  		DefCauslate: allegrosql.DefaultDefCauslationName,
   360  		Blocks:      schemaReplicantBlocks,
   361  	}
   362  	RegisterVirtualBlock(schemaReplicantDB, createSchemaReplicantBlock)
   363  }
   364  
   365  // HasAutoIncrementDeferredCauset checks whether the causet has auto_increment defCausumns, if so, return true and the defCausumn name.
   366  func HasAutoIncrementDeferredCauset(tbInfo *perceptron.BlockInfo) (bool, string) {
   367  	for _, defCaus := range tbInfo.DeferredCausets {
   368  		if allegrosql.HasAutoIncrementFlag(defCaus.Flag) {
   369  			return true, defCaus.Name.L
   370  		}
   371  	}
   372  	return false, ""
   373  }
   374  
   375  // GetSchemaReplicant gets TxnCtx SchemaReplicant if snapshot schemaReplicant is not set,
   376  // Otherwise, snapshot schemaReplicant is returned.
   377  func GetSchemaReplicant(ctx stochastikctx.Context) SchemaReplicant {
   378  	return GetSchemaReplicantByStochastikVars(ctx.GetStochastikVars())
   379  }
   380  
   381  // GetSchemaReplicantByStochastikVars gets TxnCtx SchemaReplicant if snapshot schemaReplicant is not set,
   382  // Otherwise, snapshot schemaReplicant is returned.
   383  func GetSchemaReplicantByStochastikVars(sessVar *variable.StochastikVars) SchemaReplicant {
   384  	var is SchemaReplicant
   385  	if snap := sessVar.SnapshotschemaReplicant; snap != nil {
   386  		is = snap.(SchemaReplicant)
   387  		logutil.BgLogger().Info("use snapshot schemaReplicant", zap.Uint64("conn", sessVar.ConnectionID), zap.Int64("schemaVersion", is.SchemaMetaVersion()))
   388  	} else {
   389  		is = sessVar.TxnCtx.SchemaReplicant.(SchemaReplicant)
   390  	}
   391  	return is
   392  }