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

     1  // Copyright 2015 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 localstore
    15  
    16  import (
    17  	"github.com/insionng/yougam/libraries/juju/errors"
    18  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    19  	"github.com/insionng/yougam/libraries/pingcap/tidb/store/localstore/engine"
    20  	"github.com/insionng/yougam/libraries/pingcap/tidb/terror"
    21  )
    22  
    23  var (
    24  	_ kv.Snapshot = (*dbSnapshot)(nil)
    25  	_ kv.Iterator = (*dbIter)(nil)
    26  )
    27  
    28  // dbSnapshot implements MvccSnapshot interface.
    29  type dbSnapshot struct {
    30  	store   *dbStore
    31  	version kv.Version // transaction begin version
    32  }
    33  
    34  func newSnapshot(store *dbStore, ver kv.Version) *dbSnapshot {
    35  	ss := &dbSnapshot{
    36  		store:   store,
    37  		version: ver,
    38  	}
    39  
    40  	return ss
    41  }
    42  
    43  // mvccSeek seeks for the first key in db which has a k >= key and a version <=
    44  // snapshot's version, returns kv.ErrNotExist if such key is not found. If exact
    45  // is true, only k == key can be returned.
    46  func (s *dbSnapshot) mvccSeek(key kv.Key, exact bool) (kv.Key, []byte, error) {
    47  	// Key layout:
    48  	// ...
    49  	// Key_verMax      -- (1)
    50  	// ...
    51  	// Key_ver+1       -- (2)
    52  	// Key_ver         -- (3)
    53  	// Key_ver-1       -- (4)
    54  	// ...
    55  	// Key_0           -- (5)
    56  	// NextKey_verMax  -- (6)
    57  	// ...
    58  	// NextKey_ver+1   -- (7)
    59  	// NextKey_ver     -- (8)
    60  	// NextKey_ver-1   -- (9)
    61  	// ...
    62  	// NextKey_0       -- (10)
    63  	// ...
    64  	// EOF
    65  	for {
    66  		mvccKey := MvccEncodeVersionKey(key, s.version)
    67  		mvccK, v, err := s.store.Seek([]byte(mvccKey), s.version.Ver) // search for [3...EOF)
    68  		if err != nil {
    69  			if terror.ErrorEqual(err, engine.ErrNotFound) { // EOF
    70  				return nil, nil, errors.Trace(kv.ErrNotExist)
    71  			}
    72  			return nil, nil, errors.Trace(err)
    73  		}
    74  		k, ver, err := MvccDecode(mvccK)
    75  		if err != nil {
    76  			return nil, nil, errors.Trace(err)
    77  		}
    78  		// quick test for exact mode
    79  		if exact {
    80  			if key.Cmp(k) != 0 || isTombstone(v) {
    81  				return nil, nil, errors.Trace(kv.ErrNotExist)
    82  			}
    83  			return k, v, nil
    84  		}
    85  		if ver.Ver > s.version.Ver {
    86  			// currently on [6...7]
    87  			key = k // search for [8...EOF) next loop
    88  			continue
    89  		}
    90  		// currently on [3...5] or [8...10]
    91  		if isTombstone(v) {
    92  			key = k.Next() // search for (5...EOF) or (10..EOF) next loop
    93  			continue
    94  		}
    95  		// target found
    96  		return k, v, nil
    97  	}
    98  }
    99  
   100  // reverseMvccSeek seeks for the first key in db which has a k < key and a version <=
   101  // snapshot's version, returns kv.ErrNotExist if such key is not found.
   102  func (s *dbSnapshot) reverseMvccSeek(key kv.Key) (kv.Key, []byte, error) {
   103  	for {
   104  		var mvccKey []byte
   105  		if len(key) != 0 {
   106  			mvccKey = MvccEncodeVersionKey(key, kv.MaxVersion)
   107  		}
   108  		revMvccKey, _, err := s.store.SeekReverse(mvccKey, s.version.Ver)
   109  		if err != nil {
   110  			if terror.ErrorEqual(err, engine.ErrNotFound) {
   111  				return nil, nil, kv.ErrNotExist
   112  			}
   113  			return nil, nil, errors.Trace(err)
   114  		}
   115  		revKey, _, err := MvccDecode(revMvccKey)
   116  		if err != nil {
   117  			return nil, nil, errors.Trace(err)
   118  		}
   119  		resultKey, v, err := s.mvccSeek(revKey, true)
   120  		if terror.ErrorEqual(err, kv.ErrNotExist) {
   121  			key = revKey
   122  			continue
   123  		}
   124  		return resultKey, v, errors.Trace(err)
   125  	}
   126  }
   127  
   128  func (s *dbSnapshot) Get(key kv.Key) ([]byte, error) {
   129  	_, v, err := s.mvccSeek(key, true)
   130  	if err != nil {
   131  		return nil, errors.Trace(err)
   132  	}
   133  	return v, nil
   134  }
   135  
   136  func (s *dbSnapshot) BatchGet(keys []kv.Key) (map[string][]byte, error) {
   137  	m := make(map[string][]byte)
   138  	for _, k := range keys {
   139  		v, err := s.Get(k)
   140  		if err != nil && !kv.IsErrNotFound(err) {
   141  			return nil, errors.Trace(err)
   142  		}
   143  		if len(v) > 0 {
   144  			m[string(k)] = v
   145  		}
   146  	}
   147  	return m, nil
   148  }
   149  
   150  func (s *dbSnapshot) Seek(k kv.Key) (kv.Iterator, error) {
   151  	it, err := newDBIter(s, k, false)
   152  	return it, errors.Trace(err)
   153  }
   154  
   155  func (s *dbSnapshot) SeekReverse(k kv.Key) (kv.Iterator, error) {
   156  	it, err := newDBIter(s, k, true)
   157  	return it, errors.Trace(err)
   158  }
   159  
   160  func (s *dbSnapshot) Release() {
   161  }
   162  
   163  type dbIter struct {
   164  	s       *dbSnapshot
   165  	valid   bool
   166  	k       kv.Key
   167  	v       []byte
   168  	reverse bool
   169  }
   170  
   171  func newDBIter(s *dbSnapshot, key kv.Key, reverse bool) (*dbIter, error) {
   172  	var (
   173  		k   kv.Key
   174  		v   []byte
   175  		err error
   176  	)
   177  	if reverse {
   178  		k, v, err = s.reverseMvccSeek(key)
   179  	} else {
   180  		k, v, err = s.mvccSeek(key, false)
   181  	}
   182  	if err != nil {
   183  		if terror.ErrorEqual(err, kv.ErrNotExist) {
   184  			err = nil
   185  		}
   186  		return &dbIter{valid: false}, errors.Trace(err)
   187  	}
   188  
   189  	return &dbIter{
   190  		s:       s,
   191  		valid:   true,
   192  		k:       k,
   193  		v:       v,
   194  		reverse: reverse,
   195  	}, nil
   196  }
   197  
   198  func (it *dbIter) Next() error {
   199  	var k, v []byte
   200  	var err error
   201  	if it.reverse {
   202  		k, v, err = it.s.reverseMvccSeek(it.k)
   203  	} else {
   204  		k, v, err = it.s.mvccSeek(it.k.Next(), false)
   205  	}
   206  	if err != nil {
   207  		it.valid = false
   208  		if !terror.ErrorEqual(err, kv.ErrNotExist) {
   209  			return errors.Trace(err)
   210  		}
   211  	}
   212  	it.k, it.v = k, v
   213  	return nil
   214  }
   215  
   216  func (it *dbIter) Valid() bool {
   217  	return it.valid
   218  }
   219  
   220  func (it *dbIter) Key() kv.Key {
   221  	return it.k
   222  }
   223  
   224  func (it *dbIter) Value() []byte {
   225  	return it.v
   226  }
   227  
   228  func (it *dbIter) Close() {}