github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/go-themis/themis_lock_manager.go (about) 1 package themis 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "math" 7 "strings" 8 9 "github.com/insionng/yougam/libraries/juju/errors" 10 "github.com/insionng/yougam/libraries/ngaut/log" 11 "github.com/insionng/yougam/libraries/pingcap/go-hbase" 12 ) 13 14 var _ LockManager = (*themisLockManager)(nil) 15 16 type themisLockManager struct { 17 rpc *themisRPC 18 hbaseClient hbase.HBaseClient 19 } 20 21 func newThemisLockManager(rpc *themisRPC, hbaseCli hbase.HBaseClient) LockManager { 22 return &themisLockManager{ 23 rpc: rpc, 24 hbaseClient: hbaseCli, 25 } 26 } 27 28 func getDataColFromMetaCol(lockOrWriteCol hbase.Column) hbase.Column { 29 // get data column from lock column 30 // key is like => L:family#qual, #p:family#qual 31 parts := strings.Split(string(lockOrWriteCol.Qual), "#") 32 if len(parts) != 2 { 33 return lockOrWriteCol 34 } 35 c := hbase.Column{ 36 Family: []byte(parts[0]), 37 Qual: []byte(parts[1]), 38 } 39 return c 40 } 41 42 func getLocksFromResults(tbl []byte, lockKvs []*hbase.Kv, client *themisRPC) ([]Lock, error) { 43 var locks []Lock 44 for _, kv := range lockKvs { 45 col := &hbase.ColumnCoordinate{ 46 Table: tbl, 47 Row: kv.Row, 48 Column: hbase.Column{ 49 Family: kv.Family, 50 Qual: kv.Qual, 51 }, 52 } 53 if !isLockColumn(col.Column) { 54 return nil, errors.New("invalid lock") 55 } 56 l, err := parseLockFromBytes(kv.Value) 57 if err != nil { 58 return nil, errors.Trace(err) 59 } 60 cc := &hbase.ColumnCoordinate{ 61 Table: tbl, 62 Row: kv.Row, 63 Column: getDataColFromMetaCol(col.Column), 64 } 65 l.SetCoordinate(cc) 66 client.checkAndSetLockIsExpired(l) 67 locks = append(locks, l) 68 } 69 return locks, nil 70 } 71 72 func (m *themisLockManager) IsLockExists(cc *hbase.ColumnCoordinate, startTs, endTs uint64) (bool, error) { 73 get := hbase.NewGet(cc.Row) 74 get.AddTimeRange(startTs, endTs+1) 75 get.AddStringColumn(string(LockFamilyName), string(cc.Family)+"#"+string(cc.Qual)) 76 // check if lock exists 77 rs, err := m.hbaseClient.Get(string(cc.Table), get) 78 if err != nil { 79 return false, errors.Trace(err) 80 } 81 // primary lock has been released 82 if rs == nil { 83 return false, nil 84 } 85 return true, nil 86 } 87 88 func (m *themisLockManager) GetCommitTimestamp(cc *hbase.ColumnCoordinate, prewriteTs uint64) (uint64, error) { 89 g := hbase.NewGet(cc.Row) 90 // add put write column 91 qual := string(cc.Family) + "#" + string(cc.Qual) 92 g.AddStringColumn("#p", qual) 93 // add del write column 94 g.AddStringColumn("#d", qual) 95 // time range => [ours startTs, +Inf) 96 g.AddTimeRange(prewriteTs, math.MaxInt64) 97 g.SetMaxVersion(math.MaxInt32) 98 r, err := m.hbaseClient.Get(string(cc.Table), g) 99 if err != nil { 100 return 0, errors.Trace(err) 101 } 102 // may delete by other client 103 if r == nil { 104 return 0, nil 105 } 106 for _, kv := range r.SortedColumns { 107 for commitTs, val := range kv.Values { 108 var ts uint64 109 binary.Read(bytes.NewBuffer(val), binary.BigEndian, &ts) 110 if ts == prewriteTs { 111 // get this commit's commitTs 112 return commitTs, nil 113 } 114 } 115 } 116 // no such transction 117 return 0, nil 118 } 119 120 func (m *themisLockManager) CleanLock(cc *hbase.ColumnCoordinate, prewriteTs uint64) (uint64, Lock, error) { 121 l, err := m.rpc.getLockAndErase(cc, prewriteTs) 122 if err != nil { 123 return 0, nil, errors.Trace(err) 124 } 125 pl, _ := l.(*themisPrimaryLock) 126 // if primary lock is nil, means someothers have already committed 127 if pl == nil { 128 commitTs, err := m.GetCommitTimestamp(cc, prewriteTs) 129 if err != nil { 130 return 0, nil, errors.Trace(err) 131 } 132 return commitTs, nil, nil 133 } 134 return 0, pl, nil 135 } 136 137 func (m *themisLockManager) EraseLockAndData(cc *hbase.ColumnCoordinate, prewriteTs uint64) error { 138 log.Debugf("erase row=%q txn=%d", cc.Row, prewriteTs) 139 d := hbase.NewDelete(cc.Row) 140 d.AddColumnWithTimestamp(LockFamilyName, []byte(string(cc.Family)+"#"+string(cc.Qual)), prewriteTs) 141 d.AddColumnWithTimestamp(cc.Family, cc.Qual, prewriteTs) 142 ok, err := m.hbaseClient.Delete(string(cc.Table), d) 143 if !ok { 144 log.Error(err) 145 } 146 return errors.Trace(err) 147 }