class Lhm::LockedSwitcher

Switches origin with destination table nonatomically using a locked write. LockedSwitcher adopts the Facebook strategy, with the following caveat:

"Since alter table causes an implicit commit in innodb, innodb locks get
released after the first alter table. So any transaction that sneaks in
after the first alter table and before the second alter table gets
a 'table not found' error. The second alter table is expected to be very
fast though because copytable is not visible to other transactions and so
there is no need to wait."

Attributes

connection[R]

Public Class Methods

new(migration, connection = nil) click to toggle source
# File lib/lhm/locked_switcher.rb, line 25
def initialize(migration, connection = nil)
  @migration = migration
  @connection = connection
  @origin = migration.origin
  @destination = migration.destination
end

Public Instance Methods

statements() click to toggle source
# File lib/lhm/locked_switcher.rb, line 32
def statements
  uncommitted { switch }
end
switch() click to toggle source
# File lib/lhm/locked_switcher.rb, line 36
def switch
  [
    "lock table `#{ @origin.name }` write, `#{ @destination.name }` write",
    "alter table `#{ @origin.name }` rename `#{ @migration.archive_name }`",
    "alter table `#{ @destination.name }` rename `#{ @origin.name }`",
    'commit',
    'unlock tables'
  ]
end
uncommitted() { || ... } click to toggle source
# File lib/lhm/locked_switcher.rb, line 46
def uncommitted
  [
    'set @lhm_auto_commit = @@session.autocommit',
    'set session autocommit = 0',
    yield,
    'set session autocommit = @lhm_auto_commit'
  ].flatten
end
validate() click to toggle source
# File lib/lhm/locked_switcher.rb, line 55
def validate
  unless @connection.data_source_exists?(@origin.name) &&
         @connection.data_source_exists?(@destination.name)
    error "`#{ @origin.name }` and `#{ @destination.name }` must exist"
  end
end

Private Instance Methods

execute() click to toggle source
# File lib/lhm/locked_switcher.rb, line 68
def execute
  statements.each do |stmt|
    @connection.execute(tagged(stmt))
  end
end
revert() click to toggle source
# File lib/lhm/locked_switcher.rb, line 64
def revert
  @connection.execute(tagged('unlock tables'))
end