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  }