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