lhm-shopify 3.3.6 → 3.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/lhm/chunker.rb +17 -0
- data/lib/lhm/version.rb +1 -1
- data/spec/fixtures/composite_primary_key.ddl +1 -2
- data/spec/fixtures/composite_primary_key_dest.ddl +6 -0
- data/spec/fixtures/custom_primary_key_dest.ddl +6 -0
- data/spec/integration/chunker_spec.rb +104 -22
- data/spec/test_helper.rb +13 -0
- data/spec/unit/chunker_spec.rb +5 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c60de7019efd80463c07434cb2312197009347dc5e7b8d238c1f3ba0355b7a9e
|
4
|
+
data.tar.gz: 44658f6f74b6c98739c6fd58046dd3ffa20436949f379eb9607a070afabeee8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 318c3a3f051c8bfd8cb8e30bdfef2bad0c0c61fcbc7081780adb4eaba60023e94ac9d86b4f203a950ad31c304cc3bdd3affb88eb29633ef115185aab92596d55
|
7
|
+
data.tar.gz: 644b728df70002076404e93133dbed4f53565bec70de02ca39640a482276ad7480de18a45a06a277bd55c1d6cad906026a7454bd05e7471efd055921da51708a
|
data/CHANGELOG.md
CHANGED
data/lib/lhm/chunker.rb
CHANGED
@@ -20,6 +20,7 @@ module Lhm
|
|
20
20
|
@connection = connection
|
21
21
|
@chunk_finder = ChunkFinder.new(migration, connection, options)
|
22
22
|
@options = options
|
23
|
+
@raise_on_warnings = options.fetch(:raise_on_warnings, false)
|
23
24
|
@verifier = options[:verifier]
|
24
25
|
if @throttler = options[:throttler]
|
25
26
|
@throttler.connection = @connection if @throttler.respond_to?(:connection=)
|
@@ -44,6 +45,12 @@ module Lhm
|
|
44
45
|
verify_can_run
|
45
46
|
|
46
47
|
affected_rows = ChunkInsert.new(@migration, @connection, bottom, top, @options).insert_and_return_count_of_rows_created
|
48
|
+
expected_rows = top - bottom + 1
|
49
|
+
|
50
|
+
if affected_rows < expected_rows
|
51
|
+
raise_on_non_pk_duplicate_warning
|
52
|
+
end
|
53
|
+
|
47
54
|
if @throttler && affected_rows > 0
|
48
55
|
@throttler.run
|
49
56
|
end
|
@@ -59,6 +66,16 @@ module Lhm
|
|
59
66
|
|
60
67
|
private
|
61
68
|
|
69
|
+
def raise_on_non_pk_duplicate_warning
|
70
|
+
@connection.query("show warnings").each do |level, code, message|
|
71
|
+
unless message.match?(/Duplicate entry .+ for key 'PRIMARY'/)
|
72
|
+
m = "Unexpected warning found for inserted row: #{message}"
|
73
|
+
Lhm.logger.warn(m)
|
74
|
+
raise Error.new(m) if @raise_on_warnings
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
62
79
|
def bottom
|
63
80
|
@next_to_insert
|
64
81
|
end
|
data/lib/lhm/version.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
2
1
|
CREATE TABLE `composite_primary_key` (
|
3
2
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
4
3
|
`shop_id` bigint(20) NOT NULL,
|
5
|
-
PRIMARY KEY (`shop_id`,`id`),
|
4
|
+
CONSTRAINT `pk_composite` PRIMARY KEY (`shop_id`,`id`),
|
6
5
|
INDEX `index_key_id` (`id`)
|
7
6
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
@@ -15,16 +15,18 @@ describe Lhm::Chunker do
|
|
15
15
|
@origin = table_create(:origin)
|
16
16
|
@destination = table_create(:destination)
|
17
17
|
@migration = Lhm::Migration.new(@origin, @destination)
|
18
|
+
@logs = StringIO.new
|
19
|
+
Lhm.logger = Logger.new(@logs)
|
20
|
+
end
|
21
|
+
|
22
|
+
def log_messages
|
23
|
+
@logs.string.split("\n")
|
18
24
|
end
|
19
25
|
|
20
26
|
it 'should copy 1 row from origin to destination even if the id of the single row does not start at 1' do
|
21
27
|
execute("insert into origin set id = 1001 ")
|
22
|
-
printer = Lhm::Printer::Base.new
|
23
|
-
|
24
|
-
def printer.notify(*) ;end
|
25
|
-
def printer.end(*) [] ;end
|
26
28
|
|
27
|
-
Lhm::Chunker.new(@migration, connection, {
|
29
|
+
Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
|
28
30
|
|
29
31
|
slave do
|
30
32
|
count_all(@destination.name).must_equal(1)
|
@@ -32,14 +34,98 @@ describe Lhm::Chunker do
|
|
32
34
|
|
33
35
|
end
|
34
36
|
|
37
|
+
it 'should copy and ignore duplicate primary key' do
|
38
|
+
execute("insert into origin set id = 1001 ")
|
39
|
+
execute("insert into origin set id = 1002 ")
|
40
|
+
execute("insert into destination set id = 1002 ")
|
41
|
+
|
42
|
+
Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
|
43
|
+
|
44
|
+
slave do
|
45
|
+
count_all(@destination.name).must_equal(2)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should copy and ignore duplicate composite primary key' do
|
50
|
+
origin = table_create(:composite_primary_key)
|
51
|
+
destination = table_create(:composite_primary_key_dest)
|
52
|
+
migration = Lhm::Migration.new(origin, destination)
|
53
|
+
|
54
|
+
execute("insert into composite_primary_key set id = 1001, shop_id = 1")
|
55
|
+
execute("insert into composite_primary_key set id = 1002, shop_id = 1")
|
56
|
+
execute("insert into composite_primary_key_dest set id = 1002, shop_id = 1")
|
57
|
+
|
58
|
+
Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
|
59
|
+
|
60
|
+
slave do
|
61
|
+
count_all(destination.name).must_equal(2)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should copy and raise on unexpected warnings' do
|
66
|
+
origin = table_create(:custom_primary_key)
|
67
|
+
destination = table_create(:custom_primary_key_dest)
|
68
|
+
migration = Lhm::Migration.new(origin, destination)
|
69
|
+
|
70
|
+
execute("insert into custom_primary_key set id = 1001, pk = 1")
|
71
|
+
execute("insert into custom_primary_key_dest set id = 1001, pk = 2")
|
72
|
+
|
73
|
+
exception = assert_raises(Lhm::Error) do
|
74
|
+
Lhm::Chunker.new(migration, connection, {raise_on_warnings: true, throttler: throttler, printer: printer} ).run
|
75
|
+
end
|
76
|
+
|
77
|
+
assert_match "Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'", exception.message
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should copy and warn on unexpected warnings by default' do
|
81
|
+
origin = table_create(:custom_primary_key)
|
82
|
+
destination = table_create(:custom_primary_key_dest)
|
83
|
+
migration = Lhm::Migration.new(origin, destination)
|
84
|
+
|
85
|
+
execute("insert into custom_primary_key set id = 1001, pk = 1")
|
86
|
+
execute("insert into custom_primary_key_dest set id = 1001, pk = 2")
|
87
|
+
|
88
|
+
Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
|
89
|
+
|
90
|
+
assert_equal 2, log_messages.length
|
91
|
+
assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'"), log_messages
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should log two times for two unexpected warnings' do
|
95
|
+
origin = table_create(:custom_primary_key)
|
96
|
+
destination = table_create(:custom_primary_key_dest)
|
97
|
+
migration = Lhm::Migration.new(origin, destination)
|
98
|
+
|
99
|
+
execute("insert into custom_primary_key set id = 1001, pk = 1")
|
100
|
+
execute("insert into custom_primary_key set id = 1002, pk = 2")
|
101
|
+
execute("insert into custom_primary_key_dest set id = 1001, pk = 3")
|
102
|
+
execute("insert into custom_primary_key_dest set id = 1002, pk = 4")
|
103
|
+
|
104
|
+
Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
|
105
|
+
|
106
|
+
assert_equal 3, log_messages.length
|
107
|
+
assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'"), log_messages
|
108
|
+
assert log_messages[2].include?("Unexpected warning found for inserted row: Duplicate entry '1002' for key 'index_custom_primary_key_on_id'"), log_messages
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should copy and warn on unexpected warnings' do
|
112
|
+
origin = table_create(:custom_primary_key)
|
113
|
+
destination = table_create(:custom_primary_key_dest)
|
114
|
+
migration = Lhm::Migration.new(origin, destination)
|
115
|
+
|
116
|
+
execute("insert into custom_primary_key set id = 1001, pk = 1")
|
117
|
+
execute("insert into custom_primary_key_dest set id = 1001, pk = 2")
|
118
|
+
|
119
|
+
Lhm::Chunker.new(migration, connection, {raise_on_warnings: false, throttler: throttler, printer: printer} ).run
|
120
|
+
|
121
|
+
assert_equal 2, log_messages.length
|
122
|
+
assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'"), log_messages
|
123
|
+
end
|
124
|
+
|
35
125
|
it 'should create the modified destination, even if the source is empty' do
|
36
126
|
execute("truncate origin ")
|
37
|
-
printer = Lhm::Printer::Base.new
|
38
127
|
|
39
|
-
|
40
|
-
def printer.end(*) [] ;end
|
41
|
-
|
42
|
-
Lhm::Chunker.new(@migration, connection, {:throttler => Lhm::Throttler::Time.new(:stride => 100), :printer => printer} ).run
|
128
|
+
Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
|
43
129
|
|
44
130
|
slave do
|
45
131
|
count_all(@destination.name).must_equal(0)
|
@@ -55,7 +141,7 @@ describe Lhm::Chunker do
|
|
55
141
|
printer.expect(:end, :return_value, [])
|
56
142
|
|
57
143
|
Lhm::Chunker.new(
|
58
|
-
@migration, connection, {
|
144
|
+
@migration, connection, { throttler: throttler, printer: printer }
|
59
145
|
).run
|
60
146
|
|
61
147
|
slave do
|
@@ -69,13 +155,9 @@ describe Lhm::Chunker do
|
|
69
155
|
it 'should copy all the records of a table, even if the last chunk starts with the last record of it.' do
|
70
156
|
11.times { |n| execute("insert into origin set id = '#{ n + 1 }'") }
|
71
157
|
|
72
|
-
printer = Lhm::Printer::Base.new
|
73
|
-
|
74
|
-
def printer.notify(*) ;end
|
75
|
-
def printer.end(*) [] ;end
|
76
158
|
|
77
159
|
Lhm::Chunker.new(
|
78
|
-
@migration, connection, { :
|
160
|
+
@migration, connection, { throttler: Lhm::Throttler::Time.new(stride: 10), printer: printer }
|
79
161
|
).run
|
80
162
|
|
81
163
|
slave do
|
@@ -92,7 +174,7 @@ describe Lhm::Chunker do
|
|
92
174
|
printer.expect(:end, :return_value, [])
|
93
175
|
|
94
176
|
Lhm::Chunker.new(
|
95
|
-
@migration, connection, { :
|
177
|
+
@migration, connection, { throttler: Lhm::Throttler::SlaveLag.new(stride: 100), printer: printer }
|
96
178
|
).run
|
97
179
|
|
98
180
|
slave do
|
@@ -109,13 +191,13 @@ describe Lhm::Chunker do
|
|
109
191
|
printer.expects(:notify).with(instance_of(Integer), instance_of(Integer)).twice
|
110
192
|
printer.expects(:end)
|
111
193
|
|
112
|
-
throttler = Lhm::Throttler::SlaveLag.new(:
|
194
|
+
throttler = Lhm::Throttler::SlaveLag.new(stride: 10, allowed_lag: 0)
|
113
195
|
def throttler.max_current_slave_lag
|
114
196
|
1
|
115
197
|
end
|
116
198
|
|
117
199
|
Lhm::Chunker.new(
|
118
|
-
@migration, connection, { :
|
200
|
+
@migration, connection, { throttler: throttler, printer: printer }
|
119
201
|
).run
|
120
202
|
|
121
203
|
assert_equal(Lhm::Throttler::SlaveLag::INITIAL_TIMEOUT * 2 * 2, throttler.timeout_seconds)
|
@@ -133,7 +215,7 @@ describe Lhm::Chunker do
|
|
133
215
|
printer.expects(:verify)
|
134
216
|
printer.expects(:end)
|
135
217
|
|
136
|
-
throttler = Lhm::Throttler::SlaveLag.new(:
|
218
|
+
throttler = Lhm::Throttler::SlaveLag.new(stride: 10, allowed_lag: 0)
|
137
219
|
|
138
220
|
def throttler.slave_hosts
|
139
221
|
['127.0.0.1']
|
@@ -149,7 +231,7 @@ describe Lhm::Chunker do
|
|
149
231
|
end
|
150
232
|
|
151
233
|
Lhm::Chunker.new(
|
152
|
-
@migration, connection, { :
|
234
|
+
@migration, connection, { throttler: throttler, printer: printer }
|
153
235
|
).run
|
154
236
|
|
155
237
|
assert_equal(Lhm::Throttler::SlaveLag::INITIAL_TIMEOUT, throttler.timeout_seconds)
|
@@ -171,7 +253,7 @@ describe Lhm::Chunker do
|
|
171
253
|
|
172
254
|
exception = assert_raises do
|
173
255
|
Lhm::Chunker.new(
|
174
|
-
@migration, connection, { :
|
256
|
+
@migration, connection, { verifier: failer, printer: printer, throttler: throttler }
|
175
257
|
).run
|
176
258
|
end
|
177
259
|
|
data/spec/test_helper.rb
CHANGED
@@ -30,3 +30,16 @@ def without_verbose(&block)
|
|
30
30
|
ensure
|
31
31
|
$VERBOSE = old_verbose
|
32
32
|
end
|
33
|
+
|
34
|
+
def printer
|
35
|
+
printer = Lhm::Printer::Base.new
|
36
|
+
|
37
|
+
def printer.notify(*) ;end
|
38
|
+
def printer.end(*) [] ;end
|
39
|
+
|
40
|
+
printer
|
41
|
+
end
|
42
|
+
|
43
|
+
def throttler
|
44
|
+
Lhm::Throttler::Time.new(:stride => 100)
|
45
|
+
end
|
data/spec/unit/chunker_spec.rb
CHANGED
@@ -41,6 +41,7 @@ describe Lhm::Chunker do
|
|
41
41
|
@connection.expects(:select_value).with(regexp_matches(/where id >= 8 order by id limit 1 offset 4/)).returns(21)
|
42
42
|
@connection.expects(:update).with(regexp_matches(/between 1 and 7/)).returns(2)
|
43
43
|
@connection.expects(:update).with(regexp_matches(/between 8 and 10/)).returns(2)
|
44
|
+
@connection.expects(:query).twice.with(regexp_matches(/show warnings/)).returns([])
|
44
45
|
|
45
46
|
@chunker.run
|
46
47
|
end
|
@@ -88,6 +89,8 @@ describe Lhm::Chunker do
|
|
88
89
|
@connection.expects(:update).with(regexp_matches(/between 6 and 8/)).returns(2)
|
89
90
|
@connection.expects(:update).with(regexp_matches(/between 9 and 10/)).returns(2)
|
90
91
|
|
92
|
+
@connection.expects(:query).twice.with(regexp_matches(/show warnings/)).returns([])
|
93
|
+
|
91
94
|
@chunker.run
|
92
95
|
end
|
93
96
|
|
@@ -136,6 +139,7 @@ describe Lhm::Chunker do
|
|
136
139
|
|
137
140
|
@connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/)).returns(2)
|
138
141
|
@connection.expects(:update).with(regexp_matches(/where \(foo.created_at > '2013-07-10' or foo.baz = 'quux'\) and `foo`/)).returns(1)
|
142
|
+
@connection.expects(:query).with(regexp_matches(/show warnings/)).returns([])
|
139
143
|
|
140
144
|
def @migration.conditions
|
141
145
|
"where foo.created_at > '2013-07-10' or foo.baz = 'quux'"
|
@@ -155,6 +159,7 @@ describe Lhm::Chunker do
|
|
155
159
|
|
156
160
|
@connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/)).returns(2)
|
157
161
|
@connection.expects(:update).with(regexp_matches(/inner join bar on foo.id = bar.foo_id and/)).returns(1)
|
162
|
+
@connection.expects(:query).with(regexp_matches(/show warnings/)).returns([])
|
158
163
|
|
159
164
|
def @migration.conditions
|
160
165
|
'inner join bar on foo.id = bar.foo_id'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhm-shopify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SoundCloud
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2021-07-
|
15
|
+
date: 2021-07-19 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: retriable
|
@@ -173,7 +173,9 @@ files:
|
|
173
173
|
- spec/README.md
|
174
174
|
- spec/fixtures/bigint_table.ddl
|
175
175
|
- spec/fixtures/composite_primary_key.ddl
|
176
|
+
- spec/fixtures/composite_primary_key_dest.ddl
|
176
177
|
- spec/fixtures/custom_primary_key.ddl
|
178
|
+
- spec/fixtures/custom_primary_key_dest.ddl
|
177
179
|
- spec/fixtures/destination.ddl
|
178
180
|
- spec/fixtures/lines.ddl
|
179
181
|
- spec/fixtures/origin.ddl
|