Class: ActiveRecord::DatabaseMutex::Implementation

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

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Implementation

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



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/active_record/database_mutex/implementation.rb', line 14

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

Class Attribute Details

.table_nameObject

Returns the value of attribute table_name.



9
10
11
# File 'lib/active_record/database_mutex/implementation.rb', line 9

def table_name
  @table_name
end

Instance Attribute Details

#nameObject (readonly)

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



35
36
37
# File 'lib/active_record/database_mutex/implementation.rb', line 35

def name
  @name
end

Instance Method Details

#aquired_lock?Boolean

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

Returns:

  • (Boolean)


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

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

#dbObject



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

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.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/active_record/database_mutex/implementation.rb', line 65

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)


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

def locked?
  not unlocked?
end

#not_aquired_lock?Boolean

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

Returns:

  • (Boolean)


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

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.



51
52
53
54
55
56
57
58
# File 'lib/active_record/database_mutex/implementation.rb', line 51

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

#table_nameObject



26
27
28
# File 'lib/active_record/database_mutex/implementation.rb', line 26

def table_name
  self.class.table_name
end

#to_sObject Also known as: inspect

Returns a string representation of this DatabaseMutex instance.



131
132
133
# File 'lib/active_record/database_mutex/implementation.rb', line 131

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

#unlockObject

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



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/active_record/database_mutex/implementation.rb', line 85

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)


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

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

#unlocked?Boolean

Returns true if this mutex is unlocked at the moment.

Returns:

  • (Boolean)


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

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