github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/client/client_test.go (about)

     1  // Copyright 2022 Matrix Origin
     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 client
    16  
    17  import (
    18  	"context"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/lni/goutils/leaktest"
    24  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    25  	"github.com/matrixorigin/matrixone/pkg/logutil"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    29  	"github.com/matrixorigin/matrixone/pkg/txn/clock"
    30  	"github.com/matrixorigin/matrixone/pkg/txn/rpc"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  func TestAdjustClient(t *testing.T) {
    36  	runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
    37  	c := &txnClient{}
    38  	c.adjust()
    39  	assert.NotNil(t, c.generator)
    40  	assert.NotNil(t, c.generator)
    41  }
    42  
    43  func TestNewTxn(t *testing.T) {
    44  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
    45  		logutil.GetPanicLogger(),
    46  		runtime.WithClock(clock.NewHLCClock(func() int64 {
    47  			return 1
    48  		}, 0)))
    49  	runtime.SetupProcessLevelRuntime(rt)
    50  	c := NewTxnClient(newTestTxnSender())
    51  	c.Resume()
    52  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
    53  	defer cancel()
    54  	tx, err := c.New(ctx, newTestTimestamp(0))
    55  	assert.Nil(t, err)
    56  	txnMeta := tx.(*txnOperator).mu.txn
    57  	assert.Equal(t, timestamp.Timestamp{PhysicalTime: 0}, txnMeta.SnapshotTS)
    58  	assert.NotEmpty(t, txnMeta.ID)
    59  	assert.Equal(t, txn.TxnStatus_Active, txnMeta.Status)
    60  }
    61  
    62  func TestNewTxnWithNormalStateWait(t *testing.T) {
    63  	defer leaktest.AfterTest(t)()
    64  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
    65  		logutil.GetPanicLogger(),
    66  		runtime.WithClock(clock.NewHLCClock(func() int64 {
    67  			return 1
    68  		}, 0)))
    69  	runtime.SetupProcessLevelRuntime(rt)
    70  	c := NewTxnClient(newTestTxnSender())
    71  	// Do not resume the txn client for now.
    72  	// c.Resume()
    73  	var wg sync.WaitGroup
    74  	for i := 0; i < 20; i++ {
    75  		wg.Add(1)
    76  		go func() {
    77  			defer wg.Done()
    78  			ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
    79  			defer cancel()
    80  			tx, err := c.New(ctx, newTestTimestamp(0))
    81  			assert.Nil(t, err)
    82  			txnMeta := tx.(*txnOperator).mu.txn
    83  			assert.Equal(t, int64(0), txnMeta.SnapshotTS.PhysicalTime)
    84  			assert.NotEmpty(t, txnMeta.ID)
    85  			assert.Equal(t, txn.TxnStatus_Active, txnMeta.Status)
    86  		}()
    87  	}
    88  	// Resume it now.
    89  	c.Resume()
    90  	wg.Wait()
    91  }
    92  
    93  func TestNewTxnWithNormalStateNoWait(t *testing.T) {
    94  	defer leaktest.AfterTest(t)()
    95  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
    96  		logutil.GetPanicLogger(),
    97  		runtime.WithClock(clock.NewHLCClock(func() int64 {
    98  			return 1
    99  		}, 0)))
   100  	runtime.SetupProcessLevelRuntime(rt)
   101  	c := NewTxnClient(newTestTxnSender(), WithNormalStateNoWait(true))
   102  	// Do not resume the txn client.
   103  	// c.Resume()
   104  	var wg sync.WaitGroup
   105  	for i := 0; i < 20; i++ {
   106  		wg.Add(1)
   107  		go func() {
   108  			defer wg.Done()
   109  			ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
   110  			defer cancel()
   111  			tx, err := c.New(ctx, newTestTimestamp(0))
   112  			assert.Error(t, err)
   113  			assert.Nil(t, tx)
   114  		}()
   115  	}
   116  	wg.Wait()
   117  }
   118  
   119  func TestNewTxnWithSnapshotTS(t *testing.T) {
   120  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
   121  		logutil.GetPanicLogger(),
   122  		runtime.WithClock(clock.NewHLCClock(func() int64 {
   123  			return 1
   124  		}, 0)))
   125  	runtime.SetupProcessLevelRuntime(rt)
   126  	c := NewTxnClient(newTestTxnSender())
   127  	c.Resume()
   128  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
   129  	defer cancel()
   130  	tx, err := c.New(ctx, newTestTimestamp(0), WithSnapshotTS(timestamp.Timestamp{PhysicalTime: 10}))
   131  	assert.Nil(t, err)
   132  	txnMeta := tx.(*txnOperator).mu.txn
   133  	assert.Equal(t, timestamp.Timestamp{PhysicalTime: 10}, txnMeta.SnapshotTS)
   134  	assert.NotEmpty(t, txnMeta.ID)
   135  	assert.Equal(t, txn.TxnStatus_Active, txnMeta.Status)
   136  }
   137  
   138  func TestTxnClientAbortAllRunningTxn(t *testing.T) {
   139  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
   140  		logutil.GetPanicLogger(),
   141  		runtime.WithClock(clock.NewHLCClock(func() int64 {
   142  			return 1
   143  		}, 0)))
   144  	runtime.SetupProcessLevelRuntime(rt)
   145  
   146  	c := NewTxnClient(newTestTxnSender())
   147  	c.Resume()
   148  
   149  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
   150  	defer cancel()
   151  	var ops []TxnOperator
   152  	for i := 0; i < 10; i++ {
   153  		op, err := c.New(ctx, newTestTimestamp(0))
   154  		assert.Nil(t, err)
   155  		ops = append(ops, op)
   156  	}
   157  	require.Equal(t, 10, len(c.(*txnClient).mu.activeTxns))
   158  
   159  	c.AbortAllRunningTxn()
   160  	require.Equal(t, 0, len(c.(*txnClient).mu.activeTxns))
   161  	for _, op := range ops {
   162  		assert.Equal(t, txn.TxnStatus_Aborted, op.(*txnOperator).mu.txn.Status)
   163  	}
   164  }
   165  
   166  func TestTxnClientPauseAndResume(t *testing.T) {
   167  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
   168  		logutil.GetPanicLogger(),
   169  		runtime.WithClock(clock.NewHLCClock(func() int64 {
   170  			return 1
   171  		}, 0)))
   172  	runtime.SetupProcessLevelRuntime(rt)
   173  	c := NewTxnClient(newTestTxnSender())
   174  
   175  	c.Pause()
   176  	require.Equal(t, paused, c.(*txnClient).mu.state)
   177  	c.Resume()
   178  	require.Equal(t, normal, c.(*txnClient).mu.state)
   179  }
   180  
   181  func TestLimit(t *testing.T) {
   182  	RunTxnTests(
   183  		func(tc TxnClient, ts rpc.TxnSender) {
   184  			ctx := context.Background()
   185  
   186  			c := make(chan struct{})
   187  			c2 := make(chan struct{})
   188  			n := 0
   189  			go func() {
   190  				defer close(c2)
   191  				for {
   192  					select {
   193  					case <-c:
   194  						return
   195  					default:
   196  						op, err := tc.New(ctx, newTestTimestamp(0))
   197  						require.NoError(t, err)
   198  						require.NoError(t, op.Rollback(ctx))
   199  						n++
   200  					}
   201  				}
   202  			}()
   203  			time.Sleep(time.Millisecond * 200)
   204  			close(c)
   205  			<-c2
   206  			require.True(t, n < 5)
   207  		},
   208  		WithTxnLimit(1))
   209  }
   210  
   211  func TestMaxActiveTxnWithWaitPrevClosed(t *testing.T) {
   212  	RunTxnTests(
   213  		func(tc TxnClient, ts rpc.TxnSender) {
   214  			ctx := context.Background()
   215  			op1, err := tc.New(ctx, newTestTimestamp(0), WithUserTxn())
   216  			require.NoError(t, err)
   217  
   218  			c := make(chan struct{})
   219  			go func() {
   220  				defer close(c)
   221  				_, err = tc.New(ctx, newTestTimestamp(0), WithUserTxn())
   222  				require.NoError(t, err)
   223  			}()
   224  
   225  			require.NoError(t, op1.Rollback(ctx))
   226  			<-c
   227  		},
   228  		WithMaxActiveTxn(1))
   229  }
   230  
   231  func TestMaxActiveTxnWithWaitTimeout(t *testing.T) {
   232  	RunTxnTests(
   233  		func(tc TxnClient, ts rpc.TxnSender) {
   234  			ctx := context.Background()
   235  			op1, err := tc.New(ctx, newTestTimestamp(0), WithUserTxn())
   236  			require.NoError(t, err)
   237  			defer func() {
   238  				require.NoError(t, op1.Rollback(ctx))
   239  			}()
   240  
   241  			ctx2, cancel := context.WithTimeout(context.Background(), time.Second)
   242  			defer cancel()
   243  			_, err = tc.New(ctx2, newTestTimestamp(0), WithUserTxn())
   244  			require.Error(t, err)
   245  		},
   246  		WithMaxActiveTxn(1))
   247  }