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 }