Sha256: 28c86603e0618d0075846cf665e805db855334435dc75db215836977a3476d86

Contents?: true

Size: 1.37 KB

Versions: 2

Compression:

Stored size: 1.37 KB

Contents

module WithAdvisoryLock
  class PostgreSQL < Base
    # See http://www.postgresql.org/docs/9.1/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
    def try_lock
      pg_function = "pg_try_advisory#{transaction ? '_xact' : ''}_lock#{shared ? '_shared' : ''}"
      execute_successful?(pg_function)
    end

    def release_lock
      return if transaction
      pg_function = "pg_advisory_unlock#{shared ? '_shared' : ''}"
      execute_successful?(pg_function)
    rescue ActiveRecord::StatementInvalid => e
      raise unless e.message =~ / ERROR: +current transaction is aborted,/
      begin
        connection.rollback_db_transaction
        execute_successful?(pg_function)
      ensure
        connection.begin_db_transaction
      end
    end

    def execute_successful?(pg_function)
      comment = lock_name.gsub(/(\/\*)|(\*\/)/, '--')
      sql = "SELECT #{pg_function}(#{lock_keys.join(',')}) AS #{unique_column_name} /* #{comment} */"
      result = connection.select_value(sql)
      # MRI returns 't', jruby returns true. YAY!
      (result == 't' || result == true)
    end

    # PostgreSQL wants 2 32bit integers as the lock key.
    def lock_keys
      @lock_keys ||= begin
        [stable_hashcode(lock_name), ENV['WITH_ADVISORY_LOCK_PREFIX']].map do |ea|
          # pg advisory args must be 31 bit ints
          ea.to_i & 0x7fffffff
        end
      end
    end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
with_advisory_lock-4.6.0 lib/with_advisory_lock/postgresql.rb
with_advisory_lock-4.0.0 lib/with_advisory_lock/postgresql.rb