Merge pull request #39758 from tgxworld/create_own_connection_handler_for_advisory_locks

Move advisory locks to own connection handler.
This commit is contained in:
Eileen M. Uchitelle 2020-08-04 09:27:04 -04:00 committed by GitHub
commit 8de10f9bb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 24 additions and 32 deletions

View File

@ -36,7 +36,6 @@ require "active_record/errors"
module ActiveRecord
extend ActiveSupport::Autoload
autoload :AdvisoryLockBase
autoload :Base
autoload :Callbacks
autoload :Core

View File

@ -1,18 +0,0 @@
# frozen_string_literal: true
module ActiveRecord
# This class is used to create a connection that we can use for advisory
# locks. This will take out a "global" lock that can't be accidentally
# removed if a new connection is established during a migration.
class AdvisoryLockBase < ActiveRecord::Base # :nodoc:
self.abstract_class = true
self.connection_specification_name = "AdvisoryLockBase"
class << self
def _internal?
true
end
end
end
end

View File

@ -1376,20 +1376,29 @@ module ActiveRecord
def with_advisory_lock
lock_id = generate_migrator_advisory_lock_id
AdvisoryLockBase.establish_connection(ActiveRecord::Base.connection_db_config) unless AdvisoryLockBase.connected?
connection = AdvisoryLockBase.connection
got_lock = connection.get_advisory_lock(lock_id)
raise ConcurrentMigrationError unless got_lock
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
yield
ensure
if got_lock && !connection.release_advisory_lock(lock_id)
raise ConcurrentMigrationError.new(
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
)
with_advisory_lock_connection do |connection|
got_lock = connection.get_advisory_lock(lock_id)
raise ConcurrentMigrationError unless got_lock
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
yield
ensure
if got_lock && !connection.release_advisory_lock(lock_id)
raise ConcurrentMigrationError.new(
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
)
end
end
end
def with_advisory_lock_connection
pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
ActiveRecord::Base.connection_db_config
)
pool.with_connection { |connection| yield(connection) }
end
MIGRATOR_SALT = 2053462845
def generate_migrator_advisory_lock_id
db_name_hash = Zlib.crc32(Base.connection.current_database)

View File

@ -940,8 +940,10 @@ class MigrationTest < ActiveRecord::TestCase
e = assert_raises(ActiveRecord::ConcurrentMigrationError) do
silence_stream($stderr) do
migrator.send(:with_advisory_lock) do
ActiveRecord::AdvisoryLockBase.connection.release_advisory_lock(lock_id)
migrator.stub(:with_advisory_lock_connection, ->(&block) { block.call(ActiveRecord::Base.connection) }) do
migrator.send(:with_advisory_lock) do
ActiveRecord::Base.connection.release_advisory_lock(lock_id)
end
end
end
end