class Lhm::Invoker

Copies an origin table to an altered destination table. Live activity is synchronized into the destination table using triggers.

Once the origin and destination tables have converged, origin is archived and replaced by destination.

Constants

INNODB_LOCK_WAIT_TIMEOUT_MAX
LOCK_WAIT_TIMEOUT_DELTA
LOCK_WAIT_TIMEOUT_MAX

Attributes

connection[R]
migrator[R]

Public Class Methods

new(origin, connection) click to toggle source
# File lib/lhm/invoker.rb, line 24
def initialize(origin, connection)
  @connection = connection
  @migrator = Migrator.new(origin, connection)
end

Public Instance Methods

run(options = {}) click to toggle source
# File lib/lhm/invoker.rb, line 48
def run(options = {})
  normalize_options(options)
  set_session_lock_wait_timeouts
  migration = @migrator.run
  entangler = Entangler.new(migration, @connection, options)

  entangler.run do
    options[:verifier] ||= Proc.new { |conn| triggers_still_exist?(conn, entangler) }
    Chunker.new(migration, @connection, options).run
    raise "Required triggers do not exist" unless triggers_still_exist?(@connection, entangler)
    if options[:atomic_switch]
      AtomicSwitcher.new(migration, @connection, options).run
    else
      LockedSwitcher.new(migration, @connection).run
    end
  end
end
set_session_lock_wait_timeouts() click to toggle source
# File lib/lhm/invoker.rb, line 29
def set_session_lock_wait_timeouts
  global_innodb_lock_wait_timeout = @connection.select_one("SHOW GLOBAL VARIABLES LIKE 'innodb_lock_wait_timeout'")
  global_lock_wait_timeout = @connection.select_one("SHOW GLOBAL VARIABLES LIKE 'lock_wait_timeout'")

  if global_innodb_lock_wait_timeout
    desired_innodb_lock_wait_timeout = global_innodb_lock_wait_timeout['Value'].to_i + LOCK_WAIT_TIMEOUT_DELTA
    if desired_innodb_lock_wait_timeout <= INNODB_LOCK_WAIT_TIMEOUT_MAX
      @connection.execute("SET SESSION innodb_lock_wait_timeout=#{desired_innodb_lock_wait_timeout}")
    end
  end

  if global_lock_wait_timeout
    desired_lock_wait_timeout = global_lock_wait_timeout['Value'].to_i + LOCK_WAIT_TIMEOUT_DELTA
    if desired_lock_wait_timeout <= LOCK_WAIT_TIMEOUT_MAX
      @connection.execute("SET SESSION lock_wait_timeout=#{desired_lock_wait_timeout}")
    end
  end
end
triggers_still_exist?(conn, entangler) click to toggle source
# File lib/lhm/invoker.rb, line 66
def triggers_still_exist?(conn, entangler)
  triggers = conn.select_values("SHOW TRIGGERS LIKE '%#{migrator.origin.name}'").select { |name| name =~ /^lhmt/ }
  triggers.sort == entangler.expected_triggers.sort
end

Private Instance Methods

normalize_options(options) click to toggle source
# File lib/lhm/invoker.rb, line 73
def normalize_options(options)
  Lhm.logger.info "Starting LHM run on table=#{@migrator.name}"

  unless options.include?(:atomic_switch)
    if supports_atomic_switch?
      options[:atomic_switch] = true
    else
      raise Error.new(
        "Using mysql #{version_string}. You must explicitly set " \
        'options[:atomic_switch] (re SqlHelper#supports_atomic_switch?)')
    end
  end

  if options[:throttler]
    throttler_options = options[:throttler_options] || {}
    options[:throttler] = Throttler::Factory.create_throttler(options[:throttler], throttler_options)
  else
    options[:throttler] = Lhm.throttler
  end

rescue => e
  Lhm.logger.error "LHM run failed with exception=#{e.class} message=#{e.message}"
  raise
end