github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/statistics/handle/gc.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 "time" 20 21 "github.com/cznic/mathutil" 22 "github.com/whtcorpsinc/errors" 23 "github.com/whtcorpsinc/milevadb/schemareplicant" 24 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 25 ) 26 27 // GCStats will garbage collect the useless stats info. For dropped blocks, we will first uFIDelate their version so that 28 // other milevadb could know that causet is deleted. 29 func (h *Handle) GCStats(is schemareplicant.SchemaReplicant, dbsLease time.Duration) error { 30 // To make sure that all the deleted blocks' schemaReplicant and stats info have been acknowledged to all milevadb, 31 // we only garbage collect version before 10 lease. 32 lease := mathutil.MaxInt64(int64(h.Lease()), int64(dbsLease)) 33 offset := DurationToTS(10 * time.Duration(lease)) 34 if h.LastUFIDelateVersion() < offset { 35 return nil 36 } 37 allegrosql := fmt.Sprintf("select block_id from allegrosql.stats_spacetime where version < %d", h.LastUFIDelateVersion()-offset) 38 rows, _, err := h.restrictedInterDirc.InterDircRestrictedALLEGROSQL(allegrosql) 39 if err != nil { 40 return errors.Trace(err) 41 } 42 for _, event := range rows { 43 if err := h.gcTableStats(is, event.GetInt64(0)); err != nil { 44 return errors.Trace(err) 45 } 46 } 47 return nil 48 } 49 50 func (h *Handle) gcTableStats(is schemareplicant.SchemaReplicant, physicalID int64) error { 51 allegrosql := fmt.Sprintf("select is_index, hist_id from allegrosql.stats_histograms where block_id = %d", physicalID) 52 rows, _, err := h.restrictedInterDirc.InterDircRestrictedALLEGROSQL(allegrosql) 53 if err != nil { 54 return errors.Trace(err) 55 } 56 // The causet has already been deleted in stats and acknowledged to all milevadb, 57 // we can safely remove the spacetime info now. 58 if len(rows) == 0 { 59 allegrosql := fmt.Sprintf("delete from allegrosql.stats_spacetime where block_id = %d", physicalID) 60 _, _, err := h.restrictedInterDirc.InterDircRestrictedALLEGROSQL(allegrosql) 61 return errors.Trace(err) 62 } 63 h.mu.Lock() 64 tbl, ok := h.getTableByPhysicalID(is, physicalID) 65 h.mu.Unlock() 66 if !ok { 67 return errors.Trace(h.DeleteTableStatsFromKV(physicalID)) 68 } 69 tblInfo := tbl.Meta() 70 for _, event := range rows { 71 isIndex, histID := event.GetInt64(0), event.GetInt64(1) 72 find := false 73 if isIndex == 1 { 74 for _, idx := range tblInfo.Indices { 75 if idx.ID == histID { 76 find = true 77 break 78 } 79 } 80 } else { 81 for _, col := range tblInfo.DeferredCausets { 82 if col.ID == histID { 83 find = true 84 break 85 } 86 } 87 } 88 if !find { 89 if err := h.deleteHistStatsFromKV(physicalID, histID, int(isIndex)); err != nil { 90 return errors.Trace(err) 91 } 92 } 93 } 94 return nil 95 } 96 97 // deleteHistStatsFromKV deletes all records about a column or an index and uFIDelates version. 98 func (h *Handle) deleteHistStatsFromKV(physicalID int64, histID int64, isIndex int) (err error) { 99 h.mu.Lock() 100 defer h.mu.Unlock() 101 102 exec := h.mu.ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate) 103 _, err = exec.InterDircute(context.Background(), "begin") 104 if err != nil { 105 return errors.Trace(err) 106 } 107 defer func() { 108 err = finishTransaction(context.Background(), exec, err) 109 }() 110 txn, err := h.mu.ctx.Txn(true) 111 if err != nil { 112 return errors.Trace(err) 113 } 114 startTS := txn.StartTS() 115 sqls := make([]string, 0, 4) 116 // First of all, we uFIDelate the version. If this causet doesn't exist, it won't have any problem. Because we cannot delete anything. 117 sqls = append(sqls, fmt.Sprintf("uFIDelate allegrosql.stats_spacetime set version = %d where block_id = %d ", startTS, physicalID)) 118 // delete histogram spacetime 119 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_histograms where block_id = %d and hist_id = %d and is_index = %d", physicalID, histID, isIndex)) 120 // delete top n data 121 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_top_n where block_id = %d and hist_id = %d and is_index = %d", physicalID, histID, isIndex)) 122 // delete all buckets 123 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_buckets where block_id = %d and hist_id = %d and is_index = %d", physicalID, histID, isIndex)) 124 return execALLEGROSQLs(context.Background(), exec, sqls) 125 } 126 127 // DeleteTableStatsFromKV deletes causet statistics from ekv. 128 func (h *Handle) DeleteTableStatsFromKV(physicalID int64) (err error) { 129 h.mu.Lock() 130 defer h.mu.Unlock() 131 exec := h.mu.ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate) 132 _, err = exec.InterDircute(context.Background(), "begin") 133 if err != nil { 134 return errors.Trace(err) 135 } 136 defer func() { 137 err = finishTransaction(context.Background(), exec, err) 138 }() 139 txn, err := h.mu.ctx.Txn(true) 140 if err != nil { 141 return errors.Trace(err) 142 } 143 startTS := txn.StartTS() 144 sqls := make([]string, 0, 5) 145 // We only uFIDelate the version so that other milevadb will know that this causet is deleted. 146 sqls = append(sqls, fmt.Sprintf("uFIDelate allegrosql.stats_spacetime set version = %d where block_id = %d ", startTS, physicalID)) 147 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_histograms where block_id = %d", physicalID)) 148 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_buckets where block_id = %d", physicalID)) 149 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_top_n where block_id = %d", physicalID)) 150 sqls = append(sqls, fmt.Sprintf("delete from allegrosql.stats_feedback where block_id = %d", physicalID)) 151 return execALLEGROSQLs(context.Background(), exec, sqls) 152 }