github.com/matrixorigin/matrixone@v1.2.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 "context" 19 "fmt" 20 "sync" 21 "testing" 22 "time" 23 24 "github.com/lni/goutils/leaktest" 25 "github.com/matrixorigin/matrixone/pkg/common/runtime" 26 "github.com/matrixorigin/matrixone/pkg/container/vector" 27 "github.com/matrixorigin/matrixone/pkg/tests/service" 28 "github.com/matrixorigin/matrixone/pkg/txn/client" 29 "github.com/matrixorigin/matrixone/pkg/util/executor" 30 "github.com/stretchr/testify/require" 31 ) 32 33 var ( 34 testOptionsSet = map[string][]func(opts service.Options) service.Options{ 35 "tae-cn-tae-dn": {useDistributedTAEEngine, useTAEStorage}, 36 } 37 ) 38 39 func TestBasicSingleShard(t *testing.T) { 40 defer leaktest.AfterTest(t)() 41 if testing.Short() { 42 t.Skip("skipping in short mode.") 43 return 44 } 45 ctx := context.Background() 46 47 // this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService. 48 // A Txn read and write will success. 49 for name, options := range testOptionsSet { 50 t.Run(name, func(t *testing.T) { 51 c, err := NewCluster(ctx, t, 52 getBasicClusterOptions(options...)) 53 require.NoError(t, err) 54 defer c.Stop() 55 c.Start() 56 57 cli := c.NewClient() 58 59 key := "k" 60 value := "v" 61 62 checkRead(t, mustNewTxn(t, cli), key, "", nil, true) 63 checkWrite(t, mustNewTxn(t, cli), key, value, nil, true) 64 checkRead(t, mustNewTxn(t, cli), key, value, nil, true) 65 }) 66 } 67 } 68 69 func TestBasicSingleShardCannotReadUncommittedValue(t *testing.T) { 70 defer leaktest.AfterTest(t)() 71 if testing.Short() { 72 t.Skip("skipping in short mode.") 73 return 74 } 75 ctx := context.Background() 76 77 // this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService. 78 // 1. start t1 79 // 2. start t2 80 // 3. t1 write 81 // 4. t2 can not read t1's write 82 for name, options := range testOptionsSet { 83 t.Run(name, func(t *testing.T) { 84 c, err := NewCluster(ctx, t, 85 getBasicClusterOptions(options...)) 86 require.NoError(t, err) 87 defer c.Stop() 88 c.Start() 89 90 cli := c.NewClient() 91 92 key := "k" 93 value := "v" 94 95 t1 := mustNewTxn(t, cli) 96 t2 := mustNewTxn(t, cli) 97 98 checkWrite(t, t1, key, value, nil, false) 99 checkRead(t, t2, key, "", nil, true) 100 101 require.NoError(t, t1.Commit()) 102 }) 103 } 104 } 105 106 func TestWriteSkewIsAllowed(t *testing.T) { 107 defer leaktest.AfterTest(t)() 108 // this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService. 109 // 1. start t1 110 // 2. start t2 111 // 3. t1 reads x 112 // 4. t2 reads y 113 // 5. t1 writes x -> y 114 // 6. t2 writes y -> x 115 // 7. t1 commits 116 // 8. t2 commits 117 if testing.Short() { 118 t.Skip("skipping in short mode.") 119 return 120 } 121 ctx := context.Background() 122 123 for name, options := range testOptionsSet { 124 t.Run(name, func(t *testing.T) { 125 c, err := NewCluster(ctx, t, 126 getBasicClusterOptions(options...)) 127 require.NoError(t, err) 128 defer c.Stop() 129 c.Start() 130 131 cli := c.NewClient() 132 133 k1 := "x" 134 k2 := "y" 135 136 checkWrite(t, mustNewTxn(t, cli), k1, "a", nil, true) 137 checkWrite(t, mustNewTxn(t, cli), k2, "b", nil, true) 138 139 t1 := mustNewTxn(t, cli) 140 t2 := mustNewTxn(t, cli) 141 142 x, err := t1.Read(k1) 143 require.NoError(t, err) 144 err = t1.Write(k2, x) 145 require.NoError(t, err) 146 y, err := t2.Read(k2) 147 require.NoError(t, err) 148 err = t2.Write(k1, y) 149 require.NoError(t, err) 150 err = t1.Commit() 151 require.NoError(t, err) 152 err = t2.Commit() 153 require.NoError(t, err) 154 155 checkRead(t, mustNewTxn(t, cli), k1, "b", nil, true) 156 checkRead(t, mustNewTxn(t, cli), k2, "a", nil, true) 157 }) 158 } 159 } 160 161 func TestBasicSingleShardWithInternalSQLExecutor(t *testing.T) { 162 if testing.Short() { 163 t.Skip("skipping in short mode.") 164 return 165 } 166 ctx := context.Background() 167 168 // this case will start a mo cluster with 1 CNService, 1 DNService and 3 LogService. 169 // A Txn read and write will success. 170 for name, options := range testOptionsSet { 171 t.Run(name, func(t *testing.T) { 172 c, err := NewCluster(ctx, t, 173 getBasicClusterOptions(options...)) 174 require.NoError(t, err) 175 defer c.Stop() 176 c.Start() 177 178 v, ok := runtime.ProcessLevelRuntime().GetGlobalVariables(runtime.InternalSQLExecutor) 179 if !ok { 180 panic("missing internal sql executor") 181 } 182 exec := v.(executor.SQLExecutor) 183 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 184 defer cancel() 185 exec.ExecTxn( 186 ctx, 187 func(te executor.TxnExecutor) error { 188 res, err := te.Exec("create database zx", executor.StatementOption{}) 189 require.NoError(t, err) 190 res.Close() 191 192 res, err = te.Exec("create table t1 (id int primary key, name varchar(255))", executor.StatementOption{}) 193 require.NoError(t, err) 194 res.Close() 195 196 res, err = te.Exec("insert into t1 values (1, 'a'),(2, 'b'),(3, 'c')", executor.StatementOption{}) 197 require.NoError(t, err) 198 require.Equal(t, uint64(3), res.AffectedRows) 199 res.Close() 200 201 res, err = te.Exec("select id,name from t1 order by id", executor.StatementOption{}) 202 require.NoError(t, err) 203 var ids []int32 204 var names []string 205 res.ReadRows(func(_ int, cols []*vector.Vector) bool { 206 ids = append(ids, executor.GetFixedRows[int32](cols[0])...) 207 names = append(names, executor.GetStringRows(cols[1])...) 208 return true 209 }) 210 require.Equal(t, []int32{1, 2, 3}, ids) 211 require.Equal(t, []string{"a", "b", "c"}, names) 212 res.Close() 213 return nil 214 }, 215 executor.Options{}.WithDatabase("zx")) 216 }) 217 } 218 } 219 220 func TestSingleShardWithCreateTable(t *testing.T) { 221 defer leaktest.AfterTest(t)() 222 if testing.Short() { 223 t.Skip("skipping in short mode.") 224 return 225 } 226 ctx := context.Background() 227 228 c, err := NewCluster(ctx, t, 229 getBasicClusterOptions(useTAEStorage, useDistributedTAEEngine)) 230 require.NoError(t, err) 231 defer c.Stop() 232 c.Start() 233 234 cli := c.NewClient() 235 236 txn, err := cli.NewTxn() 237 require.NoError(t, err) 238 sqlTxn := txn.(SQLBasedTxn) 239 240 _, err = sqlTxn.ExecSQL("create database test_db") 241 require.NoError(t, err) 242 require.NoError(t, sqlTxn.Commit()) 243 244 txn, err = cli.NewTxn() 245 require.NoError(t, err) 246 sqlTxn = txn.(SQLBasedTxn) 247 _, err = sqlTxn.ExecSQL("use test_db") 248 require.NoError(t, err) 249 require.NoError(t, sqlTxn.Commit()) 250 } 251 252 // # issue for #7748 253 // SQL statement here refers to func_aggr_avg.test 254 func TestAggTable(t *testing.T) { 255 defer leaktest.AfterTest(t)() 256 if testing.Short() { 257 t.Skip("skipping in short mode.") 258 return 259 } 260 ctx := context.Background() 261 262 c, err := NewCluster(ctx, t, 263 getBasicClusterOptions(useTAEStorage, useDistributedTAEEngine)) 264 require.NoError(t, err) 265 defer c.Stop() 266 c.Start() 267 268 cli1 := c.NewClient() 269 cli2 := c.NewClient() 270 271 txn1, err := cli1.NewTxn() 272 require.NoError(t, err) 273 txn2, err := cli2.NewTxn() 274 require.NoError(t, err) 275 276 sqlTxn1 := txn1.(SQLBasedTxn) 277 sqlTxn2 := txn2.(SQLBasedTxn) 278 var txnList []SQLBasedTxn = []SQLBasedTxn{sqlTxn1, sqlTxn2} 279 var tblList []string = []string{"t1", "t2"} 280 type avgline struct { 281 a int 282 b float64 283 } 284 285 _, err = sqlTxn1.ExecSQL("create database test_avg;") 286 require.NoError(t, err) 287 _, err = sqlTxn1.ExecSQL("use test_avg;") 288 require.NoError(t, err) 289 _, err = sqlTxn1.ExecSQL("CREATE TABLE t1 (a INT, b INT);") 290 require.NoError(t, err) 291 _, err = sqlTxn1.ExecSQL("INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8);") 292 require.NoError(t, err) 293 _, err = sqlTxn2.ExecSQL("CREATE TABLE t2 (a INT, b INT);") 294 require.NoError(t, err) 295 _, err = sqlTxn2.ExecSQL("INSERT INTO t2 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7);") 296 require.NoError(t, err) 297 298 wg := sync.WaitGroup{} 299 for i := 0; i < 2; i++ { 300 wg.Add(1) 301 go func(i int) { 302 defer wg.Done() 303 insertTable(txnList[i], t, tblList[i]) 304 }(i) 305 } 306 wg.Wait() 307 308 for i := 0; i < 2; i++ { 309 wg.Add(1) 310 go func(i int, t *testing.T) { 311 defer wg.Done() 312 rows, err := txnList[i].ExecSQLQuery(fmt.Sprintf("SELECT DISTINCT a, AVG( b) FROM %s GROUP BY a HAVING AVG( b) > 50;", tblList[i])) 313 defer mustCloseRows(t, rows) 314 defer func() { 315 err := rows.Err() 316 require.NoError(t, err) 317 }() 318 require.NoError(t, err) 319 var l avgline 320 if !rows.Next() { 321 return 322 } 323 err = rows.Scan(&l.a, &l.b) 324 require.NoError(t, err) 325 if tblList[i] == "t1" { 326 require.Equal(t, 32768.5, l.b) 327 } else { 328 require.Equal(t, 32774.5, l.b) 329 } 330 }(i, t) 331 } 332 wg.Wait() 333 334 require.NoError(t, sqlTxn1.Commit()) 335 require.NoError(t, sqlTxn2.Commit()) 336 } 337 338 func checkRead(t *testing.T, txn Txn, key string, expectValue string, expectError error, commit bool) { 339 v, err := txn.Read(key) 340 defer func() { 341 if commit { 342 require.NoError(t, txn.Commit()) 343 } 344 }() 345 require.Equal(t, expectError, err) 346 require.Equal(t, expectValue, v) 347 } 348 349 func checkWrite(t *testing.T, txn Txn, key, value string, expectError error, commit bool) { 350 defer func() { 351 if commit { 352 require.NoError(t, txn.Commit()) 353 } 354 }() 355 require.Equal(t, expectError, txn.Write(key, value)) 356 } 357 358 func getBasicClusterOptions(opts ...func(opts service.Options) service.Options) service.Options { 359 basic := service.DefaultOptions(). 360 WithTNShardNum(1). 361 WithLogShardNum(1). 362 WithTNServiceNum(1). 363 WithLogServiceNum(3). 364 WithCNShardNum(1). 365 WithCNServiceNum(1) 366 for _, opt := range opts { 367 basic = opt(basic) 368 } 369 return basic 370 } 371 372 func useTAEStorage(opts service.Options) service.Options { 373 return opts.WithTNUseTAEStorage() 374 } 375 376 func useDistributedTAEEngine(opts service.Options) service.Options { 377 return opts.WithCNUseDistributedTAEEngine() 378 } 379 380 func mustNewTxn(t *testing.T, cli Client, options ...client.TxnOption) Txn { 381 txn, err := cli.NewTxn(options...) 382 require.NoError(t, err) 383 return txn 384 } 385 386 // helper function for TestAggTable 387 func insertTable(s SQLBasedTxn, t *testing.T, tbl string) { 388 var arr []int = []int{8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768} 389 for _, v := range arr { 390 if tbl == "t1" { 391 _, err := s.ExecSQL(fmt.Sprintf("INSERT INTO %s SELECT a, b+%d FROM %s;", tbl, v, tbl)) 392 require.NoError(t, err) 393 } else { 394 _, err := s.ExecSQL(fmt.Sprintf("INSERT INTO %s SELECT a, b+%d FROM %s;", tbl, v+1, tbl)) 395 require.NoError(t, err) 396 } 397 } 398 } 399 400 // helper function for TestAggTable