diff --git a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go index 4ed1e3be6..113958437 100644 --- a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go +++ b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go @@ -59,6 +59,7 @@ func init() { Column string Default *new_gtsmodel.Visibility IndexCleanupCallback func(ctx context.Context, tx bun.Tx) error + BatchByColumn string }{ { Table: "statuses", @@ -76,19 +77,26 @@ func init() { } return nil }, + BatchByColumn: "id", }, { - Table: "sin_bin_statuses", - Column: "visibility", + Table: "sin_bin_statuses", + Column: "visibility", + BatchByColumn: "id", }, { - Table: "account_settings", - Column: "privacy", - Default: util.Ptr(new_gtsmodel.VisibilityDefault)}, + Table: "account_settings", + Column: "privacy", + Default: util.Ptr(new_gtsmodel.VisibilityDefault), + BatchByColumn: "account_id", + }, + { - Table: "account_settings", - Column: "web_visibility", - Default: util.Ptr(new_gtsmodel.VisibilityDefault)}, + Table: "account_settings", + Column: "web_visibility", + Default: util.Ptr(new_gtsmodel.VisibilityDefault), + BatchByColumn: "account_id", + }, } // Get the mapping of old enum string values to new integer values. @@ -100,7 +108,7 @@ func init() { // 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) + visibilityMapping, table.Default, table.IndexCleanupCallback, table.BatchByColumn) }); err != nil { return err } @@ -128,7 +136,7 @@ func init() { // 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) + notificationMapping, nil, nil, "id") }); err != nil { return err } diff --git a/internal/db/bundb/migrations/util.go b/internal/db/bundb/migrations/util.go index 7f8b57c42..d91bb4991 100644 --- a/internal/db/bundb/migrations/util.go +++ b/internal/db/bundb/migrations/util.go @@ -27,6 +27,7 @@ import ( "codeberg.org/gruf/go-byteutil" "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/id" "github.com/superseriousbusiness/gotosocial/internal/log" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect" @@ -46,6 +47,7 @@ func convertEnums[OldType ~string, NewType ~int16]( mapping map[OldType]NewType, defaultValue *NewType, indexCleanupCallback func(context.Context, bun.Tx) error, + batchByColumn string, ) error { if len(mapping) == 0 { return errors.New("empty mapping") @@ -98,15 +100,54 @@ func convertEnums[OldType ~string, NewType ~int16]( } qbuf.B = append(qbuf.B, "ELSE ? END)"...) args = append(args, *defaultValue) + qbuf.B = append(qbuf.B, " WHERE ? IN (?)"...) + args = append(args, bun.Ident(batchByColumn)) + baseQ := qbuf.String() - // Execute the prepared raw query with arguments. - res, err := tx.NewRaw(qbuf.String(), args...).Exec(ctx) - if err != nil { - return gtserror.Newf("error updating old column values: %w", err) + var ( + nextHighest = id.Highest + updated int64 + ) + + for { + batchQ := tx.NewRaw( + "SELECT ? FROM ? WHERE ? < ? ORDER BY ? DESC LIMIT ?", + bun.Ident(batchByColumn), + bun.Ident(table), + bun.Ident(batchByColumn), + nextHighest, + bun.Ident(batchByColumn), + 5000, + ) + + q := baseQ + " RETURNING ?" + qArgs := append(args, batchQ) // nolint:gocritic + qArgs = append(qArgs, bun.Ident(batchByColumn)) + + // Execute the prepared raw query with arguments. + var ids []string + res, err := tx.NewRaw(q, qArgs...).Exec(ctx, &ids) + if err != nil { + return gtserror.Newf("error updating old column values: %w", err) + } + + // Count number items updated. + thisUpdated, _ := res.RowsAffected() + if thisUpdated == 0 { + break + } + + updated += thisUpdated + highestID := ids[0] + lowestID := ids[len(ids)-1] + log.Infof(ctx, + "updated %d of %d %s (just done from %s to %s)", + updated, total, table, highestID, lowestID, + ) + + nextHighest = lowestID } - // Count number items updated. - updated, _ := res.RowsAffected() if total != int(updated) { log.Warnf(ctx, "total=%d does not match updated=%d", total, updated) }