vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/concurrentdml/main_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package concurrentdml
    18  
    19  import (
    20  	"context"
    21  	_ "embed"
    22  	"flag"
    23  	"fmt"
    24  	"os"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"vitess.io/vitess/go/test/endtoend/utils"
    30  
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  
    34  	"vitess.io/vitess/go/mysql"
    35  	"vitess.io/vitess/go/test/endtoend/cluster"
    36  )
    37  
    38  var (
    39  	clusterInstance *cluster.LocalProcessCluster
    40  	cell            = "zone1"
    41  	hostname        = "localhost"
    42  	unsKs           = "commerce"
    43  	unsSchema       = `
    44  CREATE TABLE t1_seq (
    45      id INT, 
    46      next_id BIGINT, 
    47      cache BIGINT, 
    48      PRIMARY KEY(id)
    49  ) comment 'vitess_sequence';
    50  
    51  INSERT INTO t1_seq (id, next_id, cache) values(0, 1, 1000);
    52  `
    53  
    54  	unsVSchema = `
    55  {
    56    "sharded": false,
    57    "tables": {}
    58  }
    59  `
    60  	sKs = "customer"
    61  	//go:embed sharded_schema.sql
    62  	sSchema string
    63  
    64  	//go:embed sharded_vschema.json
    65  	sVSchema string
    66  )
    67  
    68  func TestMain(m *testing.M) {
    69  	defer cluster.PanicHandler(nil)
    70  	flag.Parse()
    71  
    72  	exitCode := func() int {
    73  		clusterInstance = cluster.NewCluster(cell, hostname)
    74  		defer clusterInstance.Teardown()
    75  
    76  		// Start topo server
    77  		if err := clusterInstance.StartTopo(); err != nil {
    78  			return 1
    79  		}
    80  
    81  		// Start keyspace
    82  		uKeyspace := &cluster.Keyspace{
    83  			Name:      unsKs,
    84  			SchemaSQL: unsSchema,
    85  			VSchema:   unsVSchema,
    86  		}
    87  		if err := clusterInstance.StartUnshardedKeyspace(*uKeyspace, 0, false); err != nil {
    88  			return 1
    89  		}
    90  
    91  		sKeyspace := &cluster.Keyspace{
    92  			Name:      sKs,
    93  			SchemaSQL: sSchema,
    94  			VSchema:   sVSchema,
    95  		}
    96  		if err := clusterInstance.StartKeyspace(*sKeyspace, []string{"-80", "80-"}, 0, false); err != nil {
    97  			return 1
    98  		}
    99  
   100  		// Start vtgate
   101  		if err := clusterInstance.StartVtgate(); err != nil {
   102  			return 1
   103  		}
   104  
   105  		return m.Run()
   106  	}()
   107  	os.Exit(exitCode)
   108  }
   109  
   110  func TestInsertIgnoreOnLookupUniqueVindex(t *testing.T) {
   111  	defer cluster.PanicHandler(t)
   112  	ctx := context.Background()
   113  	vtParams := mysql.ConnParams{
   114  		Host: "localhost",
   115  		Port: clusterInstance.VtgateMySQLPort,
   116  	}
   117  
   118  	// end-to-end test
   119  	conn, err := mysql.Connect(ctx, &vtParams)
   120  	require.Nil(t, err)
   121  	defer conn.Close()
   122  
   123  	defer utils.Exec(t, conn, `delete from t1`)
   124  	utils.Exec(t, conn, `insert into t1(c1, c2, c3) values (300,100,300)`)
   125  	qr1 := utils.Exec(t, conn, `select c2.keyspace_id, c3.keyspace_id from lookup_t1 c2, lookup_t2 c3`)
   126  
   127  	qr := utils.Exec(t, conn, `insert ignore into t1(c1, c2, c3) values (200,100,200)`)
   128  	assert.Zero(t, qr.RowsAffected)
   129  
   130  	qr = utils.Exec(t, conn, `select c1, c2, c3 from t1 order by c1`)
   131  	assert.Equal(t, fmt.Sprintf("%v", qr.Rows), `[[INT64(300) INT64(100) INT64(300)]]`)
   132  
   133  	qr2 := utils.Exec(t, conn, `select c2.keyspace_id, c3.keyspace_id from lookup_t1 c2, lookup_t2 c3`)
   134  	// To ensure lookup vindex is not updated.
   135  	assert.Equal(t, qr1.Rows, qr2.Rows, "")
   136  }
   137  
   138  func TestOpenTxBlocksInSerial(t *testing.T) {
   139  	t.Skip("Update and Insert in same transaction does not work with the unique consistent lookup having same value.")
   140  	defer cluster.PanicHandler(t)
   141  	ctx := context.Background()
   142  	vtParams := mysql.ConnParams{
   143  		Host: "localhost",
   144  		Port: clusterInstance.VtgateMySQLPort,
   145  	}
   146  	conn1, err := mysql.Connect(ctx, &vtParams)
   147  	require.Nil(t, err)
   148  	defer conn1.Close()
   149  
   150  	conn2, err := mysql.Connect(ctx, &vtParams)
   151  	require.Nil(t, err)
   152  	defer conn2.Close()
   153  
   154  	defer utils.Exec(t, conn1, `delete from t1`)
   155  	utils.Exec(t, conn1, `insert into t1(c1, c2, c3) values (300,100,300)`)
   156  	utils.Exec(t, conn1, `begin`)
   157  	utils.Exec(t, conn1, `UPDATE t1 SET c3 = 400 WHERE c2 = 100`)
   158  
   159  	// This will wait for innodb_lock_wait_timeout timeout pf 20 seconds to kick in.
   160  	utils.AssertContainsError(t, conn2, `insert into t1(c1, c2, c3) values (400,100,400)`, `Lock wait timeout exceeded`)
   161  
   162  	qr := utils.Exec(t, conn1, `insert ignore into t1(c1, c2, c3) values (200,100,200)`)
   163  	assert.Zero(t, qr.RowsAffected)
   164  	utils.Exec(t, conn1, `commit`)
   165  
   166  	qr = utils.Exec(t, conn1, `select c1, c2, c3 from t1 order by c1`)
   167  	assert.Equal(t, fmt.Sprintf("%v", qr.Rows), `[[INT64(300) INT64(100) INT64(400)]]`)
   168  }
   169  
   170  func TestOpenTxBlocksInConcurrent(t *testing.T) {
   171  	t.Skip("Update and Insert in same transaction does not work with the unique consistent lookup having same value.")
   172  	defer cluster.PanicHandler(t)
   173  	ctx := context.Background()
   174  	vtParams := mysql.ConnParams{
   175  		Host: "localhost",
   176  		Port: clusterInstance.VtgateMySQLPort,
   177  	}
   178  	conn1, err := mysql.Connect(ctx, &vtParams)
   179  	require.Nil(t, err)
   180  	defer conn1.Close()
   181  
   182  	conn2, err := mysql.Connect(ctx, &vtParams)
   183  	require.Nil(t, err)
   184  	defer conn2.Close()
   185  
   186  	defer utils.Exec(t, conn1, `delete from t1`)
   187  	utils.Exec(t, conn1, `insert into t1(c1, c2, c3) values (300,100,300)`)
   188  	utils.Exec(t, conn1, `begin`)
   189  	utils.Exec(t, conn1, `UPDATE t1 SET c3 = 400 WHERE c2 = 100`)
   190  
   191  	var wg sync.WaitGroup
   192  	wg.Add(1)
   193  	go func() {
   194  		// This will wait for other transaction to complete before throwing the duplicate key error.
   195  		utils.AssertContainsError(t, conn2, `insert into t1(c1, c2, c3) values (400,100,400)`, `Duplicate entry '100' for key`)
   196  		wg.Done()
   197  	}()
   198  
   199  	time.Sleep(3 * time.Second)
   200  	qr := utils.Exec(t, conn1, `insert ignore into t1(c1, c2, c3) values (200,100,200)`)
   201  	assert.Zero(t, qr.RowsAffected)
   202  	utils.Exec(t, conn1, `commit`)
   203  
   204  	qr = utils.Exec(t, conn1, `select c1, c2, c3 from t1 order by c1`)
   205  	assert.Equal(t, fmt.Sprintf("%v", qr.Rows), `[[INT64(300) INT64(100) INT64(400)]]`)
   206  	wg.Wait()
   207  }
   208  
   209  func TestUpdateLookupUniqueVindex(t *testing.T) {
   210  	defer cluster.PanicHandler(t)
   211  	ctx := context.Background()
   212  	vtParams := mysql.ConnParams{
   213  		Host: "localhost",
   214  		Port: clusterInstance.VtgateMySQLPort,
   215  	}
   216  	conn, err := mysql.Connect(ctx, &vtParams)
   217  	require.Nil(t, err)
   218  	defer conn.Close()
   219  
   220  	defer utils.Exec(t, conn, `delete from t1`)
   221  	utils.Exec(t, conn, `insert into t1(c1, c2, c3) values (999,100,300)`)
   222  	utils.AssertMatches(t, conn, `select c1,c2,c3 from t1`, `[[INT64(999) INT64(100) INT64(300)]]`)
   223  	utils.AssertMatches(t, conn, `select c2 from lookup_t1`, `[[INT64(100)]]`)
   224  	utils.AssertMatches(t, conn, `select c3 from lookup_t2`, `[[INT64(300)]]`)
   225  	// not changed - same vindex
   226  	utils.Exec(t, conn, `update t1 set c2 = 100 where c2 = 100`)
   227  	// changed - same vindex
   228  	utils.Exec(t, conn, `update t1 set c2 = 200 where c2 = 100`)
   229  	// not changed - different vindex
   230  	utils.Exec(t, conn, `update t1 set c3 = 300 where c2 = 200`)
   231  	// changed - different vindex
   232  	utils.Exec(t, conn, `update t1 set c3 = 400 where c2 = 200`)
   233  	// changed - same vindex
   234  	utils.Exec(t, conn, `update t1 set c4 = 'abc' where c1 = 999`)
   235  	// not changed - same vindex
   236  	utils.Exec(t, conn, `update t1 set c4 = 'abc' where c4 = 'abc'`)
   237  }