public
Description: Global named locks (req. mysql) -- Extraction from Shopify
Homepage: http://www.shopify.com
Clone URL: git://github.com/tobi/locking.git
Search Repo:
Tobias Lütke (author)
Wed Mar 05 15:17:24 -0800 2008
commit  ef1e9941feb2788d6a4580bd7e033aaefad2cd73
tree    e2c02b89c229fdb16ba6d45f9e965ea9a3890504
locking / lib / locking.rb
100755 39 lines (31 sloc) 1.141 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
module Locking
  class LockError < ActiveRecord::ActiveRecordError
  end
  
  class LockTimeout < LockError
  end
  
  def self.included(base)
    base.send(:extend, ClassMethods)
  end
    
  module ClassMethods
    
    # Aquires an application level lock in the mysql server.
    def aquire_lock(lock_name = table_name, wait_timeout = 0)
      case c = connection.select_value("SELECT GET_LOCK(#{quote_value(lock_name)}, #{quote_value(wait_timeout)})")
      when '1'
        yield if block_given?
      when '0'
        false
      when 'NULL'
        raise LockError, "Error in locking mechanism"
      else
        raise LockError, "Unknown response from database: #{c.inspect}"
      end
      
    ensure
      connection.select_one("SELECT RELEASE_LOCK(#{quote_value(lock_name)})")
    end
    
    # Aquires an application level lock in the mysql server. Throws Locking::LockTimeout if the
    # lock cannot be aquired.
    def aquire_lock!(lock_name = table_name, wait_timeout = 0, &block)
      aquire_lock(lock_name, table_name, &block) or raise LockTimeout, 'Timeout waiting for lock'
    end
    
  end
  
end