github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/write.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 "strings" 19 20 "github.com/opentracing/opentracing-go" 21 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 22 "github.com/whtcorpsinc/BerolinaSQL/ast" 23 "github.com/whtcorpsinc/milevadb/blockcodec" 24 "github.com/whtcorpsinc/milevadb/causet" 25 "github.com/whtcorpsinc/milevadb/causet/blocks" 26 "github.com/whtcorpsinc/milevadb/ekv" 27 "github.com/whtcorpsinc/milevadb/memex" 28 "github.com/whtcorpsinc/milevadb/soliton/codec" 29 "github.com/whtcorpsinc/milevadb/soliton/memory" 30 "github.com/whtcorpsinc/milevadb/spacetime/autoid" 31 "github.com/whtcorpsinc/milevadb/stochastikctx" 32 "github.com/whtcorpsinc/milevadb/types" 33 ) 34 35 var ( 36 _ InterlockingDirectorate = &UFIDelateInterDirc{} 37 _ InterlockingDirectorate = &DeleteInterDirc{} 38 _ InterlockingDirectorate = &InsertInterDirc{} 39 _ InterlockingDirectorate = &ReplaceInterDirc{} 40 _ InterlockingDirectorate = &LoadDataInterDirc{} 41 ) 42 43 // uFIDelateRecord uFIDelates the event specified by the handle `h`, from `oldData` to `newData`. 44 // `modified` means which defCausumns are really modified. It's used for secondary indices. 45 // Length of `oldData` and `newData` equals to length of `t.WriblockDefCauss()`. 46 // The return values: 47 // 1. changed (bool) : does the uFIDelate really change the event values. e.g. uFIDelate set i = 1 where i = 1; 48 // 2. err (error) : error in the uFIDelate. 49 func uFIDelateRecord(ctx context.Context, sctx stochastikctx.Context, h ekv.Handle, oldData, newData []types.Causet, modified []bool, t causet.Block, 50 onDup bool, memTracker *memory.Tracker) (bool, error) { 51 if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { 52 span1 := span.Tracer().StartSpan("interlock.uFIDelateRecord", opentracing.ChildOf(span.Context())) 53 defer span1.Finish() 54 ctx = opentracing.ContextWithSpan(ctx, span1) 55 } 56 txn, err := sctx.Txn(false) 57 if err != nil { 58 return false, err 59 } 60 memUsageOfTxnState := txn.Size() 61 defer memTracker.Consume(int64(txn.Size() - memUsageOfTxnState)) 62 sc := sctx.GetStochastikVars().StmtCtx 63 changed, handleChanged := false, false 64 // onUFIDelateSpecified is for "UFIDelATE SET ts_field = old_value", the 65 // timestamp field is explicitly set, but not changed in fact. 66 onUFIDelateSpecified := make(map[int]bool) 67 var newHandle ekv.Handle 68 69 // We can iterate on public defCausumns not wriblock defCausumns, 70 // because all of them are sorted by their `Offset`, which 71 // causes all wriblock defCausumns are after public defCausumns. 72 73 // 1. Cast modified values. 74 for i, defCaus := range t.DefCauss() { 75 if modified[i] { 76 // Cast changed fields with respective defCausumns. 77 v, err := causet.CastValue(sctx, newData[i], defCaus.ToInfo(), false, false) 78 if err != nil { 79 return false, err 80 } 81 newData[i] = v 82 } 83 } 84 85 // 2. Handle the bad null error. 86 for i, defCaus := range t.DefCauss() { 87 var err error 88 if err = defCaus.HandleBadNull(&newData[i], sc); err != nil { 89 return false, err 90 } 91 } 92 93 // 3. Compare causet, then handle some flags. 94 for i, defCaus := range t.DefCauss() { 95 cmp, err := newData[i].CompareCauset(sc, &oldData[i]) 96 if err != nil { 97 return false, err 98 } 99 if cmp != 0 { 100 changed = true 101 modified[i] = true 102 // Rebase auto increment id if the field is changed. 103 if allegrosql.HasAutoIncrementFlag(defCaus.Flag) { 104 recordID, err := getAutoRecordID(newData[i], &defCaus.FieldType, false) 105 if err != nil { 106 return false, err 107 } 108 if err = t.RebaseAutoID(sctx, recordID, true, autoid.EventIDAllocType); err != nil { 109 return false, err 110 } 111 } 112 if defCaus.IsPKHandleDeferredCauset(t.Meta()) { 113 handleChanged = true 114 newHandle = ekv.IntHandle(newData[i].GetInt64()) 115 // Rebase auto random id if the field is changed. 116 if err := rebaseAutoRandomValue(sctx, t, &newData[i], defCaus); err != nil { 117 return false, err 118 } 119 } 120 if defCaus.IsCommonHandleDeferredCauset(t.Meta()) { 121 pkIdx := blocks.FindPrimaryIndex(t.Meta()) 122 handleChanged = true 123 pkDts := make([]types.Causet, 0, len(pkIdx.DeferredCausets)) 124 for _, idxDefCaus := range pkIdx.DeferredCausets { 125 pkDts = append(pkDts, newData[idxDefCaus.Offset]) 126 } 127 blockcodec.TruncateIndexValues(t.Meta(), pkIdx, pkDts) 128 handleBytes, err := codec.EncodeKey(sctx.GetStochastikVars().StmtCtx, nil, pkDts...) 129 if err != nil { 130 return false, err 131 } 132 newHandle, err = ekv.NewCommonHandle(handleBytes) 133 if err != nil { 134 return false, err 135 } 136 } 137 } else { 138 if allegrosql.HasOnUFIDelateNowFlag(defCaus.Flag) && modified[i] { 139 // It's for "UFIDelATE t SET ts = ts" and ts is a timestamp. 140 onUFIDelateSpecified[i] = true 141 } 142 modified[i] = false 143 } 144 } 145 146 sc.AddTouchedEvents(1) 147 // If no changes, nothing to do, return directly. 148 if !changed { 149 // See https://dev.allegrosql.com/doc/refman/5.7/en/allegrosql-real-connect.html CLIENT_FOUND_ROWS 150 if sctx.GetStochastikVars().ClientCapability&allegrosql.ClientFoundEvents > 0 { 151 sc.AddAffectedEvents(1) 152 } 153 154 physicalID := t.Meta().ID 155 if pt, ok := t.(causet.PartitionedBlock); ok { 156 p, err := pt.GetPartitionByEvent(sctx, oldData) 157 if err != nil { 158 return false, err 159 } 160 physicalID = p.GetPhysicalID() 161 } 162 163 unchangedEventKey := blockcodec.EncodeEventKeyWithHandle(physicalID, h) 164 txnCtx := sctx.GetStochastikVars().TxnCtx 165 if txnCtx.IsPessimistic { 166 txnCtx.AddUnchangedEventKey(unchangedEventKey) 167 } 168 return false, nil 169 } 170 171 // 4. Fill values into on-uFIDelate-now fields, only if they are really changed. 172 for i, defCaus := range t.DefCauss() { 173 if allegrosql.HasOnUFIDelateNowFlag(defCaus.Flag) && !modified[i] && !onUFIDelateSpecified[i] { 174 if v, err := memex.GetTimeValue(sctx, strings.ToUpper(ast.CurrentTimestamp), defCaus.Tp, int8(defCaus.Decimal)); err == nil { 175 newData[i] = v 176 modified[i] = true 177 } else { 178 return false, err 179 } 180 } 181 } 182 183 // 5. If handle changed, remove the old then add the new record, otherwise uFIDelate the record. 184 if handleChanged { 185 if sc.DupKeyAsWarning { 186 // For `UFIDelATE IGNORE`/`INSERT IGNORE ON DUPLICATE KEY UFIDelATE` 187 // If the new handle exists, this will avoid to remove the record. 188 err = blocks.CheckHandleExists(ctx, sctx, t, newHandle, newData) 189 if err != nil { 190 return false, err 191 } 192 } 193 if err = t.RemoveRecord(sctx, h, oldData); err != nil { 194 return false, err 195 } 196 // the `affectedEvents` is increased when adding new record. 197 if sc.DupKeyAsWarning { 198 _, err = t.AddRecord(sctx, newData, causet.IsUFIDelate, causet.SkipHandleCheck, causet.WithCtx(ctx)) 199 } else { 200 _, err = t.AddRecord(sctx, newData, causet.IsUFIDelate, causet.WithCtx(ctx)) 201 } 202 203 if err != nil { 204 return false, err 205 } 206 if onDup { 207 sc.AddAffectedEvents(1) 208 } 209 } else { 210 // UFIDelate record to new value and uFIDelate index. 211 if err = t.UFIDelateRecord(ctx, sctx, h, oldData, newData, modified); err != nil { 212 return false, err 213 } 214 if onDup { 215 sc.AddAffectedEvents(2) 216 } else { 217 sc.AddAffectedEvents(1) 218 } 219 } 220 sc.AddUFIDelatedEvents(1) 221 sc.AddCopiedEvents(1) 222 223 return true, nil 224 } 225 226 func rebaseAutoRandomValue(sctx stochastikctx.Context, t causet.Block, newData *types.Causet, defCaus *causet.DeferredCauset) error { 227 blockInfo := t.Meta() 228 if !blockInfo.ContainsAutoRandomBits() { 229 return nil 230 } 231 recordID, err := getAutoRecordID(*newData, &defCaus.FieldType, false) 232 if err != nil { 233 return err 234 } 235 if recordID < 0 { 236 return nil 237 } 238 layout := autoid.NewAutoRandomIDLayout(&defCaus.FieldType, blockInfo.AutoRandomBits) 239 // Set bits except incremental_bits to zero. 240 recordID = recordID & (1<<layout.IncrementalBits - 1) 241 return t.SlabPredictors(sctx).Get(autoid.AutoRandomType).Rebase(blockInfo.ID, recordID, true) 242 } 243 244 // resetErrDataTooLong reset ErrDataTooLong error msg. 245 // types.ErrDataTooLong is produced in types.ProduceStrWithSpecifiedTp, there is no defCausumn info in there, 246 // so we reset the error msg here, and wrap old err with errors.Wrap. 247 func resetErrDataTooLong(defCausName string, rowIdx int, err error) error { 248 newErr := types.ErrDataTooLong.GenWithStack("Data too long for defCausumn '%v' at event %v", defCausName, rowIdx) 249 return newErr 250 }