Class: Lhm::LockedSwitcher

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

Overview

Switches origin with destination table with a write lock. Use this as a safe alternative to rename, which can cause slave inconsistencies:

http://bugs.mysql.com/bug.php?id=39675

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, #sql, #table?, #update

Methods included from Command

#run

Constructor Details

#initialize(migration, connection = nil) ⇒ LockedSwitcher

Returns a new instance of LockedSwitcher.



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

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.



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

def connection
  @connection
end

Instance Method Details

#statementsObject



36
37
38
# File 'lib/lhm/locked_switcher.rb', line 36

def statements
  uncommitted { switch }
end

#switchObject



40
41
42
43
44
45
46
47
48
# File 'lib/lhm/locked_switcher.rb', line 40

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



50
51
52
53
54
55
56
57
# File 'lib/lhm/locked_switcher.rb', line 50

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

#validateObject



59
60
61
62
63
# File 'lib/lhm/locked_switcher.rb', line 59

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