Class: Lhm::LockedSwitcher

Inherits:
Object
  • Object
show all
Includes:
Command, SqlHelper
Defined in:
lib/lhm/locked_switcher.rb

Overview

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."

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SqlHelper

#annotation, #idx_name, #idx_spec, #version_string

Methods included from Command

#run

Constructor Details

#initialize(migration, connection = nil) ⇒ LockedSwitcher

Returns a new instance of LockedSwitcher.



25
26
27
28
29
30
# File 'lib/lhm/locked_switcher.rb', line 25

def initialize(migration, connection = nil)
  @migration = migration
  @connection = connection
  @origin = migration.origin
  @destination = migration.destination
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



23
24
25
# File 'lib/lhm/locked_switcher.rb', line 23

def connection
  @connection
end

Instance Method Details

#statementsObject



32
33
34
# File 'lib/lhm/locked_switcher.rb', line 32

def statements
  uncommitted { switch }
end

#switchObject



36
37
38
39
40
41
42
43
44
# 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(&block) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/lhm/locked_switcher.rb', line 46

def uncommitted(&block)
  [
    'set @lhm_auto_commit = @@session.autocommit',
    'set session autocommit = 0',
    yield,
    'set session autocommit = @lhm_auto_commit'
  ].flatten
end

#validateObject



55
56
57
58
59
60
# File 'lib/lhm/locked_switcher.rb', line 55

def validate
  unless @connection.table_exists?(@origin.name) &&
         @connection.table_exists?(@destination.name)
    error "`#{ @origin.name }` and `#{ @destination.name }` must exist"
  end
end