github.com/matrixorigin/matrixone@v0.7.0/pkg/tests/txn/cluster_basic_test.go (about)

     1  // Copyright 2021 - 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 txn
    16  
    17  import (
    18  	"fmt"
    19  	"sync"
    20  	"testing"
    21  
    22  	"github.com/lni/goutils/leaktest"
    23  	"github.com/matrixorigin/matrixone/pkg/tests/service"
    24  	"github.com/matrixorigin/matrixone/pkg/txn/client"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  var (
    29  	testOptionsSet = map[string][]func(opts service.Options) service.Options{
    30  		"tae-cn-tae-dn": {useDistributedTAEEngine, useTAEStorage},
    31  	}
    32  )
    33  
    34  func TestBasicSingleShard(t *testing.T) {
    35  	defer leaktest.AfterTest(t)()
    36  	if testing.Short() {
    37  		t.Skip("skipping in short mode.")
    38  		return
    39  	}
    40  
    41  	// this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService.
    42  	// A Txn read and write will success.
    43  	for name, options := range testOptionsSet {
    44  		t.Run(name, func(t *testing.T) {
    45  			c, err := NewCluster(t,
    46  				getBasicClusterOptions(options...))
    47  			require.NoError(t, err)
    48  			defer c.Stop()
    49  			c.Start()
    50  
    51  			cli := c.NewClient()
    52  
    53  			key := "k"
    54  			value := "v"
    55  
    56  			checkRead(t, mustNewTxn(t, cli), key, "", nil, true)
    57  			checkWrite(t, mustNewTxn(t, cli), key, value, nil, true)
    58  			checkRead(t, mustNewTxn(t, cli), key, value, nil, true)
    59  		})
    60  	}
    61  }
    62  
    63  func TestBasicSingleShardCannotReadUncommittedValue(t *testing.T) {
    64  	defer leaktest.AfterTest(t)()
    65  	if testing.Short() {
    66  		t.Skip("skipping in short mode.")
    67  		return
    68  	}
    69  
    70  	// this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService.
    71  	// 1. start t1
    72  	// 2. start t2
    73  	// 3. t1 write
    74  	// 4. t2 can not read t1's write
    75  	for name, options := range testOptionsSet {
    76  		t.Run(name, func(t *testing.T) {
    77  			c, err := NewCluster(t,
    78  				getBasicClusterOptions(options...))
    79  			require.NoError(t, err)
    80  			defer c.Stop()
    81  			c.Start()
    82  
    83  			cli := c.NewClient()
    84  
    85  			key := "k"
    86  			value := "v"
    87  
    88  			t1 := mustNewTxn(t, cli)
    89  			t2 := mustNewTxn(t, cli)
    90  
    91  			checkWrite(t, t1, key, value, nil, false)
    92  			checkRead(t, t2, key, "", nil, true)
    93  
    94  			require.NoError(t, t1.Commit())
    95  		})
    96  	}
    97  }
    98  
    99  func TestWriteSkewIsAllowed(t *testing.T) {
   100  	defer leaktest.AfterTest(t)()
   101  	// this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService.
   102  	// 1. start t1
   103  	// 2. start t2
   104  	// 3. t1 reads x
   105  	// 4. t2 reads y
   106  	// 5. t1 writes x -> y
   107  	// 6. t2 writes y -> x
   108  	// 7. t1 commits
   109  	// 8. t2 commits
   110  	if testing.Short() {
   111  		t.Skip("skipping in short mode.")
   112  		return
   113  	}
   114  	for name, options := range testOptionsSet {
   115  		t.Run(name, func(t *testing.T) {
   116  			c, err := NewCluster(t,
   117  				getBasicClusterOptions(options...))
   118  			require.NoError(t, err)
   119  			defer c.Stop()
   120  			c.Start()
   121  
   122  			cli := c.NewClient()
   123  
   124  			k1 := "x"
   125  			k2 := "y"
   126  
   127  			checkWrite(t, mustNewTxn(t, cli), k1, "a", nil, true)
   128  			checkWrite(t, mustNewTxn(t, cli), k2, "b", nil, true)
   129  
   130  			t1 := mustNewTxn(t, cli)
   131  			t2 := mustNewTxn(t, cli)
   132  
   133  			x, err := t1.Read(k1)
   134  			require.NoError(t, err)
   135  			err = t1.Write(k2, x)
   136  			require.NoError(t, err)
   137  			y, err := t2.Read(k2)
   138  			require.NoError(t, err)
   139  			err = t2.Write(k1, y)
   140  			require.NoError(t, err)
   141  			err = t1.Commit()
   142  			require.NoError(t, err)
   143  			err = t2.Commit()
   144  			require.NoError(t, err)
   145  
   146  			checkRead(t, mustNewTxn(t, cli), k1, "b", nil, true)
   147  			checkRead(t, mustNewTxn(t, cli), k2, "a", nil, true)
   148  		})
   149  	}
   150  }
   151  
   152  func TestSingleShardWithCreateTable(t *testing.T) {
   153  	defer leaktest.AfterTest(t)()
   154  	if testing.Short() {
   155  		t.Skip("skipping in short mode.")
   156  		return
   157  	}
   158  
   159  	c, err := NewCluster(t,
   160  		getBasicClusterOptions(useTAEStorage, useDistributedTAEEngine))
   161  	require.NoError(t, err)
   162  	defer c.Stop()
   163  	c.Start()
   164  
   165  	cli := c.NewClient()
   166  
   167  	txn, err := cli.NewTxn()
   168  	require.NoError(t, err)
   169  	sqlTxn := txn.(SQLBasedTxn)
   170  
   171  	_, err = sqlTxn.ExecSQL("create database test_db")
   172  	require.NoError(t, err)
   173  	require.NoError(t, sqlTxn.Commit())
   174  
   175  	txn, err = cli.NewTxn()
   176  	require.NoError(t, err)
   177  	sqlTxn = txn.(SQLBasedTxn)
   178  	_, err = sqlTxn.ExecSQL("use test_db")
   179  	require.NoError(t, err)
   180  	require.NoError(t, sqlTxn.Commit())
   181  }
   182  
   183  // # issue for #7748
   184  // SQL statement here refers to func_aggr_avg.test
   185  func TestAggTable(t *testing.T) {
   186  	defer leaktest.AfterTest(t)()
   187  	if testing.Short() {
   188  		t.Skip("skipping in short mode.")
   189  		return
   190  	}
   191  
   192  	c, err := NewCluster(t,
   193  		getBasicClusterOptions(useTAEStorage, useDistributedTAEEngine))
   194  	require.NoError(t, err)
   195  	defer c.Stop()
   196  	c.Start()
   197  
   198  	cli1 := c.NewClient()
   199  	cli2 := c.NewClient()
   200  
   201  	txn1, err := cli1.NewTxn()
   202  	require.NoError(t, err)
   203  	txn2, err := cli2.NewTxn()
   204  	require.NoError(t, err)
   205  
   206  	sqlTxn1 := txn1.(SQLBasedTxn)
   207  	sqlTxn2 := txn2.(SQLBasedTxn)
   208  	var txnList []SQLBasedTxn = []SQLBasedTxn{sqlTxn1, sqlTxn2}
   209  	var tblList []string = []string{"t1", "t2"}
   210  	type avgline struct {
   211  		a int
   212  		b float64
   213  	}
   214  
   215  	_, err = sqlTxn1.ExecSQL("create database test_avg;")
   216  	require.NoError(t, err)
   217  	_, err = sqlTxn1.ExecSQL("use test_avg;")
   218  	require.NoError(t, err)
   219  	_, err = sqlTxn1.ExecSQL("CREATE TABLE t1 (a INT, b INT);")
   220  	require.NoError(t, err)
   221  	_, err = sqlTxn1.ExecSQL("INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8);")
   222  	require.NoError(t, err)
   223  	_, err = sqlTxn2.ExecSQL("CREATE TABLE t2 (a INT, b INT);")
   224  	require.NoError(t, err)
   225  	_, err = sqlTxn2.ExecSQL("INSERT INTO t2 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7);")
   226  	require.NoError(t, err)
   227  
   228  	wg := sync.WaitGroup{}
   229  	for i := 0; i < 2; i++ {
   230  		wg.Add(1)
   231  		go func(i int) {
   232  			defer wg.Done()
   233  			insertTable(txnList[i], t, tblList[i])
   234  		}(i)
   235  	}
   236  	wg.Wait()
   237  
   238  	for i := 0; i < 2; i++ {
   239  		wg.Add(1)
   240  		go func(i int, t *testing.T) {
   241  			defer wg.Done()
   242  			rows, err := txnList[i].ExecSQLQuery(fmt.Sprintf("SELECT DISTINCT a, AVG( b) FROM %s GROUP BY a HAVING AVG( b) > 50;", tblList[i]))
   243  			defer mustCloseRows(t, rows)
   244  			require.NoError(t, err)
   245  			var l avgline
   246  			if !rows.Next() {
   247  				rows.Close()
   248  			}
   249  			err = rows.Scan(&l.a, &l.b)
   250  			require.NoError(t, err)
   251  			if tblList[i] == "t1" {
   252  				require.Equal(t, 32768.5, l.b)
   253  			} else {
   254  				require.Equal(t, 32774.5, l.b)
   255  			}
   256  		}(i, t)
   257  	}
   258  	wg.Wait()
   259  
   260  	require.NoError(t, sqlTxn1.Commit())
   261  	require.NoError(t, sqlTxn2.Commit())
   262  }
   263  
   264  func checkRead(t *testing.T, txn Txn, key string, expectValue string, expectError error, commit bool) {
   265  	v, err := txn.Read(key)
   266  	defer func() {
   267  		if commit {
   268  			require.NoError(t, txn.Commit())
   269  		}
   270  	}()
   271  	require.Equal(t, expectError, err)
   272  	require.Equal(t, expectValue, v)
   273  }
   274  
   275  func checkWrite(t *testing.T, txn Txn, key, value string, expectError error, commit bool) {
   276  	defer func() {
   277  		if commit {
   278  			require.NoError(t, txn.Commit())
   279  		}
   280  	}()
   281  	require.Equal(t, expectError, txn.Write(key, value))
   282  }
   283  
   284  func getBasicClusterOptions(opts ...func(opts service.Options) service.Options) service.Options {
   285  	basic := service.DefaultOptions().
   286  		WithDNShardNum(1).
   287  		WithLogShardNum(1).
   288  		WithDNServiceNum(1).
   289  		WithLogServiceNum(3).
   290  		WithCNShardNum(1).
   291  		WithCNServiceNum(1)
   292  	for _, opt := range opts {
   293  		basic = opt(basic)
   294  	}
   295  	return basic
   296  }
   297  
   298  func useTAEStorage(opts service.Options) service.Options {
   299  	return opts.WithDNUseTAEStorage()
   300  }
   301  
   302  func useDistributedTAEEngine(opts service.Options) service.Options {
   303  	return opts.WithCNUseDistributedTAEEngine()
   304  }
   305  
   306  func mustNewTxn(t *testing.T, cli Client, options ...client.TxnOption) Txn {
   307  	txn, err := cli.NewTxn(options...)
   308  	require.NoError(t, err)
   309  	return txn
   310  }
   311  
   312  // helper function for TestAggTable
   313  func insertTable(s SQLBasedTxn, t *testing.T, tbl string) {
   314  	var arr []int = []int{8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}
   315  	for _, v := range arr {
   316  		if tbl == "t1" {
   317  			_, err := s.ExecSQL(fmt.Sprintf("INSERT INTO %s SELECT a, b+%d       FROM %s;", tbl, v, tbl))
   318  			require.NoError(t, err)
   319  		} else {
   320  			_, err := s.ExecSQL(fmt.Sprintf("INSERT INTO %s SELECT a, b+%d       FROM %s;", tbl, v+1, tbl))
   321  			require.NoError(t, err)
   322  		}
   323  	}
   324  }
   325  
   326  // helper function for TestAggTable