github.com/KinWaiYuen/client-go/v2@v2.5.4/internal/mockstore/mocktikv/mvcc.go (about)

     1  // Copyright 2021 TiKV Authors
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // NOTE: The code in this file is based on code from the
    16  // TiDB project, licensed under the Apache License v 2.0
    17  //
    18  // https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/mockstore/mocktikv/mvcc.go
    19  //
    20  
    21  // Copyright 2016 PingCAP, Inc.
    22  //
    23  // Licensed under the Apache License, Version 2.0 (the "License");
    24  // you may not use this file except in compliance with the License.
    25  // You may obtain a copy of the License at
    26  //
    27  //     http://www.apache.org/licenses/LICENSE-2.0
    28  //
    29  // Unless required by applicable law or agreed to in writing, software
    30  // distributed under the License is distributed on an "AS IS" BASIS,
    31  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    32  // See the License for the specific language governing permissions and
    33  // limitations under the License.
    34  
    35  package mocktikv
    36  
    37  import (
    38  	"bytes"
    39  	"encoding/binary"
    40  	"io"
    41  	"math"
    42  
    43  	"github.com/KinWaiYuen/client-go/v2/util/codec"
    44  	"github.com/google/btree"
    45  	"github.com/pingcap/errors"
    46  	"github.com/pingcap/kvproto/pkg/kvrpcpb"
    47  )
    48  
    49  type mvccValueType int
    50  
    51  const (
    52  	typePut mvccValueType = iota
    53  	typeDelete
    54  	typeRollback
    55  	typeLock
    56  )
    57  
    58  type mvccValue struct {
    59  	valueType mvccValueType
    60  	startTS   uint64
    61  	commitTS  uint64
    62  	value     []byte
    63  }
    64  
    65  type mvccLock struct {
    66  	startTS     uint64
    67  	primary     []byte
    68  	value       []byte
    69  	op          kvrpcpb.Op
    70  	ttl         uint64
    71  	forUpdateTS uint64
    72  	txnSize     uint64
    73  	minCommitTS uint64
    74  }
    75  
    76  type mvccEntry struct {
    77  	key    MvccKey
    78  	values []mvccValue
    79  	lock   *mvccLock
    80  }
    81  
    82  // MarshalBinary implements encoding.BinaryMarshaler interface.
    83  func (l *mvccLock) MarshalBinary() ([]byte, error) {
    84  	var (
    85  		mh  marshalHelper
    86  		buf bytes.Buffer
    87  	)
    88  	mh.WriteNumber(&buf, l.startTS)
    89  	mh.WriteSlice(&buf, l.primary)
    90  	mh.WriteSlice(&buf, l.value)
    91  	mh.WriteNumber(&buf, l.op)
    92  	mh.WriteNumber(&buf, l.ttl)
    93  	mh.WriteNumber(&buf, l.forUpdateTS)
    94  	mh.WriteNumber(&buf, l.txnSize)
    95  	mh.WriteNumber(&buf, l.minCommitTS)
    96  	return buf.Bytes(), errors.Trace(mh.err)
    97  }
    98  
    99  // UnmarshalBinary implements encoding.BinaryUnmarshaler interface.
   100  func (l *mvccLock) UnmarshalBinary(data []byte) error {
   101  	var mh marshalHelper
   102  	buf := bytes.NewBuffer(data)
   103  	mh.ReadNumber(buf, &l.startTS)
   104  	mh.ReadSlice(buf, &l.primary)
   105  	mh.ReadSlice(buf, &l.value)
   106  	mh.ReadNumber(buf, &l.op)
   107  	mh.ReadNumber(buf, &l.ttl)
   108  	mh.ReadNumber(buf, &l.forUpdateTS)
   109  	mh.ReadNumber(buf, &l.txnSize)
   110  	mh.ReadNumber(buf, &l.minCommitTS)
   111  	return errors.Trace(mh.err)
   112  }
   113  
   114  // MarshalBinary implements encoding.BinaryMarshaler interface.
   115  func (v mvccValue) MarshalBinary() ([]byte, error) {
   116  	var (
   117  		mh  marshalHelper
   118  		buf bytes.Buffer
   119  	)
   120  	mh.WriteNumber(&buf, int64(v.valueType))
   121  	mh.WriteNumber(&buf, v.startTS)
   122  	mh.WriteNumber(&buf, v.commitTS)
   123  	mh.WriteSlice(&buf, v.value)
   124  	return buf.Bytes(), errors.Trace(mh.err)
   125  }
   126  
   127  // UnmarshalBinary implements encoding.BinaryUnmarshaler interface.
   128  func (v *mvccValue) UnmarshalBinary(data []byte) error {
   129  	var mh marshalHelper
   130  	buf := bytes.NewBuffer(data)
   131  	var vt int64
   132  	mh.ReadNumber(buf, &vt)
   133  	v.valueType = mvccValueType(vt)
   134  	mh.ReadNumber(buf, &v.startTS)
   135  	mh.ReadNumber(buf, &v.commitTS)
   136  	mh.ReadSlice(buf, &v.value)
   137  	return errors.Trace(mh.err)
   138  }
   139  
   140  type marshalHelper struct {
   141  	err error
   142  }
   143  
   144  func (mh *marshalHelper) WriteSlice(buf io.Writer, slice []byte) {
   145  	if mh.err != nil {
   146  		return
   147  	}
   148  	var tmp [binary.MaxVarintLen64]byte
   149  	off := binary.PutUvarint(tmp[:], uint64(len(slice)))
   150  	if err := writeFull(buf, tmp[:off]); err != nil {
   151  		mh.err = errors.Trace(err)
   152  		return
   153  	}
   154  	if err := writeFull(buf, slice); err != nil {
   155  		mh.err = errors.Trace(err)
   156  	}
   157  }
   158  
   159  func (mh *marshalHelper) WriteNumber(buf io.Writer, n interface{}) {
   160  	if mh.err != nil {
   161  		return
   162  	}
   163  	err := binary.Write(buf, binary.LittleEndian, n)
   164  	if err != nil {
   165  		mh.err = errors.Trace(err)
   166  	}
   167  }
   168  
   169  func writeFull(w io.Writer, slice []byte) error {
   170  	written := 0
   171  	for written < len(slice) {
   172  		n, err := w.Write(slice[written:])
   173  		if err != nil {
   174  			return errors.Trace(err)
   175  		}
   176  		written += n
   177  	}
   178  	return nil
   179  }
   180  
   181  func (mh *marshalHelper) ReadNumber(r io.Reader, n interface{}) {
   182  	if mh.err != nil {
   183  		return
   184  	}
   185  	err := binary.Read(r, binary.LittleEndian, n)
   186  	if err != nil {
   187  		mh.err = errors.Trace(err)
   188  	}
   189  }
   190  
   191  func (mh *marshalHelper) ReadSlice(r *bytes.Buffer, slice *[]byte) {
   192  	if mh.err != nil {
   193  		return
   194  	}
   195  	sz, err := binary.ReadUvarint(r)
   196  	if err != nil {
   197  		mh.err = errors.Trace(err)
   198  		return
   199  	}
   200  	const c10M = 10 * 1024 * 1024
   201  	if sz > c10M {
   202  		mh.err = errors.New("too large slice, maybe something wrong")
   203  		return
   204  	}
   205  	data := make([]byte, sz)
   206  	if _, err := io.ReadFull(r, data); err != nil {
   207  		mh.err = errors.Trace(err)
   208  		return
   209  	}
   210  	*slice = data
   211  }
   212  
   213  // lockErr returns ErrLocked.
   214  // Note that parameter key is raw key, while key in ErrLocked is mvcc key.
   215  func (l *mvccLock) lockErr(key []byte) error {
   216  	return &ErrLocked{
   217  		Key:         mvccEncode(key, lockVer),
   218  		Primary:     l.primary,
   219  		StartTS:     l.startTS,
   220  		ForUpdateTS: l.forUpdateTS,
   221  		TTL:         l.ttl,
   222  		TxnSize:     l.txnSize,
   223  		LockType:    l.op,
   224  	}
   225  }
   226  
   227  func (l *mvccLock) check(ts uint64, key []byte, resolvedLocks []uint64) (uint64, error) {
   228  	// ignore when ts is older than lock or lock's type is Lock.
   229  	// Pessimistic lock doesn't block read.
   230  	if l.startTS > ts || l.op == kvrpcpb.Op_Lock || l.op == kvrpcpb.Op_PessimisticLock {
   231  		return ts, nil
   232  	}
   233  	// for point get latest version.
   234  	if ts == math.MaxUint64 && bytes.Equal(l.primary, key) {
   235  		return l.startTS - 1, nil
   236  	}
   237  	// Skip lock if the lock is resolved.
   238  	for _, resolved := range resolvedLocks {
   239  		if l.startTS == resolved {
   240  			return ts, nil
   241  		}
   242  	}
   243  	return 0, l.lockErr(key)
   244  }
   245  
   246  func (e *mvccEntry) Less(than btree.Item) bool {
   247  	return bytes.Compare(e.key, than.(*mvccEntry).key) < 0
   248  }
   249  
   250  func (e *mvccEntry) Get(ts uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) ([]byte, error) {
   251  	if isoLevel == kvrpcpb.IsolationLevel_SI && e.lock != nil {
   252  		var err error
   253  		ts, err = e.lock.check(ts, e.key.Raw(), resolvedLocks)
   254  		if err != nil {
   255  			return nil, err
   256  		}
   257  	}
   258  	for _, v := range e.values {
   259  		if v.commitTS <= ts && v.valueType != typeRollback && v.valueType != typeLock {
   260  			return v.value, nil
   261  		}
   262  	}
   263  	return nil, nil
   264  }
   265  
   266  // MVCCStore is a mvcc key-value storage.
   267  type MVCCStore interface {
   268  	Get(key []byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) ([]byte, error)
   269  	Scan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) []Pair
   270  	ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) []Pair
   271  	BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) []Pair
   272  	PessimisticLock(req *kvrpcpb.PessimisticLockRequest) *kvrpcpb.PessimisticLockResponse
   273  	PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error
   274  	Prewrite(req *kvrpcpb.PrewriteRequest) []error
   275  	Commit(keys [][]byte, startTS, commitTS uint64) error
   276  	Rollback(keys [][]byte, startTS uint64) error
   277  	Cleanup(key []byte, startTS, currentTS uint64) error
   278  	ScanLock(startKey, endKey []byte, maxTS uint64) ([]*kvrpcpb.LockInfo, error)
   279  	TxnHeartBeat(primaryKey []byte, startTS uint64, adviseTTL uint64) (uint64, error)
   280  	ResolveLock(startKey, endKey []byte, startTS, commitTS uint64) error
   281  	BatchResolveLock(startKey, endKey []byte, txnInfos map[uint64]uint64) error
   282  	GC(startKey, endKey []byte, safePoint uint64) error
   283  	DeleteRange(startKey, endKey []byte) error
   284  	CheckTxnStatus(primaryKey []byte, lockTS uint64, startTS, currentTS uint64, rollbackIfNotFound bool, resolvingPessimisticLock bool) (uint64, uint64, kvrpcpb.Action, error)
   285  	Close() error
   286  }
   287  
   288  // RawKV is a key-value storage. MVCCStore can be implemented upon it with timestamp encoded into key.
   289  type RawKV interface {
   290  	RawGet(key []byte) []byte
   291  	RawBatchGet(keys [][]byte) [][]byte
   292  	RawScan(startKey, endKey []byte, limit int) []Pair        // Scan the range of [startKey, endKey)
   293  	RawReverseScan(startKey, endKey []byte, limit int) []Pair // Scan the range of [endKey, startKey)
   294  	RawPut(key, value []byte)
   295  	RawBatchPut(keys, values [][]byte)
   296  	RawDelete(key []byte)
   297  	RawBatchDelete(keys [][]byte)
   298  	RawDeleteRange(startKey, endKey []byte)
   299  }
   300  
   301  // MVCCDebugger is for debugging.
   302  type MVCCDebugger interface {
   303  	MvccGetByStartTS(starTS uint64) (*kvrpcpb.MvccInfo, []byte)
   304  	MvccGetByKey(key []byte) *kvrpcpb.MvccInfo
   305  }
   306  
   307  // Pair is a KV pair read from MvccStore or an error if any occurs.
   308  type Pair struct {
   309  	Key   []byte
   310  	Value []byte
   311  	Err   error
   312  }
   313  
   314  func regionContains(startKey []byte, endKey []byte, key []byte) bool {
   315  	return bytes.Compare(startKey, key) <= 0 &&
   316  		(bytes.Compare(key, endKey) < 0 || len(endKey) == 0)
   317  }
   318  
   319  // MvccKey is the encoded key type.
   320  // On TiKV, keys are encoded before they are saved into storage engine.
   321  type MvccKey []byte
   322  
   323  // NewMvccKey encodes a key into MvccKey.
   324  func NewMvccKey(key []byte) MvccKey {
   325  	if len(key) == 0 {
   326  		return nil
   327  	}
   328  	return codec.EncodeBytes(nil, key)
   329  }
   330  
   331  // Raw decodes a MvccKey to original key.
   332  func (key MvccKey) Raw() []byte {
   333  	if len(key) == 0 {
   334  		return nil
   335  	}
   336  	_, k, err := codec.DecodeBytes(key, nil)
   337  	if err != nil {
   338  		panic(err)
   339  	}
   340  	return k
   341  }