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 }