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  }