forked from soundcloud/lhm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlhm.rb
116 lines (105 loc) · 3.65 KB
/
lhm.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Copyright (c) 2011 - 2013, SoundCloud Ltd., Rany Keddo, Tobias Bielohlawek, Tobias
# Schmidt
require 'lhm/table'
require 'lhm/invoker'
require 'lhm/throttler'
require 'lhm/version'
require 'logger'
# Large hadron migrator - online schema change tool
#
# @example
#
# Lhm.change_table(:users) do |m|
# m.add_column(:arbitrary, "INT(12)")
# m.add_index([:arbitrary, :created_at])
# m.ddl("alter table %s add column flag tinyint(1)" % m.name)
# end
#
module Lhm
extend Throttler
extend self
DEFAULT_LOGGER_OPTIONS = { level: Logger::INFO, file: STDOUT }
# Alters a table with the changes described in the block
#
# @param [String, Symbol] table_name Name of the table
# @param [Hash] options Optional options to alter the chunk / switch behavior
# @option options [Fixnum] :stride
# Size of a chunk (defaults to: 40,000)
# @option options [Fixnum] :throttle
# Time to wait between chunks in milliseconds (defaults to: 100)
# @option options [Fixnum] :start
# Primary Key position at which to start copying chunks
# @option options [Fixnum] :limit
# Primary Key position at which to stop copying chunks
# @option options [Boolean] :atomic_switch
# Use atomic switch to rename tables (defaults to: true)
# If using a version of mysql affected by atomic switch bug, LHM forces user
# to set this option (see SqlHelper#supports_atomic_switch?)
# @yield [Migrator] Yielded Migrator object records the changes
# @return [Boolean] Returns true if the migration finishes
# @raise [Error] Raises Lhm::Error in case of a error and aborts the migration
def change_table(table_name, options = {}, &block)
origin = Table.parse(table_name, connection)
invoker = Invoker.new(origin, connection)
block.call(invoker.migrator)
invoker.run(options)
true
end
# Cleanup tables and triggers
#
# @param [Boolean] run execute now or just display information
# @param [Hash] options Optional options to alter cleanup behaviour
# @option options [Time] :until
# Filter to only remove tables up to specified time (defaults to: nil)
def cleanup(run = false, options = {})
lhm_tables = connection.select_values('show tables').select { |name| name =~ /^lhm(a|n)_/ }
if options[:until]
lhm_tables.select! do |table|
table_date_time = Time.strptime(table, 'lhma_%Y_%m_%d_%H_%M_%S')
table_date_time <= options[:until]
end
end
lhm_triggers = connection.select_values('show triggers').collect do |trigger|
trigger.respond_to?(:trigger) ? trigger.trigger : trigger
end.select { |name| name =~ /^lhmt/ }
if run
lhm_triggers.each do |trigger|
connection.execute("drop trigger if exists #{trigger}")
end
lhm_tables.each do |table|
connection.execute("drop table if exists #{table}")
end
true
elsif lhm_tables.empty? && lhm_triggers.empty?
puts 'Everything is clean. Nothing to do.'
true
else
puts "Existing LHM backup tables: #{lhm_tables.join(', ')}."
puts "Existing LHM triggers: #{lhm_triggers.join(', ')}."
puts 'Run Lhm.cleanup(:run) to drop them all.'
false
end
end
def setup(connection)
@@connection = connection
end
def connection
@@connection ||=
begin
raise 'Please call Lhm.setup' unless defined?(ActiveRecord)
ActiveRecord::Base.connection
end
end
def self.logger=(new_logger)
@@logger = new_logger
end
def self.logger
@@logger ||=
begin
logger = Logger.new(DEFAULT_LOGGER_OPTIONS[:file])
logger.level = DEFAULT_LOGGER_OPTIONS[:level]
logger.formatter = nil
logger
end
end
end