github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/lightning/backend/kv/session.go (about) 1 // Copyright 2019 PingCAP, 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 // TODO combine with the pkg/kv package outside. 15 16 package kv 17 18 import ( 19 "context" 20 "errors" 21 "fmt" 22 "strconv" 23 "sync" 24 25 "github.com/docker/go-units" 26 "github.com/pingcap/parser/model" 27 "github.com/pingcap/parser/mysql" 28 "github.com/pingcap/tidb/kv" 29 "github.com/pingcap/tidb/sessionctx" 30 "github.com/pingcap/tidb/sessionctx/variable" 31 32 "github.com/pingcap/br/pkg/lightning/common" 33 "github.com/pingcap/br/pkg/lightning/log" 34 "github.com/pingcap/br/pkg/lightning/manual" 35 "github.com/pingcap/br/pkg/utils" 36 37 "go.uber.org/zap" 38 ) 39 40 // invalidIterator is a trimmed down Iterator type which is invalid. 41 type invalidIterator struct { 42 kv.Iterator 43 } 44 45 // Valid implements the kv.Iterator interface 46 func (*invalidIterator) Valid() bool { 47 return false 48 } 49 50 // Close implements the kv.Iterator interface 51 func (*invalidIterator) Close() { 52 } 53 54 type bytesBuf struct { 55 buf []byte 56 idx int 57 cap int 58 } 59 60 func (b *bytesBuf) add(v []byte) []byte { 61 start := b.idx 62 copy(b.buf[start:], v) 63 b.idx += len(v) 64 return b.buf[start:b.idx:b.idx] 65 } 66 67 func newBytesBuf(size int) *bytesBuf { 68 return &bytesBuf{ 69 buf: manual.New(size), 70 cap: size, 71 } 72 } 73 74 func (b *bytesBuf) destroy() { 75 if b != nil { 76 manual.Free(b.buf) 77 b.buf = nil 78 } 79 } 80 81 type kvMemBuf struct { 82 sync.Mutex 83 kv.MemBuffer 84 buf *bytesBuf 85 availableBufs []*bytesBuf 86 kvPairs *KvPairs 87 size int 88 } 89 90 func (mb *kvMemBuf) Recycle(buf *bytesBuf) { 91 buf.idx = 0 92 buf.cap = len(buf.buf) 93 mb.Lock() 94 mb.availableBufs = append(mb.availableBufs, buf) 95 mb.Unlock() 96 } 97 98 func (mb *kvMemBuf) AllocateBuf(size int) { 99 mb.Lock() 100 size = utils.MaxInt(units.MiB, int(utils.NextPowerOfTwo(int64(size)))*2) 101 if len(mb.availableBufs) > 0 && mb.availableBufs[0].cap >= size { 102 mb.buf = mb.availableBufs[0] 103 mb.availableBufs = mb.availableBufs[1:] 104 } else { 105 mb.buf = newBytesBuf(size) 106 } 107 mb.Unlock() 108 } 109 110 func (mb *kvMemBuf) Set(k kv.Key, v []byte) error { 111 kvPairs := mb.kvPairs 112 size := len(k) + len(v) 113 if mb.buf == nil || mb.buf.cap-mb.buf.idx < size { 114 if mb.buf != nil { 115 kvPairs.bytesBuf = mb.buf 116 } 117 mb.AllocateBuf(size) 118 } 119 kvPairs.pairs = append(kvPairs.pairs, common.KvPair{ 120 Key: mb.buf.add(k), 121 Val: mb.buf.add(v), 122 }) 123 mb.size += size 124 return nil 125 } 126 127 func (mb *kvMemBuf) SetWithFlags(k kv.Key, v []byte, ops ...kv.FlagsOp) error { 128 return mb.Set(k, v) 129 } 130 131 func (mb *kvMemBuf) Delete(k kv.Key) error { 132 return errors.New("unsupported operation") 133 } 134 135 // Release publish all modifications in the latest staging buffer to upper level. 136 func (mb *kvMemBuf) Release(h kv.StagingHandle) { 137 } 138 139 func (mb *kvMemBuf) Staging() kv.StagingHandle { 140 return 0 141 } 142 143 // Cleanup cleanup the resources referenced by the StagingHandle. 144 // If the changes are not published by `Release`, they will be discarded. 145 func (mb *kvMemBuf) Cleanup(h kv.StagingHandle) {} 146 147 // Size returns sum of keys and values length. 148 func (mb *kvMemBuf) Size() int { 149 return mb.size 150 } 151 152 // Len returns the number of entries in the DB. 153 func (t *transaction) Len() int { 154 return t.GetMemBuffer().Len() 155 } 156 157 type kvUnionStore struct { 158 kvMemBuf 159 } 160 161 func (s *kvUnionStore) GetMemBuffer() kv.MemBuffer { 162 return &s.kvMemBuf 163 } 164 165 func (s *kvUnionStore) GetIndexName(tableID, indexID int64) string { 166 panic("Unsupported Operation") 167 } 168 169 func (s *kvUnionStore) CacheIndexName(tableID, indexID int64, name string) { 170 } 171 172 func (s *kvUnionStore) CacheTableInfo(id int64, info *model.TableInfo) { 173 } 174 175 // transaction is a trimmed down Transaction type which only supports adding a 176 // new KV pair. 177 type transaction struct { 178 kv.Transaction 179 kvUnionStore 180 } 181 182 func (t *transaction) GetMemBuffer() kv.MemBuffer { 183 return &t.kvUnionStore.kvMemBuf 184 } 185 186 func (t *transaction) Discard() { 187 // do nothing 188 } 189 190 func (t *transaction) Flush() (int, error) { 191 // do nothing 192 return 0, nil 193 } 194 195 // Reset implements the kv.MemBuffer interface 196 func (t *transaction) Reset() {} 197 198 // Get implements the kv.Retriever interface 199 func (t *transaction) Get(ctx context.Context, key kv.Key) ([]byte, error) { 200 return nil, kv.ErrNotExist 201 } 202 203 // Iter implements the kv.Retriever interface 204 func (t *transaction) Iter(k kv.Key, upperBound kv.Key) (kv.Iterator, error) { 205 return &invalidIterator{}, nil 206 } 207 208 // Set implements the kv.Mutator interface 209 func (t *transaction) Set(k kv.Key, v []byte) error { 210 return t.kvMemBuf.Set(k, v) 211 } 212 213 // GetTableInfo implements the kv.Transaction interface. 214 func (t *transaction) GetTableInfo(id int64) *model.TableInfo { 215 return nil 216 } 217 218 // CacheTableInfo implements the kv.Transaction interface. 219 func (t *transaction) CacheTableInfo(id int64, info *model.TableInfo) { 220 } 221 222 // session is a trimmed down Session type which only wraps our own trimmed-down 223 // transaction type and provides the session variables to the TiDB library 224 // optimized for Lightning. 225 type session struct { 226 sessionctx.Context 227 txn transaction 228 vars *variable.SessionVars 229 // currently, we only set `CommonAddRecordCtx` 230 values map[fmt.Stringer]interface{} 231 } 232 233 // SessionOptions is the initial configuration of the session. 234 type SessionOptions struct { 235 SQLMode mysql.SQLMode 236 Timestamp int64 237 SysVars map[string]string 238 // a seed used for tableKvEncoder's auto random bits value 239 AutoRandomSeed int64 240 } 241 242 // NewSession creates a new trimmed down Session matching the options. 243 func NewSession(options *SessionOptions) sessionctx.Context { 244 return newSession(options) 245 } 246 247 func newSession(options *SessionOptions) *session { 248 sqlMode := options.SQLMode 249 vars := variable.NewSessionVars() 250 vars.SkipUTF8Check = true 251 vars.StmtCtx.InInsertStmt = true 252 vars.StmtCtx.BatchCheck = true 253 vars.StmtCtx.BadNullAsWarning = !sqlMode.HasStrictMode() 254 vars.StmtCtx.TruncateAsWarning = !sqlMode.HasStrictMode() 255 vars.StmtCtx.OverflowAsWarning = !sqlMode.HasStrictMode() 256 vars.StmtCtx.AllowInvalidDate = sqlMode.HasAllowInvalidDatesMode() 257 vars.StmtCtx.IgnoreZeroInDate = !sqlMode.HasStrictMode() || sqlMode.HasAllowInvalidDatesMode() 258 vars.SQLMode = sqlMode 259 if options.SysVars != nil { 260 for k, v := range options.SysVars { 261 if err := vars.SetSystemVar(k, v); err != nil { 262 log.L().DPanic("new session: failed to set system var", 263 log.ShortError(err), 264 zap.String("key", k)) 265 } 266 } 267 } 268 vars.StmtCtx.TimeZone = vars.Location() 269 if err := vars.SetSystemVar("timestamp", strconv.FormatInt(options.Timestamp, 10)); err != nil { 270 log.L().Warn("new session: failed to set timestamp", 271 log.ShortError(err)) 272 } 273 vars.TxnCtx = nil 274 s := &session{ 275 vars: vars, 276 values: make(map[fmt.Stringer]interface{}, 1), 277 } 278 s.txn.kvPairs = &KvPairs{} 279 280 return s 281 } 282 283 func (se *session) takeKvPairs() *KvPairs { 284 memBuf := &se.txn.kvMemBuf 285 pairs := memBuf.kvPairs 286 if pairs.bytesBuf != nil { 287 pairs.memBuf = memBuf 288 } 289 memBuf.kvPairs = &KvPairs{pairs: make([]common.KvPair, 0, len(pairs.pairs))} 290 memBuf.size = 0 291 return pairs 292 } 293 294 // Txn implements the sessionctx.Context interface 295 func (se *session) Txn(active bool) (kv.Transaction, error) { 296 return &se.txn, nil 297 } 298 299 // GetSessionVars implements the sessionctx.Context interface 300 func (se *session) GetSessionVars() *variable.SessionVars { 301 return se.vars 302 } 303 304 // SetValue saves a value associated with this context for key. 305 func (se *session) SetValue(key fmt.Stringer, value interface{}) { 306 se.values[key] = value 307 } 308 309 // Value returns the value associated with this context for key. 310 func (se *session) Value(key fmt.Stringer) interface{} { 311 return se.values[key] 312 } 313 314 // StmtAddDirtyTableOP implements the sessionctx.Context interface 315 func (se *session) StmtAddDirtyTableOP(op int, physicalID int64, handle kv.Handle) {} 316 317 // GetInfoSchema implements the sessionctx.Context interface. 318 func (se *session) GetInfoSchema() sessionctx.InfoschemaMetaVersion { 319 return nil 320 } 321 322 // GetBuiltinFunctionUsage returns the BuiltinFunctionUsage of current Context, which is not thread safe. 323 // Use primitive map type to prevent circular import. Should convert it to telemetry.BuiltinFunctionUsage before using. 324 func (se *session) GetBuiltinFunctionUsage() map[string]uint32 { 325 return make(map[string]uint32) 326 } 327 328 func (se *session) Close() { 329 memBuf := &se.txn.kvMemBuf 330 if memBuf.buf != nil { 331 memBuf.buf.destroy() 332 memBuf.buf = nil 333 } 334 for _, b := range memBuf.availableBufs { 335 b.destroy() 336 } 337 memBuf.availableBufs = nil 338 }