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