lhm-shopify 3.4.0 → 3.4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c60de7019efd80463c07434cb2312197009347dc5e7b8d238c1f3ba0355b7a9e
4
- data.tar.gz: 44658f6f74b6c98739c6fd58046dd3ffa20436949f379eb9607a070afabeee8e
3
+ metadata.gz: ef0c285f7d63755816429aa2795220be251c0c93c4506f8255f7e547c074d574
4
+ data.tar.gz: 5de29d0b924375634c061a459837f0ea6a12d5ccf58226032ef25f708ef15628
5
5
  SHA512:
6
- metadata.gz: 318c3a3f051c8bfd8cb8e30bdfef2bad0c0c61fcbc7081780adb4eaba60023e94ac9d86b4f203a950ad31c304cc3bdd3affb88eb29633ef115185aab92596d55
7
- data.tar.gz: 644b728df70002076404e93133dbed4f53565bec70de02ca39640a482276ad7480de18a45a06a277bd55c1d6cad906026a7454bd05e7471efd055921da51708a
6
+ metadata.gz: 2d24b1d78c6fdd67129ee91a01d043ccefb1f2e8c4b8322553f1c6cbfed6237105e58eb6ddab0e143869b813682ea6b3c25e5a40e66199f76adc0cc99a97050b
7
+ data.tar.gz: 327b3a438ac2fb1b0763396094baed303a2ecb9a37558295b8b516b089bcca73534102351281883679263f7e69647d1129941df4970d3abae004faf93d91db62
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 3.4.1 (Sep 22, 2021)
2
+
3
+ * Add better logging to the LHM components (https://github.com/Shopify/lhm/pull/108)
4
+
1
5
  # 3.4.0 (Jul 19, 2021)
2
6
 
3
7
  * Log or raise on unexpected duplicated entry warnings during INSERT IGNORE (https://github.com/Shopify/lhm/pull/100)
data/lib/lhm/chunker.rb CHANGED
@@ -37,6 +37,8 @@ module Lhm
37
37
  end
38
38
 
39
39
  def execute
40
+ @start_time = Time.now
41
+
40
42
  return if @chunk_finder.table_empty?
41
43
  @next_to_insert = @start
42
44
  while @next_to_insert <= @limit || (@start == @limit)
@@ -47,6 +49,8 @@ module Lhm
47
49
  affected_rows = ChunkInsert.new(@migration, @connection, bottom, top, @options).insert_and_return_count_of_rows_created
48
50
  expected_rows = top - bottom + 1
49
51
 
52
+ rate_limited_log_progress
53
+
50
54
  if affected_rows < expected_rows
51
55
  raise_on_non_pk_duplicate_warning
52
56
  end
@@ -54,8 +58,10 @@ module Lhm
54
58
  if @throttler && affected_rows > 0
55
59
  @throttler.run
56
60
  end
57
- @printer.notify(bottom, @limit)
61
+
58
62
  @next_to_insert = top + 1
63
+ @printer.notify(bottom, @limit)
64
+
59
65
  break if @start == @limit
60
66
  end
61
67
  @printer.end
@@ -100,5 +106,14 @@ module Lhm
100
106
  return if @chunk_finder.table_empty?
101
107
  @chunk_finder.validate
102
108
  end
109
+
110
+ # Only log the chunker progress every 5 minutes instead of every iteration
111
+ def rate_limited_log_progress
112
+ current_time = Time.now
113
+ if current_time - @start_time > (5 * 60)
114
+ Lhm.logger.info("Inserted #{affected_rows} rows into the destination table from #{bottom} to #{top}")
115
+ @start_time = current_time
116
+ end
117
+ end
103
118
  end
104
119
  end
@@ -63,11 +63,12 @@ module Lhm
63
63
  retriable_connection.execute(ddl)
64
64
  end
65
65
  end
66
+ Lhm.logger.info("Dropped triggers on #{@lhm_triggers_for_origin.join(', ')}")
67
+ Lhm.logger.info("Dropped tables #{@lhm_triggers_for_origin.join(', ')}")
66
68
  end
67
69
 
68
70
  def report_ddls
69
- puts "The following DDLs would be executed:"
70
- ddls.each { |ddl| puts ddl }
71
+ Lhm.logger.info("The following DDLs would be executed: #{ddls}")
71
72
  end
72
73
  end
73
74
  end
data/lib/lhm/entangler.rb CHANGED
@@ -94,6 +94,7 @@ module Lhm
94
94
  retriable_connection.execute(stmt)
95
95
  end
96
96
  end
97
+ Lhm.logger.info("Created triggers on #{@origin.name}")
97
98
  end
98
99
 
99
100
  def after
@@ -102,6 +103,7 @@ module Lhm
102
103
  retriable_connection.execute(stmt)
103
104
  end
104
105
  end
106
+ Lhm.logger.info("Dropped triggers on #{@origin.name}")
105
107
  end
106
108
 
107
109
  def revert
data/lib/lhm/migrator.rb CHANGED
@@ -214,6 +214,8 @@ module Lhm
214
214
  replacement = %{CREATE TABLE `#{ @origin.destination_name }`}
215
215
  stmt = @origin.ddl.gsub(original, replacement)
216
216
  @connection.execute(tagged(stmt))
217
+
218
+ Lhm.logger.info("Created destination table #{@origin.destination_name}")
217
219
  end
218
220
 
219
221
  def destination_read
data/lib/lhm/printer.rb CHANGED
@@ -12,26 +12,30 @@ module Lhm
12
12
  end
13
13
  end
14
14
 
15
- class Percentage < Base
15
+ class Percentage
16
16
  def initialize
17
- super
18
17
  @max_length = 0
19
18
  end
20
19
 
21
20
  def notify(lowest, highest)
22
21
  return if !highest || highest == 0
22
+
23
+ # The argument lowest represents the next_to_insert row id, and highest represents the
24
+ # maximum id upto which chunker has to copy the data.
25
+ # If all the rows are inserted upto highest, then lowest passed here from chunker was
26
+ # highest + 1, which leads to the printer printing the progress > 100%.
27
+ return if lowest >= highest
28
+
23
29
  message = "%.2f%% (#{lowest}/#{highest}) complete" % (lowest.to_f / highest * 100.0)
24
30
  write(message)
25
31
  end
26
32
 
27
33
  def end
28
34
  write('100% complete')
29
- @output.write "\n"
30
35
  end
31
36
 
32
37
  def exception(e)
33
- write("failed: #{e}")
34
- @output.write "\n"
38
+ Lhm.logger.error("failed: #{e}")
35
39
  end
36
40
 
37
41
  private
@@ -42,7 +46,7 @@ module Lhm
42
46
  extra = 0
43
47
  end
44
48
 
45
- @output.write "\r#{message}" + (' ' * extra)
49
+ Lhm.logger.info(message)
46
50
  end
47
51
  end
48
52
 
data/lib/lhm/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Schmidt
3
3
 
4
4
  module Lhm
5
- VERSION = '3.4.0'
5
+ VERSION = '3.4.1'
6
6
  end
data/lib/lhm.rb CHANGED
@@ -114,17 +114,21 @@ module Lhm
114
114
  triggers.each do |trigger|
115
115
  connection.execute("drop trigger if exists #{trigger}")
116
116
  end
117
+ logger.info("Dropped triggers #{triggers.join(', ')}")
118
+
117
119
  tables.each do |table|
118
120
  connection.execute("drop table if exists #{table}")
119
121
  end
122
+ logger.info("Dropped tables #{tables.join(', ')}")
123
+
120
124
  true
121
125
  elsif tables.empty? && triggers.empty?
122
- puts 'Everything is clean. Nothing to do.'
126
+ logger.info('Everything is clean. Nothing to do.')
123
127
  true
124
128
  else
125
- puts "Would drop LHM backup tables: #{tables.join(', ')}."
126
- puts "Would drop LHM triggers: #{triggers.join(', ')}."
127
- puts 'Run with Lhm.cleanup(true) to drop all LHM triggers and tables, or Lhm.cleanup_current_run(true, table_name) to clean up a specific LHM.'
129
+ logger.info("Would drop LHM backup tables: #{tables.join(', ')}.")
130
+ logger.info("Would drop LHM triggers: #{triggers.join(', ')}.")
131
+ logger.info('Run with Lhm.cleanup(true) to drop all LHM triggers and tables, or Lhm.cleanup_current_run(true, table_name) to clean up a specific LHM.')
128
132
  false
129
133
  end
130
134
  end
@@ -58,7 +58,7 @@ describe Lhm::AtomicSwitcher do
58
58
  switcher.send :define_singleton_method, :atomic_switch do
59
59
  'SELECT * FROM nonexistent'
60
60
  end
61
- -> { switcher.run }.must_raise(ActiveRecord::StatementInvalid)
61
+ value(-> { switcher.run }).must_raise(ActiveRecord::StatementInvalid)
62
62
  end
63
63
 
64
64
  it "should raise when destination doesn't exist" do
@@ -75,8 +75,8 @@ describe Lhm::AtomicSwitcher do
75
75
  switcher.run
76
76
 
77
77
  slave do
78
- data_source_exists?(@origin).must_equal true
79
- table_read(@migration.archive_name).columns.keys.must_include 'origin'
78
+ value(data_source_exists?(@origin)).must_equal true
79
+ value(table_read(@migration.archive_name).columns.keys).must_include 'origin'
80
80
  end
81
81
  end
82
82
 
@@ -85,8 +85,8 @@ describe Lhm::AtomicSwitcher do
85
85
  switcher.run
86
86
 
87
87
  slave do
88
- data_source_exists?(@destination).must_equal false
89
- table_read(@origin.name).columns.keys.must_include 'destination'
88
+ value(data_source_exists?(@destination)).must_equal false
89
+ value(table_read(@origin.name).columns.keys).must_include 'destination'
90
90
  end
91
91
  end
92
92
  end
@@ -22,7 +22,7 @@ describe Lhm::ChunkInsert do
22
22
  @instance.insert_and_return_count_of_rows_created
23
23
 
24
24
  slave do
25
- count_all(@destination.name).must_equal(1)
25
+ value(count_all(@destination.name)).must_equal(1)
26
26
  end
27
27
  end
28
28
  end
@@ -29,7 +29,7 @@ describe Lhm::Chunker do
29
29
  Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
30
30
 
31
31
  slave do
32
- count_all(@destination.name).must_equal(1)
32
+ value(count_all(@destination.name)).must_equal(1)
33
33
  end
34
34
 
35
35
  end
@@ -42,7 +42,7 @@ describe Lhm::Chunker do
42
42
  Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
43
43
 
44
44
  slave do
45
- count_all(@destination.name).must_equal(2)
45
+ value(count_all(@destination.name)).must_equal(2)
46
46
  end
47
47
  end
48
48
 
@@ -58,7 +58,7 @@ describe Lhm::Chunker do
58
58
  Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
59
59
 
60
60
  slave do
61
- count_all(destination.name).must_equal(2)
61
+ value(count_all(destination.name)).must_equal(2)
62
62
  end
63
63
  end
64
64
 
@@ -128,7 +128,7 @@ describe Lhm::Chunker do
128
128
  Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
129
129
 
130
130
  slave do
131
- count_all(@destination.name).must_equal(0)
131
+ value(count_all(@destination.name)).must_equal(0)
132
132
  end
133
133
 
134
134
  end
@@ -145,7 +145,7 @@ describe Lhm::Chunker do
145
145
  ).run
146
146
 
147
147
  slave do
148
- count_all(@destination.name).must_equal(23)
148
+ value(count_all(@destination.name)).must_equal(23)
149
149
  end
150
150
 
151
151
  printer.verify
@@ -161,7 +161,7 @@ describe Lhm::Chunker do
161
161
  ).run
162
162
 
163
163
  slave do
164
- count_all(@destination.name).must_equal(11)
164
+ value(count_all(@destination.name)).must_equal(11)
165
165
  end
166
166
 
167
167
  end
@@ -178,7 +178,7 @@ describe Lhm::Chunker do
178
178
  ).run
179
179
 
180
180
  slave do
181
- count_all(@destination.name).must_equal(23)
181
+ value(count_all(@destination.name)).must_equal(23)
182
182
  end
183
183
 
184
184
  printer.verify
@@ -203,7 +203,7 @@ describe Lhm::Chunker do
203
203
  assert_equal(Lhm::Throttler::SlaveLag::INITIAL_TIMEOUT * 2 * 2, throttler.timeout_seconds)
204
204
 
205
205
  slave do
206
- count_all(@destination.name).must_equal(15)
206
+ value(count_all(@destination.name)).must_equal(15)
207
207
  end
208
208
  end
209
209
 
@@ -238,7 +238,7 @@ describe Lhm::Chunker do
238
238
  assert_equal(0, throttler.send(:max_current_slave_lag))
239
239
 
240
240
  slave do
241
- count_all(@destination.name).must_equal(15)
241
+ value(count_all(@destination.name)).must_equal(15)
242
242
  end
243
243
 
244
244
  printer.verify
@@ -260,7 +260,7 @@ describe Lhm::Chunker do
260
260
  assert_match "Verification failed, aborting early", exception.message
261
261
 
262
262
  slave do
263
- count_all(@destination.name).must_equal(0)
263
+ value(count_all(@destination.name)).must_equal(0)
264
264
  end
265
265
  end
266
266
  end
@@ -31,12 +31,13 @@ describe Lhm, 'cleanup' do
31
31
 
32
32
  describe 'cleanup' do
33
33
  it 'should show temporary tables' do
34
- output = capture_stdout do
34
+ output = capture_stdout do |logger|
35
+ Lhm.logger = logger
35
36
  Lhm.cleanup
36
37
  end
37
- output.must_include('Would drop LHM backup tables')
38
- output.must_match(/lhma_[0-9_]*_users/)
39
- output.must_match(/lhma_[0-9_]*_permissions/)
38
+ value(output).must_include('Would drop LHM backup tables')
39
+ value(output).must_match(/lhma_[0-9_]*_users/)
40
+ value(output).must_match(/lhma_[0-9_]*_permissions/)
40
41
  end
41
42
 
42
43
  it 'should show temporary tables within range' do
@@ -48,12 +49,13 @@ describe Lhm, 'cleanup' do
48
49
  table_name2 = Lhm::Migration.new(table2, nil, nil, {}, Time.now - 172800).archive_name
49
50
  table_rename(:permissions, table_name2)
50
51
 
51
- output = capture_stdout do
52
+ output = capture_stdout do |logger|
53
+ Lhm.logger = logger
52
54
  Lhm.cleanup false, { :until => Time.now - 86400 }
53
55
  end
54
- output.must_include('Would drop LHM backup tables')
55
- output.must_match(/lhma_[0-9_]*_users/)
56
- output.must_match(/lhma_[0-9_]*_permissions/)
56
+ value(output).must_include('Would drop LHM backup tables')
57
+ value(output).must_match(/lhma_[0-9_]*_users/)
58
+ value(output).must_match(/lhma_[0-9_]*_permissions/)
57
59
  end
58
60
 
59
61
  it 'should exclude temporary tables outside range' do
@@ -65,30 +67,40 @@ describe Lhm, 'cleanup' do
65
67
  table_name2 = Lhm::Migration.new(table2, nil, nil, {}, Time.now).archive_name
66
68
  table_rename(:permissions, table_name2)
67
69
 
68
- output = capture_stdout do
70
+ output = capture_stdout do |logger|
71
+ Lhm.logger = logger
69
72
  Lhm.cleanup false, { :until => Time.now - 172800 }
70
73
  end
71
- output.must_include('Would drop LHM backup tables')
72
- output.wont_match(/lhma_[0-9_]*_users/)
73
- output.wont_match(/lhma_[0-9_]*_permissions/)
74
+ value(output).must_include('Would drop LHM backup tables')
75
+ value(output).wont_match(/lhma_[0-9_]*_users/)
76
+ value(output).wont_match(/lhma_[0-9_]*_permissions/)
74
77
  end
75
78
 
76
79
  it 'should show temporary triggers' do
77
- output = capture_stdout do
80
+ output = capture_stdout do |logger|
81
+ Lhm.logger = logger
78
82
  Lhm.cleanup
79
83
  end
80
- output.must_include('Would drop LHM triggers')
81
- output.must_include('lhmt_ins_users')
82
- output.must_include('lhmt_del_users')
83
- output.must_include('lhmt_upd_users')
84
- output.must_include('lhmt_ins_permissions')
85
- output.must_include('lhmt_del_permissions')
86
- output.must_include('lhmt_upd_permissions')
84
+ value(output).must_include('Would drop LHM triggers')
85
+ value(output).must_include('lhmt_ins_users')
86
+ value(output).must_include('lhmt_del_users')
87
+ value(output).must_include('lhmt_upd_users')
88
+ value(output).must_include('lhmt_ins_permissions')
89
+ value(output).must_include('lhmt_del_permissions')
90
+ value(output).must_include('lhmt_upd_permissions')
87
91
  end
88
92
 
89
93
  it 'should delete temporary tables' do
90
- Lhm.cleanup(true).must_equal(true)
91
- Lhm.cleanup.must_equal(true)
94
+ value(Lhm.cleanup(true)).must_equal(true)
95
+ value(Lhm.cleanup).must_equal(true)
96
+ end
97
+
98
+ it 'outputs deleted tables and triggers' do
99
+ output = capture_stdout do |logger|
100
+ Lhm.logger = logger
101
+ Lhm.cleanup(true)
102
+ end
103
+ value(output).must_include('Dropped triggers lhmt_ins_users, lhmt_upd_users, lhmt_del_users, lhmt_ins_permissions, lhmt_upd_permissions, lhmt_del_permissions')
92
104
  end
93
105
  end
94
106
 
@@ -96,27 +108,26 @@ describe Lhm, 'cleanup' do
96
108
  it 'should show lhmn table for the specified table only' do
97
109
  table_create(:permissions)
98
110
  table_rename(:permissions, 'lhmn_permissions')
99
- output = capture_stdout do
111
+ output = capture_stdout do |logger|
112
+ Lhm.logger = logger
100
113
  Lhm.cleanup_current_run(false, 'permissions')
101
- end.split("\n")
102
-
103
- assert_equal "The following DDLs would be executed:", output[0]
104
- assert_equal "drop trigger if exists lhmt_ins_permissions", output[1]
105
- assert_equal "drop trigger if exists lhmt_upd_permissions", output[2]
106
- assert_equal "drop trigger if exists lhmt_del_permissions", output[3]
107
- assert_match(/rename table lhmn_permissions to lhma_[0-9_]*_permissions_failed/, output[4])
108
- assert_equal 5, output.length
114
+ end
115
+
116
+ value(output).must_include("The following DDLs would be executed:")
117
+ value(output).must_include("drop trigger if exists lhmt_ins_permissions")
118
+ value(output).must_include("drop trigger if exists lhmt_upd_permissions")
119
+ value(output).must_include("drop trigger if exists lhmt_del_permissions")
109
120
  end
110
121
 
111
122
  it 'should show temporary triggers for the specified table only' do
112
- output = capture_stdout do
123
+ output = capture_stdout do |logger|
124
+ Lhm.logger = logger
113
125
  Lhm.cleanup_current_run(false, 'permissions')
114
- end.split("\n")
115
- assert_equal "The following DDLs would be executed:", output[0]
116
- assert_equal "drop trigger if exists lhmt_ins_permissions", output[1]
117
- assert_equal "drop trigger if exists lhmt_upd_permissions", output[2]
118
- assert_equal "drop trigger if exists lhmt_del_permissions", output[3]
119
- assert_equal 4, output.length
126
+ end
127
+ value(output).must_include("The following DDLs would be executed:")
128
+ value(output).must_include("drop trigger if exists lhmt_ins_permissions")
129
+ value(output).must_include("drop trigger if exists lhmt_upd_permissions")
130
+ value(output).must_include("drop trigger if exists lhmt_del_permissions")
120
131
  end
121
132
 
122
133
  it 'should delete temporary tables and triggers for the specified table only' do
@@ -26,7 +26,7 @@ describe Lhm::Entangler do
26
26
  end
27
27
 
28
28
  slave do
29
- count(:destination, 'common', 'inserted').must_equal(1)
29
+ value(count(:destination, 'common', 'inserted')).must_equal(1)
30
30
  end
31
31
  end
32
32
 
@@ -38,7 +38,7 @@ describe Lhm::Entangler do
38
38
  end
39
39
 
40
40
  slave do
41
- count(:destination, 'common', 'inserted').must_equal(0)
41
+ value(count(:destination, 'common', 'inserted')).must_equal(0)
42
42
  end
43
43
  end
44
44
 
@@ -49,7 +49,7 @@ describe Lhm::Entangler do
49
49
  end
50
50
 
51
51
  slave do
52
- count(:destination, 'common', 'updated').must_equal(1)
52
+ value(count(:destination, 'common', 'updated')).must_equal(1)
53
53
  end
54
54
  end
55
55
 
@@ -59,7 +59,7 @@ describe Lhm::Entangler do
59
59
  execute("insert into origin (common) values ('inserted')")
60
60
 
61
61
  slave do
62
- count(:destination, 'common', 'inserted').must_equal(0)
62
+ value(count(:destination, 'common', 'inserted')).must_equal(0)
63
63
  end
64
64
  end
65
65
  end
@@ -3,6 +3,7 @@
3
3
  require 'test_helper'
4
4
  require 'yaml'
5
5
  require 'active_support'
6
+ require 'logger'
6
7
 
7
8
  begin
8
9
  $db_config = YAML.load_file(File.expand_path(File.dirname(__FILE__)) + '/database.yml')
@@ -212,7 +213,8 @@ module IntegrationHelper
212
213
  def capture_stdout
213
214
  out = StringIO.new
214
215
  $stdout = out
215
- yield
216
+ logger = Logger.new($stdout)
217
+ yield logger
216
218
  return out.string
217
219
  ensure
218
220
  $stdout = ::STDOUT