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  }