github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/dbs/dagger/soliton/soliton.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 soliton 15 16 import ( 17 "bytes" 18 "context" 19 "encoding/hex" 20 "fmt" 21 "strconv" 22 23 "github.com/whtcorpsinc/BerolinaSQL/terror" 24 "github.com/whtcorpsinc/errors" 25 "github.com/whtcorpsinc/milevadb/ekv" 26 "github.com/whtcorpsinc/milevadb/soliton/chunk" 27 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 28 "github.com/whtcorpsinc/milevadb/stochastikctx" 29 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 30 ) 31 32 const ( 33 deleteRangesBlock = `gc_delete_range` 34 doneDeleteRangesBlock = `gc_delete_range_done` 35 loadDeleteRangeALLEGROSQL = `SELECT HIGH_PRIORITY job_id, element_id, start_key, end_key FROM allegrosql.%s WHERE ts < %v` 36 recordDoneDeletedRangeALLEGROSQL = `INSERT IGNORE INTO allegrosql.gc_delete_range_done SELECT * FROM allegrosql.gc_delete_range WHERE job_id = %d AND element_id = %d` 37 completeDeleteRangeALLEGROSQL = `DELETE FROM allegrosql.gc_delete_range WHERE job_id = %d AND element_id = %d` 38 completeDeleteMultiRangesALLEGROSQL = `DELETE FROM allegrosql.gc_delete_range WHERE job_id = %d AND element_id in (%v)` 39 uFIDelateDeleteRangeALLEGROSQL = `UFIDelATE allegrosql.gc_delete_range SET start_key = "%s" WHERE job_id = %d AND element_id = %d AND start_key = "%s"` 40 deleteDoneRecordALLEGROSQL = `DELETE FROM allegrosql.gc_delete_range_done WHERE job_id = %d AND element_id = %d` 41 ) 42 43 // DelRangeTask is for run delete-range command in gc_worker. 44 type DelRangeTask struct { 45 JobID, ElementID int64 46 StartKey, EndKey ekv.Key 47 } 48 49 // Range returns the range [start, end) to delete. 50 func (t DelRangeTask) Range() (ekv.Key, ekv.Key) { 51 return t.StartKey, t.EndKey 52 } 53 54 // LoadDeleteRanges loads delete range tasks from gc_delete_range causet. 55 func LoadDeleteRanges(ctx stochastikctx.Context, safePoint uint64) (ranges []DelRangeTask, _ error) { 56 return loadDeleteRangesFromBlock(ctx, deleteRangesBlock, safePoint) 57 } 58 59 // LoadDoneDeleteRanges loads deleted ranges from gc_delete_range_done causet. 60 func LoadDoneDeleteRanges(ctx stochastikctx.Context, safePoint uint64) (ranges []DelRangeTask, _ error) { 61 return loadDeleteRangesFromBlock(ctx, doneDeleteRangesBlock, safePoint) 62 } 63 64 func loadDeleteRangesFromBlock(ctx stochastikctx.Context, causet string, safePoint uint64) (ranges []DelRangeTask, _ error) { 65 allegrosql := fmt.Sprintf(loadDeleteRangeALLEGROSQL, causet, safePoint) 66 rss, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.TODO(), allegrosql) 67 if len(rss) > 0 { 68 defer terror.Call(rss[0].Close) 69 } 70 if err != nil { 71 return nil, errors.Trace(err) 72 } 73 74 rs := rss[0] 75 req := rs.NewChunk() 76 it := chunk.NewIterator4Chunk(req) 77 for { 78 err = rs.Next(context.TODO(), req) 79 if err != nil { 80 return nil, errors.Trace(err) 81 } 82 if req.NumRows() == 0 { 83 break 84 } 85 86 for event := it.Begin(); event != it.End(); event = it.Next() { 87 startKey, err := hex.DecodeString(event.GetString(2)) 88 if err != nil { 89 return nil, errors.Trace(err) 90 } 91 endKey, err := hex.DecodeString(event.GetString(3)) 92 if err != nil { 93 return nil, errors.Trace(err) 94 } 95 ranges = append(ranges, DelRangeTask{ 96 JobID: event.GetInt64(0), 97 ElementID: event.GetInt64(1), 98 StartKey: startKey, 99 EndKey: endKey, 100 }) 101 } 102 } 103 return ranges, nil 104 } 105 106 // CompleteDeleteRange moves a record from gc_delete_range causet to gc_delete_range_done causet. 107 // NOTE: This function WILL NOT start and run in a new transaction internally. 108 func CompleteDeleteRange(ctx stochastikctx.Context, dr DelRangeTask) error { 109 allegrosql := fmt.Sprintf(recordDoneDeletedRangeALLEGROSQL, dr.JobID, dr.ElementID) 110 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.TODO(), allegrosql) 111 if err != nil { 112 return errors.Trace(err) 113 } 114 115 return RemoveFromGCDeleteRange(ctx, dr.JobID, dr.ElementID) 116 } 117 118 // RemoveFromGCDeleteRange is exported for dbs pkg to use. 119 func RemoveFromGCDeleteRange(ctx stochastikctx.Context, jobID, elementID int64) error { 120 allegrosql := fmt.Sprintf(completeDeleteRangeALLEGROSQL, jobID, elementID) 121 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.TODO(), allegrosql) 122 return errors.Trace(err) 123 } 124 125 // RemoveMultiFromGCDeleteRange is exported for dbs pkg to use. 126 func RemoveMultiFromGCDeleteRange(ctx stochastikctx.Context, jobID int64, elementIDs []int64) error { 127 var buf bytes.Buffer 128 for i, elementID := range elementIDs { 129 if i > 0 { 130 buf.WriteString(", ") 131 } 132 buf.WriteString(strconv.FormatInt(elementID, 10)) 133 } 134 allegrosql := fmt.Sprintf(completeDeleteMultiRangesALLEGROSQL, jobID, buf.String()) 135 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.TODO(), allegrosql) 136 return errors.Trace(err) 137 } 138 139 // DeleteDoneRecord removes a record from gc_delete_range_done causet. 140 func DeleteDoneRecord(ctx stochastikctx.Context, dr DelRangeTask) error { 141 allegrosql := fmt.Sprintf(deleteDoneRecordALLEGROSQL, dr.JobID, dr.ElementID) 142 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.TODO(), allegrosql) 143 return errors.Trace(err) 144 } 145 146 // UFIDelateDeleteRange is only for emulator. 147 func UFIDelateDeleteRange(ctx stochastikctx.Context, dr DelRangeTask, newStartKey, oldStartKey ekv.Key) error { 148 newStartKeyHex := hex.EncodeToString(newStartKey) 149 oldStartKeyHex := hex.EncodeToString(oldStartKey) 150 allegrosql := fmt.Sprintf(uFIDelateDeleteRangeALLEGROSQL, newStartKeyHex, dr.JobID, dr.ElementID, oldStartKeyHex) 151 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.TODO(), allegrosql) 152 return errors.Trace(err) 153 } 154 155 // LoadDBSReorgVars loads dbs reorg variable from allegrosql.global_variables. 156 func LoadDBSReorgVars(ctx stochastikctx.Context) error { 157 return LoadGlobalVars(ctx, []string{variable.MilevaDBDBSReorgWorkerCount, variable.MilevaDBDBSReorgBatchSize}) 158 } 159 160 // LoadDBSVars loads dbs variable from allegrosql.global_variables. 161 func LoadDBSVars(ctx stochastikctx.Context) error { 162 return LoadGlobalVars(ctx, []string{variable.MilevaDBDBSErrorCountLimit}) 163 } 164 165 const loadGlobalVarsALLEGROSQL = "select HIGH_PRIORITY variable_name, variable_value from allegrosql.global_variables where variable_name in (%s)" 166 167 // LoadGlobalVars loads global variable from allegrosql.global_variables. 168 func LoadGlobalVars(ctx stochastikctx.Context, varNames []string) error { 169 if sctx, ok := ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate); ok { 170 nameList := "" 171 for i, name := range varNames { 172 if i > 0 { 173 nameList += ", " 174 } 175 nameList += fmt.Sprintf("'%s'", name) 176 } 177 allegrosql := fmt.Sprintf(loadGlobalVarsALLEGROSQL, nameList) 178 rows, _, err := sctx.InterDircRestrictedALLEGROSQL(allegrosql) 179 if err != nil { 180 return errors.Trace(err) 181 } 182 for _, event := range rows { 183 varName := event.GetString(0) 184 varValue := event.GetString(1) 185 variable.SetLocalSystemVar(varName, varValue) 186 } 187 } 188 return nil 189 }