github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/storage/mvcc/mvcc.go (about)

     1  // Copyright 2022 zGraph Authors. All rights reserved.
     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  package mvcc
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"io"
    21  	"math"
    22  
    23  	"github.com/google/btree"
    24  	"github.com/pingcap/errors"
    25  	"github.com/vescale/zgraph/storage/kv"
    26  )
    27  
    28  type ValueType int
    29  
    30  const (
    31  	ValueTypePut ValueType = iota
    32  	ValueTypeDelete
    33  	ValueTypeRollback
    34  	ValueTypeLock
    35  )
    36  
    37  type Value struct {
    38  	Type      ValueType
    39  	StartVer  kv.Version
    40  	CommitVer kv.Version
    41  	Value     []byte
    42  }
    43  
    44  type Lock struct {
    45  	StartVer kv.Version
    46  	Primary  []byte
    47  	Value    []byte
    48  	Op       Op
    49  	TTL      uint64
    50  }
    51  
    52  type Entry struct {
    53  	Key    Key
    54  	Values []Value
    55  	Lock   *Lock
    56  }
    57  
    58  // MarshalBinary implements encoding.BinaryMarshaler interface.
    59  func (l *Lock) MarshalBinary() ([]byte, error) {
    60  	var (
    61  		mh  marshalHelper
    62  		buf bytes.Buffer
    63  	)
    64  	mh.WriteNumber(&buf, l.StartVer)
    65  	mh.WriteSlice(&buf, l.Primary)
    66  	mh.WriteSlice(&buf, l.Value)
    67  	mh.WriteNumber(&buf, l.Op)
    68  	mh.WriteNumber(&buf, l.TTL)
    69  	return buf.Bytes(), mh.err
    70  }
    71  
    72  // UnmarshalBinary implements encoding.BinaryUnmarshaler interface.
    73  func (l *Lock) UnmarshalBinary(data []byte) error {
    74  	var mh marshalHelper
    75  	buf := bytes.NewBuffer(data)
    76  	mh.ReadNumber(buf, &l.StartVer)
    77  	mh.ReadSlice(buf, &l.Primary)
    78  	mh.ReadSlice(buf, &l.Value)
    79  	mh.ReadNumber(buf, &l.Op)
    80  	mh.ReadNumber(buf, &l.TTL)
    81  	return mh.err
    82  }
    83  
    84  // MarshalBinary implements encoding.BinaryMarshaler interface.
    85  func (v *Value) MarshalBinary() ([]byte, error) {
    86  	var (
    87  		mh  marshalHelper
    88  		buf bytes.Buffer
    89  	)
    90  	mh.WriteNumber(&buf, int64(v.Type))
    91  	mh.WriteNumber(&buf, v.StartVer)
    92  	mh.WriteNumber(&buf, v.CommitVer)
    93  	mh.WriteSlice(&buf, v.Value)
    94  	return buf.Bytes(), mh.err
    95  }
    96  
    97  // UnmarshalBinary implements encoding.BinaryUnmarshaler interface.
    98  func (v *Value) UnmarshalBinary(data []byte) error {
    99  	var mh marshalHelper
   100  	buf := bytes.NewBuffer(data)
   101  	var vt int64
   102  	mh.ReadNumber(buf, &vt)
   103  	v.Type = ValueType(vt)
   104  	mh.ReadNumber(buf, &v.StartVer)
   105  	mh.ReadNumber(buf, &v.CommitVer)
   106  	mh.ReadSlice(buf, &v.Value)
   107  	return mh.err
   108  }
   109  
   110  type marshalHelper struct {
   111  	err error
   112  }
   113  
   114  func (mh *marshalHelper) WriteSlice(buf io.Writer, slice []byte) {
   115  	if mh.err != nil {
   116  		return
   117  	}
   118  	var tmp [binary.MaxVarintLen64]byte
   119  	off := binary.PutUvarint(tmp[:], uint64(len(slice)))
   120  	if err := writeFull(buf, tmp[:off]); err != nil {
   121  		mh.err = err
   122  	}
   123  	if err := writeFull(buf, slice); err != nil {
   124  		mh.err = err
   125  	}
   126  }
   127  
   128  func (mh *marshalHelper) WriteNumber(buf io.Writer, n interface{}) {
   129  	if mh.err != nil {
   130  		return
   131  	}
   132  	err := binary.Write(buf, binary.LittleEndian, n)
   133  	if err != nil {
   134  		mh.err = errors.Trace(err)
   135  	}
   136  }
   137  
   138  func writeFull(w io.Writer, slice []byte) error {
   139  	written := 0
   140  	for written < len(slice) {
   141  		n, err := w.Write(slice[written:])
   142  		if err != nil {
   143  			return errors.Trace(err)
   144  		}
   145  		written += n
   146  	}
   147  	return nil
   148  }
   149  
   150  func (mh *marshalHelper) ReadNumber(r io.Reader, n interface{}) {
   151  	if mh.err != nil {
   152  		return
   153  	}
   154  	err := binary.Read(r, binary.LittleEndian, n)
   155  	if err != nil {
   156  		mh.err = errors.WithStack(err)
   157  	}
   158  }
   159  
   160  func (mh *marshalHelper) ReadSlice(r *bytes.Buffer, slice *[]byte) {
   161  	if mh.err != nil {
   162  		return
   163  	}
   164  	sz, err := binary.ReadUvarint(r)
   165  	if err != nil {
   166  		mh.err = errors.WithStack(err)
   167  		return
   168  	}
   169  	const c10M = 10 * 1024 * 1024
   170  	if sz > c10M {
   171  		mh.err = errors.New("too large slice, maybe something wrong")
   172  		return
   173  	}
   174  	data := make([]byte, sz)
   175  	if _, err := io.ReadFull(r, data); err != nil {
   176  		mh.err = errors.WithStack(err)
   177  		return
   178  	}
   179  	*slice = data
   180  }
   181  
   182  // LockErr returns LockedError.
   183  // Note that parameter key is raw key, while key in LockedError is mvcc key.
   184  func (l *Lock) LockErr(key []byte) error {
   185  	return &LockedError{
   186  		Key:      key,
   187  		Primary:  l.Primary,
   188  		StartVer: l.StartVer,
   189  		TTL:      l.TTL,
   190  	}
   191  }
   192  
   193  func (l *Lock) Check(ver kv.Version, key []byte, resolvedLocks []kv.Version) (kv.Version, error) {
   194  	// ignore when ver is older than lock or lock's type is Lock.
   195  	if l.StartVer > ver || l.Op == Op_Lock {
   196  		return ver, nil
   197  	}
   198  	// for point get the latest version.
   199  	if ver == math.MaxUint64 && bytes.Equal(l.Primary, key) {
   200  		return l.StartVer - 1, nil
   201  	}
   202  	// Skip lock if the lock is resolved.
   203  	for _, resolved := range resolvedLocks {
   204  		if l.StartVer == resolved {
   205  			return ver, nil
   206  		}
   207  	}
   208  	return 0, l.LockErr(key)
   209  }
   210  
   211  func (e *Entry) Less(than btree.Item) bool {
   212  	return bytes.Compare(e.Key, than.(*Entry).Key) < 0
   213  }
   214  
   215  func (e *Entry) Get(ver kv.Version, resolvedLocks []kv.Version) ([]byte, error) {
   216  	if e.Lock != nil {
   217  		var err error
   218  		ver, err = e.Lock.Check(ver, e.Key.Raw(), resolvedLocks)
   219  		if err != nil {
   220  			return nil, err
   221  		}
   222  	}
   223  	for _, v := range e.Values {
   224  		if v.CommitVer <= ver && v.Type != ValueTypeRollback && v.Type != ValueTypeLock {
   225  			return v.Value, nil
   226  		}
   227  	}
   228  	return nil, nil
   229  }