vitess.io/vitess@v0.16.2/go/vt/wrangler/resharder_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 wrangler 18 19 import ( 20 "fmt" 21 "strings" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 26 "context" 27 28 "github.com/stretchr/testify/assert" 29 30 "vitess.io/vitess/go/sqltypes" 31 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 32 tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" 33 vschemapb "vitess.io/vitess/go/vt/proto/vschema" 34 "vitess.io/vitess/go/vt/vtgate/vindexes" 35 ) 36 37 const rsSelectFrozenQuery = "select 1 from _vt.vreplication where db_name='vt_ks' and message='FROZEN' and workflow_sub_type != 1" 38 const insertPrefix = `/insert into _vt.vreplication\(workflow, source, pos, max_tps, max_replication_lag, cell, tablet_types, time_updated, transaction_timestamp, state, db_name, workflow_type, workflow_sub_type, defer_secondary_keys\) values ` 39 const eol = "$" 40 41 func TestResharderOneToMany(t *testing.T) { 42 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 43 defer env.close() 44 45 schm := &tabletmanagerdatapb.SchemaDefinition{ 46 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 47 Name: "t1", 48 Columns: []string{"c1", "c2"}, 49 PrimaryKeyColumns: []string{"c1"}, 50 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 51 }}, 52 } 53 env.tmc.schema = schm 54 55 env.expectValidation() 56 env.expectNoRefStream() 57 58 type testCase struct { 59 cells string 60 tabletTypes string 61 } 62 var newTestCase = func(cells, tabletTypes string) *testCase { 63 return &testCase{ 64 cells: cells, 65 tabletTypes: tabletTypes, 66 } 67 } 68 var testCases []*testCase 69 70 testCases = append(testCases, newTestCase("", "")) 71 testCases = append(testCases, newTestCase("cell", "primary")) 72 testCases = append(testCases, newTestCase("cell", "primary,replica")) 73 testCases = append(testCases, newTestCase("", "replica,rdonly")) 74 75 for _, tc := range testCases { 76 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 77 78 schm := &tabletmanagerdatapb.SchemaDefinition{ 79 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 80 Name: "t1", 81 Columns: []string{"c1", "c2"}, 82 PrimaryKeyColumns: []string{"c1"}, 83 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 84 }}, 85 } 86 env.tmc.schema = schm 87 88 env.expectValidation() 89 env.expectNoRefStream() 90 name := tc.cells + "/" + tc.tabletTypes 91 t.Run(name, func(t *testing.T) { 92 env.tmc.expectVRQuery( 93 200, 94 insertPrefix+ 95 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '`+ 96 tc.cells+`', '`+tc.tabletTypes+`', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+eol, 97 &sqltypes.Result{}, 98 ) 99 env.tmc.expectVRQuery( 100 210, 101 insertPrefix+ 102 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '`+ 103 tc.cells+`', '`+tc.tabletTypes+`', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+eol, 104 &sqltypes.Result{}, 105 ) 106 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 107 env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 108 109 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, tc.cells, tc.tabletTypes, defaultOnDDL, true, false, false) 110 require.NoError(t, err) 111 env.tmc.verifyQueries(t) 112 }) 113 env.close() 114 } 115 } 116 117 func TestResharderManyToOne(t *testing.T) { 118 env := newTestResharderEnv(t, []string{"-80", "80-"}, []string{"0"}) 119 defer env.close() 120 121 schm := &tabletmanagerdatapb.SchemaDefinition{ 122 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 123 Name: "t1", 124 Columns: []string{"c1", "c2"}, 125 PrimaryKeyColumns: []string{"c1"}, 126 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 127 }}, 128 } 129 env.tmc.schema = schm 130 131 env.expectValidation() 132 env.expectNoRefStream() 133 134 env.tmc.expectVRQuery( 135 200, 136 insertPrefix+ 137 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"-80\\" filter:{rules:{match:\\"/.*\\" filter:\\"-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+ 138 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"80-\\" filter:{rules:{match:\\"/.*\\" filter:\\"-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 139 eol, 140 &sqltypes.Result{}, 141 ) 142 143 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 144 145 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 146 assert.NoError(t, err) 147 env.tmc.verifyQueries(t) 148 } 149 150 func TestResharderManyToMany(t *testing.T) { 151 env := newTestResharderEnv(t, []string{"-40", "40-"}, []string{"-80", "80-"}) 152 defer env.close() 153 154 schm := &tabletmanagerdatapb.SchemaDefinition{ 155 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 156 Name: "t1", 157 Columns: []string{"c1", "c2"}, 158 PrimaryKeyColumns: []string{"c1"}, 159 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 160 }}, 161 } 162 env.tmc.schema = schm 163 164 env.expectValidation() 165 env.expectNoRefStream() 166 167 env.tmc.expectVRQuery( 168 200, 169 insertPrefix+ 170 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"-40\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+ 171 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"40-\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 172 eol, 173 &sqltypes.Result{}, 174 ) 175 env.tmc.expectVRQuery( 176 210, 177 insertPrefix+ 178 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"40-\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 179 eol, 180 &sqltypes.Result{}, 181 ) 182 183 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 184 env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 185 186 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 187 assert.NoError(t, err) 188 env.tmc.verifyQueries(t) 189 } 190 191 // TestResharderOneRefTable tests the case where there's one ref table, but no stream for it. 192 // This means that the table is being updated manually. 193 func TestResharderOneRefTable(t *testing.T) { 194 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 195 defer env.close() 196 197 schm := &tabletmanagerdatapb.SchemaDefinition{ 198 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 199 Name: "t1", 200 Columns: []string{"c1", "c2"}, 201 PrimaryKeyColumns: []string{"c1"}, 202 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 203 }}, 204 } 205 env.tmc.schema = schm 206 207 vs := &vschemapb.Keyspace{ 208 Tables: map[string]*vschemapb.Table{ 209 "t1": { 210 Type: vindexes.TypeReference, 211 }, 212 }, 213 } 214 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 215 t.Fatal(err) 216 } 217 218 env.expectValidation() 219 env.expectNoRefStream() 220 221 env.tmc.expectVRQuery( 222 200, 223 insertPrefix+ 224 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 225 eol, 226 &sqltypes.Result{}, 227 ) 228 env.tmc.expectVRQuery( 229 210, 230 insertPrefix+ 231 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 232 eol, 233 &sqltypes.Result{}, 234 ) 235 236 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 237 env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 238 239 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 240 assert.NoError(t, err) 241 env.tmc.verifyQueries(t) 242 } 243 244 // TestReshardStopFlags tests the flags -stop_started and -stop_after_copy 245 func TestReshardStopFlags(t *testing.T) { 246 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 247 defer env.close() 248 249 schm := &tabletmanagerdatapb.SchemaDefinition{ 250 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 251 Name: "t1", 252 Columns: []string{"c1", "c2"}, 253 PrimaryKeyColumns: []string{"c1"}, 254 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 255 }}, 256 } 257 env.tmc.schema = schm 258 259 vs := &vschemapb.Keyspace{ 260 Tables: map[string]*vschemapb.Table{ 261 "t1": { 262 Type: vindexes.TypeReference, 263 }, 264 }, 265 } 266 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 267 t.Fatal(err) 268 } 269 270 env.expectValidation() 271 env.expectNoRefStream() 272 // inserts into the two shards expects flag stop_after_copy to be true 273 274 env.tmc.expectVRQuery( 275 200, 276 insertPrefix+ 277 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"-80\\"}} stop_after_copy:true', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 278 eol, 279 &sqltypes.Result{}, 280 ) 281 env.tmc.expectVRQuery( 282 210, 283 insertPrefix+ 284 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"80-\\"}} stop_after_copy:true', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 285 eol, 286 &sqltypes.Result{}, 287 ) 288 // -auto_start=false is tested by NOT expecting the update query which sets state to RUNNING 289 290 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, false, true, false) 291 assert.NoError(t, err) 292 env.tmc.verifyQueries(t) 293 } 294 295 // TestResharderOneRefStream tests the case where there's one ref table and an associated stream. 296 func TestResharderOneRefStream(t *testing.T) { 297 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 298 defer env.close() 299 300 schm := &tabletmanagerdatapb.SchemaDefinition{ 301 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 302 Name: "t1", 303 Columns: []string{"c1", "c2"}, 304 PrimaryKeyColumns: []string{"c1"}, 305 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 306 }}, 307 } 308 env.tmc.schema = schm 309 310 vs := &vschemapb.Keyspace{ 311 Tables: map[string]*vschemapb.Table{ 312 "t1": { 313 Type: vindexes.TypeReference, 314 }, 315 }, 316 } 317 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 318 t.Fatal(err) 319 } 320 321 env.expectValidation() 322 323 bls := &binlogdatapb.BinlogSource{ 324 Keyspace: "ks1", 325 Shard: "0", 326 Filter: &binlogdatapb.Filter{ 327 Rules: []*binlogdatapb.Rule{{ 328 Match: "t1", 329 }}, 330 }, 331 } 332 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 333 "workflow|source|cell|tablet_types", 334 "varchar|varchar|varchar|varchar"), 335 fmt.Sprintf("t1|%v|cell1|primary,replica", bls), 336 ) 337 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result) 338 339 refRow := `\('t1', 'keyspace:\\"ks1\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\"}}', '', [0-9]*, [0-9]*, 'cell1', 'primary,replica', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)` 340 env.tmc.expectVRQuery( 341 200, 342 insertPrefix+ 343 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+ 344 refRow+eol, 345 &sqltypes.Result{}, 346 ) 347 env.tmc.expectVRQuery( 348 210, 349 insertPrefix+ 350 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+ 351 refRow+eol, 352 &sqltypes.Result{}, 353 ) 354 355 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 356 env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 357 358 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 359 assert.NoError(t, err) 360 env.tmc.verifyQueries(t) 361 } 362 363 // TestResharderNoRefStream tests the case where there's a stream, but it's not a reference. 364 func TestResharderNoRefStream(t *testing.T) { 365 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 366 defer env.close() 367 368 schm := &tabletmanagerdatapb.SchemaDefinition{ 369 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 370 Name: "t1", 371 Columns: []string{"c1", "c2"}, 372 PrimaryKeyColumns: []string{"c1"}, 373 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 374 }}, 375 } 376 env.tmc.schema = schm 377 378 vs := &vschemapb.Keyspace{ 379 Sharded: true, 380 Vindexes: map[string]*vschemapb.Vindex{ 381 "hash": { 382 Type: "hash", 383 }, 384 }, 385 Tables: map[string]*vschemapb.Table{ 386 "t1": { 387 ColumnVindexes: []*vschemapb.ColumnVindex{{ 388 Column: "c1", 389 Name: "hash", 390 }}, 391 }, 392 }, 393 } 394 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 395 t.Fatal(err) 396 } 397 398 env.expectValidation() 399 400 bls := &binlogdatapb.BinlogSource{ 401 Keyspace: "ks1", 402 Shard: "0", 403 Filter: &binlogdatapb.Filter{ 404 Rules: []*binlogdatapb.Rule{{ 405 Match: "t1", 406 Filter: "select * from t2", 407 }}, 408 }, 409 } 410 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 411 "workflow|source|cell|tablet_types", 412 "varchar|varchar|varchar|varchar"), 413 fmt.Sprintf("t1|%v|cell1|primary,replica", bls), 414 ) 415 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result) 416 417 env.tmc.expectVRQuery( 418 200, 419 insertPrefix+ 420 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 421 eol, 422 &sqltypes.Result{}, 423 ) 424 env.tmc.expectVRQuery( 425 210, 426 insertPrefix+ 427 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 428 eol, 429 &sqltypes.Result{}, 430 ) 431 432 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 433 env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 434 435 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 436 assert.NoError(t, err) 437 env.tmc.verifyQueries(t) 438 } 439 440 func TestResharderCopySchema(t *testing.T) { 441 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 442 defer env.close() 443 444 schm := &tabletmanagerdatapb.SchemaDefinition{ 445 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 446 Name: "t1", 447 Columns: []string{"c1", "c2"}, 448 PrimaryKeyColumns: []string{"c1"}, 449 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 450 }}, 451 } 452 env.tmc.schema = schm 453 454 env.expectValidation() 455 env.expectNoRefStream() 456 457 env.tmc.expectVRQuery( 458 200, 459 insertPrefix+ 460 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 461 eol, 462 &sqltypes.Result{}, 463 ) 464 env.tmc.expectVRQuery( 465 210, 466 insertPrefix+ 467 `\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+ 468 eol, 469 &sqltypes.Result{}, 470 ) 471 472 env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 473 env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{}) 474 475 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, false, "", "", defaultOnDDL, true, false, false) 476 assert.NoError(t, err) 477 env.tmc.verifyQueries(t) 478 } 479 480 func TestResharderDupWorkflow(t *testing.T) { 481 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 482 defer env.close() 483 484 schm := &tabletmanagerdatapb.SchemaDefinition{ 485 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 486 Name: "t1", 487 Columns: []string{"c1", "c2"}, 488 PrimaryKeyColumns: []string{"c1"}, 489 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 490 }}, 491 } 492 env.tmc.schema = schm 493 494 env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 495 env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 496 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 497 "1", 498 "int64"), 499 "1", 500 ) 501 env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), result) 502 503 env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{}) 504 env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{}) 505 506 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 507 assert.EqualError(t, err, "validateWorkflowName.VReplicationExec: workflow resharderTest already exists in keyspace ks on tablet 210") 508 env.tmc.verifyQueries(t) 509 } 510 511 func TestResharderServingState(t *testing.T) { 512 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 513 defer env.close() 514 515 schm := &tabletmanagerdatapb.SchemaDefinition{ 516 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 517 Name: "t1", 518 Columns: []string{"c1", "c2"}, 519 PrimaryKeyColumns: []string{"c1"}, 520 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 521 }}, 522 } 523 env.tmc.schema = schm 524 525 env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 526 env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 527 env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 528 env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{}) 529 env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{}) 530 env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{}) 531 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, []string{"-80"}, nil, true, "", "", defaultOnDDL, true, false, false) 532 assert.EqualError(t, err, "buildResharder: source shard -80 is not in serving state") 533 534 env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 535 env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 536 env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 537 env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{}) 538 env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{}) 539 env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{}) 540 err = env.wr.Reshard(context.Background(), env.keyspace, env.workflow, []string{"0"}, []string{"0"}, true, "", "", defaultOnDDL, true, false, false) 541 assert.EqualError(t, err, "buildResharder: target shard 0 is in serving state") 542 543 env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 544 env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 545 env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 546 env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{}) 547 env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{}) 548 env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{}) 549 err = env.wr.Reshard(context.Background(), env.keyspace, env.workflow, []string{"0"}, []string{"-80"}, true, "", "", defaultOnDDL, true, false, false) 550 assert.EqualError(t, err, "buildResharder: ValidateForReshard: source and target keyranges don't match: - vs -80") 551 } 552 553 func TestResharderTargetAlreadyResharding(t *testing.T) { 554 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 555 defer env.close() 556 557 schm := &tabletmanagerdatapb.SchemaDefinition{ 558 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 559 Name: "t1", 560 Columns: []string{"c1", "c2"}, 561 PrimaryKeyColumns: []string{"c1"}, 562 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 563 }}, 564 } 565 env.tmc.schema = schm 566 567 env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 568 env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 569 env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{}) 570 571 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 572 "1", 573 "int64"), 574 "1", 575 ) 576 env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{}) 577 env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{}) 578 env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s'", env.keyspace), result) 579 env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s'", env.keyspace), &sqltypes.Result{}) 580 env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{}) 581 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 582 assert.EqualError(t, err, "buildResharder: validateTargets: some streams already exist in the target shards, please clean them up and retry the command") 583 env.tmc.verifyQueries(t) 584 } 585 586 func TestResharderUnnamedStream(t *testing.T) { 587 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 588 defer env.close() 589 590 schm := &tabletmanagerdatapb.SchemaDefinition{ 591 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 592 Name: "t1", 593 Columns: []string{"c1", "c2"}, 594 PrimaryKeyColumns: []string{"c1"}, 595 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 596 }}, 597 } 598 env.tmc.schema = schm 599 600 vs := &vschemapb.Keyspace{ 601 Tables: map[string]*vschemapb.Table{ 602 "t1": { 603 Type: vindexes.TypeReference, 604 }, 605 }, 606 } 607 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 608 t.Fatal(err) 609 } 610 611 env.expectValidation() 612 613 bls := &binlogdatapb.BinlogSource{ 614 Keyspace: "ks1", 615 Shard: "0", 616 Filter: &binlogdatapb.Filter{ 617 Rules: []*binlogdatapb.Rule{{ 618 Match: "t1", 619 }}, 620 }, 621 } 622 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 623 "workflow|source|cell|tablet_types", 624 "varchar|varchar|varchar|varchar"), 625 fmt.Sprintf("|%v|cell1|primary,replica", bls), 626 ) 627 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result) 628 629 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 630 assert.EqualError(t, err, "buildResharder: readRefStreams: VReplication streams must have named workflows for migration: shard: ks:0") 631 env.tmc.verifyQueries(t) 632 } 633 634 func TestResharderMismatchedRefStreams(t *testing.T) { 635 env := newTestResharderEnv(t, []string{"-80", "80-"}, []string{"0"}) 636 defer env.close() 637 638 schm := &tabletmanagerdatapb.SchemaDefinition{ 639 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 640 Name: "t1", 641 Columns: []string{"c1", "c2"}, 642 PrimaryKeyColumns: []string{"c1"}, 643 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 644 }}, 645 } 646 env.tmc.schema = schm 647 648 vs := &vschemapb.Keyspace{ 649 Tables: map[string]*vschemapb.Table{ 650 "t1": { 651 Type: vindexes.TypeReference, 652 }, 653 }, 654 } 655 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 656 t.Fatal(err) 657 } 658 659 env.expectValidation() 660 661 bls1 := &binlogdatapb.BinlogSource{ 662 Keyspace: "ks1", 663 Shard: "0", 664 Filter: &binlogdatapb.Filter{ 665 Rules: []*binlogdatapb.Rule{{ 666 Match: "t1", 667 }}, 668 }, 669 } 670 result1 := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 671 "workflow|source|cell|tablet_types", 672 "varchar|varchar|varchar|varchar"), 673 fmt.Sprintf("t1|%v|cell1|primary,replica", bls1), 674 ) 675 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result1) 676 bls2 := &binlogdatapb.BinlogSource{ 677 Keyspace: "ks2", 678 Shard: "0", 679 Filter: &binlogdatapb.Filter{ 680 Rules: []*binlogdatapb.Rule{{ 681 Match: "t1", 682 }}, 683 }, 684 } 685 result2 := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 686 "workflow|source|cell|tablet_types", 687 "varchar|varchar|varchar|varchar"), 688 fmt.Sprintf("t1|%v|cell1|primary,replica", bls1), 689 fmt.Sprintf("t1|%v|cell1|primary,replica", bls2), 690 ) 691 env.tmc.expectVRQuery(110, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result2) 692 693 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 694 want := "buildResharder: readRefStreams: streams are mismatched across source shards" 695 if err == nil || !strings.HasPrefix(err.Error(), want) { 696 t.Errorf("Reshard err: %v, want %v", err, want) 697 } 698 env.tmc.verifyQueries(t) 699 } 700 701 func TestResharderTableNotInVSchema(t *testing.T) { 702 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 703 defer env.close() 704 705 schm := &tabletmanagerdatapb.SchemaDefinition{ 706 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 707 Name: "t1", 708 Columns: []string{"c1", "c2"}, 709 PrimaryKeyColumns: []string{"c1"}, 710 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 711 }}, 712 } 713 env.tmc.schema = schm 714 715 env.expectValidation() 716 717 bls := &binlogdatapb.BinlogSource{ 718 Keyspace: "ks1", 719 Shard: "0", 720 Filter: &binlogdatapb.Filter{ 721 Rules: []*binlogdatapb.Rule{{ 722 Match: "t1", 723 }}, 724 }, 725 } 726 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 727 "workflow|source|cell|tablet_types", 728 "varchar|varchar|varchar|varchar"), 729 fmt.Sprintf("t1|%v|cell1|primary,replica", bls), 730 ) 731 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result) 732 733 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 734 assert.EqualError(t, err, "buildResharder: readRefStreams: blsIsReference: table t1 not found in vschema") 735 env.tmc.verifyQueries(t) 736 } 737 738 func TestResharderMixedTablesOrder1(t *testing.T) { 739 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 740 defer env.close() 741 742 schm := &tabletmanagerdatapb.SchemaDefinition{ 743 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 744 Name: "t1", 745 Columns: []string{"c1", "c2"}, 746 PrimaryKeyColumns: []string{"c1"}, 747 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 748 }}, 749 } 750 env.tmc.schema = schm 751 752 vs := &vschemapb.Keyspace{ 753 Sharded: true, 754 Vindexes: map[string]*vschemapb.Vindex{ 755 "hash": { 756 Type: "hash", 757 }, 758 }, 759 Tables: map[string]*vschemapb.Table{ 760 "t1": { 761 ColumnVindexes: []*vschemapb.ColumnVindex{{ 762 Column: "c1", 763 Name: "hash", 764 }}, 765 }, 766 "t2": { 767 Type: vindexes.TypeReference, 768 }, 769 }, 770 } 771 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 772 t.Fatal(err) 773 } 774 775 env.expectValidation() 776 777 bls := &binlogdatapb.BinlogSource{ 778 Keyspace: "ks1", 779 Shard: "0", 780 Filter: &binlogdatapb.Filter{ 781 Rules: []*binlogdatapb.Rule{{ 782 Match: "t1", 783 Filter: "select * from t2", 784 }, { 785 Match: "t2", 786 Filter: "select * from t2", 787 }}, 788 }, 789 } 790 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 791 "workflow|source|cell|tablet_types", 792 "varchar|varchar|varchar|varchar"), 793 fmt.Sprintf("t1t2|%v|cell1|primary,replica", bls), 794 ) 795 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result) 796 797 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 798 want := "buildResharder: readRefStreams: blsIsReference: cannot reshard streams with a mix of reference and sharded tables" 799 if err == nil || !strings.HasPrefix(err.Error(), want) { 800 t.Errorf("Reshard err: %v, want %v", err.Error(), want) 801 } 802 env.tmc.verifyQueries(t) 803 } 804 805 func TestResharderMixedTablesOrder2(t *testing.T) { 806 env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"}) 807 defer env.close() 808 809 schm := &tabletmanagerdatapb.SchemaDefinition{ 810 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 811 Name: "t1", 812 Columns: []string{"c1", "c2"}, 813 PrimaryKeyColumns: []string{"c1"}, 814 Fields: sqltypes.MakeTestFields("c1|c2", "int64|int64"), 815 }}, 816 } 817 env.tmc.schema = schm 818 819 vs := &vschemapb.Keyspace{ 820 Sharded: true, 821 Vindexes: map[string]*vschemapb.Vindex{ 822 "hash": { 823 Type: "hash", 824 }, 825 }, 826 Tables: map[string]*vschemapb.Table{ 827 "t1": { 828 ColumnVindexes: []*vschemapb.ColumnVindex{{ 829 Column: "c1", 830 Name: "hash", 831 }}, 832 }, 833 "t2": { 834 Type: vindexes.TypeReference, 835 }, 836 }, 837 } 838 if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil { 839 t.Fatal(err) 840 } 841 842 env.expectValidation() 843 844 bls := &binlogdatapb.BinlogSource{ 845 Keyspace: "ks1", 846 Shard: "0", 847 Filter: &binlogdatapb.Filter{ 848 Rules: []*binlogdatapb.Rule{{ 849 Match: "t2", 850 Filter: "select * from t2", 851 }, { 852 Match: "t1", 853 Filter: "select * from t2", 854 }}, 855 }, 856 } 857 result := sqltypes.MakeTestResult(sqltypes.MakeTestFields( 858 "workflow|source|cell|tablet_types", 859 "varchar|varchar|varchar|varchar"), 860 fmt.Sprintf("t1t2|%v|cell1|primary,replica", bls), 861 ) 862 env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result) 863 864 err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false) 865 want := "buildResharder: readRefStreams: blsIsReference: cannot reshard streams with a mix of reference and sharded tables" 866 if err == nil || !strings.HasPrefix(err.Error(), want) { 867 t.Errorf("Reshard err: %v, want %v", err.Error(), want) 868 } 869 env.tmc.verifyQueries(t) 870 }