github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/schemareplicant/metrics_schema.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  	"bytes"
    18  	"fmt"
    19  	"sort"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"github.com/whtcorpsinc/errors"
    24  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    25  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    26  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    27  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    28  	"github.com/whtcorpsinc/milevadb/causet"
    29  	"github.com/whtcorpsinc/milevadb/soliton"
    30  	"github.com/whtcorpsinc/milevadb/soliton/set"
    31  )
    32  
    33  const (
    34  	promQLQuantileKey       = "$QUANTILE"
    35  	promQLLabelConditionKey = "$LABEL_CONDITIONS"
    36  	promQRangeDurationKey   = "$RANGE_DURATION"
    37  )
    38  
    39  func init() {
    40  	// Initialize the metric schemaReplicant database and register the driver to `drivers`.
    41  	dbID := autoid.MetricSchemaDBID
    42  	blockID := dbID + 1
    43  	metricBlocks := make([]*perceptron.BlockInfo, 0, len(MetricBlockMap))
    44  	for name, def := range MetricBlockMap {
    45  		defcaus := def.genDeferredCausetInfos()
    46  		blockInfo := buildBlockMeta(name, defcaus)
    47  		blockInfo.ID = blockID
    48  		blockInfo.Comment = def.Comment
    49  		blockID++
    50  		metricBlocks = append(metricBlocks, blockInfo)
    51  	}
    52  	dbInfo := &perceptron.DBInfo{
    53  		ID:      dbID,
    54  		Name:    perceptron.NewCIStr(soliton.MetricSchemaName.O),
    55  		Charset: allegrosql.DefaultCharset,
    56  		DefCauslate: allegrosql.DefaultDefCauslationName,
    57  		Blocks:  metricBlocks,
    58  	}
    59  	RegisterVirtualBlock(dbInfo, blockFromMeta)
    60  }
    61  
    62  // MetricBlockDef is the metric causet define.
    63  type MetricBlockDef struct {
    64  	PromQL   string
    65  	Labels   []string
    66  	Quantile float64
    67  	Comment  string
    68  }
    69  
    70  // IsMetricBlock uses to checks whether the causet is a metric causet.
    71  func IsMetricBlock(lowerBlockName string) bool {
    72  	_, ok := MetricBlockMap[lowerBlockName]
    73  	return ok
    74  }
    75  
    76  // GetMetricBlockDef gets the metric causet define.
    77  func GetMetricBlockDef(lowerBlockName string) (*MetricBlockDef, error) {
    78  	def, ok := MetricBlockMap[lowerBlockName]
    79  	if !ok {
    80  		return nil, errors.Errorf("can not find metric causet: %v", lowerBlockName)
    81  	}
    82  	return &def, nil
    83  }
    84  
    85  func (def *MetricBlockDef) genDeferredCausetInfos() []defCausumnInfo {
    86  	defcaus := []defCausumnInfo{
    87  		{name: "time", tp: allegrosql.TypeDatetime, size: 19, deflt: "CURRENT_TIMESTAMP"},
    88  	}
    89  	for _, label := range def.Labels {
    90  		defcaus = append(defcaus, defCausumnInfo{name: label, tp: allegrosql.TypeVarchar, size: 512})
    91  	}
    92  	if def.Quantile > 0 {
    93  		defaultValue := strconv.FormatFloat(def.Quantile, 'f', -1, 64)
    94  		defcaus = append(defcaus, defCausumnInfo{name: "quantile", tp: allegrosql.TypeDouble, size: 22, deflt: defaultValue})
    95  	}
    96  	defcaus = append(defcaus, defCausumnInfo{name: "value", tp: allegrosql.TypeDouble, size: 22})
    97  	return defcaus
    98  }
    99  
   100  // GenPromQL generates the promQL.
   101  func (def *MetricBlockDef) GenPromQL(sctx stochastikctx.Context, labels map[string]set.StringSet, quantile float64) string {
   102  	promQL := def.PromQL
   103  	if strings.Contains(promQL, promQLQuantileKey) {
   104  		promQL = strings.Replace(promQL, promQLQuantileKey, strconv.FormatFloat(quantile, 'f', -1, 64), -1)
   105  	}
   106  
   107  	if strings.Contains(promQL, promQLLabelConditionKey) {
   108  		promQL = strings.Replace(promQL, promQLLabelConditionKey, def.genLabelCondition(labels), -1)
   109  	}
   110  
   111  	if strings.Contains(promQL, promQRangeDurationKey) {
   112  		promQL = strings.Replace(promQL, promQRangeDurationKey, strconv.FormatInt(sctx.GetStochastikVars().MetricSchemaRangeDuration, 10)+"s", -1)
   113  	}
   114  	return promQL
   115  }
   116  
   117  func (def *MetricBlockDef) genLabelCondition(labels map[string]set.StringSet) string {
   118  	var buf bytes.Buffer
   119  	index := 0
   120  	for _, label := range def.Labels {
   121  		values := labels[label]
   122  		if len(values) == 0 {
   123  			continue
   124  		}
   125  		if index > 0 {
   126  			buf.WriteByte(',')
   127  		}
   128  		switch len(values) {
   129  		case 1:
   130  			buf.WriteString(fmt.Sprintf("%s=\"%s\"", label, GenLabelConditionValues(values)))
   131  		default:
   132  			buf.WriteString(fmt.Sprintf("%s=~\"%s\"", label, GenLabelConditionValues(values)))
   133  		}
   134  		index++
   135  	}
   136  	return buf.String()
   137  }
   138  
   139  // GenLabelConditionValues generates the label condition values.
   140  func GenLabelConditionValues(values set.StringSet) string {
   141  	vs := make([]string, 0, len(values))
   142  	for k := range values {
   143  		vs = append(vs, k)
   144  	}
   145  	sort.Strings(vs)
   146  	return strings.Join(vs, "|")
   147  }
   148  
   149  // metricSchemaBlock stands for the fake causet all its data is in the memory.
   150  type metricSchemaBlock struct {
   151  	schemareplicantBlock
   152  }
   153  
   154  func blockFromMeta(alloc autoid.SlabPredictors, spacetime *perceptron.BlockInfo) (causet.Block, error) {
   155  	defCausumns := make([]*causet.DeferredCauset, 0, len(spacetime.DeferredCausets))
   156  	for _, defCausInfo := range spacetime.DeferredCausets {
   157  		defCaus := causet.ToDeferredCauset(defCausInfo)
   158  		defCausumns = append(defCausumns, defCaus)
   159  	}
   160  	t := &metricSchemaBlock{
   161  		schemareplicantBlock: schemareplicantBlock{
   162  			spacetime: spacetime,
   163  			defcaus: defCausumns,
   164  			tp:   causet.VirtualBlock,
   165  		},
   166  	}
   167  	return t, nil
   168  }