github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/chaos/cases/generator.go (about)

     1  // Copyright 2021 PingCAP, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package main
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"math/rand"
    20  
    21  	config2 "github.com/pingcap/tiflow/dm/config"
    22  )
    23  
    24  const (
    25  	source1 = iota
    26  	source2
    27  	source3
    28  )
    29  
    30  // SQL represents sql statement for a source.
    31  type SQL struct {
    32  	statement string
    33  	source    int
    34  }
    35  
    36  // SQLs represents sql statements in a group.
    37  type SQLs []SQL
    38  
    39  // Case represents a sqls test case.
    40  type Case []SQLs
    41  
    42  var (
    43  	// add some flags column, so we can make sure the order of new column in optimsitic.
    44  	preSQLs1 = SQLs{
    45  		{"ALTER TABLE %s.%s ADD COLUMN case3_flag1 INT, ADD COLUMN case3_flag2 INT, ADD COLUMN case3_flag3 INT", source1},
    46  		{"ALTER TABLE %s.%s ADD COLUMN case3_flag1 INT, ADD COLUMN case3_flag2 INT, ADD COLUMN case3_flag3 INT", source2},
    47  		{"ALTER TABLE %s.%s ADD COLUMN case3_flag1 INT, ADD COLUMN case3_flag2 INT, ADD COLUMN case3_flag3 INT", source3},
    48  		{"ALTER TABLE %s.%s ADD COLUMN case4_flag1 INT, ADD COLUMN case4_flag2 INT, ADD COLUMN case4_flag3 INT", source1},
    49  		{"ALTER TABLE %s.%s ADD COLUMN case4_flag1 INT, ADD COLUMN case4_flag2 INT, ADD COLUMN case4_flag3 INT", source2},
    50  		{"ALTER TABLE %s.%s ADD COLUMN case4_flag1 INT, ADD COLUMN case4_flag2 INT, ADD COLUMN case4_flag3 INT", source3},
    51  		{"ALTER TABLE %s.%s ADD COLUMN case5_flag1 INT, ADD COLUMN case5_flag2 INT, ADD COLUMN case5_flag3 INT;", source1},
    52  		{"ALTER TABLE %s.%s ADD COLUMN case5_flag1 INT, ADD COLUMN case5_flag2 INT, ADD COLUMN case5_flag3 INT;", source2},
    53  		{"ALTER TABLE %s.%s ADD COLUMN case5_flag1 INT, ADD COLUMN case5_flag2 INT, ADD COLUMN case5_flag3 INT;", source3},
    54  		{"ALTER TABLE %s.%s ADD COLUMN case9_flag INT;", source1},
    55  		{"ALTER TABLE %s.%s ADD COLUMN case9_flag INT;", source2},
    56  		{"ALTER TABLE %s.%s ADD COLUMN case9_flag INT;", source3},
    57  	}
    58  
    59  	// ALL ADD COLUMN, ALL DROP COLUMN.
    60  	case1 = Case{
    61  		{{"ALTER TABLE %s.%s ADD COLUMN case1 INT;", source1}},
    62  		{{"ALTER TABLE %s.%s ADD COLUMN case1 INT;", source2}},
    63  		{{"ALTER TABLE %s.%s ADD COLUMN case1 INT;", source3}},
    64  		{{"ALTER TABLE %s.%s DROP COLUMN case1;", source1}},
    65  		{{"ALTER TABLE %s.%s DROP COLUMN case1;", source2}},
    66  		{{"ALTER TABLE %s.%s DROP COLUMN case1;", source3}},
    67  	}
    68  	// ADD COLUMN, DROP COLUMN for one source.
    69  	case2 = Case{
    70  		{{"ALTER TABLE %s.%s ADD COLUMN case2 INT;", source1}},
    71  		{{"ALTER TABLE %s.%s DROP COLUMN case2;", source1}},
    72  	}
    73  	// ADD columns out of order.
    74  	case3 = Case{
    75  		{
    76  			{"ALTER TABLE %s.%s DROP COLUMN case3_1;", source1},
    77  			{"ALTER TABLE %s.%s DROP COLUMN case3_2;", source1},
    78  			{"ALTER TABLE %s.%s DROP COLUMN case3_3;", source1},
    79  			{"ALTER TABLE %s.%s DROP COLUMN case3_1;", source2},
    80  			{"ALTER TABLE %s.%s DROP COLUMN case3_2;", source2},
    81  			{"ALTER TABLE %s.%s DROP COLUMN case3_3;", source2},
    82  			{"ALTER TABLE %s.%s DROP COLUMN case3_1;", source3},
    83  			{"ALTER TABLE %s.%s DROP COLUMN case3_2;", source3},
    84  			{"ALTER TABLE %s.%s DROP COLUMN case3_3;", source3},
    85  		},
    86  		{{"ALTER TABLE %s.%s ADD COLUMN case3_1 INT AFTER case3_flag1;", source1}},
    87  		{{"ALTER TABLE %s.%s ADD COLUMN case3_2 INT AFTER case3_flag2;", source2}},
    88  		{{"ALTER TABLE %s.%s ADD COLUMN case3_3 INT AFTER case3_flag3;", source3}},
    89  		{{"ALTER TABLE %s.%s ADD COLUMN case3_2 INT AFTER case3_flag2;", source1}},
    90  		{{"ALTER TABLE %s.%s ADD COLUMN case3_3 INT AFTER case3_flag3;", source2}},
    91  		{{"ALTER TABLE %s.%s ADD COLUMN case3_1 INT AFTER case3_flag1;", source3}},
    92  		{{"ALTER TABLE %s.%s ADD COLUMN case3_3 INT AFTER case3_flag3;", source1}},
    93  		{{"ALTER TABLE %s.%s ADD COLUMN case3_1 INT AFTER case3_flag1;", source2}},
    94  		{{"ALTER TABLE %s.%s ADD COLUMN case3_2 INT AFTER case3_flag2;", source3}},
    95  	}
    96  	// MULTIPLE ADD COLUMN out of order.
    97  	case4 = Case{
    98  		{
    99  			{"ALTER TABLE %s.%s DROP COLUMN case4_1, DROP COLUMN case4_2, DROP COLUMN case4_3;", source1},
   100  			{"ALTER TABLE %s.%s DROP COLUMN case4_1, DROP COLUMN case4_2, DROP COLUMN case4_3;", source2},
   101  			{"ALTER TABLE %s.%s DROP COLUMN case4_1, DROP COLUMN case4_2, DROP COLUMN case4_3;", source3},
   102  		},
   103  		{{"ALTER TABLE %s.%s ADD COLUMN case4_1 INT AFTER case4_flag1, ADD COLUMN case4_2 INT AFTER case4_flag2, ADD COLUMN case4_3 INT AFTER case4_flag3;", source1}},
   104  		{{"ALTER TABLE %s.%s ADD COLUMN case4_2 INT AFTER case4_flag2, ADD COLUMN case4_3 INT AFTER case4_flag3, ADD COLUMN case4_1 INT AFTER case4_flag1;", source2}},
   105  		{{"ALTER TABLE %s.%s ADD COLUMN case4_3 INT AFTER case4_flag3, ADD COLUMN case4_1 INT AFTER case4_flag1, ADD COLUMN case4_2 INT AFTER case4_flag2;", source3}},
   106  	}
   107  	// MULTIPLE ADD COLUMN vs ADD columns.
   108  	case5 = Case{
   109  		{
   110  			{"ALTER TABLE %s.%s DROP COLUMN case5_1;", source1},
   111  			{"ALTER TABLE %s.%s DROP COLUMN case5_2;", source1},
   112  			{"ALTER TABLE %s.%s DROP COLUMN case5_3;", source1},
   113  			{"ALTER TABLE %s.%s DROP COLUMN case5_1;", source2},
   114  			{"ALTER TABLE %s.%s DROP COLUMN case5_2;", source2},
   115  			{"ALTER TABLE %s.%s DROP COLUMN case5_3;", source2},
   116  			{"ALTER TABLE %s.%s DROP COLUMN case5_1;", source3},
   117  			{"ALTER TABLE %s.%s DROP COLUMN case5_2;", source3},
   118  			{"ALTER TABLE %s.%s DROP COLUMN case5_3;", source3},
   119  		},
   120  		{{"ALTER TABLE %s.%s ADD COLUMN case5_1 INT AFTER case5_flag1;", source1}},
   121  		{{"ALTER TABLE %s.%s ADD COLUMN case5_2 INT AFTER case5_flag2, ADD COLUMN case5_1 INT AFTER case5_flag1;", source2}},
   122  		{{"ALTER TABLE %s.%s ADD COLUMN case5_3 INT AFTER case5_flag3, ADD COLUMN case5_1 INT AFTER case5_flag1, ADD COLUMN case5_2 INT AFTER case5_flag2;", source3}},
   123  		{{"ALTER TABLE %s.%s ADD COLUMN case5_3 INT AFTER case5_flag3;", source2}},
   124  		{{"ALTER TABLE %s.%s ADD COLUMN case5_2 INT AFTER case5_flag2, ADD COLUMN case5_3 INT AFTER case5_flag3;", source1}},
   125  	}
   126  	// ALL ADD INDEX, ALL DROP INDEX.
   127  	case6 = Case{
   128  		{{"ALTER TABLE %s.%s ADD INDEX case6_idx(case3_flag1);", source1}},
   129  		{{"ALTER TABLE %s.%s ADD INDEX case6_idx(case3_flag1);", source2}},
   130  		{{"ALTER TABLE %s.%s ADD INDEX case6_idx(case3_flag1);", source3}},
   131  		{{"ALTER TABLE %s.%s DROP INDEX case6_idx;", source1}},
   132  		{{"ALTER TABLE %s.%s DROP INDEX case6_idx;", source2}},
   133  		{{"ALTER TABLE %s.%s DROP INDEX case6_idx;", source3}},
   134  	}
   135  	// ADD INDEX, DROP INDEX for one source.
   136  	case7 = Case{
   137  		{{"ALTER TABLE %s.%s ADD INDEX case7_idx(uuid);", source1}},
   138  		{{"ALTER TABLE %s.%s DROP INDEX case7_idx;", source1}},
   139  	}
   140  	// ADD MULTI-COLUMN INDEX.
   141  	case8 = Case{
   142  		{
   143  			{"ALTER TABLE %s.%s DROP INDEX case8_idx;", source1},
   144  			{"ALTER TABLE %s.%s DROP INDEX case8_idx;", source2},
   145  			{"ALTER TABLE %s.%s DROP INDEX case8_idx;", source3},
   146  		},
   147  		{{"ALTER TABLE %s.%s ADD INDEX case8_idx(case4_flag1, case4_flag2, case4_flag3);", source1}},
   148  		{{"ALTER TABLE %s.%s ADD INDEX case8_idx(case4_flag1, case4_flag2, case4_flag3);", source2}},
   149  		{{"ALTER TABLE %s.%s ADD INDEX case8_idx(case4_flag1, case4_flag2, case4_flag3);", source3}},
   150  	}
   151  	// ADD COLUMN AND INDEX.
   152  	case9 = Case{
   153  		{
   154  			{"ALTER TABLE %s.%s DROP INDEX case9_idx;", source1},
   155  			{"ALTER TABLE %s.%s DROP INDEX case9_idx;", source2},
   156  			{"ALTER TABLE %s.%s DROP INDEX case9_idx;", source3},
   157  			{"ALTER TABLE %s.%s DROP COLUMN case9;", source1},
   158  			{"ALTER TABLE %s.%s DROP COLUMN case9;", source2},
   159  			{"ALTER TABLE %s.%s DROP COLUMN case9;", source3},
   160  		},
   161  		{{"ALTER TABLE %s.%s ADD COLUMN case9 INT AFTER case9_flag;", source1}},
   162  		{{"ALTER TABLE %s.%s ADD INDEX case9_idx(case9);", source1}},
   163  		{{"ALTER TABLE %s.%s ADD COLUMN case9 INT AFTER case9_flag;", source2}},
   164  		{{"ALTER TABLE %s.%s ADD INDEX case9_idx(case9);", source2}},
   165  		{{"ALTER TABLE %s.%s ADD COLUMN case9 INT AFTER case9_flag;", source3}},
   166  		{{"ALTER TABLE %s.%s ADD INDEX case9_idx(case9);", source3}},
   167  	}
   168  	cases = map[string][]Case{
   169  		config2.ShardOptimistic: {
   170  			case1,
   171  			case2,
   172  			case3,
   173  			case4,
   174  			case5,
   175  			case6,
   176  			case7,
   177  			case8,
   178  			case9,
   179  		},
   180  		config2.ShardPessimistic: {},
   181  		"":                       {},
   182  	}
   183  	preSQLs = map[string]SQLs{
   184  		config2.ShardOptimistic:  preSQLs1,
   185  		config2.ShardPessimistic: nil,
   186  		"":                       nil,
   187  	}
   188  )
   189  
   190  // CaseGenerator generator test cases.
   191  type CaseGenerator struct {
   192  	testCases   []Case
   193  	testPreSQLs SQLs
   194  	sqlsChan    chan SQLs
   195  	schema      string
   196  	tables      []string
   197  }
   198  
   199  // NewCaseGenerator creates a new CaseGenerator instance.
   200  func NewCaseGenerator(shardMode string) *CaseGenerator {
   201  	g := &CaseGenerator{
   202  		testCases:   cases[shardMode],
   203  		sqlsChan:    make(chan SQLs),
   204  		testPreSQLs: preSQLs[shardMode],
   205  	}
   206  	return g
   207  }
   208  
   209  // Start starts to generate sqls case.
   210  func (g *CaseGenerator) Start(ctx context.Context, schema string, tables []string) {
   211  	g.schema = schema
   212  	g.tables = tables
   213  	go g.genSQLs(ctx)
   214  }
   215  
   216  func (g *CaseGenerator) genSQLs(ctx context.Context) {
   217  	for {
   218  		select {
   219  		case <-ctx.Done():
   220  			return
   221  		default:
   222  			for _, table := range g.tables {
   223  				rand.Shuffle(len(g.testCases), func(i, j int) { g.testCases[i], g.testCases[j] = g.testCases[j], g.testCases[i] })
   224  				casesNum := rand.Intn(len(g.testCases) + 1)
   225  				for i := 0; i < casesNum; i++ {
   226  					for _, sqls := range g.testCases[i] {
   227  						fullSqls := make(SQLs, len(sqls))
   228  						copy(fullSqls, sqls)
   229  						for idx, sql := range fullSqls {
   230  							fullSqls[idx].statement = fmt.Sprintf(sql.statement, g.schema, table)
   231  						}
   232  						g.sqlsChan <- fullSqls
   233  					}
   234  				}
   235  			}
   236  			g.sqlsChan <- nil
   237  		}
   238  	}
   239  }
   240  
   241  // GetSQLs gets sql from CaseGenerator.
   242  func (g *CaseGenerator) GetSQLs() SQLs {
   243  	return <-g.sqlsChan
   244  }
   245  
   246  // GetPreSQLs gets preSQLs from CaseGenerator.
   247  func (g *CaseGenerator) GetPreSQLs() SQLs {
   248  	testPreSQLs := make(SQLs, 0, len(g.testPreSQLs)*len(g.tables))
   249  	for _, table := range g.tables {
   250  		for _, sql := range g.testPreSQLs {
   251  			testPreSQLs = append(testPreSQLs, SQL{fmt.Sprintf(sql.statement, g.schema, table), sql.source})
   252  		}
   253  	}
   254  	return testPreSQLs
   255  }