From 3fb15b015725e4d2429fd611983f4f60e7694b03 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Thu, 6 Jun 2024 12:23:34 +0200 Subject: [PATCH 1/4] Fix schemadiff semantics handling (#16073) Signed-off-by: Dirkjan Bussink --- go/vt/schemadiff/schema_diff_test.go | 10 ++++++---- go/vt/schemadiff/schema_test.go | 9 +++++++++ go/vt/schemadiff/semantics.go | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/go/vt/schemadiff/schema_diff_test.go b/go/vt/schemadiff/schema_diff_test.go index 3dc1ab291fd..ac3a921acc5 100644 --- a/go/vt/schemadiff/schema_diff_test.go +++ b/go/vt/schemadiff/schema_diff_test.go @@ -415,13 +415,15 @@ func TestSchemaDiff(t *testing.T) { instantCapability: InstantDDLCapabilityIrrelevant, }, { - name: "add view with over", + name: "add view with over and keyword table", toQueries: append( createQueries, - "create view v2 as SELECT *, ROW_NUMBER() OVER(PARTITION BY info) AS row_num1, ROW_NUMBER() OVER(PARTITION BY info ORDER BY id) AS row_num2 FROM t1;\n", + "create table `order` (id int primary key, info int not null);", + "create view v2 as SELECT *, ROW_NUMBER() OVER(PARTITION BY info) AS row_num1, ROW_NUMBER() OVER(PARTITION BY info ORDER BY id) AS row_num2 FROM `order`;", ), - expectDiffs: 1, - entityOrder: []string{"v2"}, + expectDiffs: 2, + expectDeps: 1, + entityOrder: []string{"order", "v2"}, instantCapability: InstantDDLCapabilityIrrelevant, }, { diff --git a/go/vt/schemadiff/schema_test.go b/go/vt/schemadiff/schema_test.go index 7eab685f0d7..23782e676a1 100644 --- a/go/vt/schemadiff/schema_test.go +++ b/go/vt/schemadiff/schema_test.go @@ -125,6 +125,15 @@ func TestNewSchemaFromQueriesUnresolved(t *testing.T) { assert.Equal(t, "CREATE VIEW `v7` AS SELECT * FROM `v8`, `t2`", v.Create().CanonicalStatementString()) } +func TestNewSchemaFromQueriesWithSQLKeyword(t *testing.T) { + queries := []string{ + "create table `order` (id int primary key, info int not null)", + "create view v2 as SELECT *, ROW_NUMBER() OVER(PARTITION BY info) AS row_num1, ROW_NUMBER() OVER(PARTITION BY info ORDER BY id) AS row_num2 FROM `order`;", + } + _, err := NewSchemaFromQueries(NewTestEnv(), queries) + assert.NoError(t, err) +} + func TestNewSchemaFromQueriesUnresolvedAlias(t *testing.T) { // v8 does not exist queries := append(schemaTestCreateQueries, diff --git a/go/vt/schemadiff/semantics.go b/go/vt/schemadiff/semantics.go index ccbf654f566..cbba8c79497 100644 --- a/go/vt/schemadiff/semantics.go +++ b/go/vt/schemadiff/semantics.go @@ -51,7 +51,7 @@ func newDeclarativeSchemaInformation(env *Environment) *declarativeSchemaInforma // FindTableOrVindex implements the SchemaInformation interface func (si *declarativeSchemaInformation) FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error) { - table := si.Tables[sqlparser.String(tablename)] + table := si.Tables[tablename.Name.String()] return table, nil, "", 0, nil, nil } From b81c6175d2bb0bfc0d336f4e80bcda16c7826a1b Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:47:54 +0300 Subject: [PATCH 2/4] Online DDL: Fail a --in-order-completion migration, if a _prior_ migration within the same context is 'failed' or 'cancelled' (#16071) Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- .../scheduler/onlineddl_scheduler_test.go | 123 ++++++++++++++- go/vt/vttablet/onlineddl/executor.go | 149 +++++++++++++----- go/vt/vttablet/onlineddl/schema.go | 14 ++ 3 files changed, 239 insertions(+), 47 deletions(-) diff --git a/go/test/endtoend/onlineddl/scheduler/onlineddl_scheduler_test.go b/go/test/endtoend/onlineddl/scheduler/onlineddl_scheduler_test.go index 4362069af66..5b88b1f8678 100644 --- a/go/test/endtoend/onlineddl/scheduler/onlineddl_scheduler_test.go +++ b/go/test/endtoend/onlineddl/scheduler/onlineddl_scheduler_test.go @@ -198,7 +198,7 @@ func waitForReadyToComplete(t *testing.T, uuid string, expected bool) { case <-ticker.C: case <-ctx.Done(): } - require.NoError(t, ctx.Err()) + require.NoError(t, ctx.Err(), "waiting for ready_to_complete=%t for %v", expected, uuid) } } @@ -422,6 +422,14 @@ func testScheduler(t *testing.T) { assert.GreaterOrEqual(t, endTime2, endTime1) }) } + testTableCompletionAndStartTimes := func(t *testing.T, uuid1, uuid2 string) { + // expect uuid1 to complete before uuid2 + t.Run("Compare t1, t2 completion times", func(t *testing.T) { + endTime1 := testReadTimestamp(t, uuid1, "completed_timestamp") + startedTime2 := testReadTimestamp(t, uuid2, "started_timestamp") + assert.GreaterOrEqual(t, startedTime2, endTime1) + }) + } testAllowConcurrent := func(t *testing.T, name string, uuid string, expect int64) { t.Run("verify allow_concurrent: "+name, func(t *testing.T) { rs := onlineddl.ReadMigrations(t, &vtParams, uuid) @@ -434,7 +442,7 @@ func testScheduler(t *testing.T) { } // CREATE - t.Run("CREATE TABLEs t1, t1", func(t *testing.T) { + t.Run("CREATE TABLEs t1, t2", func(t *testing.T) { { // The table does not exist t1uuid = testOnlineDDLStatement(t, createParams(createT1Statement, ddlStrategy, "vtgate", "just-created", "", false)) onlineddl.CheckMigrationStatus(t, &vtParams, shards, t1uuid, schema.OnlineDDLStatusComplete) @@ -1183,6 +1191,36 @@ func testScheduler(t *testing.T) { }) }) // in-order-completion + t.Run("in-order-completion: multiple drops for nonexistent tables and views, sequential", func(t *testing.T) { + u, err := schema.CreateOnlineDDLUUID() + require.NoError(t, err) + + sqls := []string{ + fmt.Sprintf("drop table if exists t4_%s", u), + fmt.Sprintf("drop view if exists t1_%s", u), + fmt.Sprintf("drop table if exists t2_%s", u), + fmt.Sprintf("drop view if exists t3_%s", u), + } + sql := strings.Join(sqls, ";") + var vuuids []string + t.Run("drop multiple tables and views, in-order-completion", func(t *testing.T) { + uuidList := testOnlineDDLStatement(t, createParams(sql, ddlStrategy+" --in-order-completion", "vtctl", "", "", true)) // skip wait + vuuids = strings.Split(uuidList, "\n") + assert.Len(t, vuuids, 4) + for _, uuid := range vuuids { + status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, uuid, normalWaitTime, schema.OnlineDDLStatusComplete, schema.OnlineDDLStatusFailed) + fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + } + }) + require.Len(t, vuuids, 4) + for i := range vuuids { + if i > 0 { + testTableCompletionTimes(t, vuuids[i-1], vuuids[i]) + testTableCompletionAndStartTimes(t, vuuids[i-1], vuuids[i]) + } + } + }) t.Run("in-order-completion: multiple drops for nonexistent tables and views", func(t *testing.T) { u, err := schema.CreateOnlineDDLUUID() require.NoError(t, err) @@ -1198,20 +1236,93 @@ func testScheduler(t *testing.T) { t.Run("drop multiple tables and views, in-order-completion", func(t *testing.T) { uuidList := testOnlineDDLStatement(t, createParams(sql, ddlStrategy+" --allow-concurrent --in-order-completion", "vtctl", "", "", true)) // skip wait vuuids = strings.Split(uuidList, "\n") - assert.Equal(t, 4, len(vuuids)) + assert.Len(t, vuuids, 4) for _, uuid := range vuuids { status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, uuid, normalWaitTime, schema.OnlineDDLStatusComplete, schema.OnlineDDLStatusFailed) fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) } }) - require.Equal(t, 4, len(vuuids)) + require.Len(t, vuuids, 4) for i := range vuuids { if i > 0 { testTableCompletionTimes(t, vuuids[i-1], vuuids[i]) } } }) + + t.Run("in-order-completion: bail out on first error", func(t *testing.T) { + u, err := schema.CreateOnlineDDLUUID() + require.NoError(t, err) + + sqls := []string{ + fmt.Sprintf("drop table if exists t4_%s", u), + fmt.Sprintf("drop view if exists t1_%s", u), + fmt.Sprintf("drop table t2_%s", u), // non existent + fmt.Sprintf("drop view if exists t3_%s", u), + } + sql := strings.Join(sqls, ";") + var vuuids []string + t.Run("apply schema", func(t *testing.T) { + uuidList := testOnlineDDLStatement(t, createParams(sql, ddlStrategy+" --in-order-completion", "vtctl", "", "", true)) // skip wait + vuuids = strings.Split(uuidList, "\n") + assert.Len(t, vuuids, 4) + for _, uuid := range vuuids[0:2] { + status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, uuid, normalWaitTime, schema.OnlineDDLStatusComplete, schema.OnlineDDLStatusFailed) + fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + } + { + uuid := vuuids[2] // the failed one + status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, uuid, normalWaitTime, schema.OnlineDDLStatusComplete, schema.OnlineDDLStatusFailed) + fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusFailed) + } + { + uuid := vuuids[3] // should consequently fail without even running + status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, uuid, normalWaitTime, schema.OnlineDDLStatusComplete, schema.OnlineDDLStatusFailed) + fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusQueued, schema.OnlineDDLStatusFailed) + + rs := onlineddl.ReadMigrations(t, &vtParams, uuid) + require.NotNil(t, rs) + for _, row := range rs.Named().Rows { + message := row["message"].ToString() + require.Contains(t, message, vuuids[2]) // Indicating this migration failed due to vuuids[2] failure + } + } + }) + testTableCompletionTimes(t, vuuids[0], vuuids[1]) + testTableCompletionAndStartTimes(t, vuuids[0], vuuids[1]) + testTableCompletionAndStartTimes(t, vuuids[1], vuuids[2]) + }) + t.Run("in-order-completion concurrent: bail out on first error", func(t *testing.T) { + sqls := []string{ + `alter table t1_test force`, + `alter table t2_test force`, + } + sql := strings.Join(sqls, ";") + var vuuids []string + t.Run("apply schema", func(t *testing.T) { + uuidList := testOnlineDDLStatement(t, createParams(sql, ddlStrategy+" --in-order-completion --postpone-completion --allow-concurrent", "vtctl", "", "", true)) // skip wait + vuuids = strings.Split(uuidList, "\n") + assert.Len(t, vuuids, 2) + for _, uuid := range vuuids { + waitForReadyToComplete(t, uuid, true) + } + t.Run("cancel 1st migration", func(t *testing.T) { + onlineddl.CheckCancelMigration(t, &vtParams, shards, vuuids[0], true) + status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, vuuids[0], normalWaitTime, schema.OnlineDDLStatusFailed, schema.OnlineDDLStatusCancelled) + fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, vuuids[0], schema.OnlineDDLStatusCancelled) + }) + t.Run("expect 2nd migration to fail", func(t *testing.T) { + status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, vuuids[1], normalWaitTime, schema.OnlineDDLStatusFailed, schema.OnlineDDLStatusCancelled) + fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, vuuids[1], schema.OnlineDDLStatusFailed) + }) + }) + }) t.Run("in-order-completion: two new views, one depends on the other", func(t *testing.T) { u, err := schema.CreateOnlineDDLUUID() require.NoError(t, err) @@ -1225,14 +1336,14 @@ func testScheduler(t *testing.T) { t.Run("create two views, expect both complete", func(t *testing.T) { uuidList := testOnlineDDLStatement(t, createParams(sql, ddlStrategy+" --allow-concurrent --in-order-completion", "vtctl", "", "", true)) // skip wait vuuids = strings.Split(uuidList, "\n") - assert.Equal(t, 2, len(vuuids)) + assert.Len(t, vuuids, 2) for _, uuid := range vuuids { status := onlineddl.WaitForMigrationStatus(t, &vtParams, shards, uuid, normalWaitTime, schema.OnlineDDLStatusComplete, schema.OnlineDDLStatusFailed) fmt.Printf("# Migration status (for debug purposes): <%s>\n", status) onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) } }) - require.Equal(t, 2, len(vuuids)) + require.Len(t, vuuids, 2) testTableCompletionTimes(t, vuuids[0], vuuids[1]) }) t.Run("in-order-completion: new table column, new view depends on said column", func(t *testing.T) { diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go index 42b2a4f827b..ebce8f0619c 100644 --- a/go/vt/vttablet/onlineddl/executor.go +++ b/go/vt/vttablet/onlineddl/executor.go @@ -2854,6 +2854,31 @@ func (e *Executor) getCompletedMigrationByContextAndSQL(ctx context.Context, onl return completedUUID, nil } +// readFailedCancelledMigrationsInContextBeforeMigration returns UUIDs for migrations that are failed/cancelled +// and are in the same context as given migration and _precede_ it chronologically (have lower `id` value) +func (e *Executor) readFailedCancelledMigrationsInContextBeforeMigration(ctx context.Context, onlineDDL *schema.OnlineDDL) (uuids []string, err error) { + if onlineDDL.MigrationContext == "" { + // only applies to migrations with an explicit context + return nil, nil + } + query, err := sqlparser.ParseAndBind(sqlSelectFailedCancelledMigrationsInContextBeforeMigration, + sqltypes.StringBindVariable(onlineDDL.MigrationContext), + sqltypes.StringBindVariable(onlineDDL.UUID), + ) + if err != nil { + return nil, err + } + r, err := e.execQuery(ctx, query) + if err != nil { + return uuids, err + } + for _, row := range r.Named().Rows { + uuid := row["migration_uuid"].ToString() + uuids = append(uuids, uuid) + } + return uuids, err +} + // failMigration marks a migration as failed func (e *Executor) failMigration(ctx context.Context, onlineDDL *schema.OnlineDDL, withError error) error { defer e.triggerNextCheckInterval() @@ -2865,6 +2890,23 @@ func (e *Executor) failMigration(ctx context.Context, onlineDDL *schema.OnlineDD return withError } +// validateInOrderMigration checks whether an in-order migration should be forced to fail, either before running or +// while running. +// This may happen if a prior migration in the same context has failed or was cancelled. +func (e *Executor) validateInOrderMigration(ctx context.Context, onlineDDL *schema.OnlineDDL) (wasFailed bool, err error) { + if !onlineDDL.StrategySetting().IsInOrderCompletion() { + return false, nil + } + uuids, err := e.readFailedCancelledMigrationsInContextBeforeMigration(ctx, onlineDDL) + if err != nil { + return false, err + } + if len(uuids) == 0 { + return false, err + } + return true, e.failMigration(ctx, onlineDDL, fmt.Errorf("migration %v cannot run because prior migration %v in same context has failed/was cancelled", onlineDDL.UUID, uuids[0])) +} + // analyzeDropDDLActionMigration analyzes a DROP migration. func (e *Executor) analyzeDropDDLActionMigration(ctx context.Context, onlineDDL *schema.OnlineDDL) error { // Schema analysis: @@ -3384,6 +3426,58 @@ func (e *Executor) executeMigration(ctx context.Context, onlineDDL *schema.Onlin return nil } +// getNonConflictingMigration finds a single 'ready' migration which does not conflict with running migrations. +// Conflicts are: +// - a migration is 'ready' but is not set to run _concurrently_, and there's a running migration that is also non-concurrent +// - a migration is 'ready' but there's another migration 'running' on the exact same table +func (e *Executor) getNonConflictingMigration(ctx context.Context) (*schema.OnlineDDL, error) { + pendingMigrationsUUIDs, err := e.readPendingMigrationsUUIDs(ctx) + if err != nil { + return nil, err + } + r, err := e.execQuery(ctx, sqlSelectReadyMigrations) + if err != nil { + return nil, err + } + for _, row := range r.Named().Rows { + uuid := row["migration_uuid"].ToString() + onlineDDL, migrationRow, err := e.readMigration(ctx, uuid) + if err != nil { + return nil, err + } + isImmediateOperation := migrationRow.AsBool("is_immediate_operation", false) + + if conflictFound, _ := e.isAnyConflictingMigrationRunning(onlineDDL); conflictFound { + continue // this migration conflicts with a running one + } + if e.countOwnedRunningMigrations() >= maxConcurrentOnlineDDLs { + return nil, nil // too many running migrations + } + if isImmediateOperation && onlineDDL.StrategySetting().IsInOrderCompletion() { + // This migration is immediate: if we run it now, it will complete within a second or two at most. + if len(pendingMigrationsUUIDs) > 0 && pendingMigrationsUUIDs[0] != onlineDDL.UUID { + continue + } + } + // We will fail an in-order migration if there's _prior_ migrations within the same migration-context + // which have failed. + if onlineDDL.StrategySetting().IsInOrderCompletion() { + wasFailed, err := e.validateInOrderMigration(ctx, onlineDDL) + if err != nil { + return nil, err + } + if wasFailed { + continue + } + } + // This migration seems good to go + return onlineDDL, err + } + // no non-conflicting migration found... + // Either all ready migrations are conflicting, or there are no ready migrations... + return nil, nil +} + // runNextMigration picks up to one 'ready' migration that is able to run, and executes it. // Possible scenarios: // - no migration is in 'ready' state -- nothing to be done @@ -3405,47 +3499,7 @@ func (e *Executor) runNextMigration(ctx context.Context) error { return nil } - // getNonConflictingMigration finds a single 'ready' migration which does not conflict with running migrations. - // Conflicts are: - // - a migration is 'ready' but is not set to run _concurrently_, and there's a running migration that is also non-concurrent - // - a migration is 'ready' but there's another migration 'running' on the exact same table - getNonConflictingMigration := func() (*schema.OnlineDDL, error) { - pendingMigrationsUUIDs, err := e.readPendingMigrationsUUIDs(ctx) - if err != nil { - return nil, err - } - r, err := e.execQuery(ctx, sqlSelectReadyMigrations) - if err != nil { - return nil, err - } - for _, row := range r.Named().Rows { - uuid := row["migration_uuid"].ToString() - onlineDDL, migrationRow, err := e.readMigration(ctx, uuid) - if err != nil { - return nil, err - } - isImmediateOperation := migrationRow.AsBool("is_immediate_operation", false) - - if conflictFound, _ := e.isAnyConflictingMigrationRunning(onlineDDL); conflictFound { - continue // this migration conflicts with a running one - } - if e.countOwnedRunningMigrations() >= maxConcurrentOnlineDDLs { - continue // too many running migrations - } - if isImmediateOperation && onlineDDL.StrategySetting().IsInOrderCompletion() { - // This migration is immediate: if we run it now, it will complete within a second or two at most. - if len(pendingMigrationsUUIDs) > 0 && pendingMigrationsUUIDs[0] != onlineDDL.UUID { - continue - } - } - // This migration seems good to go - return onlineDDL, err - } - // no non-conflicting migration found... - // Either all ready migrations are conflicting, or there are no ready migrations... - return nil, nil - } - onlineDDL, err := getNonConflictingMigration() + onlineDDL, err := e.getNonConflictingMigration(ctx) if err != nil { return err } @@ -3792,6 +3846,19 @@ func (e *Executor) reviewRunningMigrations(ctx context.Context) (countRunnning i _ = e.updateMigrationETASecondsByProgress(ctx, uuid) _ = e.updateMigrationLastThrottled(ctx, uuid, time.Unix(s.timeThrottled, 0), s.componentThrottled) + if onlineDDL.StrategySetting().IsInOrderCompletion() { + // We will fail an in-order migration if there's _prior_ migrations within the same migration-context + // which have failed. + wasFailed, err := e.validateInOrderMigration(ctx, onlineDDL) + if err != nil { + return err + } + if wasFailed { + return nil + } + } + + // Check if the migration is ready to cut-over, and proceed to do so if it is. isReady, err := e.isVReplMigrationReadyToCutOver(ctx, onlineDDL, s) if err != nil { _ = e.updateMigrationMessage(ctx, uuid, err.Error()) diff --git a/go/vt/vttablet/onlineddl/schema.go b/go/vt/vttablet/onlineddl/schema.go index 2ba566703e5..30f132bd0e3 100644 --- a/go/vt/vttablet/onlineddl/schema.go +++ b/go/vt/vttablet/onlineddl/schema.go @@ -303,6 +303,7 @@ const ( FROM _vt.schema_migrations WHERE migration_status='running' + ORDER BY id ` sqlSelectCompleteMigrationsOnTable = `SELECT migration_uuid, @@ -333,6 +334,18 @@ const ( WHERE migration_status='running' AND liveness_timestamp < NOW() - INTERVAL %a MINUTE + ORDER BY id + ` + sqlSelectFailedCancelledMigrationsInContextBeforeMigration = `SELECT + migration_uuid + FROM _vt.schema_migrations + WHERE + migration_context=%a + AND migration_status IN ('failed', 'cancelled') + AND id < ( + SELECT id FROM _vt.schema_migrations WHERE migration_uuid=%a + ) + ORDER BY id ` sqlSelectPendingMigrations = `SELECT migration_uuid, @@ -365,6 +378,7 @@ const ( NOW() - INTERVAL %a SECOND, NOW() - INTERVAL retain_artifacts_seconds SECOND ) + ORDER BY id ` sqlFixCompletedTimestamp = `UPDATE _vt.schema_migrations SET From 307b290a356644aad1b5a2135e22be92b258ef4e Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:08:51 +0300 Subject: [PATCH 3/4] Changelog 20.0: Fix broken links (#16048) Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- changelog/20.0/20.0.0/summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog/20.0/20.0.0/summary.md b/changelog/20.0/20.0.0/summary.md index 27016536815..6e09cc982ef 100644 --- a/changelog/20.0/20.0.0/summary.md +++ b/changelog/20.0/20.0.0/summary.md @@ -183,7 +183,7 @@ This makes reparenting in Vitess resilient to client errors, and prevents Planne In order to preserve the old behaviour, the users can set the flag back to `0 seconds` causing open transactions to never be shutdown, but in that case, they run the risk of PlannedReparentShard calls timing out. -#### New `unmanaged` Flag and `disable_active_reparents` deprecation +#### New `unmanaged` Flag and `disable_active_reparents` deprecation New flag `--unmanaged` has been introduced in this release to make it easier to flag unmanaged tablets. It also runs validations to make sure the unmanaged tablets are configured properly. `--disable_active_reparents` flag has been deprecated for `vttablet`, `vtcombo` and `vttestserver` binaries and will be removed in future releases. Specifying the `--unmanaged` flag will also block replication commands and replication repairs. @@ -338,7 +338,7 @@ VTTablet exposes two new counter stats: * `QueryCacheHits`: Query engine query cache hits * `QueryCacheMisses`: Query engine query cache misses -### VTTablet Query Text Characters Processed +### VTTablet Query Text Characters Processed VTGate and VTTablet expose a new counter stat `QueryTextCharactersProcessed` to reflect the number of query text characters processed. From 87ecae7de905e2bccedb9d26ed3d4a34e76d4d8e Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:11:40 +0300 Subject: [PATCH 4/4] `schemadiff`: adding a FK dependency unit test (#16069) Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/schemadiff/schema_diff_test.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/go/vt/schemadiff/schema_diff_test.go b/go/vt/schemadiff/schema_diff_test.go index ac3a921acc5..4d6ca522d1e 100644 --- a/go/vt/schemadiff/schema_diff_test.go +++ b/go/vt/schemadiff/schema_diff_test.go @@ -979,6 +979,22 @@ func TestSchemaDiff(t *testing.T) { conflictingDiffs: 2, instantCapability: InstantDDLCapabilityImpossible, }, + { + name: "add and drop FK, add and drop respective tables", + fromQueries: []string{ + "create table t1 (id int primary key, p int, key p_idx (p));", + "create table t2 (id int primary key, p int, key p_idx (p), foreign key (p) references t1 (p) on delete no action);", + }, + toQueries: []string{ + "create table t2 (id int primary key, p int, key p_idx (p), foreign key (p) references t3 (p) on delete no action);", + "create table t3 (id int primary key, p int, key p_idx (p));", + }, + expectDiffs: 3, + expectDeps: 2, // [alter t2]/[drop t1], [alter t2]/[create t3] + sequential: true, + entityOrder: []string{"t3", "t2", "t1"}, + instantCapability: InstantDDLCapabilityImpossible, + }, { name: "two identical foreign keys in table, drop one", fromQueries: []string{ @@ -1053,7 +1069,7 @@ func TestSchemaDiff(t *testing.T) { for _, dep := range deps { depsKeys = append(depsKeys, dep.hashKey()) } - assert.Equalf(t, tc.expectDeps, len(deps), "found deps: %v", depsKeys) + assert.Equalf(t, tc.expectDeps, len(deps), "found %v deps: %v", len(depsKeys), depsKeys) assert.Equal(t, tc.sequential, schemaDiff.HasSequentialExecutionDependencies()) orderedDiffs, err := schemaDiff.OrderedDiffs(ctx)