github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/localstore/txn.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 "fmt" 18 19 "github.com/insionng/yougam/libraries/juju/errors" 20 "github.com/insionng/yougam/libraries/ngaut/log" 21 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 22 ) 23 24 var ( 25 _ kv.Transaction = (*dbTxn)(nil) 26 ) 27 28 // dbTxn is not thread safe 29 type dbTxn struct { 30 us kv.UnionStore 31 store *dbStore // for commit 32 tid uint64 33 valid bool 34 version kv.Version // commit version 35 lockedKeys map[string]struct{} // origin version in snapshot 36 dirty bool 37 } 38 39 func newTxn(s *dbStore, ver kv.Version) *dbTxn { 40 txn := &dbTxn{ 41 us: kv.NewUnionStore(newSnapshot(s, ver)), 42 store: s, 43 tid: ver.Ver, 44 valid: true, 45 version: kv.MinVersion, 46 lockedKeys: make(map[string]struct{}), 47 } 48 log.Debugf("[kv] Begin txn:%d", txn.tid) 49 return txn 50 } 51 52 // Implement transaction interface 53 func (txn *dbTxn) Get(k kv.Key) ([]byte, error) { 54 log.Debugf("[kv] get key:% x, txn:%d", k, txn.tid) 55 return txn.us.Get(k) 56 } 57 58 func (txn *dbTxn) Set(k kv.Key, data []byte) error { 59 log.Debugf("[kv] set key:% x, txn:%d", k, txn.tid) 60 txn.dirty = true 61 return txn.us.Set(k, data) 62 } 63 64 func (txn *dbTxn) String() string { 65 return fmt.Sprintf("%d", txn.tid) 66 } 67 68 func (txn *dbTxn) Seek(k kv.Key) (kv.Iterator, error) { 69 log.Debugf("[kv] seek key:% x, txn:%d", k, txn.tid) 70 return txn.us.Seek(k) 71 } 72 73 func (txn *dbTxn) SeekReverse(k kv.Key) (kv.Iterator, error) { 74 log.Debugf("[kv] seek reverse key:% x, txn:%d", k, txn.tid) 75 return txn.us.SeekReverse(k) 76 } 77 78 func (txn *dbTxn) Delete(k kv.Key) error { 79 log.Debugf("[kv] delete key:% x, txn:%d", k, txn.tid) 80 txn.dirty = true 81 return txn.us.Delete(k) 82 } 83 84 func (txn *dbTxn) SetOption(opt kv.Option, val interface{}) { 85 txn.us.SetOption(opt, val) 86 } 87 88 func (txn *dbTxn) DelOption(opt kv.Option) { 89 txn.us.DelOption(opt) 90 } 91 92 func (txn *dbTxn) doCommit() error { 93 // check lazy condition pairs 94 if err := txn.us.CheckLazyConditionPairs(); err != nil { 95 return errors.Trace(err) 96 } 97 98 err := txn.us.WalkBuffer(func(k kv.Key, v []byte) error { 99 e := txn.LockKeys(k) 100 return errors.Trace(e) 101 }) 102 if err != nil { 103 return errors.Trace(err) 104 } 105 106 return txn.store.CommitTxn(txn) 107 } 108 109 func (txn *dbTxn) Commit() error { 110 if !txn.valid { 111 return errors.Trace(kv.ErrInvalidTxn) 112 } 113 log.Debugf("[kv] commit txn %d", txn.tid) 114 defer func() { 115 txn.close() 116 }() 117 118 return errors.Trace(txn.doCommit()) 119 } 120 121 func (txn *dbTxn) close() error { 122 txn.us.Release() 123 txn.lockedKeys = nil 124 txn.valid = false 125 return nil 126 } 127 128 func (txn *dbTxn) Rollback() error { 129 if !txn.valid { 130 return errors.Trace(kv.ErrInvalidTxn) 131 } 132 log.Warnf("[kv] Rollback txn %d", txn.tid) 133 return txn.close() 134 } 135 136 func (txn *dbTxn) LockKeys(keys ...kv.Key) error { 137 for _, key := range keys { 138 txn.lockedKeys[string(key)] = struct{}{} 139 } 140 return nil 141 } 142 143 func (txn *dbTxn) IsReadOnly() bool { 144 return !txn.dirty 145 } 146 147 func (txn *dbTxn) StartTS() uint64 { 148 return txn.tid 149 } 150 151 func (txn *dbTxn) GetClient() kv.Client { 152 return &dbClient{store: txn.store, regionInfo: txn.store.pd.GetRegionInfo()} 153 }