@@ -3793,14 +3793,15 @@ def up
3793
3793
let ( :alternate_connection_pool ) do
3794
3794
ActiveRecord ::ConnectionAdapters ::ConnectionPool . new ( pool_config )
3795
3795
end
3796
- let ( :alternate_connection ) do
3797
- alternate_connection_pool . connection
3798
- end
3796
+
3797
+ let ( :alternate_connection ) { alternate_connection_pool . connection }
3798
+ let ( :alternate_connection_2 ) { alternate_connection_pool . connection }
3799
3799
let ( :migration ) { Class . new ( migration_klass ) . new }
3800
3800
3801
3801
before ( :each ) do
3802
3802
ActiveRecord ::Base . connection . execute ( <<~SQL )
3803
3803
CREATE TABLE #{ table_name } (pk SERIAL, i INTEGER);
3804
+ CREATE TABLE #{ table_name } _2(pk SERIAL, i INTEGER);
3804
3805
CREATE SCHEMA partman;
3805
3806
CREATE EXTENSION pg_partman SCHEMA partman;
3806
3807
SQL
@@ -3829,6 +3830,28 @@ def up
3829
3830
end
3830
3831
end
3831
3832
3833
+ it "acquires exclusive locks by default when multiple tables provided" do
3834
+ migration . safely_acquire_lock_for_table ( table_name , "bogus_table_2" ) do
3835
+ expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to contain_exactly (
3836
+ having_attributes (
3837
+ table : "bogus_table" ,
3838
+ lock_type : "AccessExclusiveLock" ,
3839
+ granted : true ,
3840
+ pid : kind_of ( Integer ) ,
3841
+ )
3842
+ )
3843
+
3844
+ expect ( locks_for_table ( "bogus_table_2" , connection : alternate_connection ) ) . to contain_exactly (
3845
+ having_attributes (
3846
+ table : "bogus_table_2" ,
3847
+ lock_type : "AccessExclusiveLock" ,
3848
+ granted : true ,
3849
+ pid : kind_of ( Integer ) ,
3850
+ )
3851
+ )
3852
+ end
3853
+ end
3854
+
3832
3855
it "acquires a lock in a different mode when provided" do
3833
3856
migration . safely_acquire_lock_for_table ( table_name , mode : :share ) do
3834
3857
expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to contain_exactly (
@@ -3842,6 +3865,28 @@ def up
3842
3865
end
3843
3866
end
3844
3867
3868
+ it "acquires locks in a different mode when multiple tables and mode provided" do
3869
+ migration . safely_acquire_lock_for_table ( table_name , "bogus_table_2" , mode : :share_row_exclusive ) do
3870
+ expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to contain_exactly (
3871
+ having_attributes (
3872
+ table : "bogus_table" ,
3873
+ lock_type : "ShareRowExclusiveLock" ,
3874
+ granted : true ,
3875
+ pid : kind_of ( Integer ) ,
3876
+ )
3877
+ )
3878
+
3879
+ expect ( locks_for_table ( "bogus_table_2" , connection : alternate_connection ) ) . to contain_exactly (
3880
+ having_attributes (
3881
+ table : "bogus_table_2" ,
3882
+ lock_type : "ShareRowExclusiveLock" ,
3883
+ granted : true ,
3884
+ pid : kind_of ( Integer ) ,
3885
+ )
3886
+ )
3887
+ end
3888
+ end
3889
+
3845
3890
it "raises error when invalid lock mode provided" do
3846
3891
expect do
3847
3892
migration . safely_acquire_lock_for_table ( table_name , mode : :garbage ) { }
@@ -3883,6 +3928,39 @@ def up
3883
3928
end
3884
3929
end
3885
3930
3931
+ it "times out the lock query after LOCK_TIMEOUT_SECONDS when multiple tables provided" do
3932
+ stub_const ( "PgHaMigrations::LOCK_TIMEOUT_SECONDS" , 1 )
3933
+ stub_const ( "PgHaMigrations::LOCK_FAILURE_RETRY_DELAY_MULTLIPLIER" , 0 )
3934
+ allow ( PgHaMigrations ::BlockingDatabaseTransactions ) . to receive ( :find_blocking_transactions ) . and_return ( [ ] )
3935
+ allow ( ActiveRecord ::Base . connection ) . to receive ( :execute ) . and_call_original
3936
+
3937
+ expect ( ActiveRecord ::Base . connection ) . to receive ( :execute )
3938
+ . with ( "LOCK \" public\" .\" bogus_table\" , \" public\" .\" bogus_table_2\" IN ACCESS EXCLUSIVE MODE;" )
3939
+ . at_least ( 2 )
3940
+ . times
3941
+
3942
+ begin
3943
+ query_thread = Thread . new do
3944
+ alternate_connection . execute ( "BEGIN; LOCK bogus_table_2;" )
3945
+ sleep 3
3946
+ alternate_connection . execute ( "ROLLBACK" )
3947
+ end
3948
+
3949
+ sleep 0.5
3950
+
3951
+ migration . suppress_messages do
3952
+ migration . safely_acquire_lock_for_table ( table_name , "bogus_table_2" ) do
3953
+ aggregate_failures do
3954
+ expect ( locks_for_table ( table_name , connection : alternate_connection_2 ) ) . not_to be_empty
3955
+ expect ( locks_for_table ( "bogus_table_2" , connection : alternate_connection_2 ) ) . not_to be_empty
3956
+ end
3957
+ end
3958
+ end
3959
+ ensure
3960
+ query_thread . join
3961
+ end
3962
+ end
3963
+
3886
3964
it "does not wait to acquire a lock if the table has an existing but non-conflicting lock" do
3887
3965
stub_const ( "PgHaMigrations::LOCK_TIMEOUT_SECONDS" , 1 )
3888
3966
@@ -4303,6 +4381,53 @@ def up
4303
4381
expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to be_empty
4304
4382
end
4305
4383
4384
+ it "allows re-entrancy when multiple tables provided" do
4385
+ migration . safely_acquire_lock_for_table ( table_name , "bogus_table_2" ) do
4386
+ # The ordering of the args is intentional here to ensure
4387
+ # the array sorting and equality logic works as intended
4388
+ migration . safely_acquire_lock_for_table ( "bogus_table_2" , table_name ) do
4389
+ expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to contain_exactly (
4390
+ having_attributes (
4391
+ table : "bogus_table" ,
4392
+ lock_type : "AccessExclusiveLock" ,
4393
+ granted : true ,
4394
+ pid : kind_of ( Integer ) ,
4395
+ ) ,
4396
+ )
4397
+
4398
+ expect ( locks_for_table ( "bogus_table_2" , connection : alternate_connection ) ) . to contain_exactly (
4399
+ having_attributes (
4400
+ table : "bogus_table_2" ,
4401
+ lock_type : "AccessExclusiveLock" ,
4402
+ granted : true ,
4403
+ pid : kind_of ( Integer ) ,
4404
+ ) ,
4405
+ )
4406
+ end
4407
+
4408
+ expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to contain_exactly (
4409
+ having_attributes (
4410
+ table : "bogus_table" ,
4411
+ lock_type : "AccessExclusiveLock" ,
4412
+ granted : true ,
4413
+ pid : kind_of ( Integer ) ,
4414
+ ) ,
4415
+ )
4416
+
4417
+ expect ( locks_for_table ( "bogus_table_2" , connection : alternate_connection ) ) . to contain_exactly (
4418
+ having_attributes (
4419
+ table : "bogus_table_2" ,
4420
+ lock_type : "AccessExclusiveLock" ,
4421
+ granted : true ,
4422
+ pid : kind_of ( Integer ) ,
4423
+ ) ,
4424
+ )
4425
+ end
4426
+
4427
+ expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to be_empty
4428
+ expect ( locks_for_table ( "bogus_table_2" , connection : alternate_connection ) ) . to be_empty
4429
+ end
4430
+
4306
4431
it "allows re-entrancy when inner lock is a lower level" do
4307
4432
migration . safely_acquire_lock_for_table ( table_name ) do
4308
4433
migration . safely_acquire_lock_for_table ( table_name , mode : :exclusive ) do
@@ -4405,26 +4530,6 @@ def up
4405
4530
4406
4531
expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to be_empty
4407
4532
end
4408
-
4409
- it "uses statement_timeout instead of lock_timeout when on Postgres 9.1" do
4410
- allow ( ActiveRecord ::Base . connection ) . to receive ( :postgresql_version ) . and_wrap_original do |m , *args |
4411
- if caller . detect { |line | line =~ /lib\/ pg_ha_migrations\/ blocking_database_transactions\. rb/ }
4412
- # The long-running transactions check needs to know the actual
4413
- # Postgres version to use the proper columns, so we don't want
4414
- # to mock any calls from it.
4415
- m . call ( *args )
4416
- else
4417
- 9_01_12
4418
- end
4419
- end
4420
-
4421
- expect do
4422
- migration . safely_acquire_lock_for_table ( table_name ) do
4423
- expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . not_to be_empty
4424
- end
4425
- expect ( locks_for_table ( table_name , connection : alternate_connection ) ) . to be_empty
4426
- end . not_to make_database_queries ( matching : /lock_timeout/i )
4427
- end
4428
4533
end
4429
4534
end
4430
4535
0 commit comments