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  }