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() {}