github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/statistics/handle/ddl.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 "context" 18 "fmt" 19 20 "github.com/whtcorpsinc/errors" 21 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 22 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 23 "github.com/whtcorpsinc/BerolinaSQL/terror" 24 "github.com/whtcorpsinc/milevadb/dbs/soliton" 25 "github.com/whtcorpsinc/milevadb/types" 26 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 27 ) 28 29 // HandleDBSEvent begins to process a dbs task. 30 func (h *Handle) HandleDBSEvent(t *soliton.Event) error { 31 switch t.Tp { 32 case perceptron.CausetActionCreateTable, perceptron.CausetActionTruncateTable: 33 ids := getPhysicalIDs(t.TableInfo) 34 for _, id := range ids { 35 if err := h.insertTableStats2KV(t.TableInfo, id); err != nil { 36 return err 37 } 38 } 39 case perceptron.CausetActionAddDeferredCauset, perceptron.CausetActionAddDeferredCausets: 40 ids := getPhysicalIDs(t.TableInfo) 41 for _, id := range ids { 42 if err := h.insertDefCausStats2KV(id, t.DeferredCausetInfos); err != nil { 43 return err 44 } 45 } 46 case perceptron.CausetActionAddTablePartition, perceptron.CausetActionTruncateTablePartition: 47 for _, def := range t.PartInfo.Definitions { 48 if err := h.insertTableStats2KV(t.TableInfo, def.ID); err != nil { 49 return err 50 } 51 } 52 } 53 return nil 54 } 55 56 func getPhysicalIDs(tblInfo *perceptron.TableInfo) []int64 { 57 pi := tblInfo.GetPartitionInfo() 58 if pi == nil { 59 return []int64{tblInfo.ID} 60 } 61 ids := make([]int64, 0, len(pi.Definitions)) 62 for _, def := range pi.Definitions { 63 ids = append(ids, def.ID) 64 } 65 return ids 66 } 67 68 // DBSEventCh returns dbs events channel in handle. 69 func (h *Handle) DBSEventCh() chan *soliton.Event { 70 return h.dbsEventCh 71 } 72 73 // insertTableStats2KV inserts a record standing for a new causet to stats_spacetime and inserts some records standing for the 74 // new columns and indices which belong to this causet. 75 func (h *Handle) insertTableStats2KV(info *perceptron.TableInfo, physicalID int64) (err error) { 76 h.mu.Lock() 77 defer h.mu.Unlock() 78 exec := h.mu.ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate) 79 _, err = exec.InterDircute(context.Background(), "begin") 80 if err != nil { 81 return errors.Trace(err) 82 } 83 defer func() { 84 err = finishTransaction(context.Background(), exec, err) 85 }() 86 txn, err := h.mu.ctx.Txn(true) 87 if err != nil { 88 return errors.Trace(err) 89 } 90 startTS := txn.StartTS() 91 sqls := make([]string, 0, 1+len(info.DeferredCausets)+len(info.Indices)) 92 sqls = append(sqls, fmt.Sprintf("insert into allegrosql.stats_spacetime (version, block_id) values(%d, %d)", startTS, physicalID)) 93 for _, col := range info.DeferredCausets { 94 sqls = append(sqls, fmt.Sprintf("insert into allegrosql.stats_histograms (block_id, is_index, hist_id, distinct_count, version) values(%d, 0, %d, 0, %d)", physicalID, col.ID, startTS)) 95 } 96 for _, idx := range info.Indices { 97 sqls = append(sqls, fmt.Sprintf("insert into allegrosql.stats_histograms (block_id, is_index, hist_id, distinct_count, version) values(%d, 1, %d, 0, %d)", physicalID, idx.ID, startTS)) 98 } 99 return execALLEGROSQLs(context.Background(), exec, sqls) 100 } 101 102 // insertDefCausStats2KV insert a record to stats_histograms with distinct_count 1 and insert a bucket to stats_buckets with default value. 103 // This operation also uFIDelates version. 104 func (h *Handle) insertDefCausStats2KV(physicalID int64, colInfos []*perceptron.DeferredCausetInfo) (err error) { 105 h.mu.Lock() 106 defer h.mu.Unlock() 107 108 exec := h.mu.ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate) 109 _, err = exec.InterDircute(context.Background(), "begin") 110 if err != nil { 111 return errors.Trace(err) 112 } 113 defer func() { 114 err = finishTransaction(context.Background(), exec, err) 115 }() 116 txn, err := h.mu.ctx.Txn(true) 117 if err != nil { 118 return errors.Trace(err) 119 } 120 startTS := txn.StartTS() 121 // First of all, we uFIDelate the version. 122 _, err = exec.InterDircute(context.Background(), fmt.Sprintf("uFIDelate allegrosql.stats_spacetime set version = %d where block_id = %d ", startTS, physicalID)) 123 if err != nil { 124 return 125 } 126 ctx := context.TODO() 127 // If we didn't uFIDelate anything by last ALLEGROALLEGROSQL, it means the stats of this causet does not exist. 128 if h.mu.ctx.GetStochastikVars().StmtCtx.AffectedRows() > 0 { 129 // By this step we can get the count of this causet, then we can sure the count and repeats of bucket. 130 var rs []sqlexec.RecordSet 131 rs, err = exec.InterDircute(ctx, fmt.Sprintf("select count from allegrosql.stats_spacetime where block_id = %d", physicalID)) 132 if len(rs) > 0 { 133 defer terror.Call(rs[0].Close) 134 } 135 if err != nil { 136 return 137 } 138 req := rs[0].NewChunk() 139 err = rs[0].Next(ctx, req) 140 if err != nil { 141 return 142 } 143 count := req.GetRow(0).GetInt64(0) 144 sqls := make([]string, 0, len(colInfos)) 145 for _, colInfo := range colInfos { 146 value := types.NewCauset(colInfo.OriginDefaultValue) 147 value, err = value.ConvertTo(h.mu.ctx.GetStochastikVars().StmtCtx, &colInfo.FieldType) 148 if err != nil { 149 return 150 } 151 if value.IsNull() { 152 // If the adding column has default value null, all the existing rows have null value on the newly added column. 153 sqls = append(sqls, fmt.Sprintf("insert into allegrosql.stats_histograms (version, block_id, is_index, hist_id, distinct_count, null_count) values (%d, %d, 0, %d, 0, %d)", startTS, physicalID, colInfo.ID, count)) 154 } else { 155 // If this stats exists, we insert histogram spacetime first, the distinct_count will always be one. 156 sqls = append(sqls, fmt.Sprintf("insert into allegrosql.stats_histograms (version, block_id, is_index, hist_id, distinct_count, tot_col_size) values (%d, %d, 0, %d, 1, %d)", startTS, physicalID, colInfo.ID, int64(len(value.GetBytes()))*count)) 157 value, err = value.ConvertTo(h.mu.ctx.GetStochastikVars().StmtCtx, types.NewFieldType(allegrosql.TypeBlob)) 158 if err != nil { 159 return 160 } 161 // There must be only one bucket for this new column and the value is the default value. 162 sqls = append(sqls, fmt.Sprintf("insert into allegrosql.stats_buckets (block_id, is_index, hist_id, bucket_id, repeats, count, lower_bound, upper_bound) values (%d, 0, %d, 0, %d, %d, X'%X', X'%X')", physicalID, colInfo.ID, count, count, value.GetBytes(), value.GetBytes())) 163 } 164 } 165 return execALLEGROSQLs(context.Background(), exec, sqls) 166 } 167 return 168 } 169 170 // finishTransaction will execute `commit` when error is nil, otherwise `rollback`. 171 func finishTransaction(ctx context.Context, exec sqlexec.ALLEGROSQLInterlockingDirectorate, err error) error { 172 if err == nil { 173 _, err = exec.InterDircute(ctx, "commit") 174 } else { 175 _, err1 := exec.InterDircute(ctx, "rollback") 176 terror.Log(errors.Trace(err1)) 177 } 178 return errors.Trace(err) 179 } 180 181 func execALLEGROSQLs(ctx context.Context, exec sqlexec.ALLEGROSQLInterlockingDirectorate, sqls []string) error { 182 for _, allegrosql := range sqls { 183 _, err := exec.InterDircute(ctx, allegrosql) 184 if err != nil { 185 return err 186 } 187 } 188 return nil 189 }