Skip to content
  • aschmitz's avatar
    Make IdsToBigints (mostly!) non-blocking (#5088) · 97c02c33
    aschmitz authored and Eugen Rochko's avatar Eugen Rochko committed
    * Make IdsToBigints (mostly!) non-blocking
    
    This pulls in GitLab's MigrationHelpers, which include code to make
    column changes in ways that Postgres can do without locking. In general,
    this involves creating a new column, adding an index and any foreign
    keys as appropriate, adding a trigger to keep it populated alongside
    the old column, and then progressively copying data over to the new
    column, before removing the old column and replacing it with the new
    one.
    
    A few changes to GitLab's MigrationHelpers were necessary:
    
    * Some changes were made to remove dependencies on other GitLab code.
    * We explicitly wait for index creation before forging ahead on column
      replacements.
    * We use different temporary column names, to avoid running into index
      name length limits.
    * We rename the generated indices back to what they "should" be after
      replacing columns.
    * We rename the generated foreign keys to use the new column names when
      we had to create them. (This allows the migration to be rolled back
      without incident.)
    
    # Big Scary Warning
    
    There are two things here that may trip up large instances:
    
    1. The change for tables' "id" columns is not concurrent. In
       particular, the stream_entries table may be big, and does not
       concurrently migrate its id column. (On the other hand, x_id type
       columns are all concurrent.)
    2. This migration will take a long time to run, *but it should not
       lock tables during that time* (with the exception of the "id"
       columns as described above). That means this should probably be run
       in `screen` or some other session that can be run for a long time.
       Notably, the migration will take *longer* than it would without
       these changes, but the website will still be responsive during that
       time.
    
    These changes were tested on a relatively large statuses table (256k
    entries), and the service remained responsive during the migration.
    Migrations both forward and backward were tested.
    
    * Rubocop fixes
    
    * MigrationHelpers: Support ID columns in some cases
    
    This doesn't work in cases where the ID column is referred to as a
    foreign key by another table.
    
    * MigrationHelpers: support foreign keys for ID cols
    
    Note that this does not yet support foreign keys on non-primary-key
    columns, but Mastodon also doesn't yet have any that we've needed to
    migrate.
    
    This means we can perform fully "concurrent" migrations to change ID
    column types, and the IdsToBigints migration can happen with effectively
    no downtime. (A few operations require a transaction, such as renaming
    columns or deleting them, but these transactions should not block for
    noticeable amounts of time.)
    
    The algorithm for generating foreign key names has changed with this,
    and therefore all of those changed in schema.rb.
    
    * Provide status, allow for interruptions
    
    The MigrationHelpers now allow restarting the rename of a column if it
    was interrupted, by removing the old "new column" and re-starting the
    process.
    
    Along with this, they now provide status updates on the changes which
    are happening, as well as indications about when the changes can be
    safely interrupted (when there are at least 10 seconds estimated to be
    left before copying data is complete).
    
    The IdsToBigints migration now also sorts the columns it migrates by
    size, starting with the largest tables. This should provide
    administrators a worst-case scenario estimate for the length of
    migrations: each successive change will get faster, giving admins a
    chance to abort early on if they need to run the migration later. The
    idea is that this does not force them to try to time interruptions
    between smaller migrations.
    
    * Fix column sorting in IdsToBigints
    
    Not a significant change, but it impacts the order of columns in the
    database and db/schema.rb.
    
    * Actually pause before IdsToBigints
    97c02c33