github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/update.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 "fmt" 19 "runtime/trace" 20 21 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 22 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 23 "github.com/whtcorpsinc/milevadb/causet" 24 causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded" 25 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 26 "github.com/whtcorpsinc/milevadb/ekv" 27 "github.com/whtcorpsinc/milevadb/memex" 28 "github.com/whtcorpsinc/milevadb/soliton/chunk" 29 "github.com/whtcorpsinc/milevadb/soliton/memory" 30 "github.com/whtcorpsinc/milevadb/types" 31 ) 32 33 // UFIDelateInterDirc represents a new uFIDelate interlock. 34 type UFIDelateInterDirc struct { 35 baseInterlockingDirectorate 36 37 OrderedList []*memex.Assignment 38 39 // uFIDelatedEventKeys is a map for unique (Block, handle) pair. 40 // The value is true if the event is changed, or false otherwise 41 uFIDelatedEventKeys map[int64]*ekv.HandleMap 42 tblID2block map[int64]causet.Block 43 44 matched uint64 // a counter of matched rows during uFIDelate 45 // tblDefCausPosInfos stores relationship between defCausumn ordinal to its causet handle. 46 // the defCausumns ordinals is present in ordinal range format, @see causetembedded.TblDefCausPosInfos 47 tblDefCausPosInfos causetembedded.TblDefCausPosInfoSlice 48 evalBuffer chunk.MutEvent 49 allAssignmentsAreConstant bool 50 drained bool 51 memTracker *memory.Tracker 52 53 stats *runtimeStatsWithSnapshot 54 } 55 56 func (e *UFIDelateInterDirc) exec(ctx context.Context, schemaReplicant *memex.Schema, event, newData []types.Causet) error { 57 defer trace.StartRegion(ctx, "UFIDelateInterDirc").End() 58 assignFlag, err := causetembedded.GetUFIDelateDeferredCausets(e.ctx, e.OrderedList, schemaReplicant.Len()) 59 if err != nil { 60 return err 61 } 62 if e.uFIDelatedEventKeys == nil { 63 e.uFIDelatedEventKeys = make(map[int64]*ekv.HandleMap) 64 } 65 for _, content := range e.tblDefCausPosInfos { 66 tbl := e.tblID2block[content.TblID] 67 if e.uFIDelatedEventKeys[content.TblID] == nil { 68 e.uFIDelatedEventKeys[content.TblID] = ekv.NewHandleMap() 69 } 70 var handle ekv.Handle 71 handle, err = content.HandleDefCauss.BuildHandleByCausets(event) 72 if err != nil { 73 return err 74 } 75 76 oldData := event[content.Start:content.End] 77 newBlockData := newData[content.Start:content.End] 78 uFIDelablock := false 79 flags := assignFlag[content.Start:content.End] 80 for _, flag := range flags { 81 if flag { 82 uFIDelablock = true 83 break 84 } 85 } 86 if !uFIDelablock { 87 // If there's nothing to uFIDelate, we can just skip current event 88 continue 89 } 90 var changed bool 91 v, ok := e.uFIDelatedEventKeys[content.TblID].Get(handle) 92 if !ok { 93 // Event is matched for the first time, increment `matched` counter 94 e.matched++ 95 } else { 96 changed = v.(bool) 97 } 98 if changed { 99 // Each matched event is uFIDelated once, even if it matches the conditions multiple times. 100 continue 101 } 102 103 // UFIDelate event 104 changed, err1 := uFIDelateRecord(ctx, e.ctx, handle, oldData, newBlockData, flags, tbl, false, e.memTracker) 105 if err1 == nil { 106 e.uFIDelatedEventKeys[content.TblID].Set(handle, changed) 107 continue 108 } 109 110 sc := e.ctx.GetStochastikVars().StmtCtx 111 if ekv.ErrKeyExists.Equal(err1) && sc.DupKeyAsWarning { 112 sc.AppendWarning(err1) 113 continue 114 } 115 return err1 116 } 117 return nil 118 } 119 120 // canNotUFIDelate checks the handle of a record to decide whether that record 121 // can not be uFIDelated. The handle is NULL only when it is the inner side of an 122 // outer join: the outer event can not match any inner rows, and in this scenario 123 // the inner handle field is filled with a NULL value. 124 // 125 // This fixes: https://github.com/whtcorpsinc/milevadb/issues/7176. 126 func (e *UFIDelateInterDirc) canNotUFIDelate(handle types.Causet) bool { 127 return handle.IsNull() 128 } 129 130 // Next implements the InterlockingDirectorate Next interface. 131 func (e *UFIDelateInterDirc) Next(ctx context.Context, req *chunk.Chunk) error { 132 req.Reset() 133 if !e.drained { 134 numEvents, err := e.uFIDelateEvents(ctx) 135 if err != nil { 136 return err 137 } 138 e.drained = true 139 e.ctx.GetStochastikVars().StmtCtx.AddRecordEvents(uint64(numEvents)) 140 } 141 return nil 142 } 143 144 func (e *UFIDelateInterDirc) uFIDelateEvents(ctx context.Context) (int, error) { 145 fields := retTypes(e.children[0]) 146 defcausInfo := make([]*causet.DeferredCauset, len(fields)) 147 for _, content := range e.tblDefCausPosInfos { 148 tbl := e.tblID2block[content.TblID] 149 for i, c := range tbl.WriblockDefCauss() { 150 defcausInfo[content.Start+i] = c 151 } 152 } 153 globalEventIdx := 0 154 chk := newFirstChunk(e.children[0]) 155 if !e.allAssignmentsAreConstant { 156 e.evalBuffer = chunk.MutEventFromTypes(fields) 157 } 158 composeFunc := e.fastComposeNewEvent 159 if !e.allAssignmentsAreConstant { 160 composeFunc = e.composeNewEvent 161 } 162 memUsageOfChk := int64(0) 163 totalNumEvents := 0 164 for { 165 e.memTracker.Consume(-memUsageOfChk) 166 err := Next(ctx, e.children[0], chk) 167 if err != nil { 168 return 0, err 169 } 170 171 if chk.NumEvents() == 0 { 172 break 173 } 174 memUsageOfChk = chk.MemoryUsage() 175 e.memTracker.Consume(memUsageOfChk) 176 if e.defCauslectRuntimeStatsEnabled() { 177 txn, err := e.ctx.Txn(false) 178 if err == nil && txn.GetSnapshot() != nil { 179 txn.GetSnapshot().SetOption(ekv.DefCauslectRuntimeStats, e.stats.SnapshotRuntimeStats) 180 } 181 } 182 for rowIdx := 0; rowIdx < chk.NumEvents(); rowIdx++ { 183 chunkEvent := chk.GetEvent(rowIdx) 184 datumEvent := chunkEvent.GetCausetEvent(fields) 185 newEvent, err1 := composeFunc(globalEventIdx, datumEvent, defcausInfo) 186 if err1 != nil { 187 return 0, err1 188 } 189 if err := e.exec(ctx, e.children[0].Schema(), datumEvent, newEvent); err != nil { 190 return 0, err 191 } 192 } 193 totalNumEvents += chk.NumEvents() 194 chk = chunk.Renew(chk, e.maxChunkSize) 195 } 196 return totalNumEvents, nil 197 } 198 199 func (e *UFIDelateInterDirc) handleErr(defCausName perceptron.CIStr, rowIdx int, err error) error { 200 if err == nil { 201 return nil 202 } 203 204 if types.ErrDataTooLong.Equal(err) { 205 return resetErrDataTooLong(defCausName.O, rowIdx+1, err) 206 } 207 208 if types.ErrOverflow.Equal(err) { 209 return types.ErrWarnDataOutOfRange.GenWithStackByArgs(defCausName.O, rowIdx+1) 210 } 211 212 return err 213 } 214 215 func (e *UFIDelateInterDirc) fastComposeNewEvent(rowIdx int, oldEvent []types.Causet, defcaus []*causet.DeferredCauset) ([]types.Causet, error) { 216 newEventData := types.CloneEvent(oldEvent) 217 for _, assign := range e.OrderedList { 218 handleIdx, handleFound := e.tblDefCausPosInfos.FindHandle(assign.DefCaus.Index) 219 if handleFound && e.canNotUFIDelate(oldEvent[handleIdx]) { 220 continue 221 } 222 223 con := assign.Expr.(*memex.Constant) 224 val, err := con.Eval(emptyEvent) 225 if err = e.handleErr(assign.DefCausName, rowIdx, err); err != nil { 226 return nil, err 227 } 228 229 // info of `_milevadb_rowid` defCausumn is nil. 230 // No need to cast `_milevadb_rowid` defCausumn value. 231 if defcaus[assign.DefCaus.Index] != nil { 232 val, err = causet.CastValue(e.ctx, val, defcaus[assign.DefCaus.Index].DeferredCausetInfo, false, false) 233 if err = e.handleErr(assign.DefCausName, rowIdx, err); err != nil { 234 return nil, err 235 } 236 } 237 238 val.Copy(&newEventData[assign.DefCaus.Index]) 239 } 240 return newEventData, nil 241 } 242 243 func (e *UFIDelateInterDirc) composeNewEvent(rowIdx int, oldEvent []types.Causet, defcaus []*causet.DeferredCauset) ([]types.Causet, error) { 244 newEventData := types.CloneEvent(oldEvent) 245 e.evalBuffer.SetCausets(newEventData...) 246 for _, assign := range e.OrderedList { 247 handleIdx, handleFound := e.tblDefCausPosInfos.FindHandle(assign.DefCaus.Index) 248 if handleFound && e.canNotUFIDelate(oldEvent[handleIdx]) { 249 continue 250 } 251 val, err := assign.Expr.Eval(e.evalBuffer.ToEvent()) 252 if err = e.handleErr(assign.DefCausName, rowIdx, err); err != nil { 253 return nil, err 254 } 255 256 // info of `_milevadb_rowid` defCausumn is nil. 257 // No need to cast `_milevadb_rowid` defCausumn value. 258 if defcaus[assign.DefCaus.Index] != nil { 259 val, err = causet.CastValue(e.ctx, val, defcaus[assign.DefCaus.Index].DeferredCausetInfo, false, false) 260 if err = e.handleErr(assign.DefCausName, rowIdx, err); err != nil { 261 return nil, err 262 } 263 } 264 265 val.Copy(&newEventData[assign.DefCaus.Index]) 266 e.evalBuffer.SetCauset(assign.DefCaus.Index, val) 267 } 268 return newEventData, nil 269 } 270 271 // Close implements the InterlockingDirectorate Close interface. 272 func (e *UFIDelateInterDirc) Close() error { 273 e.setMessage() 274 if e.runtimeStats != nil && e.stats != nil { 275 txn, err := e.ctx.Txn(false) 276 if err == nil && txn.GetSnapshot() != nil { 277 txn.GetSnapshot().DelOption(ekv.DefCauslectRuntimeStats) 278 } 279 } 280 return e.children[0].Close() 281 } 282 283 // Open implements the InterlockingDirectorate Open interface. 284 func (e *UFIDelateInterDirc) Open(ctx context.Context) error { 285 e.memTracker = memory.NewTracker(e.id, -1) 286 e.memTracker.AttachTo(e.ctx.GetStochastikVars().StmtCtx.MemTracker) 287 288 return e.children[0].Open(ctx) 289 } 290 291 // setMessage sets info message(ERR_UFIDelATE_INFO) generated by UFIDelATE memex 292 func (e *UFIDelateInterDirc) setMessage() { 293 stmtCtx := e.ctx.GetStochastikVars().StmtCtx 294 numMatched := e.matched 295 numChanged := stmtCtx.UFIDelatedEvents() 296 numWarnings := stmtCtx.WarningCount() 297 msg := fmt.Sprintf(allegrosql.MyALLEGROSQLErrName[allegrosql.ErrUFIDelateInfo], numMatched, numChanged, numWarnings) 298 stmtCtx.SetMessage(msg) 299 } 300 301 func (e *UFIDelateInterDirc) defCauslectRuntimeStatsEnabled() bool { 302 if e.runtimeStats != nil { 303 if e.stats == nil { 304 snapshotStats := &einsteindb.SnapshotRuntimeStats{} 305 e.stats = &runtimeStatsWithSnapshot{ 306 SnapshotRuntimeStats: snapshotStats, 307 } 308 e.ctx.GetStochastikVars().StmtCtx.RuntimeStatsDefCausl.RegisterStats(e.id, e.stats) 309 } 310 return true 311 } 312 return false 313 }