lhm-shopify 3.5.5 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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",