lhm-shopify 3.5.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +6 -6
  3. data/Appraisals +8 -13
  4. data/CHANGELOG.md +13 -0
  5. data/Gemfile.lock +22 -20
  6. data/README.md +14 -7
  7. data/dev.yml +12 -8
  8. data/docker-compose.yml +2 -0
  9. data/gemfiles/activerecord_6.0.gemfile +1 -1
  10. data/gemfiles/activerecord_6.0.gemfile.lock +25 -21
  11. data/gemfiles/activerecord_6.1.gemfile.lock +17 -13
  12. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile → activerecord_7.0.gemfile} +1 -1
  13. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile.lock → activerecord_7.0.gemfile.lock} +23 -19
  14. data/gemfiles/{activerecord_5.2.gemfile → activerecord_7.1.0.beta1.gemfile} +1 -3
  15. data/gemfiles/activerecord_7.1.0.beta1.gemfile.lock +81 -0
  16. data/lhm.gemspec +1 -1
  17. data/lib/lhm/sql_helper.rb +1 -1
  18. data/lib/lhm/sql_retry.rb +37 -47
  19. data/lib/lhm/throttler/replica_lag.rb +162 -0
  20. data/lib/lhm/throttler/slave_lag.rb +5 -155
  21. data/lib/lhm/throttler/threads_running.rb +3 -1
  22. data/lib/lhm/throttler.rb +7 -3
  23. data/lib/lhm/version.rb +1 -1
  24. data/spec/.lhm.example +1 -1
  25. data/spec/README.md +8 -9
  26. data/spec/integration/atomic_switcher_spec.rb +2 -2
  27. data/spec/integration/chunk_insert_spec.rb +2 -2
  28. data/spec/integration/chunker_spec.rb +33 -38
  29. data/spec/integration/database.yml +1 -1
  30. data/spec/integration/entangler_spec.rb +4 -4
  31. data/spec/integration/integration_helper.rb +12 -12
  32. data/spec/integration/lhm_spec.rb +41 -32
  33. data/spec/integration/locked_switcher_spec.rb +2 -2
  34. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +6 -5
  35. data/spec/integration/toxiproxy_helper.rb +1 -1
  36. data/spec/test_helper.rb +3 -0
  37. data/spec/unit/printer_spec.rb +2 -6
  38. data/spec/unit/sql_helper_spec.rb +2 -2
  39. data/spec/unit/throttler/{slave_lag_spec.rb → replica_lag_spec.rb} +79 -79
  40. data/spec/unit/throttler/threads_running_spec.rb +18 -0
  41. data/spec/unit/throttler_spec.rb +8 -8
  42. metadata +10 -9
  43. data/gemfiles/activerecord_5.2.gemfile.lock +0 -65
data/lib/lhm/sql_retry.rb CHANGED
@@ -18,6 +18,12 @@ module Lhm
18
18
  class SqlRetry
19
19
  RECONNECT_SUCCESSFUL_MESSAGE = "LHM successfully reconnected to initial host:"
20
20
  CLOUDSQL_VERSION_COMMENT = "(Google)"
21
+ # Will retry for 120 seconds (approximately, since connecting takes time).
22
+ RECONNECT_RETRY_MAX_ITERATION = 120
23
+ RECONNECT_RETRY_INTERVAL = 1
24
+ # Will abort the LHM if it had to reconnect more than 25 times in a single run (indicator that there might be
25
+ # something wrong with the network and would be better to run the LHM at a later time).
26
+ RECONNECTION_MAXIMUM = 25
21
27
 
22
28
  MYSQL_VAR_NAMES = {
23
29
  hostname: "@@global.hostname",
@@ -25,9 +31,6 @@ module Lhm
25
31
  version_comment: "@@version_comment",
26
32
  }
27
33
 
28
- # This internal error is used to trigger retries from the parent Retriable.retriable in #with_retries
29
- class ReconnectToHostSuccessful < Lhm::Error; end
30
-
31
34
  def initialize(connection, retry_options: {}, reconnect_with_consistent_host: false)
32
35
  @connection = connection
33
36
  self.retry_config = retry_options
@@ -38,11 +41,14 @@ module Lhm
38
41
  def with_retries(log_prefix: nil)
39
42
  @log_prefix = log_prefix || "" # No prefix. Just logs
40
43
 
44
+ # Amount of time LHM had to reconnect. Aborting if more than RECONNECTION_MAXIMUM
45
+ reconnection_counter = 0
46
+
41
47
  Retriable.retriable(@retry_config) do
42
48
  # Using begin -> rescue -> end for Ruby 2.4 compatibility
43
49
  begin
44
50
  if @reconnect_with_consistent_host
45
- raise Lhm::Error.new("Could not reconnected to initial MySQL host. Aborting to avoid data-loss") unless same_host_as_initial?
51
+ raise Lhm::Error.new("MySQL host has changed since the start of the LHM. Aborting to avoid data-loss") unless same_host_as_initial?
46
52
  end
47
53
 
48
54
  yield(@connection)
@@ -51,7 +57,18 @@ module Lhm
51
57
  # The error will be raised the connection is still active (i.e. no need to reconnect) or if the connection is
52
58
  # dead (i.e. not active) and @reconnect_with_host is false (i.e. instructed not to reconnect)
53
59
  raise e if @connection.active? || (!@connection.active? && !@reconnect_with_consistent_host)
54
- reconnect_with_host_check! if @reconnect_with_consistent_host
60
+
61
+ # Lhm could be stuck in a weird state where it loses connection, reconnects and re looses-connection instantly
62
+ # after, creating an infinite loop (because of the usage of `retry`). Hence, abort after 25 reconnections
63
+ raise Lhm::Error.new("LHM reached host reconnection max of #{RECONNECTION_MAXIMUM} times. " \
64
+ "Please try again later.") if reconnection_counter > RECONNECTION_MAXIMUM
65
+
66
+ reconnection_counter += 1
67
+ if reconnect_with_host_check!
68
+ retry
69
+ else
70
+ raise Lhm::Error.new("LHM tried the reconnection procedure but failed. Aborting")
71
+ end
55
72
  end
56
73
  end
57
74
  end
@@ -105,34 +122,32 @@ module Lhm
105
122
 
106
123
  def reconnect_with_host_check!
107
124
  log_with_prefix("Lost connection to MySQL, will retry to connect to same host")
108
- begin
109
- Retriable.retriable(host_retry_config) do
125
+
126
+ RECONNECT_RETRY_MAX_ITERATION.times do
127
+ begin
128
+ sleep(RECONNECT_RETRY_INTERVAL)
129
+
110
130
  # tries to reconnect. On failure will trigger a retry
111
131
  @connection.reconnect!
112
132
 
113
133
  if same_host_as_initial?
114
134
  # This is not an actual error, but controlled way to get the parent `Retriable.retriable` to retry
115
135
  # the statement that failed (since the Retriable gem only retries on errors).
116
- raise ReconnectToHostSuccessful.new("LHM successfully reconnected to initial host: #{@initial_hostname} (server_id: #{@initial_server_id})")
136
+ log_with_prefix("LHM successfully reconnected to initial host: #{@initial_hostname} (server_id: #{@initial_server_id})")
137
+ return true
117
138
  else
118
139
  # New Master --> abort LHM (reconnecting will not change anything)
119
- raise Lhm::Error.new("Reconnected to wrong host. Started migration on: #{@initial_hostname} (server_id: #{@initial_server_id}), but reconnected to: #{hostname} (server_id: #{@initial_server_id}).")
140
+ log_with_prefix("Reconnected to wrong host. Started migration on: #{@initial_hostname} (server_id: #{@initial_server_id}), but reconnected to: #{hostname} (server_id: #{server_id}).", :error)
141
+ return false
120
142
  end
143
+ rescue StandardError => e
144
+ # Retry if ActiveRecord cannot reach host
145
+ next if /Lost connection to MySQL server at 'reading initial communication packet'/ === e.message
146
+ log_with_prefix("Encountered error: [#{e.class}] #{e.message}. Will stop reconnection procedure.", :info)
147
+ return false
121
148
  end
122
- rescue StandardError => e
123
- # The parent Retriable.retriable is configured to retry if it encounters an error with the success message.
124
- # Therefore, if the connection is re-established successfully AND the host is the same, LHM can retry the query
125
- # that originally failed.
126
- raise e if reconnect_successful?(e)
127
- # If the connection was not successful, the parent retriable will raise any error that originated from the
128
- # `@connection.reconnect!`
129
- # Therefore, this error will cause the LHM to abort
130
- raise Lhm::Error.new("LHM tried the reconnection procedure but failed. Latest error: #{e.message}")
131
149
  end
132
- end
133
-
134
- def reconnect_successful?(e)
135
- e.is_a?(ReconnectToHostSuccessful)
150
+ false
136
151
  end
137
152
 
138
153
  # For a full list of configuration options see https://github.com/kamui/retriable
@@ -149,9 +164,6 @@ module Lhm
149
164
  /Unknown MySQL server host/,
150
165
  /connection is locked to hostgroup/,
151
166
  /The MySQL server is running with the --read-only option so it cannot execute this statement/,
152
- ],
153
- ReconnectToHostSuccessful => [
154
- /#{RECONNECT_SUCCESSFUL_MESSAGE}/
155
167
  ]
156
168
  },
157
169
  multiplier: 1, # each successive interval grows by this factor
@@ -159,28 +171,6 @@ module Lhm
159
171
  tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
160
172
  rand_factor: 0, # percentage to randomize the next retry interval time
161
173
  max_elapsed_time: Float::INFINITY, # max total time in seconds that code is allowed to keep being retried
162
- on_retry: Proc.new do |exception, try_number, total_elapsed_time, next_interval|
163
- if reconnect_successful?(exception)
164
- log_with_prefix("#{exception.message} -- triggering retry", :info)
165
- else
166
- log_with_prefix("#{exception.class}: '#{exception.message}' - #{try_number} tries in #{total_elapsed_time} seconds and #{next_interval} seconds until the next try.", :error)
167
- end
168
- end
169
- }.freeze
170
- end
171
-
172
- def host_retry_config
173
- {
174
- on: {
175
- StandardError => [
176
- /Lost connection to MySQL server at 'reading initial communication packet'/
177
- ]
178
- },
179
- multiplier: 1, # each successive interval grows by this factor
180
- base_interval: 0.25, # the initial interval in seconds between tries.
181
- tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
182
- rand_factor: 0, # percentage to randomize the next retry interval time
183
- max_elapsed_time: Float::INFINITY, # max total time in seconds that code is allowed to keep being retried
184
174
  on_retry: Proc.new do |exception, try_number, total_elapsed_time, next_interval|
185
175
  log_with_prefix("#{exception.class}: '#{exception.message}' - #{try_number} tries in #{total_elapsed_time} seconds and #{next_interval} seconds until the next try.", :error)
186
176
  end
@@ -0,0 +1,162 @@
1
+ module Lhm
2
+ module Throttler
3
+
4
+ def self.format_hosts(hosts)
5
+ formatted_hosts = []
6
+ hosts.each do |host|
7
+ if host && !host.match(/localhost/) && !host.match(/127.0.0.1/)
8
+ formatted_hosts << host.partition(':')[0]
9
+ end
10
+ end
11
+ formatted_hosts
12
+ end
13
+
14
+ class ReplicaLag
15
+ include Command
16
+
17
+ INITIAL_TIMEOUT = 0.1
18
+ DEFAULT_STRIDE = 2_000
19
+ DEFAULT_MAX_ALLOWED_LAG = 10
20
+
21
+ MAX_TIMEOUT = INITIAL_TIMEOUT * 1024
22
+
23
+ attr_accessor :timeout_seconds, :allowed_lag, :stride, :connection
24
+
25
+ def initialize(options = {})
26
+ @timeout_seconds = INITIAL_TIMEOUT
27
+ @stride = options[:stride] || DEFAULT_STRIDE
28
+ @allowed_lag = options[:allowed_lag] || DEFAULT_MAX_ALLOWED_LAG
29
+ @replicas = {}
30
+ @get_config = options[:current_config]
31
+ @check_only = options[:check_only]
32
+ end
33
+
34
+ def execute
35
+ sleep(throttle_seconds)
36
+ end
37
+
38
+ private
39
+
40
+ def throttle_seconds
41
+ lag = max_current_replica_lag
42
+
43
+ if lag > @allowed_lag && @timeout_seconds < MAX_TIMEOUT
44
+ Lhm.logger.info("Increasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds * 2} because #{lag} seconds of replica lag detected is greater than the maximum of #{@allowed_lag} seconds allowed.")
45
+ @timeout_seconds = @timeout_seconds * 2
46
+ elsif lag <= @allowed_lag && @timeout_seconds > INITIAL_TIMEOUT
47
+ Lhm.logger.info("Decreasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds / 2} because #{lag} seconds of replica lag detected is less than or equal to the #{@allowed_lag} seconds allowed.")
48
+ @timeout_seconds = @timeout_seconds / 2
49
+ else
50
+ @timeout_seconds
51
+ end
52
+ end
53
+
54
+ def replicas
55
+ @replicas[@connection] ||= get_replicas
56
+ end
57
+
58
+ def get_replicas
59
+ replicas = []
60
+ if @check_only.nil? or !@check_only.respond_to?(:call)
61
+ replica_hosts = master_replica_hosts
62
+ while replica_hosts.any? do
63
+ host = replica_hosts.pop
64
+ replica = Replica.new(host, @get_config)
65
+ if !replicas.map(&:host).include?(host) && replica.connection
66
+ replicas << replica
67
+ replica_hosts.concat(replica.replica_hosts)
68
+ end
69
+ end
70
+ else
71
+ replica_config = @check_only.call
72
+ replicas << Replica.new(replica_config['host'], @get_config)
73
+ end
74
+ replicas
75
+ end
76
+
77
+ def master_replica_hosts
78
+ Throttler.format_hosts(@connection.select_values(Replica::SQL_SELECT_REPLICA_HOSTS))
79
+ end
80
+
81
+ def max_current_replica_lag
82
+ max = replicas.map { |replica| replica.lag }.push(0).max
83
+ Lhm.logger.info "Max current replica lag: #{max}"
84
+ max
85
+ end
86
+ end
87
+
88
+ class Replica
89
+ SQL_SELECT_REPLICA_HOSTS = "SELECT host FROM information_schema.processlist WHERE command LIKE 'Binlog Dump%'"
90
+ SQL_SELECT_MAX_REPLICA_LAG = 'SHOW SLAVE STATUS'
91
+
92
+ attr_reader :host, :connection
93
+
94
+ def initialize(host, connection_config = nil)
95
+ @host = host
96
+ @connection_config = prepare_connection_config(connection_config)
97
+ @connection = client(@connection_config)
98
+ end
99
+
100
+ def replica_hosts
101
+ Throttler.format_hosts(query_connection(SQL_SELECT_REPLICA_HOSTS, 'host'))
102
+ end
103
+
104
+ def lag
105
+ query_connection(SQL_SELECT_MAX_REPLICA_LAG, 'Seconds_Behind_Master').first.to_i
106
+ end
107
+
108
+ private
109
+
110
+ def client(config)
111
+ begin
112
+ Lhm.logger.info "Connecting to #{@host} on database: #{config[:database]}"
113
+ Mysql2::Client.new(config)
114
+ rescue Mysql2::Error => e
115
+ Lhm.logger.info "Error connecting to #{@host}: #{e}"
116
+ nil
117
+ end
118
+ end
119
+
120
+ def prepare_connection_config(config_proc)
121
+ config = if config_proc
122
+ if config_proc.respond_to?(:call) # if we get a proc
123
+ config_proc.call
124
+ else
125
+ raise ArgumentError, "Expected #{config_proc.inspect} to respond to `call`"
126
+ end
127
+ else
128
+ db_config
129
+ end
130
+ config.deep_symbolize_keys!
131
+ config[:host] = @host
132
+ config
133
+ end
134
+
135
+ def query_connection(query, result)
136
+ begin
137
+ @connection.query(query).map { |row| row[result] }
138
+ rescue Mysql2::Error => e
139
+ Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
140
+ [nil]
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def db_config
147
+ if ar_supports_db_config?
148
+ ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
149
+ else
150
+ ActiveRecord::Base.connection_pool.spec.config.dup
151
+ end
152
+ end
153
+
154
+ def ar_supports_db_config?
155
+ # https://api.rubyonrails.org/v6.0/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has spec
156
+ # vs
157
+ # https://api.rubyonrails.org/v6.1/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has db_config
158
+ ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
159
+ end
160
+ end
161
+ end
162
+ end
@@ -1,161 +1,11 @@
1
+ require 'lhm/throttler/replica_lag'
2
+
1
3
  module Lhm
2
4
  module Throttler
3
-
4
- def self.format_hosts(hosts)
5
- formatted_hosts = []
6
- hosts.each do |host|
7
- if host && !host.match(/localhost/) && !host.match(/127.0.0.1/)
8
- formatted_hosts << host.partition(':')[0]
9
- end
10
- end
11
- formatted_hosts
12
- end
13
-
14
- class SlaveLag
15
- include Command
16
-
17
- INITIAL_TIMEOUT = 0.1
18
- DEFAULT_STRIDE = 2_000
19
- DEFAULT_MAX_ALLOWED_LAG = 10
20
-
21
- MAX_TIMEOUT = INITIAL_TIMEOUT * 1024
22
-
23
- attr_accessor :timeout_seconds, :allowed_lag, :stride, :connection
24
-
5
+ class SlaveLag < ReplicaLag
25
6
  def initialize(options = {})
26
- @timeout_seconds = INITIAL_TIMEOUT
27
- @stride = options[:stride] || DEFAULT_STRIDE
28
- @allowed_lag = options[:allowed_lag] || DEFAULT_MAX_ALLOWED_LAG
29
- @slaves = {}
30
- @get_config = options[:current_config]
31
- @check_only = options[:check_only]
32
- end
33
-
34
- def execute
35
- sleep(throttle_seconds)
36
- end
37
-
38
- private
39
-
40
- def throttle_seconds
41
- lag = max_current_slave_lag
42
-
43
- if lag > @allowed_lag && @timeout_seconds < MAX_TIMEOUT
44
- Lhm.logger.info("Increasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds * 2} because #{lag} seconds of slave lag detected is greater than the maximum of #{@allowed_lag} seconds allowed.")
45
- @timeout_seconds = @timeout_seconds * 2
46
- elsif lag <= @allowed_lag && @timeout_seconds > INITIAL_TIMEOUT
47
- Lhm.logger.info("Decreasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds / 2} because #{lag} seconds of slave lag detected is less than or equal to the #{@allowed_lag} seconds allowed.")
48
- @timeout_seconds = @timeout_seconds / 2
49
- else
50
- @timeout_seconds
51
- end
52
- end
53
-
54
- def slaves
55
- @slaves[@connection] ||= get_slaves
56
- end
57
-
58
- def get_slaves
59
- slaves = []
60
- if @check_only.nil? or !@check_only.respond_to?(:call)
61
- slave_hosts = master_slave_hosts
62
- while slave_hosts.any? do
63
- host = slave_hosts.pop
64
- slave = Slave.new(host, @get_config)
65
- if !slaves.map(&:host).include?(host) && slave.connection
66
- slaves << slave
67
- slave_hosts.concat(slave.slave_hosts)
68
- end
69
- end
70
- else
71
- slave_config = @check_only.call
72
- slaves << Slave.new(slave_config['host'], @get_config)
73
- end
74
- slaves
75
- end
76
-
77
- def master_slave_hosts
78
- Throttler.format_hosts(@connection.select_values(Slave::SQL_SELECT_SLAVE_HOSTS))
79
- end
80
-
81
- def max_current_slave_lag
82
- max = slaves.map { |slave| slave.lag }.push(0).max
83
- Lhm.logger.info "Max current slave lag: #{max}"
84
- max
85
- end
86
- end
87
-
88
- class Slave
89
- SQL_SELECT_SLAVE_HOSTS = "SELECT host FROM information_schema.processlist WHERE command LIKE 'Binlog Dump%'"
90
- SQL_SELECT_MAX_SLAVE_LAG = 'SHOW SLAVE STATUS'
91
-
92
- attr_reader :host, :connection
93
-
94
- def initialize(host, connection_config = nil)
95
- @host = host
96
- @connection_config = prepare_connection_config(connection_config)
97
- @connection = client(@connection_config)
98
- end
99
-
100
- def slave_hosts
101
- Throttler.format_hosts(query_connection(SQL_SELECT_SLAVE_HOSTS, 'host'))
102
- end
103
-
104
- def lag
105
- query_connection(SQL_SELECT_MAX_SLAVE_LAG, 'Seconds_Behind_Master').first.to_i
106
- end
107
-
108
- private
109
-
110
- def client(config)
111
- begin
112
- Lhm.logger.info "Connecting to #{@host} on database: #{config[:database]}"
113
- Mysql2::Client.new(config)
114
- rescue Mysql2::Error => e
115
- Lhm.logger.info "Error connecting to #{@host}: #{e}"
116
- nil
117
- end
118
- end
119
-
120
- def prepare_connection_config(config_proc)
121
- config = if config_proc
122
- if config_proc.respond_to?(:call) # if we get a proc
123
- config_proc.call
124
- else
125
- raise ArgumentError, "Expected #{config_proc.inspect} to respond to `call`"
126
- end
127
- else
128
- db_config
129
- end
130
- config.deep_symbolize_keys!
131
- config[:host] = @host
132
- config
133
- end
134
-
135
- def query_connection(query, result)
136
- begin
137
- @connection.query(query).map { |row| row[result] }
138
- rescue Mysql2::Error => e
139
- Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
140
- [nil]
141
- end
142
- end
143
-
144
- private
145
-
146
- def db_config
147
- if ar_supports_db_config?
148
- ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
149
- else
150
- ActiveRecord::Base.connection_pool.spec.config.dup
151
- end
152
- end
153
-
154
- def ar_supports_db_config?
155
- # https://api.rubyonrails.org/v6.0/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has spec
156
- # vs
157
- # https://api.rubyonrails.org/v6.1/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has db_config
158
- ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
7
+ Lhm.logger.warn("Class `SlaveLag` is deprecated. Use `ReplicaLag` class instead.")
8
+ super(options)
159
9
  end
160
10
  end
161
11
  end
@@ -3,14 +3,16 @@ module Lhm
3
3
  class ThreadsRunning
4
4
  include Command
5
5
 
6
+ DEFAULT_STRIDE = 2_000
6
7
  DEFAULT_INITIAL_TIMEOUT = 0.1
7
8
  DEFAULT_HEALTHY_RANGE = (0..50)
8
9
 
9
- attr_accessor :timeout_seconds, :healthy_range, :connection
10
+ attr_accessor :timeout_seconds, :healthy_range, :connection, :stride
10
11
  attr_reader :max_timeout_seconds, :initial_timeout_seconds
11
12
 
12
13
  def initialize(options = {})
13
14
  @initial_timeout_seconds = options[:initial_timeout] || DEFAULT_INITIAL_TIMEOUT
15
+ @stride = options[:stride] || DEFAULT_STRIDE
14
16
  @max_timeout_seconds = options[:max_timeout] || (@initial_timeout_seconds * 1024)
15
17
  @timeout_seconds = @initial_timeout_seconds
16
18
  @healthy_range = options[:healthy_range] || DEFAULT_HEALTHY_RANGE
data/lib/lhm/throttler.rb CHANGED
@@ -1,12 +1,16 @@
1
1
  require 'lhm/throttler/time'
2
+ require 'lhm/throttler/replica_lag'
2
3
  require 'lhm/throttler/slave_lag'
3
4
  require 'lhm/throttler/threads_running'
4
5
 
5
6
  module Lhm
6
7
  module Throttler
7
- CLASSES = { :time_throttler => Throttler::Time,
8
- :slave_lag_throttler => Throttler::SlaveLag,
9
- :threads_running_throttler => Throttler::ThreadsRunning }
8
+ CLASSES = {
9
+ :time_throttler => Throttler::Time,
10
+ :replica_lag_throttler => Throttler::ReplicaLag,
11
+ :slave_lag_throttler => Throttler::SlaveLag,
12
+ :threads_running_throttler => Throttler::ThreadsRunning
13
+ }
10
14
 
11
15
  def throttler
12
16
  @throttler ||= Throttler::Time.new
data/lib/lhm/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Schmidt
3
3
 
4
4
  module Lhm
5
- VERSION = '3.5.4'
5
+ VERSION = '4.0.0'
6
6
  end
data/spec/.lhm.example CHANGED
@@ -1,4 +1,4 @@
1
1
  mysqldir=/usr/local/mysql
2
2
  basedir=~/lhm-cluster
3
3
  master_port=3306
4
- slave_port=3307
4
+ replica_port=3307
data/spec/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Preparing for master slave integration tests
1
+ # Preparing for master replica integration tests
2
2
 
3
3
  ## Configuration
4
4
 
@@ -7,10 +7,10 @@ create ~/.lhm:
7
7
  mysqldir=/usr/local/mysql
8
8
  basedir=~/lhm-cluster
9
9
  master_port=3306
10
- slave_port=3307
10
+ replica_port=3307
11
11
 
12
12
  mysqldir specifies the location of your mysql install. basedir is the
13
- directory master and slave databases will get installed into.
13
+ directory master and replica databases will get installed into.
14
14
 
15
15
  ## Automatic setup
16
16
 
@@ -18,8 +18,8 @@ directory master and slave databases will get installed into.
18
18
 
19
19
  bin/lhm-spec-clobber.sh
20
20
 
21
- You can set the integration specs up to run against a master slave setup by
22
- running the included that. This deletes the configured lhm master slave setup and reinstalls and configures a master slave setup.
21
+ You can set the integration specs up to run against a master replica setup by
22
+ running the included that. This deletes the configured lhm master replica setup and reinstalls and configures a master replica setup.
23
23
 
24
24
  Follow the manual instructions if you want more control over this process.
25
25
 
@@ -33,7 +33,7 @@ Follow the manual instructions if you want more control over this process.
33
33
 
34
34
  basedir=/opt/lhm-luster
35
35
  mysqld --defaults-file="$basedir/master/my.cnf"
36
- mysqld --defaults-file="$basedir/slave/my.cnf"
36
+ mysqld --defaults-file="$basedir/replica/my.cnf"
37
37
 
38
38
  ### run the grants
39
39
 
@@ -46,13 +46,12 @@ Setup the dependency gems
46
46
  export BUNDLE_GEMFILE=gemfiles/ar-4.2_mysql2.gemfile
47
47
  bundle install
48
48
 
49
- To run specs in slave mode, set the MASTER_SLAVE=1 when running tests:
49
+ To run specs in replica mode, set the MASTER_REPLICA=1 when running tests:
50
50
 
51
- MASTER_SLAVE=1 bundle exec rake specs
51
+ MASTER_REPLICA=1 bundle exec rake specs
52
52
 
53
53
  # connecting
54
54
 
55
55
  you can connect by running (with the respective ports):
56
56
 
57
57
  mysql --protocol=TCP -p3307
58
-
@@ -110,7 +110,7 @@ describe Lhm::AtomicSwitcher do
110
110
  switcher = Lhm::AtomicSwitcher.new(@migration, connection)
111
111
  switcher.run
112
112
 
113
- slave do
113
+ replica do
114
114
  value(data_source_exists?(@origin)).must_equal true
115
115
  value(table_read(@migration.archive_name).columns.keys).must_include 'origin'
116
116
  end
@@ -120,7 +120,7 @@ describe Lhm::AtomicSwitcher do
120
120
  switcher = Lhm::AtomicSwitcher.new(@migration, connection)
121
121
  switcher.run
122
122
 
123
- slave do
123
+ replica do
124
124
  value(data_source_exists?(@destination)).must_equal false
125
125
  value(table_read(@origin.name).columns.keys).must_include 'destination'
126
126
  end
@@ -19,10 +19,10 @@ describe Lhm::ChunkInsert do
19
19
  assert_equal 1, @instance.insert_and_return_count_of_rows_created
20
20
  end
21
21
 
22
- it "inserts the record into the slave" do
22
+ it "inserts the record into the replica" do
23
23
  @instance.insert_and_return_count_of_rows_created
24
24
 
25
- slave do
25
+ replica do
26
26
  value(count_all(@destination.name)).must_equal(1)
27
27
  end
28
28
  end