github.com/KinWaiYuen/client-go/v2@v2.5.4/txnkv/transaction/test_probe.go (about)

     1  // Copyright 2021 TiKV Authors
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package transaction
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"sync/atomic"
    21  	"time"
    22  
    23  	"github.com/KinWaiYuen/client-go/v2/internal/locate"
    24  	"github.com/KinWaiYuen/client-go/v2/internal/retry"
    25  	"github.com/KinWaiYuen/client-go/v2/internal/unionstore"
    26  	"github.com/KinWaiYuen/client-go/v2/tikvrpc"
    27  	"github.com/KinWaiYuen/client-go/v2/txnkv/txnsnapshot"
    28  	"github.com/pingcap/errors"
    29  )
    30  
    31  // TxnProbe wraps a txn and exports internal states for testing purpose.
    32  type TxnProbe struct {
    33  	*KVTxn
    34  }
    35  
    36  // SetStartTS resets the txn's start ts.
    37  func (txn TxnProbe) SetStartTS(ts uint64) {
    38  	txn.startTS = ts
    39  }
    40  
    41  // GetCommitTS returns the commit ts.
    42  func (txn TxnProbe) GetCommitTS() uint64 {
    43  	return txn.commitTS
    44  }
    45  
    46  // GetUnionStore returns transaction's embedded unionstore.
    47  func (txn TxnProbe) GetUnionStore() *unionstore.KVUnionStore {
    48  	return txn.us
    49  }
    50  
    51  // IsAsyncCommit returns if the txn is committed using async commit.
    52  func (txn TxnProbe) IsAsyncCommit() bool {
    53  	return txn.committer.isAsyncCommit()
    54  }
    55  
    56  // NewCommitter creates an committer.
    57  func (txn TxnProbe) NewCommitter(sessionID uint64) (CommitterProbe, error) {
    58  	committer, err := newTwoPhaseCommitterWithInit(txn.KVTxn, sessionID)
    59  	return CommitterProbe{twoPhaseCommitter: committer}, err
    60  }
    61  
    62  // GetCommitter returns the transaction committer.
    63  func (txn TxnProbe) GetCommitter() CommitterProbe {
    64  	return CommitterProbe{txn.committer}
    65  }
    66  
    67  // SetCommitter sets the bind committer of a transaction.
    68  func (txn TxnProbe) SetCommitter(committer CommitterProbe) {
    69  	txn.committer = committer.twoPhaseCommitter
    70  }
    71  
    72  // CollectLockedKeys returns all locked keys of a transaction.
    73  func (txn TxnProbe) CollectLockedKeys() [][]byte {
    74  	return txn.collectLockedKeys()
    75  }
    76  
    77  // BatchGetSingleRegion gets a batch of keys from a region.
    78  func (txn TxnProbe) BatchGetSingleRegion(bo *retry.Backoffer, region locate.RegionVerID, keys [][]byte, collect func([]byte, []byte)) error {
    79  	snapshot := txnsnapshot.SnapshotProbe{KVSnapshot: txn.GetSnapshot()}
    80  
    81  	return snapshot.BatchGetSingleRegion(bo, region, keys, collect)
    82  }
    83  
    84  // NewScanner returns a scanner to iterate given key range.
    85  func (txn TxnProbe) NewScanner(start, end []byte, batchSize int, reverse bool) (*txnsnapshot.Scanner, error) {
    86  	snapshot := txnsnapshot.SnapshotProbe{KVSnapshot: txn.GetSnapshot()}
    87  	return snapshot.NewScanner(start, end, batchSize, reverse)
    88  }
    89  
    90  // GetStartTime returns the time when txn starts.
    91  func (txn TxnProbe) GetStartTime() time.Time {
    92  	return txn.startTime
    93  }
    94  
    95  func newTwoPhaseCommitterWithInit(txn *KVTxn, sessionID uint64) (*twoPhaseCommitter, error) {
    96  	c, err := newTwoPhaseCommitter(txn, sessionID)
    97  	if err != nil {
    98  		return nil, errors.Trace(err)
    99  	}
   100  	if err = c.initKeysAndMutations(); err != nil {
   101  		return nil, errors.Trace(err)
   102  	}
   103  	return c, nil
   104  }
   105  
   106  // CommitterProbe wraps a 2PC committer and exports internal states for testing purpose.
   107  type CommitterProbe struct {
   108  	*twoPhaseCommitter
   109  }
   110  
   111  // InitKeysAndMutations prepares the committer for commit.
   112  func (c CommitterProbe) InitKeysAndMutations() error {
   113  	return c.initKeysAndMutations()
   114  }
   115  
   116  // SetPrimaryKey resets the committer's commit ts.
   117  func (c CommitterProbe) SetPrimaryKey(key []byte) {
   118  	c.primaryKey = key
   119  }
   120  
   121  // GetPrimaryKey returns primary key of the committer.
   122  func (c CommitterProbe) GetPrimaryKey() []byte {
   123  	return c.primaryKey
   124  }
   125  
   126  // GetMutations returns the mutation buffer to commit.
   127  func (c CommitterProbe) GetMutations() CommitterMutations {
   128  	return c.mutations
   129  }
   130  
   131  // SetMutations replace the mutation buffer.
   132  func (c CommitterProbe) SetMutations(muts CommitterMutations) {
   133  	c.mutations = muts.(*memBufferMutations)
   134  }
   135  
   136  // SetCommitTS resets the committer's commit ts.
   137  func (c CommitterProbe) SetCommitTS(ts uint64) {
   138  	atomic.StoreUint64(&c.commitTS, ts)
   139  }
   140  
   141  // GetCommitTS returns the commit ts of the committer.
   142  func (c CommitterProbe) GetCommitTS() uint64 {
   143  	return atomic.LoadUint64(&c.commitTS)
   144  }
   145  
   146  // GetMinCommitTS returns the minimal commit ts can be used.
   147  func (c CommitterProbe) GetMinCommitTS() uint64 {
   148  	return c.minCommitTS
   149  }
   150  
   151  // SetMinCommitTS sets the minimal commit ts can be used.
   152  func (c CommitterProbe) SetMinCommitTS(ts uint64) {
   153  	c.minCommitTS = ts
   154  }
   155  
   156  // SetMaxCommitTS sets the max commit ts can be used.
   157  func (c CommitterProbe) SetMaxCommitTS(ts uint64) {
   158  	c.maxCommitTS = ts
   159  }
   160  
   161  // SetSessionID sets the session id of the committer.
   162  func (c CommitterProbe) SetSessionID(id uint64) {
   163  	c.sessionID = id
   164  }
   165  
   166  // GetForUpdateTS returns the pessimistic ForUpdate ts.
   167  func (c CommitterProbe) GetForUpdateTS() uint64 {
   168  	return c.forUpdateTS
   169  }
   170  
   171  // SetForUpdateTS sets pessimistic ForUpdate ts.
   172  func (c CommitterProbe) SetForUpdateTS(ts uint64) {
   173  	c.forUpdateTS = ts
   174  }
   175  
   176  // GetStartTS returns the start ts of the transaction.
   177  func (c CommitterProbe) GetStartTS() uint64 {
   178  	return c.startTS
   179  }
   180  
   181  // GetLockTTL returns the lock ttl duration of the transaction.
   182  func (c CommitterProbe) GetLockTTL() uint64 {
   183  	return c.lockTTL
   184  }
   185  
   186  // SetLockTTL sets the lock ttl duration.
   187  func (c CommitterProbe) SetLockTTL(ttl uint64) {
   188  	c.lockTTL = ttl
   189  }
   190  
   191  // SetLockTTLByTimeAndSize sets the lock ttl duration by time and size.
   192  func (c CommitterProbe) SetLockTTLByTimeAndSize(start time.Time, size int) {
   193  	c.lockTTL = txnLockTTL(start, size)
   194  }
   195  
   196  // SetTxnSize resets the txn size of the committer and updates lock TTL.
   197  func (c CommitterProbe) SetTxnSize(sz int) {
   198  	c.txnSize = sz
   199  	c.lockTTL = txnLockTTL(c.txn.startTime, sz)
   200  }
   201  
   202  // SetUseAsyncCommit enables async commit feature.
   203  func (c CommitterProbe) SetUseAsyncCommit() {
   204  	c.useAsyncCommit = 1
   205  }
   206  
   207  // Execute runs the commit process.
   208  func (c CommitterProbe) Execute(ctx context.Context) error {
   209  	return c.execute(ctx)
   210  }
   211  
   212  // PrewriteAllMutations performs the first phase of commit.
   213  func (c CommitterProbe) PrewriteAllMutations(ctx context.Context) error {
   214  	return c.PrewriteMutations(ctx, c.mutations)
   215  }
   216  
   217  // PrewriteMutations performs the first phase of commit for given keys.
   218  func (c CommitterProbe) PrewriteMutations(ctx context.Context, mutations CommitterMutations) error {
   219  	return c.prewriteMutations(retry.NewBackofferWithVars(ctx, PrewriteMaxBackoff, nil), mutations)
   220  }
   221  
   222  // CommitMutations performs the second phase of commit.
   223  func (c CommitterProbe) CommitMutations(ctx context.Context) error {
   224  	return c.commitMutations(retry.NewBackofferWithVars(ctx, int(atomic.LoadUint64(&CommitMaxBackoff)), nil), c.mutationsOfKeys([][]byte{c.primaryKey}))
   225  }
   226  
   227  // MutationsOfKeys returns mutations match the keys.
   228  func (c CommitterProbe) MutationsOfKeys(keys [][]byte) CommitterMutations {
   229  	return c.mutationsOfKeys(keys)
   230  }
   231  
   232  // PessimisticRollbackMutations rolls mutations back.
   233  func (c CommitterProbe) PessimisticRollbackMutations(ctx context.Context, muts CommitterMutations) error {
   234  	return c.pessimisticRollbackMutations(retry.NewBackofferWithVars(ctx, pessimisticRollbackMaxBackoff, nil), muts)
   235  }
   236  
   237  // Cleanup cleans dirty data of a committer.
   238  func (c CommitterProbe) Cleanup(ctx context.Context) {
   239  	c.cleanup(ctx)
   240  	c.cleanWg.Wait()
   241  }
   242  
   243  // WaitCleanup waits for the committer to complete.
   244  func (c CommitterProbe) WaitCleanup() {
   245  	c.cleanWg.Wait()
   246  }
   247  
   248  // IsOnePC returns if the committer is using one PC.
   249  func (c CommitterProbe) IsOnePC() bool {
   250  	return c.isOnePC()
   251  }
   252  
   253  // BuildPrewriteRequest builds rpc request for mutation.
   254  func (c CommitterProbe) BuildPrewriteRequest(regionID, regionConf, regionVersion uint64, mutations CommitterMutations, txnSize uint64) *tikvrpc.Request {
   255  	var batch batchMutations
   256  	batch.mutations = mutations
   257  	batch.region = locate.NewRegionVerID(regionID, regionConf, regionVersion)
   258  	for _, key := range mutations.GetKeys() {
   259  		if bytes.Equal(key, c.primary()) {
   260  			batch.isPrimary = true
   261  			break
   262  		}
   263  	}
   264  	return c.buildPrewriteRequest(batch, txnSize)
   265  }
   266  
   267  // IsAsyncCommit returns if the committer uses async commit.
   268  func (c CommitterProbe) IsAsyncCommit() bool {
   269  	return c.isAsyncCommit()
   270  }
   271  
   272  // CheckAsyncCommit returns if async commit is available.
   273  func (c CommitterProbe) CheckAsyncCommit() bool {
   274  	return c.checkAsyncCommit()
   275  }
   276  
   277  // GetOnePCCommitTS returns the commit ts of one pc.
   278  func (c CommitterProbe) GetOnePCCommitTS() uint64 {
   279  	return c.onePCCommitTS
   280  }
   281  
   282  // IsTTLUninitialized returns if the TTL manager is uninitialized.
   283  func (c CommitterProbe) IsTTLUninitialized() bool {
   284  	state := atomic.LoadUint32((*uint32)(&c.ttlManager.state))
   285  	return state == uint32(stateUninitialized)
   286  }
   287  
   288  // IsTTLRunning returns if the TTL manager is running state.
   289  func (c CommitterProbe) IsTTLRunning() bool {
   290  	state := atomic.LoadUint32((*uint32)(&c.ttlManager.state))
   291  	return state == uint32(stateRunning)
   292  }
   293  
   294  // CloseTTLManager closes the TTL manager.
   295  func (c CommitterProbe) CloseTTLManager() {
   296  	c.ttlManager.close()
   297  }
   298  
   299  // GetUndeterminedErr returns the encountered undetermined error (if any).
   300  func (c CommitterProbe) GetUndeterminedErr() error {
   301  	c.mu.RLock()
   302  	defer c.mu.RUnlock()
   303  	return c.mu.undeterminedErr
   304  }
   305  
   306  // SetNoFallBack disallows async commit to fall back to normal mode.
   307  func (c CommitterProbe) SetNoFallBack() {
   308  	c.testingKnobs.noFallBack = true
   309  }
   310  
   311  // SetPrimaryKeyBlocker is used to block committer after primary is sent.
   312  func (c CommitterProbe) SetPrimaryKeyBlocker(ac, bk chan struct{}) {
   313  	c.testingKnobs.acAfterCommitPrimary = ac
   314  	c.testingKnobs.bkAfterCommitPrimary = bk
   315  }
   316  
   317  // CleanupMutations performs the clean up phase.
   318  func (c CommitterProbe) CleanupMutations(ctx context.Context) error {
   319  	bo := retry.NewBackofferWithVars(ctx, cleanupMaxBackoff, nil)
   320  	return c.cleanupMutations(bo, c.mutations)
   321  }
   322  
   323  // SendTxnHeartBeat renews a txn's ttl.
   324  func SendTxnHeartBeat(bo *retry.Backoffer, store kvstore, primary []byte, startTS, ttl uint64) (newTTL uint64, stopHeartBeat bool, err error) {
   325  	return sendTxnHeartBeat(bo, store, primary, startTS, ttl)
   326  }
   327  
   328  // ConfigProbe exposes configurations and global variables for testing purpose.
   329  type ConfigProbe struct{}
   330  
   331  // GetTxnCommitBatchSize returns the batch size to commit txn.
   332  func (c ConfigProbe) GetTxnCommitBatchSize() uint64 {
   333  	return txnCommitBatchSize
   334  }
   335  
   336  // GetPessimisticLockMaxBackoff returns pessimisticLockMaxBackoff
   337  func (c ConfigProbe) GetPessimisticLockMaxBackoff() int {
   338  	return pessimisticLockMaxBackoff
   339  }
   340  
   341  // GetDefaultLockTTL returns the default lock TTL.
   342  func (c ConfigProbe) GetDefaultLockTTL() uint64 {
   343  	return defaultLockTTL
   344  }
   345  
   346  // GetTTLFactor returns the factor to calculate txn TTL.
   347  func (c ConfigProbe) GetTTLFactor() int {
   348  	return ttlFactor
   349  }
   350  
   351  // LoadPreSplitDetectThreshold returns presplit detect threshold config.
   352  func (c ConfigProbe) LoadPreSplitDetectThreshold() uint32 {
   353  	return atomic.LoadUint32(&preSplitDetectThreshold)
   354  }
   355  
   356  // StorePreSplitDetectThreshold updates presplit detect threshold config.
   357  func (c ConfigProbe) StorePreSplitDetectThreshold(v uint32) {
   358  	atomic.StoreUint32(&preSplitDetectThreshold, v)
   359  }
   360  
   361  // LoadPreSplitSizeThreshold returns presplit size threshold config.
   362  func (c ConfigProbe) LoadPreSplitSizeThreshold() uint32 {
   363  	return atomic.LoadUint32(&preSplitSizeThreshold)
   364  }
   365  
   366  // StorePreSplitSizeThreshold updates presplit size threshold config.
   367  func (c ConfigProbe) StorePreSplitSizeThreshold(v uint32) {
   368  	atomic.StoreUint32(&preSplitSizeThreshold, v)
   369  }