github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/tikv/mock-tikv/mvcc.go (about)

     1  // Copyright 2016 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  package mocktikv
    15  
    16  import (
    17  	"bytes"
    18  	"sync"
    19  
    20  	"github.com/insionng/yougam/libraries/petar/GoLLRB/llrb"
    21  	"github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/kvrpcpb"
    22  )
    23  
    24  type mvccValue struct {
    25  	startTS  uint64
    26  	commitTS uint64
    27  	value    []byte
    28  }
    29  
    30  type mvccLock struct {
    31  	startTS uint64
    32  	primary []byte
    33  	value   []byte
    34  	op      kvrpcpb.Op
    35  }
    36  
    37  type mvccEntry struct {
    38  	key    []byte
    39  	values []mvccValue
    40  	lock   *mvccLock
    41  }
    42  
    43  func newEntry(key []byte) *mvccEntry {
    44  	return &mvccEntry{
    45  		key: key,
    46  	}
    47  }
    48  
    49  func (e *mvccEntry) Clone() *mvccEntry {
    50  	var entry mvccEntry
    51  	entry.key = append([]byte(nil), e.key...)
    52  	for _, v := range e.values {
    53  		entry.values = append(entry.values, mvccValue{
    54  			startTS:  v.startTS,
    55  			commitTS: v.commitTS,
    56  			value:    append([]byte(nil), v.value...),
    57  		})
    58  	}
    59  	if e.lock != nil {
    60  		entry.lock = &mvccLock{
    61  			startTS: e.lock.startTS,
    62  			primary: append([]byte(nil), e.lock.primary...),
    63  			value:   append([]byte(nil), e.lock.value...),
    64  			op:      e.lock.op,
    65  		}
    66  	}
    67  	return &entry
    68  }
    69  
    70  func (e *mvccEntry) Less(than llrb.Item) bool {
    71  	return bytes.Compare(e.key, than.(*mvccEntry).key) < 0
    72  }
    73  
    74  func (e *mvccEntry) lockErr() error {
    75  	return &ErrLocked{
    76  		Key:     e.key,
    77  		Primary: e.lock.primary,
    78  		StartTS: e.lock.startTS,
    79  	}
    80  }
    81  
    82  func (e *mvccEntry) Get(ts uint64) ([]byte, error) {
    83  	if e.lock != nil {
    84  		if e.lock.startTS <= ts {
    85  			return nil, e.lockErr()
    86  		}
    87  	}
    88  	for _, v := range e.values {
    89  		if v.commitTS <= ts {
    90  			return v.value, nil
    91  		}
    92  	}
    93  	return nil, nil
    94  }
    95  
    96  func (e *mvccEntry) Prewrite(mutation *kvrpcpb.Mutation, startTS uint64, primary []byte) error {
    97  	if len(e.values) > 0 {
    98  		if e.values[0].commitTS >= startTS {
    99  			return ErrRetryable("write conflict")
   100  		}
   101  	}
   102  	if e.lock != nil {
   103  		if e.lock.startTS != startTS {
   104  			return e.lockErr()
   105  		}
   106  		return nil
   107  	}
   108  	e.lock = &mvccLock{
   109  		startTS: startTS,
   110  		primary: primary,
   111  		value:   mutation.Value,
   112  		op:      mutation.GetOp(),
   113  	}
   114  	return nil
   115  }
   116  
   117  func (e *mvccEntry) checkTxnCommitted(startTS uint64) (uint64, bool) {
   118  	for _, v := range e.values {
   119  		if v.startTS == startTS {
   120  			return v.commitTS, true
   121  		}
   122  	}
   123  	return 0, false
   124  }
   125  
   126  func (e *mvccEntry) Commit(startTS, commitTS uint64) error {
   127  	if e.lock == nil || e.lock.startTS != startTS {
   128  		if _, ok := e.checkTxnCommitted(startTS); ok {
   129  			return nil
   130  		}
   131  		return ErrRetryable("txn not found")
   132  	}
   133  	if e.lock.op != kvrpcpb.Op_Lock {
   134  		e.values = append([]mvccValue{{
   135  			startTS:  startTS,
   136  			commitTS: commitTS,
   137  			value:    e.lock.value,
   138  		}}, e.values...)
   139  	}
   140  	e.lock = nil
   141  	return nil
   142  }
   143  
   144  func (e *mvccEntry) Rollback(startTS uint64) error {
   145  	if e.lock == nil || e.lock.startTS != startTS {
   146  		if commitTS, ok := e.checkTxnCommitted(startTS); ok {
   147  			return ErrAlreadyCommitted(commitTS)
   148  		}
   149  		return nil
   150  	}
   151  	e.lock = nil
   152  	return nil
   153  }
   154  
   155  // MvccStore is an in-memory, multi-versioned, transaction-supported kv storage.
   156  type MvccStore struct {
   157  	mu   sync.RWMutex
   158  	tree *llrb.LLRB
   159  }
   160  
   161  // NewMvccStore creates a MvccStore.
   162  func NewMvccStore() *MvccStore {
   163  	return &MvccStore{
   164  		tree: llrb.New(),
   165  	}
   166  }
   167  
   168  // Get reads a key by ts.
   169  func (s *MvccStore) Get(key []byte, startTS uint64) ([]byte, error) {
   170  	s.mu.RLock()
   171  	defer s.mu.RUnlock()
   172  
   173  	return s.get(key, startTS)
   174  }
   175  
   176  func (s *MvccStore) get(key []byte, startTS uint64) ([]byte, error) {
   177  	entry := s.tree.Get(newEntry(key))
   178  	if entry == nil {
   179  		return nil, nil
   180  	}
   181  	return entry.(*mvccEntry).Get(startTS)
   182  }
   183  
   184  // A Pair is a KV pair read from MvccStore or an error if any occurs.
   185  type Pair struct {
   186  	Key   []byte
   187  	Value []byte
   188  	Err   error
   189  }
   190  
   191  // BatchGet gets values with keys and ts.
   192  func (s *MvccStore) BatchGet(ks [][]byte, startTS uint64) []Pair {
   193  	s.mu.RLock()
   194  	defer s.mu.RUnlock()
   195  
   196  	var pairs []Pair
   197  	for _, k := range ks {
   198  		val, err := s.get(k, startTS)
   199  		if val == nil && err == nil {
   200  			continue
   201  		}
   202  		pairs = append(pairs, Pair{
   203  			Key:   k,
   204  			Value: val,
   205  			Err:   err,
   206  		})
   207  	}
   208  	return pairs
   209  }
   210  
   211  func regionContains(startKey []byte, endKey []byte, key []byte) bool {
   212  	return bytes.Compare(startKey, key) <= 0 &&
   213  		(bytes.Compare(key, endKey) < 0 || len(endKey) == 0)
   214  }
   215  
   216  // Scan reads up to a limited number of Pairs that greater than or equal to startKey and less than endKey.
   217  func (s *MvccStore) Scan(startKey, endKey []byte, limit int, startTS uint64) []Pair {
   218  	s.mu.RLock()
   219  	defer s.mu.RUnlock()
   220  
   221  	var pairs []Pair
   222  	iterator := func(item llrb.Item) bool {
   223  		if len(pairs) >= limit {
   224  			return false
   225  		}
   226  		k := item.(*mvccEntry).key
   227  		if !regionContains(startKey, endKey, k) {
   228  			return false
   229  		}
   230  		val, err := s.get(k, startTS)
   231  		if val != nil || err != nil {
   232  			pairs = append(pairs, Pair{
   233  				Key:   k,
   234  				Value: val,
   235  				Err:   err,
   236  			})
   237  		}
   238  		return true
   239  	}
   240  	s.tree.AscendGreaterOrEqual(newEntry(startKey), iterator)
   241  	return pairs
   242  }
   243  
   244  // ReverseScan reads up to a limited number of Pairs that greater than or equal to startKey and less than endKey
   245  // in descending order.
   246  func (s *MvccStore) ReverseScan(startKey, endKey []byte, limit int, startTS uint64) []Pair {
   247  	s.mu.RLock()
   248  	defer s.mu.RUnlock()
   249  
   250  	var pairs []Pair
   251  	iterator := func(item llrb.Item) bool {
   252  		if len(pairs) >= limit {
   253  			return false
   254  		}
   255  		k := item.(*mvccEntry).key
   256  		if bytes.Equal(k, endKey) {
   257  			return true
   258  		}
   259  		if bytes.Compare(k, startKey) < 0 {
   260  			return false
   261  		}
   262  		val, err := s.get(k, startTS)
   263  		if val != nil || err != nil {
   264  			pairs = append(pairs, Pair{
   265  				Key:   k,
   266  				Value: val,
   267  				Err:   err,
   268  			})
   269  		}
   270  		return true
   271  	}
   272  	s.tree.DescendLessOrEqual(newEntry(endKey), iterator)
   273  	return pairs
   274  }
   275  
   276  func (s *MvccStore) getOrNewEntry(key []byte) *mvccEntry {
   277  	if item := s.tree.Get(newEntry(key)); item != nil {
   278  		return item.(*mvccEntry).Clone()
   279  	}
   280  	return newEntry(key)
   281  }
   282  
   283  // submit writes entries into the rbtree.
   284  func (s *MvccStore) submit(ents ...*mvccEntry) {
   285  	for _, ent := range ents {
   286  		s.tree.ReplaceOrInsert(ent)
   287  	}
   288  }
   289  
   290  // Prewrite acquires a lock on a key. (1st phase of 2PC).
   291  func (s *MvccStore) Prewrite(mutations []*kvrpcpb.Mutation, primary []byte, startTS uint64) []error {
   292  	s.mu.Lock()
   293  	defer s.mu.Unlock()
   294  
   295  	var errs []error
   296  	for _, m := range mutations {
   297  		entry := s.getOrNewEntry(m.Key)
   298  		err := entry.Prewrite(m, startTS, primary)
   299  		s.submit(entry)
   300  		errs = append(errs, err)
   301  	}
   302  	return errs
   303  }
   304  
   305  // Commit commits the lock on a key. (2nd phase of 2PC).
   306  func (s *MvccStore) Commit(keys [][]byte, startTS, commitTS uint64) error {
   307  	s.mu.Lock()
   308  	defer s.mu.Unlock()
   309  
   310  	var ents []*mvccEntry
   311  	for _, k := range keys {
   312  		entry := s.getOrNewEntry(k)
   313  		err := entry.Commit(startTS, commitTS)
   314  		if err != nil {
   315  			return err
   316  		}
   317  		ents = append(ents, entry)
   318  	}
   319  	s.submit(ents...)
   320  	return nil
   321  }
   322  
   323  // CommitThenGet is a shortcut for Commit+Get, often used when resolving lock.
   324  func (s *MvccStore) CommitThenGet(key []byte, lockTS, commitTS, getTS uint64) ([]byte, error) {
   325  	s.mu.Lock()
   326  	defer s.mu.Unlock()
   327  
   328  	entry := s.getOrNewEntry(key)
   329  	err := entry.Commit(lockTS, commitTS)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  	s.submit(entry)
   334  	return entry.Get(getTS)
   335  }
   336  
   337  // Cleanup cleanups a lock, often used when resolving a expired lock.
   338  func (s *MvccStore) Cleanup(key []byte, startTS uint64) error {
   339  	s.mu.Lock()
   340  	defer s.mu.Unlock()
   341  
   342  	entry := s.getOrNewEntry(key)
   343  	err := entry.Rollback(startTS)
   344  	if err != nil {
   345  		return err
   346  	}
   347  	s.submit(entry)
   348  	return nil
   349  }
   350  
   351  // Rollback cleanups multiple locks, often used when rolling back a conflict txn.
   352  func (s *MvccStore) Rollback(keys [][]byte, startTS uint64) error {
   353  	s.mu.Lock()
   354  	defer s.mu.Unlock()
   355  
   356  	var ents []*mvccEntry
   357  	for _, k := range keys {
   358  		entry := s.getOrNewEntry(k)
   359  		err := entry.Rollback(startTS)
   360  		if err != nil {
   361  			return err
   362  		}
   363  		ents = append(ents, entry)
   364  	}
   365  	s.submit(ents...)
   366  	return nil
   367  }
   368  
   369  // RollbackThenGet is a shortcut for Rollback+Get, often used when resolving lock.
   370  func (s *MvccStore) RollbackThenGet(key []byte, lockTS uint64) ([]byte, error) {
   371  	s.mu.Lock()
   372  	defer s.mu.Unlock()
   373  
   374  	entry := s.getOrNewEntry(key)
   375  	err := entry.Rollback(lockTS)
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  	s.submit(entry)
   380  	return entry.Get(lockTS)
   381  }