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 }