lhm-shopify 3.5.5 → 4.1.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +20 -18
  3. data/Appraisals +8 -19
  4. data/CHANGELOG.md +16 -0
  5. data/Gemfile.lock +37 -20
  6. data/README.md +21 -14
  7. data/dev.yml +12 -8
  8. data/docker-compose-mysql-5.7.yml +1 -0
  9. data/docker-compose-mysql-8.0.yml +63 -0
  10. data/docker-compose.yml +5 -3
  11. data/gemfiles/activerecord_6.1.gemfile +1 -0
  12. data/gemfiles/activerecord_6.1.gemfile.lock +23 -13
  13. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile → activerecord_7.0.gemfile} +2 -1
  14. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile.lock → activerecord_7.0.gemfile.lock} +29 -19
  15. data/gemfiles/{activerecord_6.0.gemfile → activerecord_7.1.gemfile} +1 -1
  16. data/gemfiles/activerecord_7.1.gemfile.lock +83 -0
  17. data/lhm.gemspec +2 -1
  18. data/lib/lhm/atomic_switcher.rb +3 -3
  19. data/lib/lhm/chunker.rb +4 -4
  20. data/lib/lhm/connection.rb +9 -1
  21. data/lib/lhm/sql_helper.rb +1 -1
  22. data/lib/lhm/sql_retry.rb +36 -18
  23. data/lib/lhm/table.rb +3 -4
  24. data/lib/lhm/throttler/replica_lag.rb +166 -0
  25. data/lib/lhm/throttler/slave_lag.rb +5 -155
  26. data/lib/lhm/throttler/threads_running.rb +3 -1
  27. data/lib/lhm/throttler.rb +7 -3
  28. data/lib/lhm/version.rb +1 -1
  29. data/scripts/helpers/wait-for-dbs.sh +3 -3
  30. data/scripts/mysql/writer/create_users.sql +1 -1
  31. data/spec/.lhm.example +1 -1
  32. data/spec/README.md +8 -9
  33. data/spec/integration/atomic_switcher_spec.rb +6 -10
  34. data/spec/integration/chunk_insert_spec.rb +2 -2
  35. data/spec/integration/chunker_spec.rb +54 -44
  36. data/spec/integration/database.yml +4 -4
  37. data/spec/integration/entangler_spec.rb +4 -4
  38. data/spec/integration/integration_helper.rb +23 -15
  39. data/spec/integration/lhm_spec.rb +70 -44
  40. data/spec/integration/locked_switcher_spec.rb +2 -2
  41. data/spec/integration/proxysql_spec.rb +10 -10
  42. data/spec/integration/sql_retry/db_connection_helper.rb +2 -4
  43. data/spec/integration/sql_retry/lock_wait_spec.rb +7 -8
  44. data/spec/integration/sql_retry/lock_wait_timeout_test_helper.rb +18 -10
  45. data/spec/integration/sql_retry/proxysql_helper.rb +1 -1
  46. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +1 -2
  47. data/spec/integration/table_spec.rb +1 -1
  48. data/spec/integration/toxiproxy_helper.rb +1 -1
  49. data/spec/test_helper.rb +27 -3
  50. data/spec/unit/atomic_switcher_spec.rb +2 -2
  51. data/spec/unit/chunker_spec.rb +43 -43
  52. data/spec/unit/connection_spec.rb +2 -2
  53. data/spec/unit/entangler_spec.rb +14 -24
  54. data/spec/unit/printer_spec.rb +2 -6
  55. data/spec/unit/sql_helper_spec.rb +2 -2
  56. data/spec/unit/throttler/{slave_lag_spec.rb → replica_lag_spec.rb} +84 -92
  57. data/spec/unit/throttler/threads_running_spec.rb +18 -0
  58. data/spec/unit/throttler_spec.rb +8 -8
  59. metadata +26 -12
  60. data/.travis.yml +0 -21
  61. data/gemfiles/activerecord_5.2.gemfile +0 -9
  62. data/gemfiles/activerecord_5.2.gemfile.lock +0 -65
  63. data/gemfiles/activerecord_6.0.gemfile.lock +0 -67
@@ -22,7 +22,7 @@ module IntegrationHelper
22
22
  def self.included(base)
23
23
  base.after(:each) do
24
24
  cleanup_connection = new_mysql_connection
25
- results = cleanup_connection.query("SELECT table_name FROM information_schema.tables WHERE table_schema = '#{$db_name}';")
25
+ results = DATABASE.query(cleanup_connection, "SELECT table_name FROM information_schema.tables WHERE table_schema = '#{$db_name}';")
26
26
  table_names_for_cleanup = results.map { |row| "#{$db_name}." + row.values.first }
27
27
  cleanup_connection.query("DROP TABLE IF EXISTS #{table_names_for_cleanup.join(', ')};") if table_names_for_cleanup.length > 0
28
28
  end
@@ -35,6 +35,14 @@ module IntegrationHelper
35
35
  @connection
36
36
  end
37
37
 
38
+ def mysql_version
39
+ @mysql_version ||= begin
40
+ # This SQL returns a value of shape: X.Y.ZZ-AA-log
41
+ result = connection.query("SELECT VERSION()")
42
+ result.dig(0, 0).split("-", 2)[0]
43
+ end
44
+ end
45
+
38
46
  def connect_proxysql!
39
47
  connect!(
40
48
  '127.0.0.1',
@@ -53,12 +61,12 @@ module IntegrationHelper
53
61
  )
54
62
  end
55
63
 
56
- def connect_slave!
64
+ def connect_replica!
57
65
  connect!(
58
66
  '127.0.0.1',
59
- $db_config['slave']['port'],
60
- $db_config['slave']['user'],
61
- $db_config['slave']['password'],
67
+ $db_config['replica']['port'],
68
+ $db_config['replica']['user'],
69
+ $db_config['replica']['password'],
62
70
  )
63
71
  end
64
72
 
@@ -81,7 +89,7 @@ module IntegrationHelper
81
89
 
82
90
  def ar_conn(host, port, user, password)
83
91
  ActiveRecord::Base.establish_connection(
84
- :adapter => 'mysql2',
92
+ :adapter => DATABASE.adapter,
85
93
  :host => host,
86
94
  :username => user,
87
95
  :port => port,
@@ -113,12 +121,12 @@ module IntegrationHelper
113
121
  end
114
122
  end
115
123
 
116
- def slave(&block)
117
- if master_slave_mode?
118
- connect_slave!
124
+ def replica(&block)
125
+ if master_replica_mode?
126
+ connect_replica!
119
127
 
120
- # need to wait for the slave to catch up. a better method would be to
121
- # check the master binlog position and wait for the slave to catch up
128
+ # need to wait for the replica to catch up. a better method would be to
129
+ # check the master binlog position and wait for the replica to catch up
122
130
  # to that position.
123
131
  sleep 1
124
132
  else
@@ -127,7 +135,7 @@ module IntegrationHelper
127
135
 
128
136
  yield block
129
137
 
130
- if master_slave_mode?
138
+ if master_replica_mode?
131
139
  connect_master!
132
140
  end
133
141
  end
@@ -171,7 +179,7 @@ module IntegrationHelper
171
179
  end
172
180
 
173
181
  def new_mysql_connection(role='master')
174
- Mysql2::Client.new(
182
+ DATABASE.client.new(
175
183
  host: '127.0.0.1',
176
184
  database: $db_name,
177
185
  username: $db_config[role]['user'],
@@ -215,8 +223,8 @@ module IntegrationHelper
215
223
  # Environment
216
224
  #
217
225
 
218
- def master_slave_mode?
219
- !!ENV['MASTER_SLAVE']
226
+ def master_replica_mode?
227
+ !!ENV['MASTER_REPLICA']
220
228
  end
221
229
 
222
230
  #
@@ -9,6 +9,10 @@ describe Lhm do
9
9
 
10
10
  before(:each) { connect_master!; Lhm.cleanup(true) }
11
11
 
12
+ let(:collation) do
13
+ mysql_version.start_with?("8.0") ? "utf8mb3_general_ci" : "utf8_general_ci"
14
+ end
15
+
12
16
  describe 'id column requirement' do
13
17
  it 'should migrate the table when id is pk' do
14
18
  table_create(:users)
@@ -17,9 +21,11 @@ describe Lhm do
17
21
  t.add_column(:logins, "int(12) default '0'")
18
22
  end
19
23
 
20
- slave do
24
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
25
+
26
+ replica do
21
27
  value(table_read(:users).columns['logins']).must_equal({
22
- :type => 'int(12)',
28
+ :type => expected_type,
23
29
  :is_nullable => 'YES',
24
30
  :column_default => '0',
25
31
  :comment => '',
@@ -35,9 +41,11 @@ describe Lhm do
35
41
  t.add_column(:logins, "int(12) default '0'")
36
42
  end
37
43
 
38
- slave do
44
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
45
+
46
+ replica do
39
47
  value(table_read(:custom_primary_key).columns['logins']).must_equal({
40
- :type => 'int(12)',
48
+ :type => expected_type,
41
49
  :is_nullable => 'YES',
42
50
  :column_default => '0',
43
51
  :comment => '',
@@ -53,9 +61,11 @@ describe Lhm do
53
61
  t.add_column(:logins, "int(12) default '0'")
54
62
  end
55
63
 
56
- slave do
64
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
65
+
66
+ replica do
57
67
  value(table_read(:composite_primary_key).columns['logins']).must_equal({
58
- :type => 'int(12)',
68
+ :type => expected_type,
59
69
  :is_nullable => 'YES',
60
70
  :column_default => '0',
61
71
  :comment => '',
@@ -82,7 +92,7 @@ describe Lhm do
82
92
  t.ddl("ALTER TABLE #{t.name} CHANGE id id bigint (20) NOT NULL AUTO_INCREMENT")
83
93
  end
84
94
 
85
- slave do
95
+ replica do
86
96
  value(connection.primary_key('users')).must_equal(['username', 'id'])
87
97
  end
88
98
  end
@@ -104,7 +114,7 @@ describe Lhm do
104
114
  describe 'when no additional data is inserted into the table' do
105
115
 
106
116
  it 'migrates the existing data' do
107
- slave do
117
+ replica do
108
118
  value(count_all(:permissions)).must_equal(11)
109
119
  end
110
120
  end
@@ -120,7 +130,7 @@ describe Lhm do
120
130
  end
121
131
 
122
132
  it 'migrates all data' do
123
- slave do
133
+ replica do
124
134
  value(count_all(:permissions)).must_equal(13)
125
135
  end
126
136
  end
@@ -132,9 +142,11 @@ describe Lhm do
132
142
  t.add_column(:logins, "INT(12) DEFAULT '0'")
133
143
  end
134
144
 
135
- slave do
145
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
146
+
147
+ replica do
136
148
  value(table_read(:users).columns['logins']).must_equal({
137
- :type => 'int(12)',
149
+ :type => expected_type,
138
150
  :is_nullable => 'YES',
139
151
  :column_default => '0',
140
152
  :comment => '',
@@ -150,7 +162,7 @@ describe Lhm do
150
162
  t.add_column(:logins, "INT(12) DEFAULT '0'")
151
163
  end
152
164
 
153
- slave do
165
+ replica do
154
166
  value(count_all(:users)).must_equal(23)
155
167
  end
156
168
  end
@@ -160,7 +172,7 @@ describe Lhm do
160
172
  t.remove_column(:comment)
161
173
  end
162
174
 
163
- slave do
175
+ replica do
164
176
  assert_nil table_read(:users).columns['comment']
165
177
  end
166
178
  end
@@ -170,7 +182,7 @@ describe Lhm do
170
182
  t.add_index([:comment, :created_at])
171
183
  end
172
184
 
173
- slave do
185
+ replica do
174
186
  value(index_on_columns?(:users, [:comment, :created_at])).must_equal(true)
175
187
  end
176
188
  end
@@ -180,7 +192,7 @@ describe Lhm do
180
192
  t.add_index([:comment, :created_at], :my_index_name)
181
193
  end
182
194
 
183
- slave do
195
+ replica do
184
196
  value(index?(:users, :my_index_name)).must_equal(true)
185
197
  end
186
198
  end
@@ -190,7 +202,7 @@ describe Lhm do
190
202
  t.add_index(:group)
191
203
  end
192
204
 
193
- slave do
205
+ replica do
194
206
  value(index_on_columns?(:users, :group)).must_equal(true)
195
207
  end
196
208
  end
@@ -200,7 +212,7 @@ describe Lhm do
200
212
  t.add_unique_index(:comment)
201
213
  end
202
214
 
203
- slave do
215
+ replica do
204
216
  value(index_on_columns?(:users, :comment, :unique)).must_equal(true)
205
217
  end
206
218
  end
@@ -210,7 +222,7 @@ describe Lhm do
210
222
  t.remove_index([:username, :created_at])
211
223
  end
212
224
 
213
- slave do
225
+ replica do
214
226
  value(index_on_columns?(:users, [:username, :created_at])).must_equal(false)
215
227
  end
216
228
  end
@@ -220,7 +232,7 @@ describe Lhm do
220
232
  t.remove_index([:username, :group])
221
233
  end
222
234
 
223
- slave do
235
+ replica do
224
236
  value(index?(:users, :index_with_a_custom_name)).must_equal(false)
225
237
  end
226
238
  end
@@ -230,17 +242,27 @@ describe Lhm do
230
242
  t.remove_index(:irrelevant_column_name, :index_with_a_custom_name)
231
243
  end
232
244
 
233
- slave do
245
+ replica do
234
246
  value(index?(:users, :index_with_a_custom_name)).must_equal(false)
235
247
  end
236
248
  end
237
249
 
250
+ it 'should add an index with column sizes' do
251
+ Lhm.change_table(:users, :atomic_switch => false) do |t|
252
+ t.add_index(["username(6)", "group (10)", "comment (10)"])
253
+ end
254
+
255
+ replica do
256
+ value(index_on_columns?(:users, [:username, :group, :comment])).must_equal(true)
257
+ end
258
+ end
259
+
238
260
  it 'should apply a ddl statement' do
239
261
  Lhm.change_table(:users, :atomic_switch => false) do |t|
240
262
  t.ddl('alter table %s add column flag tinyint(1)' % t.name)
241
263
  end
242
264
 
243
- slave do
265
+ replica do
244
266
  value(table_read(:users).columns['flag']).must_equal({
245
267
  :type => 'tinyint(1)',
246
268
  :is_nullable => 'YES',
@@ -256,13 +278,13 @@ describe Lhm do
256
278
  t.change_column(:comment, "varchar(20) DEFAULT 'none' NOT NULL")
257
279
  end
258
280
 
259
- slave do
281
+ replica do
260
282
  value(table_read(:users).columns['comment']).must_equal({
261
283
  :type => 'varchar(20)',
262
284
  :is_nullable => 'NO',
263
285
  :column_default => 'none',
264
286
  :comment => '',
265
- :collate => 'utf8_general_ci',
287
+ :collate => collation,
266
288
  })
267
289
  end
268
290
  end
@@ -274,9 +296,11 @@ describe Lhm do
274
296
  t.change_column(:id, 'int(5)')
275
297
  end
276
298
 
277
- slave do
299
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(5)"
300
+
301
+ replica do
278
302
  value(table_read(:small_table).columns['id']).must_equal({
279
- :type => 'int(5)',
303
+ :type => expected_type,
280
304
  :is_nullable => 'NO',
281
305
  :column_default => nil,
282
306
  :comment => '',
@@ -293,7 +317,7 @@ describe Lhm do
293
317
  t.rename_column(:username, :login)
294
318
  end
295
319
 
296
- slave do
320
+ replica do
297
321
  table_data = table_read(:users)
298
322
  assert_nil table_data.columns['username']
299
323
  value(table_read(:users).columns['login']).must_equal({
@@ -301,7 +325,7 @@ describe Lhm do
301
325
  :is_nullable => 'YES',
302
326
  :column_default => nil,
303
327
  :comment => '',
304
- :collate => 'utf8_general_ci',
328
+ :collate => collation,
305
329
  })
306
330
 
307
331
  result = select_one('SELECT login from users')
@@ -318,7 +342,7 @@ describe Lhm do
318
342
  t.rename_column(:group, :fnord)
319
343
  end
320
344
 
321
- slave do
345
+ replica do
322
346
  table_data = table_read(:users)
323
347
  assert_nil table_data.columns['group']
324
348
  value(table_read(:users).columns['fnord']).must_equal({
@@ -326,7 +350,7 @@ describe Lhm do
326
350
  :is_nullable => 'YES',
327
351
  :column_default => 'Superfriends',
328
352
  :comment => '',
329
- :collate => 'utf8_general_ci',
353
+ :collate => collation,
330
354
  })
331
355
 
332
356
  result = select_one('SELECT `fnord` from users')
@@ -345,7 +369,7 @@ describe Lhm do
345
369
  t.rename_column(:username, :user_name)
346
370
  end
347
371
 
348
- slave do
372
+ replica do
349
373
  table_data = table_read(:users)
350
374
  assert_nil table_data.columns['username']
351
375
  value(table_read(:users).columns['user_name']).must_equal({
@@ -373,11 +397,13 @@ describe Lhm do
373
397
  t.rename_column(:reference, :ref)
374
398
  end
375
399
 
376
- slave do
400
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(11)"
401
+
402
+ replica do
377
403
  table_data = table_read(:users)
378
404
  assert_nil table_data.columns['reference']
379
405
  value(table_read(:users).columns['ref']).must_equal({
380
- :type => 'int(11)',
406
+ :type => expected_type,
381
407
  :is_nullable => 'YES',
382
408
  :column_default => nil,
383
409
  :comment => 'RefComment',
@@ -400,7 +426,7 @@ describe Lhm do
400
426
  t.rename_column(:group, :fnord)
401
427
  end
402
428
 
403
- slave do
429
+ replica do
404
430
  table_data = table_read(:users)
405
431
  assert_nil table_data.columns['group']
406
432
  value(table_read(:users).columns['fnord']).must_equal({
@@ -408,7 +434,7 @@ describe Lhm do
408
434
  :is_nullable => 'YES',
409
435
  :column_default => nil,
410
436
  :comment => '',
411
- :collate => 'utf8_general_ci',
437
+ :collate => collation,
412
438
  })
413
439
 
414
440
  result = select_one('SELECT `fnord` from users')
@@ -425,7 +451,7 @@ describe Lhm do
425
451
  t.rename_column(:username, :user_name)
426
452
  end
427
453
 
428
- slave do
454
+ replica do
429
455
  table_data = table_read(:users)
430
456
  assert_nil table_data.columns['username']
431
457
  value(table_read(:users).columns['user_name']).must_equal({
@@ -433,7 +459,7 @@ describe Lhm do
433
459
  :is_nullable => 'YES',
434
460
  :column_default => nil,
435
461
  :comment => '',
436
- :collate => 'utf8_general_ci',
462
+ :collate => collation,
437
463
  })
438
464
 
439
465
  result = select_one('SELECT `user_name` from users')
@@ -452,7 +478,7 @@ describe Lhm do
452
478
  t.rename_column(:username, :user_name)
453
479
  end
454
480
 
455
- slave do
481
+ replica do
456
482
  table_data = table_read(:users)
457
483
  assert_nil table_data.columns['username']
458
484
  value(table_read(:users).columns['user_name']).must_equal({
@@ -460,7 +486,7 @@ describe Lhm do
460
486
  :is_nullable => 'NO',
461
487
  :column_default => nil,
462
488
  :comment => '',
463
- :collate => 'utf8_general_ci',
489
+ :collate => collation,
464
490
  })
465
491
 
466
492
  result = select_one('SELECT `user_name` from users')
@@ -499,7 +525,7 @@ describe Lhm do
499
525
  end
500
526
  end
501
527
 
502
- slave do
528
+ replica do
503
529
  table_data = table_read(:users)
504
530
  assert_nil table_data.columns['fnord']
505
531
  value(table_read(:users).columns['group']).must_equal({
@@ -507,7 +533,7 @@ describe Lhm do
507
533
  :is_nullable => 'YES',
508
534
  :column_default => 'Superfriends',
509
535
  :comment => '',
510
- :collate => 'utf8_general_ci',
536
+ :collate => collation,
511
537
  })
512
538
  end
513
539
  end
@@ -525,7 +551,7 @@ describe Lhm do
525
551
  t.remove_index('by')
526
552
  end
527
553
 
528
- slave do
554
+ replica do
529
555
  value(table_read(:lines).columns).must_include 'by'
530
556
  value(table_read(:lines).columns).wont_include 'lines'
531
557
  value(index_on_columns?(:lines, ['between'], :unique)).must_equal true
@@ -554,7 +580,7 @@ describe Lhm do
554
580
 
555
581
  insert.join
556
582
 
557
- slave do
583
+ replica do
558
584
  value(count_all(:users)).must_equal(60)
559
585
  end
560
586
  end
@@ -577,7 +603,7 @@ describe Lhm do
577
603
 
578
604
  delete.join
579
605
 
580
- slave do
606
+ replica do
581
607
  value(count_all(:users)).must_equal(40)
582
608
  end
583
609
  end
@@ -650,7 +676,7 @@ describe Lhm do
650
676
 
651
677
  Lhm::ChunkInsert.remove_all_callbacks
652
678
 
653
- slave do
679
+ replica do
654
680
  value(count_all(:users)).must_equal(100)
655
681
  end
656
682
  end
@@ -31,7 +31,7 @@ describe Lhm::LockedSwitcher do
31
31
  switcher = Lhm::LockedSwitcher.new(@migration, connection)
32
32
  switcher.run
33
33
 
34
- slave do
34
+ replica do
35
35
  value(data_source_exists?(@origin)).must_equal true
36
36
  value(table_read(@migration.archive_name).columns.keys).must_include 'origin'
37
37
  end
@@ -41,7 +41,7 @@ describe Lhm::LockedSwitcher do
41
41
  switcher = Lhm::LockedSwitcher.new(@migration, connection)
42
42
  switcher.run
43
43
 
44
- slave do
44
+ replica do
45
45
  value(data_source_exists?(@destination)).must_equal false
46
46
  value(table_read(@origin.name).columns.keys).must_include 'destination'
47
47
  end
@@ -1,34 +1,34 @@
1
1
  describe "ProxySQL integration" do
2
2
  it "Should contact the writer" do
3
- conn = Mysql2::Client.new(
3
+ conn = DATABASE.client.new(
4
4
  host: '127.0.0.1',
5
5
  username: "writer",
6
6
  password: "password",
7
- port: "33005",
7
+ port: "13005",
8
8
  )
9
9
 
10
- assert_equal conn.query("SELECT @@global.hostname as host").each.first["host"], "mysql-1"
10
+ assert_equal DATABASE.query(conn, "SELECT @@global.hostname as host").each.first["host"], "mysql-1"
11
11
  end
12
12
 
13
13
  it "Should contact the reader" do
14
- conn = Mysql2::Client.new(
14
+ conn = DATABASE.client.new(
15
15
  host: '127.0.0.1',
16
16
  username: "reader",
17
17
  password: "password",
18
- port: "33005",
18
+ port: "13005",
19
19
  )
20
20
 
21
- assert_equal conn.query("SELECT @@global.hostname as host").each.first["host"], "mysql-2"
21
+ assert_equal DATABASE.query(conn, "SELECT @@global.hostname as host").each.first["host"], "mysql-2"
22
22
  end
23
23
 
24
24
  it "Should override default hostgroup from user if rule matches" do
25
- conn = Mysql2::Client.new(
25
+ conn = DATABASE.client.new(
26
26
  host: '127.0.0.1',
27
27
  username: "reader",
28
28
  password: "password",
29
- port: "33005",
29
+ port: "13005",
30
30
  )
31
31
 
32
- assert_equal conn.query("SELECT @@global.hostname as host #{Lhm::ProxySQLHelper::ANNOTATION}").each.first["host"], "mysql-1"
32
+ assert_equal DATABASE.query(conn, "SELECT @@global.hostname as host #{Lhm::ProxySQLHelper::ANNOTATION}").each.first["host"], "mysql-1"
33
33
  end
34
- end
34
+ end
@@ -1,5 +1,4 @@
1
1
  require 'yaml'
2
- require 'mysql2'
3
2
 
4
3
  class DBConnectionHelper
5
4
 
@@ -11,12 +10,11 @@ class DBConnectionHelper
11
10
  end
12
11
 
13
12
  def new_mysql_connection(role = :master, with_data = false, toxic = false)
14
-
15
13
  key = role.to_s + toxic_postfix(toxic)
16
14
 
17
15
  conn = ActiveRecord::Base.establish_connection(
18
16
  :host => '127.0.0.1',
19
- :adapter => "mysql2",
17
+ :adapter => DATABASE.adapter,
20
18
  :username => db_config[key]['user'],
21
19
  :password => db_config[key]['password'],
22
20
  :database => test_db_name,
@@ -49,4 +47,4 @@ class DBConnectionHelper
49
47
  end
50
48
  end
51
49
  end
52
- end
50
+ end
@@ -1,5 +1,4 @@
1
1
  require 'minitest/autorun'
2
- require 'mysql2'
3
2
  require 'integration/sql_retry/lock_wait_timeout_test_helper'
4
3
  require 'lhm'
5
4
 
@@ -22,7 +21,7 @@ describe Lhm::SqlRetry do
22
21
  # Assert our pre-conditions
23
22
  assert_equal 2, @helper.record_count
24
23
 
25
- Mysql2::Client.any_instance.stubs(:active?).returns(true)
24
+ DATABASE.client.any_instance.stubs(:active?).returns(true)
26
25
  end
27
26
 
28
27
  after(:each) do
@@ -43,8 +42,8 @@ describe Lhm::SqlRetry do
43
42
 
44
43
  exception = assert_raises { @helper.trigger_wait_lock }
45
44
 
46
- assert_match /Lock wait timeout exceeded; try restarting transaction/, exception.message
47
- assert_equal Mysql2::Error::TimeoutError, exception.class
45
+ assert_match Regexp.new("Lock wait timeout exceeded; try restarting transaction"), exception.message
46
+ assert_equal DATABASE.timeout_error, exception.class
48
47
 
49
48
  assert_equal 2, @helper.record_count # no records inserted
50
49
  puts "*" * 64
@@ -82,10 +81,10 @@ describe Lhm::SqlRetry do
82
81
  logs = @logger.string.split("\n")
83
82
  assert_equal 2, logs.length
84
83
 
85
- assert logs.first.include?("Mysql2::Error::TimeoutError: 'Lock wait timeout exceeded; try restarting transaction' - 1 tries")
84
+ assert logs.first.include?("Lock wait timeout exceeded; try restarting transaction' - 1 tries")
86
85
  assert logs.first.include?("0.2 seconds until the next try")
87
86
 
88
- assert logs.last.include?("Mysql2::Error::TimeoutError: 'Lock wait timeout exceeded; try restarting transaction' - 2 tries")
87
+ assert logs.last.include?("Lock wait timeout exceeded; try restarting transaction' - 2 tries")
89
88
  assert logs.last.include?("0.2 seconds until the next try")
90
89
  end
91
90
 
@@ -118,8 +117,8 @@ describe Lhm::SqlRetry do
118
117
 
119
118
  exception = assert_raises { @helper.trigger_wait_lock }
120
119
 
121
- assert_match /Lock wait timeout exceeded; try restarting transaction/, exception.message
122
- assert_equal Mysql2::Error::TimeoutError, exception.class
120
+ assert_match Regexp.new("Lock wait timeout exceeded; try restarting transaction"), exception.message
121
+ assert_equal DATABASE.timeout_error, exception.class
123
122
 
124
123
  assert_equal 2, @helper.record_count # no records inserted
125
124
  puts "*" * 64
@@ -14,13 +14,21 @@ class LockWaitTimeoutTestHelper
14
14
 
15
15
  @lock_duration = lock_duration
16
16
 
17
- # While implementing this, I discovered that MySQL seems to have an off-by-one
18
- # bug with the innodb_lock_wait_timeout. If you ask it to wait 2 seconds, it will wait 3.
19
- # In order to avoid surprisingly the user, let's account for that here, but also
20
- # guard against a case where we go below 1, the minimum value.
21
- raise ArgumentError, "innodb_lock_wait_timeout must be greater than or equal to 2" unless innodb_lock_wait_timeout >= 2
22
17
  raise ArgumentError, "innodb_lock_wait_timeout must be an integer" if innodb_lock_wait_timeout.class != Integer
23
- @innodb_lock_wait_timeout = innodb_lock_wait_timeout - 1
18
+
19
+ result = DATABASE.query(@main_conn, "SELECT VERSION()")
20
+ mysql_version = result.to_a.dig(0, "VERSION()").split("-", 2)[0]
21
+
22
+ if mysql_version.start_with?("8")
23
+ @innodb_lock_wait_timeout = innodb_lock_wait_timeout
24
+ else
25
+ # While implementing this, I discovered that MySQL seems to have an off-by-one
26
+ # bug with the innodb_lock_wait_timeout. If you ask it to wait 2 seconds, it will wait 3.
27
+ # In order to avoid surprisingly the user, let's account for that here, but also
28
+ # guard against a case where we go below 1, the minimum value.
29
+ raise ArgumentError, "innodb_lock_wait_timeout must be greater than or equal to 2" unless innodb_lock_wait_timeout >= 2
30
+ @innodb_lock_wait_timeout = innodb_lock_wait_timeout - 1
31
+ end
24
32
 
25
33
  @threads = []
26
34
  @queue = Queue.new
@@ -51,7 +59,7 @@ class LockWaitTimeoutTestHelper
51
59
  end
52
60
 
53
61
  def record_count(connection = main_conn)
54
- response = connection.query("SELECT COUNT(id) FROM #{test_table_name}")
62
+ response = mysql_exec(connection, "SELECT COUNT(id) FROM #{test_table_name}")
55
63
  response.first.values.first
56
64
  end
57
65
 
@@ -79,7 +87,7 @@ class LockWaitTimeoutTestHelper
79
87
  attr_reader :main_conn, :lock_duration, :innodb_lock_wait_timeout
80
88
 
81
89
  def new_mysql_connection
82
- Mysql2::Client.new(
90
+ DATABASE.client.new(
83
91
  host: '127.0.0.1',
84
92
  username: db_config['master']['user'],
85
93
  password: db_config['master']['password'],
@@ -103,8 +111,8 @@ class LockWaitTimeoutTestHelper
103
111
  private
104
112
 
105
113
  def mysql_exec(connection, statement)
106
- if connection.class == Mysql2::Client
107
- connection.query(statement)
114
+ if connection.class == DATABASE.client
115
+ DATABASE.query(connection, statement)
108
116
  elsif connection.class.to_s.include?("ActiveRecord")
109
117
  connection.execute(statement)
110
118
  else
@@ -2,7 +2,7 @@ class ProxySQLHelper
2
2
  class << self
3
3
  # Flips the destination hostgroup for /maintenance:lhm/ from 0 (i.e. writer) to 1 (i.e. reader)
4
4
  def with_lhm_hostgroup_flip
5
- conn = Mysql2::Client.new(
5
+ conn = DATABASE.client.new(
6
6
  host: '127.0.0.1',
7
7
  username: "remote-admin",
8
8
  password: "password",