Class: ActiveRecord::DatabaseMutex::Implementation

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/database_mutex/implementation.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Implementation

Creates a mutex with the name given with the option :name.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/active_record/database_mutex/implementation.rb', line 9

def initialize(opts = {})
  @name = opts[:name] or raise ArgumentError, "mutex requires a :name argument"
  query %{ SET @old_autocommit = @@autocommit }
  query %{ SET autocommit = 1 }
  query %{
    CREATE TEMPORARY TABLE IF NOT EXISTS mutex_counters
      (
        name CHAR(255) NOT NULL,
        counter INT UNSIGNED NOT NULL DEFAULT 1,
        PRIMARY KEY (name(128))
      ) DEFAULT CHARSET=utf8mb4
  }
  query %{ SET autocommit = @old_autocommit }
end

Instance Attribute Details

#nameObject (readonly)

Returns the name of this mutex as given as a constructor argument.



29
30
31
# File 'lib/active_record/database_mutex/implementation.rb', line 29

def name
  @name
end

Instance Method Details

#aquired_lock?Boolean

Returns true if this mutex is locked by this database connection.

Returns:

  • (Boolean)


115
116
117
# File 'lib/active_record/database_mutex/implementation.rb', line 115

def aquired_lock?
  query("SELECT CONNECTION_ID() = IS_USED_LOCK(#{quote(name)})") == 1
end

#dbObject



24
25
26
# File 'lib/active_record/database_mutex/implementation.rb', line 24

def db
  ActiveRecord::Base.connection
end

#lock(opts = {}) ⇒ Object

Locks the mutex and returns true if successful. If the mutex is already locked and the timeout in seconds is given as the :timeout option, this method raises a MutexLocked exception after that many seconds. If the :timeout option wasn’t given, this method blocks until the lock could be aquired.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/active_record/database_mutex/implementation.rb', line 59

def lock(opts = {})
  if opts[:nonblock] # XXX document
    begin
      lock_with_timeout :timeout => 0
    rescue MutexLocked
    end
  elsif opts[:timeout]
    lock_with_timeout opts
  else
    spin_timeout = opts[:spin_timeout] || 1 # XXX document
    begin
      lock_with_timeout :timeout => spin_timeout
    rescue MutexLocked
      retry
    end
  end
end

#locked?Boolean

Returns true if this mutex is locked at the moment.

Returns:

  • (Boolean)


110
111
112
# File 'lib/active_record/database_mutex/implementation.rb', line 110

def locked?
  not unlocked?
end

#not_aquired_lock?Boolean

Returns true if this mutex is not locked by this database connection.

Returns:

  • (Boolean)


120
121
122
# File 'lib/active_record/database_mutex/implementation.rb', line 120

def not_aquired_lock?
  not aquired_lock?
end

#synchronize(opts = {}) ⇒ Object

Locks the mutex if it isn’t already locked via another database connection and yields to the given block. After executing the block’s content the mutex is unlocked (only if it was locked by this synchronize method before).

If the mutex was already locked by another database connection the method blocks until it could aquire the lock and only then the block’s content is executed. If the mutex was already locked by the current database connection then the block’s content is run and the the mutex isn’t unlocked afterwards.

If a value in seconds is passed to the :timeout option the blocking ends after that many seconds and the method returns immediately if the lock couldn’t be aquired during that time.



45
46
47
48
49
50
51
52
# File 'lib/active_record/database_mutex/implementation.rb', line 45

def synchronize(opts = {})
  locked = lock(opts) or return
  yield
rescue ActiveRecord::DatabaseMutex::MutexLocked
  return nil
ensure
  locked and unlock
end

#to_sObject Also known as: inspect

Returns a string representation of this DatabaseMutex instance.



125
126
127
# File 'lib/active_record/database_mutex/implementation.rb', line 125

def to_s
  "#<#{self.class} #{name}>"
end

#unlockObject

Unlocks the mutex and returns true if successful. Otherwise this method raises a MutexLocked exception.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/active_record/database_mutex/implementation.rb', line 79

def unlock(*)
  if aquired_lock?
    decrease_counter
    if counter_zero?
      case query %{ SELECT RELEASE_LOCK(#{quote(name)}) }
      when 1
        true
      when 0, nil
        raise MutexUnlockFailed, "unlocking of mutex '#{name}' failed"
      end
    end
  else
    raise MutexUnlockFailed, "unlocking of mutex '#{name}' failed"
  end
end

#unlock?(*a) ⇒ Boolean

Unlock this mutex and return self if successful, otherwise (the mutex was not locked) nil is returned.

Returns:

  • (Boolean)


97
98
99
100
101
102
# File 'lib/active_record/database_mutex/implementation.rb', line 97

def unlock?(*a)
  unlock(*a)
  self
rescue MutexUnlockFailed
  nil
end

#unlocked?Boolean

Returns true if this mutex is unlocked at the moment.

Returns:

  • (Boolean)


105
106
107
# File 'lib/active_record/database_mutex/implementation.rb', line 105

def unlocked?
  query(%{ SELECT IS_FREE_LOCK(#{quote(name)}) }).to_i == 1
end