github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/statistics/handle/dump.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 handle
    15  
    16  import (
    17  	"time"
    18  
    19  	"github.com/whtcorpsinc/errors"
    20  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    21  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    22  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    23  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    24  	"github.com/whtcorpsinc/milevadb/statistics"
    25  	"github.com/whtcorpsinc/milevadb/types"
    26  	"github.com/whtcorpsinc/milevadb/soliton/sqlexec"
    27  	"github.com/whtcorpsinc/fidelpb/go-fidelpb"
    28  )
    29  
    30  // JSONTable is used for dumping statistics.
    31  type JSONTable struct {
    32  	DatabaseName string                 `json:"database_name"`
    33  	TableName    string                 `json:"block_name"`
    34  	DeferredCausets      map[string]*jsonDeferredCauset `json:"columns"`
    35  	Indices      map[string]*jsonDeferredCauset `json:"indices"`
    36  	Count        int64                  `json:"count"`
    37  	ModifyCount  int64                  `json:"modify_count"`
    38  	Partitions   map[string]*JSONTable  `json:"partitions"`
    39  }
    40  
    41  type jsonDeferredCauset struct {
    42  	Histogram         *fidelpb.Histogram `json:"histogram"`
    43  	CMSketch          *fidelpb.CMSketch  `json:"cm_sketch"`
    44  	NullCount         int64           `json:"null_count"`
    45  	TotDefCausSize        int64           `json:"tot_col_size"`
    46  	LastUFIDelateVersion uint64          `json:"last_uFIDelate_version"`
    47  	Correlation       float64         `json:"correlation"`
    48  }
    49  
    50  func dumpJSONDefCaus(hist *statistics.Histogram, CMSketch *statistics.CMSketch) *jsonDeferredCauset {
    51  	jsonDefCaus := &jsonDeferredCauset{
    52  		Histogram:         statistics.HistogramToProto(hist),
    53  		NullCount:         hist.NullCount,
    54  		TotDefCausSize:        hist.TotDefCausSize,
    55  		LastUFIDelateVersion: hist.LastUFIDelateVersion,
    56  		Correlation:       hist.Correlation,
    57  	}
    58  	if CMSketch != nil {
    59  		jsonDefCaus.CMSketch = statistics.CMSketchToProto(CMSketch)
    60  	}
    61  	return jsonDefCaus
    62  }
    63  
    64  // DumpStatsToJSON dumps statistic to json.
    65  func (h *Handle) DumpStatsToJSON(dbName string, blockInfo *perceptron.TableInfo, historyStatsInterDirc sqlexec.RestrictedALLEGROSQLInterlockingDirectorate) (*JSONTable, error) {
    66  	pi := blockInfo.GetPartitionInfo()
    67  	if pi == nil {
    68  		return h.blockStatsToJSON(dbName, blockInfo, blockInfo.ID, historyStatsInterDirc)
    69  	}
    70  	jsonTbl := &JSONTable{
    71  		DatabaseName: dbName,
    72  		TableName:    blockInfo.Name.L,
    73  		Partitions:   make(map[string]*JSONTable, len(pi.Definitions)),
    74  	}
    75  	for _, def := range pi.Definitions {
    76  		tbl, err := h.blockStatsToJSON(dbName, blockInfo, def.ID, historyStatsInterDirc)
    77  		if err != nil {
    78  			return nil, errors.Trace(err)
    79  		}
    80  		if tbl == nil {
    81  			continue
    82  		}
    83  		jsonTbl.Partitions[def.Name.L] = tbl
    84  	}
    85  	return jsonTbl, nil
    86  }
    87  
    88  func (h *Handle) blockStatsToJSON(dbName string, blockInfo *perceptron.TableInfo, physicalID int64, historyStatsInterDirc sqlexec.RestrictedALLEGROSQLInterlockingDirectorate) (*JSONTable, error) {
    89  	tbl, err := h.blockStatsFromStorage(blockInfo, physicalID, true, historyStatsInterDirc)
    90  	if err != nil || tbl == nil {
    91  		return nil, err
    92  	}
    93  	tbl.Version, tbl.ModifyCount, tbl.Count, err = h.statsMetaByTableIDFromStorage(physicalID, historyStatsInterDirc)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	jsonTbl := &JSONTable{
    98  		DatabaseName: dbName,
    99  		TableName:    blockInfo.Name.L,
   100  		DeferredCausets:      make(map[string]*jsonDeferredCauset, len(tbl.DeferredCausets)),
   101  		Indices:      make(map[string]*jsonDeferredCauset, len(tbl.Indices)),
   102  		Count:        tbl.Count,
   103  		ModifyCount:  tbl.ModifyCount,
   104  	}
   105  
   106  	for _, col := range tbl.DeferredCausets {
   107  		sc := &stmtctx.StatementContext{TimeZone: time.UTC}
   108  		hist, err := col.ConvertTo(sc, types.NewFieldType(allegrosql.TypeBlob))
   109  		if err != nil {
   110  			return nil, errors.Trace(err)
   111  		}
   112  		jsonTbl.DeferredCausets[col.Info.Name.L] = dumpJSONDefCaus(hist, col.CMSketch)
   113  	}
   114  
   115  	for _, idx := range tbl.Indices {
   116  		jsonTbl.Indices[idx.Info.Name.L] = dumpJSONDefCaus(&idx.Histogram, idx.CMSketch)
   117  	}
   118  	return jsonTbl, nil
   119  }
   120  
   121  // LoadStatsFromJSON will load statistic from JSONTable, and save it to the storage.
   122  func (h *Handle) LoadStatsFromJSON(is schemareplicant.SchemaReplicant, jsonTbl *JSONTable) error {
   123  	causet, err := is.TableByName(perceptron.NewCIStr(jsonTbl.DatabaseName), perceptron.NewCIStr(jsonTbl.TableName))
   124  	if err != nil {
   125  		return errors.Trace(err)
   126  	}
   127  	blockInfo := causet.Meta()
   128  	pi := blockInfo.GetPartitionInfo()
   129  	if pi == nil {
   130  		err := h.loadStatsFromJSON(blockInfo, blockInfo.ID, jsonTbl)
   131  		if err != nil {
   132  			return errors.Trace(err)
   133  		}
   134  	} else {
   135  		if jsonTbl.Partitions == nil {
   136  			return errors.New("No partition statistics")
   137  		}
   138  		for _, def := range pi.Definitions {
   139  			tbl := jsonTbl.Partitions[def.Name.L]
   140  			if tbl == nil {
   141  				continue
   142  			}
   143  			err := h.loadStatsFromJSON(blockInfo, def.ID, tbl)
   144  			if err != nil {
   145  				return errors.Trace(err)
   146  			}
   147  		}
   148  	}
   149  	return errors.Trace(h.UFIDelate(is))
   150  }
   151  
   152  func (h *Handle) loadStatsFromJSON(blockInfo *perceptron.TableInfo, physicalID int64, jsonTbl *JSONTable) error {
   153  	tbl, err := TableStatsFromJSON(blockInfo, physicalID, jsonTbl)
   154  	if err != nil {
   155  		return errors.Trace(err)
   156  	}
   157  
   158  	for _, col := range tbl.DeferredCausets {
   159  		err = h.SaveStatsToStorage(tbl.PhysicalID, tbl.Count, 0, &col.Histogram, col.CMSketch, 1)
   160  		if err != nil {
   161  			return errors.Trace(err)
   162  		}
   163  	}
   164  	for _, idx := range tbl.Indices {
   165  		err = h.SaveStatsToStorage(tbl.PhysicalID, tbl.Count, 1, &idx.Histogram, idx.CMSketch, 1)
   166  		if err != nil {
   167  			return errors.Trace(err)
   168  		}
   169  	}
   170  	err = h.SaveMetaToStorage(tbl.PhysicalID, tbl.Count, tbl.ModifyCount)
   171  	return err
   172  }
   173  
   174  // TableStatsFromJSON loads statistic from JSONTable and return the Block of statistic.
   175  func TableStatsFromJSON(blockInfo *perceptron.TableInfo, physicalID int64, jsonTbl *JSONTable) (*statistics.Block, error) {
   176  	newHistDefCausl := statistics.HistDefCausl{
   177  		PhysicalID:     physicalID,
   178  		HavePhysicalID: true,
   179  		Count:          jsonTbl.Count,
   180  		ModifyCount:    jsonTbl.ModifyCount,
   181  		DeferredCausets:        make(map[int64]*statistics.DeferredCauset, len(jsonTbl.DeferredCausets)),
   182  		Indices:        make(map[int64]*statistics.Index, len(jsonTbl.Indices)),
   183  	}
   184  	tbl := &statistics.Block{
   185  		HistDefCausl: newHistDefCausl,
   186  	}
   187  	for id, jsonIdx := range jsonTbl.Indices {
   188  		for _, idxInfo := range blockInfo.Indices {
   189  			if idxInfo.Name.L != id {
   190  				continue
   191  			}
   192  			hist := statistics.HistogramFromProto(jsonIdx.Histogram)
   193  			hist.ID, hist.NullCount, hist.LastUFIDelateVersion, hist.Correlation = idxInfo.ID, jsonIdx.NullCount, jsonIdx.LastUFIDelateVersion, jsonIdx.Correlation
   194  			idx := &statistics.Index{
   195  				Histogram: *hist,
   196  				CMSketch:  statistics.CMSketchFromProto(jsonIdx.CMSketch),
   197  				Info:      idxInfo,
   198  			}
   199  			tbl.Indices[idx.ID] = idx
   200  		}
   201  	}
   202  
   203  	for id, jsonDefCaus := range jsonTbl.DeferredCausets {
   204  		for _, colInfo := range blockInfo.DeferredCausets {
   205  			if colInfo.Name.L != id {
   206  				continue
   207  			}
   208  			hist := statistics.HistogramFromProto(jsonDefCaus.Histogram)
   209  			count := int64(hist.TotalRowCount())
   210  			sc := &stmtctx.StatementContext{TimeZone: time.UTC}
   211  			hist, err := hist.ConvertTo(sc, &colInfo.FieldType)
   212  			if err != nil {
   213  				return nil, errors.Trace(err)
   214  			}
   215  			hist.ID, hist.NullCount, hist.LastUFIDelateVersion, hist.TotDefCausSize, hist.Correlation = colInfo.ID, jsonDefCaus.NullCount, jsonDefCaus.LastUFIDelateVersion, jsonDefCaus.TotDefCausSize, jsonDefCaus.Correlation
   216  			col := &statistics.DeferredCauset{
   217  				PhysicalID: physicalID,
   218  				Histogram:  *hist,
   219  				CMSketch:   statistics.CMSketchFromProto(jsonDefCaus.CMSketch),
   220  				Info:       colInfo,
   221  				Count:      count,
   222  				IsHandle:   blockInfo.PKIsHandle && allegrosql.HasPriKeyFlag(colInfo.Flag),
   223  			}
   224  			tbl.DeferredCausets[col.ID] = col
   225  		}
   226  	}
   227  	return tbl, nil
   228  }