github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/delete.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 interlock
    15  
    16  import (
    17  	"context"
    18  
    19  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    20  	"github.com/whtcorpsinc/milevadb/causet"
    21  	causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded"
    22  	"github.com/whtcorpsinc/milevadb/config"
    23  	"github.com/whtcorpsinc/milevadb/ekv"
    24  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    25  	"github.com/whtcorpsinc/milevadb/soliton/memory"
    26  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    27  	"github.com/whtcorpsinc/milevadb/types"
    28  )
    29  
    30  // DeleteInterDirc represents a delete interlock.
    31  // See https://dev.allegrosql.com/doc/refman/5.7/en/delete.html
    32  type DeleteInterDirc struct {
    33  	baseInterlockingDirectorate
    34  
    35  	IsMultiBlock bool
    36  	tblID2Block  map[int64]causet.Block
    37  
    38  	// tblDefCausPosInfos stores relationship between defCausumn ordinal to its causet handle.
    39  	// the defCausumns ordinals is present in ordinal range format, @see causetembedded.TblDefCausPosInfos
    40  	tblDefCausPosInfos causetembedded.TblDefCausPosInfoSlice
    41  	memTracker         *memory.Tracker
    42  }
    43  
    44  // Next implements the InterlockingDirectorate Next interface.
    45  func (e *DeleteInterDirc) Next(ctx context.Context, req *chunk.Chunk) error {
    46  	req.Reset()
    47  	if e.IsMultiBlock {
    48  		return e.deleteMultiBlocksByChunk(ctx)
    49  	}
    50  	return e.deleteSingleBlockByChunk(ctx)
    51  }
    52  
    53  func (e *DeleteInterDirc) deleteOneEvent(tbl causet.Block, handleDefCauss causetembedded.HandleDefCauss, isExtraHandle bool, event []types.Causet) error {
    54  	end := len(event)
    55  	if isExtraHandle {
    56  		end--
    57  	}
    58  	handle, err := handleDefCauss.BuildHandleByCausets(event)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	err = e.removeEvent(e.ctx, tbl, handle, event[:end])
    63  	if err != nil {
    64  		return err
    65  	}
    66  	return nil
    67  }
    68  
    69  func (e *DeleteInterDirc) deleteSingleBlockByChunk(ctx context.Context) error {
    70  	var (
    71  		tbl            causet.Block
    72  		isExtrahandle  bool
    73  		handleDefCauss causetembedded.HandleDefCauss
    74  		rowCount       int
    75  	)
    76  	for _, info := range e.tblDefCausPosInfos {
    77  		tbl = e.tblID2Block[info.TblID]
    78  		handleDefCauss = info.HandleDefCauss
    79  		if !tbl.Meta().IsCommonHandle {
    80  			isExtrahandle = handleDefCauss.IsInt() && handleDefCauss.GetDefCaus(0).ID == perceptron.ExtraHandleID
    81  		}
    82  	}
    83  
    84  	batchDMLSize := e.ctx.GetStochastikVars().DMLBatchSize
    85  	// If milevadb_batch_delete is ON and not in a transaction, we could use BatchDelete mode.
    86  	batchDelete := e.ctx.GetStochastikVars().BatchDelete && !e.ctx.GetStochastikVars().InTxn() &&
    87  		config.GetGlobalConfig().EnableBatchDML && batchDMLSize > 0
    88  	fields := retTypes(e.children[0])
    89  	chk := newFirstChunk(e.children[0])
    90  	memUsageOfChk := int64(0)
    91  	for {
    92  		e.memTracker.Consume(-memUsageOfChk)
    93  		iter := chunk.NewIterator4Chunk(chk)
    94  		err := Next(ctx, e.children[0], chk)
    95  		if err != nil {
    96  			return err
    97  		}
    98  		if chk.NumEvents() == 0 {
    99  			break
   100  		}
   101  		memUsageOfChk = chk.MemoryUsage()
   102  		e.memTracker.Consume(memUsageOfChk)
   103  		for chunkEvent := iter.Begin(); chunkEvent != iter.End(); chunkEvent = iter.Next() {
   104  			if batchDelete && rowCount >= batchDMLSize {
   105  				e.ctx.StmtCommit()
   106  				if err = e.ctx.NewTxn(ctx); err != nil {
   107  					// We should return a special error for batch insert.
   108  					return ErrBatchInsertFail.GenWithStack("BatchDelete failed with error: %v", err)
   109  				}
   110  				rowCount = 0
   111  			}
   112  
   113  			datumEvent := chunkEvent.GetCausetEvent(fields)
   114  			err = e.deleteOneEvent(tbl, handleDefCauss, isExtrahandle, datumEvent)
   115  			if err != nil {
   116  				return err
   117  			}
   118  			rowCount++
   119  		}
   120  		chk = chunk.Renew(chk, e.maxChunkSize)
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  func (e *DeleteInterDirc) composeTblEventMap(tblEventMap blockEventMapType, defCausPosInfos []causetembedded.TblDefCausPosInfo, joinedEvent []types.Causet) error {
   127  	// iterate all the joined blocks, and got the copresonding rows in joinedEvent.
   128  	for _, info := range defCausPosInfos {
   129  		if tblEventMap[info.TblID] == nil {
   130  			tblEventMap[info.TblID] = ekv.NewHandleMap()
   131  		}
   132  		handle, err := info.HandleDefCauss.BuildHandleByCausets(joinedEvent)
   133  		if err != nil {
   134  			return err
   135  		}
   136  		// tblEventMap[info.TblID][handle] hold the event quantum binding to this causet and this handle.
   137  		tblEventMap[info.TblID].Set(handle, joinedEvent[info.Start:info.End])
   138  	}
   139  	return nil
   140  }
   141  
   142  func (e *DeleteInterDirc) deleteMultiBlocksByChunk(ctx context.Context) error {
   143  	defCausPosInfos := e.tblDefCausPosInfos
   144  	tblEventMap := make(blockEventMapType)
   145  	fields := retTypes(e.children[0])
   146  	chk := newFirstChunk(e.children[0])
   147  	memUsageOfChk := int64(0)
   148  	for {
   149  		e.memTracker.Consume(-memUsageOfChk)
   150  		iter := chunk.NewIterator4Chunk(chk)
   151  		err := Next(ctx, e.children[0], chk)
   152  		if err != nil {
   153  			return err
   154  		}
   155  		if chk.NumEvents() == 0 {
   156  			break
   157  		}
   158  		memUsageOfChk = chk.MemoryUsage()
   159  		e.memTracker.Consume(memUsageOfChk)
   160  
   161  		for joinedChunkEvent := iter.Begin(); joinedChunkEvent != iter.End(); joinedChunkEvent = iter.Next() {
   162  			joinedCausetEvent := joinedChunkEvent.GetCausetEvent(fields)
   163  			err := e.composeTblEventMap(tblEventMap, defCausPosInfos, joinedCausetEvent)
   164  			if err != nil {
   165  				return err
   166  			}
   167  		}
   168  		chk = chunk.Renew(chk, e.maxChunkSize)
   169  	}
   170  
   171  	return e.removeEventsInTblEventMap(tblEventMap)
   172  }
   173  
   174  func (e *DeleteInterDirc) removeEventsInTblEventMap(tblEventMap blockEventMapType) error {
   175  	for id, rowMap := range tblEventMap {
   176  		var err error
   177  		rowMap.Range(func(h ekv.Handle, val interface{}) bool {
   178  			err = e.removeEvent(e.ctx, e.tblID2Block[id], h, val.([]types.Causet))
   179  			if err != nil {
   180  				return false
   181  			}
   182  			return true
   183  		})
   184  		if err != nil {
   185  			return err
   186  		}
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  func (e *DeleteInterDirc) removeEvent(ctx stochastikctx.Context, t causet.Block, h ekv.Handle, data []types.Causet) error {
   193  	txnState, err := e.ctx.Txn(false)
   194  	if err != nil {
   195  		return err
   196  	}
   197  	memUsageOfTxnState := txnState.Size()
   198  	err = t.RemoveRecord(ctx, h, data)
   199  	if err != nil {
   200  		return err
   201  	}
   202  	e.memTracker.Consume(int64(txnState.Size() - memUsageOfTxnState))
   203  	ctx.GetStochastikVars().StmtCtx.AddAffectedEvents(1)
   204  	return nil
   205  }
   206  
   207  // Close implements the InterlockingDirectorate Close interface.
   208  func (e *DeleteInterDirc) Close() error {
   209  	return e.children[0].Close()
   210  }
   211  
   212  // Open implements the InterlockingDirectorate Open interface.
   213  func (e *DeleteInterDirc) Open(ctx context.Context) error {
   214  	e.memTracker = memory.NewTracker(e.id, -1)
   215  	e.memTracker.AttachTo(e.ctx.GetStochastikVars().StmtCtx.MemTracker)
   216  
   217  	return e.children[0].Open(ctx)
   218  }
   219  
   220  // blockEventMapType is a map for unique (Block, Event) pair. key is the blockID.
   221  // the key in map[int64]Event is the joined causet handle, which represent a unique reference event.
   222  // the value in map[int64]Event is the deleting event.
   223  type blockEventMapType map[int64]*ekv.HandleMap