github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/hbase/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 hbasekv
    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/go-hbase"
    22  	"github.com/insionng/yougam/libraries/pingcap/go-themis"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    24  )
    25  
    26  var (
    27  	_ kv.Transaction = (*hbaseTxn)(nil)
    28  )
    29  
    30  // dbTxn implements kv.Transacton. It is not thread safe.
    31  type hbaseTxn struct {
    32  	us        kv.UnionStore
    33  	txn       themis.Txn
    34  	store     *hbaseStore // for commit
    35  	storeName string
    36  	tid       uint64
    37  	valid     bool
    38  	version   kv.Version // commit version
    39  	dirty     bool
    40  }
    41  
    42  func newHbaseTxn(t themis.Txn, storeName string) *hbaseTxn {
    43  	return &hbaseTxn{
    44  		txn:       t,
    45  		valid:     true,
    46  		storeName: storeName,
    47  		tid:       t.GetStartTS(),
    48  		us:        kv.NewUnionStore(newHbaseSnapshot(t, storeName)),
    49  	}
    50  }
    51  
    52  // Implement transaction interface
    53  
    54  func (txn *hbaseTxn) Get(k kv.Key) ([]byte, error) {
    55  	log.Debugf("[kv] get key:%q, txn:%d", k, txn.tid)
    56  	return txn.us.Get(k)
    57  }
    58  
    59  func (txn *hbaseTxn) Set(k kv.Key, v []byte) error {
    60  	log.Debugf("[kv] set %q txn:%d", k, txn.tid)
    61  	txn.dirty = true
    62  	return txn.us.Set(k, v)
    63  }
    64  
    65  func (txn *hbaseTxn) String() string {
    66  	return fmt.Sprintf("%d", txn.tid)
    67  }
    68  
    69  func (txn *hbaseTxn) Seek(k kv.Key) (kv.Iterator, error) {
    70  	log.Debugf("[kv] seek %q txn:%d", k, txn.tid)
    71  	return txn.us.Seek(k)
    72  }
    73  
    74  func (txn *hbaseTxn) SeekReverse(k kv.Key) (kv.Iterator, error) {
    75  	log.Debugf("[kv] seek prev %q txn:%d", k, txn.tid)
    76  	return txn.us.SeekReverse(k)
    77  }
    78  
    79  func (txn *hbaseTxn) Delete(k kv.Key) error {
    80  	log.Debugf("[kv] delete %q txn:%d", k, txn.tid)
    81  	txn.dirty = true
    82  	return txn.us.Delete(k)
    83  }
    84  
    85  func (txn *hbaseTxn) SetOption(opt kv.Option, val interface{}) {
    86  	txn.us.SetOption(opt, val)
    87  }
    88  
    89  func (txn *hbaseTxn) DelOption(opt kv.Option) {
    90  	txn.us.DelOption(opt)
    91  }
    92  
    93  func (txn *hbaseTxn) doCommit() error {
    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  		row := append([]byte(nil), k...)
   100  		if len(v) == 0 { // Deleted marker
   101  			d := hbase.NewDelete(row)
   102  			d.AddStringColumn(hbaseColFamily, hbaseQualifier)
   103  			err := txn.txn.Delete(txn.storeName, d)
   104  			if err != nil {
   105  				return errors.Trace(err)
   106  			}
   107  		} else {
   108  			val := append([]byte(nil), v...)
   109  			p := hbase.NewPut(row)
   110  			p.AddValue(hbaseColFamilyBytes, hbaseQualifierBytes, val)
   111  			txn.txn.Put(txn.storeName, p)
   112  		}
   113  		return nil
   114  	})
   115  
   116  	if err != nil {
   117  		return errors.Trace(err)
   118  	}
   119  
   120  	err = txn.txn.Commit()
   121  	if err != nil {
   122  		log.Error(err)
   123  		return errors.Trace(err)
   124  	}
   125  
   126  	txn.version = kv.NewVersion(txn.txn.GetCommitTS())
   127  	log.Debugf("[kv] commit successfully, txn.version:%d", txn.version.Ver)
   128  	return nil
   129  }
   130  
   131  func (txn *hbaseTxn) Commit() error {
   132  	if !txn.valid {
   133  		return kv.ErrInvalidTxn
   134  	}
   135  	log.Debugf("[kv] start to commit txn %d", txn.tid)
   136  	defer func() {
   137  		txn.close()
   138  	}()
   139  	return txn.doCommit()
   140  }
   141  
   142  func (txn *hbaseTxn) close() error {
   143  	txn.us.Release()
   144  	txn.valid = false
   145  	return nil
   146  }
   147  
   148  //if fail, themis auto rollback
   149  func (txn *hbaseTxn) Rollback() error {
   150  	if !txn.valid {
   151  		return kv.ErrInvalidTxn
   152  	}
   153  	log.Warnf("[kv] Rollback txn %d", txn.tid)
   154  	return txn.close()
   155  }
   156  
   157  func (txn *hbaseTxn) LockKeys(keys ...kv.Key) error {
   158  	for _, key := range keys {
   159  		if err := txn.txn.LockRow(txn.storeName, key); err != nil {
   160  			return errors.Trace(err)
   161  		}
   162  	}
   163  	return nil
   164  }
   165  
   166  func (txn *hbaseTxn) IsReadOnly() bool {
   167  	return !txn.dirty
   168  }
   169  
   170  func (txn *hbaseTxn) StartTS() uint64 {
   171  	return txn.tid
   172  }
   173  
   174  func (txn *hbaseTxn) GetClient() kv.Client {
   175  	return &hbaseClient{}
   176  }
   177  
   178  type hbaseClient struct {
   179  }
   180  
   181  func (c *hbaseClient) SupportRequestType(reqType, subType int64) bool {
   182  	return false
   183  }
   184  
   185  func (c *hbaseClient) Send(req *kv.Request) kv.Response {
   186  	return nil
   187  }