github.com/matrixorigin/matrixone@v1.2.0/pkg/incrservice/service_test.go (about)

     1  // Copyright 2023 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 incrservice
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/lni/goutils/leaktest"
    24  	"github.com/matrixorigin/matrixone/pkg/catalog"
    25  	"github.com/matrixorigin/matrixone/pkg/defines"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    27  	"github.com/matrixorigin/matrixone/pkg/txn/client"
    28  	"github.com/matrixorigin/matrixone/pkg/txn/rpc"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  func TestCreate(t *testing.T) {
    34  	runServiceTests(
    35  		t,
    36  		1,
    37  		func(
    38  			ctx context.Context,
    39  			ss []*service,
    40  			ops []client.TxnOperator) {
    41  			s := ss[0]
    42  			op := ops[0]
    43  
    44  			def := newTestTableDef(2)
    45  			require.NoError(t, s.Create(ctx, 0, def, op))
    46  
    47  			s.mu.Lock()
    48  			assert.Equal(t, 1, len(s.mu.tables))
    49  			assert.Equal(t, 1, len(s.mu.creates))
    50  			assert.Equal(t, 0, len(s.mu.deletes))
    51  			assert.Equal(t, 1, len(s.mu.creates[string(op.Txn().ID)]))
    52  			assert.Equal(t, 2, len(s.mu.tables[0].columns()))
    53  			s.mu.Unlock()
    54  			checkStoreCachesUncommitted(t, s.store.(*memStore), op, 2)
    55  
    56  			require.NoError(t, op.Commit(ctx))
    57  			s.mu.Lock()
    58  			assert.Equal(t, 1, len(s.mu.tables))
    59  			assert.Equal(t, 0, len(s.mu.creates))
    60  			assert.Equal(t, 0, len(s.mu.deletes))
    61  			s.mu.Unlock()
    62  			checkStoreCachesCommitted(t, s.store.(*memStore), 2)
    63  		})
    64  }
    65  
    66  func TestCreateOnOtherService(t *testing.T) {
    67  	runServiceTests(
    68  		t,
    69  		2,
    70  		func(
    71  			ctx context.Context,
    72  			ss []*service,
    73  			ops []client.TxnOperator) {
    74  			s := ss[0]
    75  			op := ops[0]
    76  			def := newTestTableDef(2)
    77  			require.NoError(t, s.Create(ctx, 0, def, op))
    78  			require.NoError(t, op.Commit(ctx))
    79  
    80  			s2 := ss[0]
    81  			_, err := s2.getCommittedTableCache(ctx, 0)
    82  			require.NoError(t, err)
    83  			s2.mu.Lock()
    84  			assert.Equal(t, 1, len(s2.mu.tables))
    85  			assert.Equal(t, 0, len(s2.mu.creates))
    86  			assert.Equal(t, 0, len(s2.mu.deletes))
    87  			s2.mu.Unlock()
    88  		})
    89  }
    90  
    91  func TestCreateWithTxnAborted(t *testing.T) {
    92  	runServiceTests(
    93  		t,
    94  		1,
    95  		func(
    96  			ctx context.Context,
    97  			ss []*service,
    98  			ops []client.TxnOperator) {
    99  			s := ss[0]
   100  			op := ops[0]
   101  			def := newTestTableDef(2)
   102  			require.NoError(t, s.Create(ctx, 0, def, op))
   103  
   104  			s.mu.Lock()
   105  			assert.Equal(t, 1, len(s.mu.tables))
   106  			assert.Equal(t, 1, len(s.mu.creates))
   107  			assert.Equal(t, 0, len(s.mu.deletes))
   108  			assert.Equal(t, 1, len(s.mu.creates[string(op.Txn().ID)]))
   109  			assert.Equal(t, 2, len(s.mu.tables[0].columns()))
   110  			s.mu.Unlock()
   111  			checkStoreCachesUncommitted(t, s.store.(*memStore), op, 2)
   112  
   113  			require.NoError(t, op.Rollback(ctx))
   114  			s.mu.Lock()
   115  			assert.Equal(t, 0, len(s.mu.creates))
   116  			assert.Equal(t, 0, len(s.mu.deletes))
   117  			s.mu.Unlock()
   118  			checkStoreCachesCommitted(t, s.store.(*memStore), 0)
   119  			assert.Equal(t, 0, len(s.mu.tables))
   120  		})
   121  }
   122  
   123  func TestDelete(t *testing.T) {
   124  	lazyDeleteInterval = time.Millisecond * 10
   125  	runServiceTests(
   126  		t,
   127  		2,
   128  		func(
   129  			ctx context.Context,
   130  			ss []*service,
   131  			ops []client.TxnOperator) {
   132  			s := ss[0]
   133  			op := ops[0]
   134  
   135  			def := newTestTableDef(2)
   136  			require.NoError(t, s.Create(ctx, 0, def, op))
   137  			require.NoError(t, op.Commit(ctx))
   138  			checkStoreCachesCommitted(t, s.store.(*memStore), 2)
   139  
   140  			s2 := ss[1]
   141  			op2 := ops[1]
   142  			require.NoError(t, s.Delete(ctx, 0, op2))
   143  			require.NoError(t, op2.Commit(ctx))
   144  			waitStoreCachesCommitted(t, s2.store.(*memStore), 0)
   145  		})
   146  }
   147  
   148  func TestDeleteWithTxnAborted(t *testing.T) {
   149  	lazyDeleteInterval = time.Millisecond * 10
   150  	runServiceTests(
   151  		t,
   152  		2,
   153  		func(
   154  			ctx context.Context,
   155  			ss []*service,
   156  			ops []client.TxnOperator) {
   157  			s := ss[0]
   158  			op := ops[0]
   159  
   160  			def := newTestTableDef(2)
   161  			require.NoError(t, s.Create(ctx, 0, def, op))
   162  			require.NoError(t, op.Commit(ctx))
   163  			checkStoreCachesCommitted(t, s.store.(*memStore), 2)
   164  
   165  			op2 := ops[1]
   166  			require.NoError(t, s.Delete(ctx, 0, op2))
   167  			require.NoError(t, op2.Rollback(ctx))
   168  			checkStoreCachesCommitted(t, s.store.(*memStore), 2)
   169  		})
   170  }
   171  
   172  func TestDeleteOnOtherService(t *testing.T) {
   173  	lazyDeleteInterval = time.Millisecond * 10
   174  	runServiceTests(
   175  		t,
   176  		2,
   177  		func(
   178  			ctx context.Context,
   179  			ss []*service,
   180  			ops []client.TxnOperator) {
   181  			s := ss[0]
   182  			op := ops[0]
   183  
   184  			def := newTestTableDef(2)
   185  			require.NoError(t, s.Create(ctx, 0, def, op))
   186  			require.NoError(t, op.Commit(ctx))
   187  			checkStoreCachesCommitted(t, s.store.(*memStore), 2)
   188  
   189  			s2 := ss[1]
   190  			op2 := ops[1]
   191  			require.NoError(t, s2.Delete(ctx, 0, op2))
   192  			require.NoError(t, op2.Commit(ctx))
   193  			waitStoreCachesCommitted(t, s2.store.(*memStore), 0)
   194  		})
   195  }
   196  
   197  func runServiceTests(
   198  	t *testing.T,
   199  	n int,
   200  	fn func(ctx context.Context, ss []*service, ops []client.TxnOperator),
   201  ) {
   202  	client.RunTxnTests(func(
   203  		tc client.TxnClient,
   204  		ts rpc.TxnSender) {
   205  		defer leaktest.AfterTest(t)()
   206  		ctx, cancel := context.WithTimeout(defines.AttachAccountId(context.Background(), catalog.System_Account), 10*time.Second)
   207  		defer cancel()
   208  
   209  		ss := make([]*service, 0, n)
   210  		ops := make([]client.TxnOperator, 0, n)
   211  		for i := 0; i < n; i++ {
   212  			store := NewMemStore()
   213  			ss = append(ss, NewIncrService("", store, Config{CountPerAllocate: 1}).(*service))
   214  
   215  			op, err := tc.New(ctx, timestamp.Timestamp{})
   216  			require.NoError(t, err)
   217  			ops = append(ops, op)
   218  		}
   219  		defer func() {
   220  			for _, s := range ss {
   221  				s.Close()
   222  			}
   223  		}()
   224  
   225  		fn(ctx, ss, ops)
   226  	})
   227  }
   228  
   229  func newTestTableDef(autoCols int) []AutoColumn {
   230  	var cols []AutoColumn
   231  	for i := 0; i < autoCols; i++ {
   232  		cols = append(cols, AutoColumn{
   233  			ColName: fmt.Sprintf("auto_%d", i),
   234  			Step:    1,
   235  			Offset:  0,
   236  		})
   237  	}
   238  	return cols
   239  }
   240  
   241  func waitStoreCachesCommitted(
   242  	_ *testing.T,
   243  	store *memStore,
   244  	n int) {
   245  	for {
   246  		store.Lock()
   247  		if len(store.caches[0]) == n {
   248  			store.Unlock()
   249  			return
   250  		}
   251  		store.Unlock()
   252  		time.Sleep(time.Millisecond * 10)
   253  	}
   254  }
   255  
   256  func checkStoreCachesCommitted(
   257  	t *testing.T,
   258  	store *memStore,
   259  	n int) {
   260  	store.Lock()
   261  	defer store.Unlock()
   262  	require.Equal(t, n, len(store.caches[0]))
   263  }
   264  
   265  func checkStoreCachesUncommitted(
   266  	t *testing.T,
   267  	store *memStore,
   268  	txnOp client.TxnOperator,
   269  	n int) {
   270  	store.Lock()
   271  	defer store.Unlock()
   272  	require.Equal(t, n, len(store.uncommitted[string(txnOp.Txn().ID)][0]))
   273  }