Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[performance] separate enum migrations into their own individual transactions #3796

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 96 additions & 93 deletions internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,107 +30,110 @@ import (

func init() {
up := func(ctx context.Context, db *bun.DB) error {
return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {

// Status visibility type indices.
var statusVisIndices = []struct {
name string
cols []string
order string
}{
{
name: "statuses_visibility_idx",
cols: []string{"visibility"},
order: "",
},
{
name: "statuses_profile_web_view_idx",
cols: []string{"account_id", "visibility"},
order: "id DESC",
},
{
name: "statuses_public_timeline_idx",
cols: []string{"visibility"},
order: "id DESC",
},
}

// Tables with visibility types.
var visTables = []struct {
Table string
Column string
Default *new_gtsmodel.Visibility
IndexCleanupCallback func(ctx context.Context, tx bun.Tx) error
}{
{
Table: "statuses",
Column: "visibility",
IndexCleanupCallback: func(ctx context.Context, tx bun.Tx) error {
// After new column has been created and
// populated, drop indices relying on old column.
for _, index := range statusVisIndices {
log.Infof(ctx, "dropping old index %s...", index.name)
if _, err := tx.NewDropIndex().
Index(index.name).
Exec(ctx); err != nil {
return err
}
// Status visibility type indices.
var statusVisIndices = []struct {
name string
cols []string
order string
}{
{
name: "statuses_visibility_idx",
cols: []string{"visibility"},
order: "",
},
{
name: "statuses_profile_web_view_idx",
cols: []string{"account_id", "visibility"},
order: "id DESC",
},
{
name: "statuses_public_timeline_idx",
cols: []string{"visibility"},
order: "id DESC",
},
}

// Tables with visibility types.
var visTables = []struct {
Table string
Column string
Default *new_gtsmodel.Visibility
IndexCleanupCallback func(ctx context.Context, tx bun.Tx) error
}{
{
Table: "statuses",
Column: "visibility",
IndexCleanupCallback: func(ctx context.Context, tx bun.Tx) error {
// After new column has been created and
// populated, drop indices relying on old column.
for _, index := range statusVisIndices {
log.Infof(ctx, "dropping old index %s...", index.name)
if _, err := tx.NewDropIndex().
Index(index.name).
Exec(ctx); err != nil {
return err
}
return nil
},
}
return nil
},
{
Table: "sin_bin_statuses",
Column: "visibility",
},
{
Table: "account_settings",
Column: "privacy",
Default: util.Ptr(new_gtsmodel.VisibilityDefault)},
{
Table: "account_settings",
Column: "web_visibility",
Default: util.Ptr(new_gtsmodel.VisibilityDefault)},
},
{
Table: "sin_bin_statuses",
Column: "visibility",
},
{
Table: "account_settings",
Column: "privacy",
Default: util.Ptr(new_gtsmodel.VisibilityDefault)},
{
Table: "account_settings",
Column: "web_visibility",
Default: util.Ptr(new_gtsmodel.VisibilityDefault)},
}

// Get the mapping of old enum string values to new integer values.
visibilityMapping := visibilityEnumMapping[old_gtsmodel.Visibility]()

// Convert all visibility tables.
for _, table := range visTables {

// Perform each enum table conversion within its own transaction.
if err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
return convertEnums(ctx, tx, table.Table, table.Column,
visibilityMapping, table.Default, table.IndexCleanupCallback)
}); err != nil {
return err
}

// Get the mapping of old enum string values to new integer values.
visibilityMapping := visibilityEnumMapping[old_gtsmodel.Visibility]()

// Convert all visibility tables.
for _, table := range visTables {
if err := convertEnums(ctx, tx, table.Table, table.Column,
visibilityMapping, table.Default, table.IndexCleanupCallback); err != nil {
return err
}
}

// Recreate the visibility indices.
log.Info(ctx, "creating new visibility indexes...")
for _, index := range statusVisIndices {
log.Infof(ctx, "creating new index %s...", index.name)
q := db.NewCreateIndex().
Table("statuses").
Index(index.name).
Column(index.cols...)
if index.order != "" {
q = q.ColumnExpr(index.order)
}

// Recreate the visibility indices.
log.Info(ctx, "creating new visibility indexes...")
for _, index := range statusVisIndices {
log.Infof(ctx, "creating new index %s...", index.name)
q := tx.NewCreateIndex().
Table("statuses").
Index(index.name).
Column(index.cols...)
if index.order != "" {
q = q.ColumnExpr(index.order)
}
if _, err := q.Exec(ctx); err != nil {
return err
}
if _, err := q.Exec(ctx); err != nil {
return err
}
}

// Get the mapping of old enum string values to the new integer value types.
notificationMapping := notificationEnumMapping[old_gtsmodel.NotificationType]()
// Get the mapping of old enum string values to the new integer value types.
notificationMapping := notificationEnumMapping[old_gtsmodel.NotificationType]()

// Migrate over old notifications table column over to new column type.
if err := convertEnums(ctx, tx, "notifications", "notification_type", //nolint:revive
notificationMapping, nil, nil); err != nil {
return err
}
// Migrate over old notifications table column to new type in tx.
if err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
return convertEnums(ctx, tx, "notifications", "notification_type", //nolint:revive
notificationMapping, nil, nil)
}); err != nil {
return err
}

return nil
})
return nil
}

down := func(ctx context.Context, db *bun.DB) error {
Expand Down