github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/batch_checker.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/blockcodec" 21 "github.com/whtcorpsinc/milevadb/causet" 22 "github.com/whtcorpsinc/milevadb/causet/blocks" 23 "github.com/whtcorpsinc/milevadb/ekv" 24 "github.com/whtcorpsinc/milevadb/memex" 25 "github.com/whtcorpsinc/milevadb/soliton/chunk" 26 "github.com/whtcorpsinc/milevadb/soliton/stringutil" 27 "github.com/whtcorpsinc/milevadb/stochastikctx" 28 "github.com/whtcorpsinc/milevadb/types" 29 ) 30 31 type keyValueWithDupInfo struct { 32 newKey ekv.Key 33 dupErr error 34 commonHandle bool 35 } 36 37 type toBeCheckedEvent struct { 38 event []types.Causet 39 handleKey *keyValueWithDupInfo 40 uniqueKeys []*keyValueWithDupInfo 41 // t is the causet or partition this event belongs to. 42 t causet.Block 43 } 44 45 // encodeNewEvent encodes a new event to value. 46 func encodeNewEvent(ctx stochastikctx.Context, t causet.Block, event []types.Causet) ([]byte, error) { 47 defCausIDs := make([]int64, 0, len(event)) 48 skimmedEvent := make([]types.Causet, 0, len(event)) 49 for _, defCaus := range t.DefCauss() { 50 if !blocks.CanSkip(t.Meta(), defCaus, &event[defCaus.Offset]) { 51 defCausIDs = append(defCausIDs, defCaus.ID) 52 skimmedEvent = append(skimmedEvent, event[defCaus.Offset]) 53 } 54 } 55 sctx, rd := ctx.GetStochastikVars().StmtCtx, &ctx.GetStochastikVars().EventCausetEncoder 56 newEventValue, err := blockcodec.EncodeEvent(sctx, skimmedEvent, defCausIDs, nil, nil, rd) 57 if err != nil { 58 return nil, err 59 } 60 return newEventValue, nil 61 } 62 63 // getKeysNeedCheck gets keys converted from to-be-insert rows to record keys and unique index keys, 64 // which need to be checked whether they are duplicate keys. 65 func getKeysNeedCheck(ctx context.Context, sctx stochastikctx.Context, t causet.Block, rows [][]types.Causet) ([]toBeCheckedEvent, error) { 66 nUnique := 0 67 for _, v := range t.WriblockIndices() { 68 if v.Meta().Unique { 69 nUnique++ 70 } 71 } 72 toBeCheckEvents := make([]toBeCheckedEvent, 0, len(rows)) 73 74 var handleDefCauss []*causet.DeferredCauset 75 // Get handle defCausumn if PK is handle. 76 if t.Meta().PKIsHandle { 77 for _, defCaus := range t.DefCauss() { 78 if defCaus.IsPKHandleDeferredCauset(t.Meta()) { 79 handleDefCauss = append(handleDefCauss, defCaus) 80 break 81 } 82 } 83 } else { 84 handleDefCauss = blocks.TryGetCommonPkDeferredCausets(t) 85 } 86 87 var err error 88 for _, event := range rows { 89 toBeCheckEvents, err = getKeysNeedCheckOneEvent(sctx, t, event, nUnique, handleDefCauss, toBeCheckEvents) 90 if err != nil { 91 return nil, err 92 } 93 } 94 return toBeCheckEvents, nil 95 } 96 97 func getKeysNeedCheckOneEvent(ctx stochastikctx.Context, t causet.Block, event []types.Causet, nUnique int, handleDefCauss []*causet.DeferredCauset, result []toBeCheckedEvent) ([]toBeCheckedEvent, error) { 98 var err error 99 if p, ok := t.(causet.PartitionedBlock); ok { 100 t, err = p.GetPartitionByEvent(ctx, event) 101 if err != nil { 102 return nil, err 103 } 104 } 105 106 uniqueKeys := make([]*keyValueWithDupInfo, 0, nUnique) 107 // Append record keys and errors. 108 var handle ekv.Handle 109 if t.Meta().IsCommonHandle { 110 var err error 111 handleOrdinals := make([]int, 0, len(handleDefCauss)) 112 for _, defCaus := range handleDefCauss { 113 handleOrdinals = append(handleOrdinals, defCaus.Offset) 114 } 115 handle, err = ekv.BuildHandleFromCausetEvent(ctx.GetStochastikVars().StmtCtx, event, handleOrdinals) 116 if err != nil { 117 return nil, err 118 } 119 } else if len(handleDefCauss) > 0 { 120 handle = ekv.IntHandle(event[handleDefCauss[0].Offset].GetInt64()) 121 } 122 var handleKey *keyValueWithDupInfo 123 if handle != nil { 124 fn := func() string { 125 return ekv.GetDuplicateErrorHandleString(handle) 126 } 127 handleKey = &keyValueWithDupInfo{ 128 newKey: t.RecordKey(handle), 129 dupErr: ekv.ErrKeyExists.FastGenByArgs(stringutil.MemoizeStr(fn), "PRIMARY"), 130 } 131 } 132 133 // addChangingDefCausTimes is used to fetch values while processing "modify/change defCausumn" operation. 134 addChangingDefCausTimes := 0 135 // append unique keys and errors 136 for _, v := range t.WriblockIndices() { 137 if !v.Meta().Unique { 138 continue 139 } 140 if t.Meta().IsCommonHandle && v.Meta().Primary { 141 continue 142 } 143 if len(event) < len(t.WriblockDefCauss()) && addChangingDefCausTimes == 0 { 144 if defCaus := blocks.FindChangingDefCaus(t.WriblockDefCauss(), v.Meta()); defCaus != nil { 145 event = append(event, event[defCaus.DependencyDeferredCausetOffset]) 146 addChangingDefCausTimes++ 147 } 148 } 149 defCausVals, err1 := v.FetchValues(event, nil) 150 if err1 != nil { 151 return nil, err1 152 } 153 // Pass handle = 0 to GenIndexKey, 154 // due to we only care about distinct key. 155 key, distinct, err1 := v.GenIndexKey(ctx.GetStochastikVars().StmtCtx, 156 defCausVals, ekv.IntHandle(0), nil) 157 if err1 != nil { 158 return nil, err1 159 } 160 // Skip the non-distinct keys. 161 if !distinct { 162 continue 163 } 164 defCausValStr, err1 := types.CausetsToString(defCausVals, false) 165 if err1 != nil { 166 return nil, err1 167 } 168 uniqueKeys = append(uniqueKeys, &keyValueWithDupInfo{ 169 newKey: key, 170 dupErr: ekv.ErrKeyExists.FastGenByArgs(defCausValStr, v.Meta().Name), 171 commonHandle: t.Meta().IsCommonHandle, 172 }) 173 } 174 if addChangingDefCausTimes == 1 { 175 event = event[:len(event)-1] 176 } 177 result = append(result, toBeCheckedEvent{ 178 event: event, 179 handleKey: handleKey, 180 uniqueKeys: uniqueKeys, 181 t: t, 182 }) 183 return result, nil 184 } 185 186 // getOldEvent gets the causet record event from storage for batch check. 187 // t could be a normal causet or a partition, but it must not be a PartitionedBlock. 188 func getOldEvent(ctx context.Context, sctx stochastikctx.Context, txn ekv.Transaction, t causet.Block, handle ekv.Handle, 189 genExprs []memex.Expression) ([]types.Causet, error) { 190 oldValue, err := txn.Get(ctx, t.RecordKey(handle)) 191 if err != nil { 192 return nil, err 193 } 194 195 defcaus := t.WriblockDefCauss() 196 oldEvent, oldEventMap, err := blocks.DecodeRawEventData(sctx, t.Meta(), handle, defcaus, oldValue) 197 if err != nil { 198 return nil, err 199 } 200 // Fill write-only and write-reorg defCausumns with originDefaultValue if not found in oldValue. 201 gIdx := 0 202 for _, defCaus := range defcaus { 203 if defCaus.State != perceptron.StatePublic && oldEvent[defCaus.Offset].IsNull() { 204 _, found := oldEventMap[defCaus.ID] 205 if !found { 206 oldEvent[defCaus.Offset], err = causet.GetDefCausOriginDefaultValue(sctx, defCaus.ToInfo()) 207 if err != nil { 208 return nil, err 209 } 210 } 211 } 212 if defCaus.IsGenerated() { 213 // only the virtual defCausumn needs fill back. 214 if !defCaus.GeneratedStored { 215 val, err := genExprs[gIdx].Eval(chunk.MutEventFromCausets(oldEvent).ToEvent()) 216 if err != nil { 217 return nil, err 218 } 219 oldEvent[defCaus.Offset], err = causet.CastValue(sctx, val, defCaus.ToInfo(), false, false) 220 if err != nil { 221 return nil, err 222 } 223 } 224 gIdx++ 225 } 226 } 227 return oldEvent, nil 228 }