Class: ActiveRecord::Materialized::TableSwap Private

Inherits:
Object
  • Object
show all
Defined in:
lib/activerecord/materialized/table_swap.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Swaps a view's cache table for a freshly-built temp table, atomically per the engine's DDL semantics: a transaction on SQLite/Postgres (transactional DDL), or a single multi-table RENAME TABLE on MySQL — whose DDL auto-commits, so a transaction could not make two separate renames atomic. Extracted from RelationCacheWriter, which builds the temp table and delegates the swap here.

Instance Method Summary collapse

Constructor Details

#initialize(view_class) ⇒ TableSwap

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of TableSwap.



13
14
15
# File 'lib/activerecord/materialized/table_swap.rb', line 13

def initialize(view_class)
  @view_class = view_class
end

Instance Method Details

#swap!(temp_table, old_table) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Replace the view table with temp_table; the displaced view table becomes old_table and is dropped. Indexes on the displaced table are preserved: the freshly built temp table only carries the schema-default index, so any index a user added to the cache table (or the default one, on a table built before it existed) would otherwise be lost with the dropped old table — unlike PostgreSQL's REFRESH MATERIALIZED VIEW, which keeps them.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/activerecord/materialized/table_swap.rb', line 22

def swap!(temp_table, old_table)
  preserved = current_indexes
  if connection.supports_ddl_transactions?
    # SQLite/Postgres: rename + index restore commit together, so readers only ever see the old
    # table or the fully-indexed new one.
    connection.transaction do
      rename_in_place!(temp_table, old_table)
      restore_missing_indexes!(preserved)
    end
  else
    # MySQL/MariaDB: RENAME TABLE auto-commits (a transaction can't make it atomic with the
    # index rebuild), so the restore runs after. A crash in this window leaves the new table live
    # but missing the preserved indexes until the next rebuild! — degraded read/maintenance
    # performance, never data loss or an empty table (the rename itself is atomic).
    atomic_rename!(temp_table, old_table)
    restore_missing_indexes!(preserved)
  end
end