Class: Locker::Advisory

Inherits:
Object
  • Object
show all
Defined in:
lib/locker/advisory.rb

Defined Under Namespace

Classes: LockConnectionLost

Constant Summary collapse

MAX_LOCK =
2147483647
MIN_LOCK =
-2147483648
OVERFLOW_ADJUSTMENT =
2**32

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, options = {}) ⇒ Advisory

Returns a new instance of Advisory.

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/locker/advisory.rb', line 13

def initialize(key, options={})
  raise ArgumentError, "key must be a string" unless key.is_a?(String)

  @key       = key
  @crc       = convert_to_crc(key)
  @lockspace = (options[:lockspace] || 1)
  @blocking  = !!options[:blocking]
  @locked    = false

  if !@lockspace.is_a?(Integer) || @lockspace < MIN_LOCK || @lockspace > MAX_LOCK
    raise ArgumentError, "The :lockspace option must be an integer between #{MIN_LOCK} and #{MAX_LOCK}"
  end
end

Instance Attribute Details

#blockingObject (readonly)

Returns the value of attribute blocking.



7
8
9
# File 'lib/locker/advisory.rb', line 7

def blocking
  @blocking
end

#crcObject (readonly)

Returns the value of attribute crc.



7
8
9
# File 'lib/locker/advisory.rb', line 7

def crc
  @crc
end

#keyObject (readonly)

Returns the value of attribute key.



7
8
9
# File 'lib/locker/advisory.rb', line 7

def key
  @key
end

#lockedObject (readonly)

Returns the value of attribute locked.



7
8
9
# File 'lib/locker/advisory.rb', line 7

def locked
  @locked
end

#lockspaceObject (readonly)

Returns the value of attribute lockspace.



7
8
9
# File 'lib/locker/advisory.rb', line 7

def lockspace
  @lockspace
end

Class Method Details

.run(key, options = {}, &block) ⇒ Object



27
28
29
30
# File 'lib/locker/advisory.rb', line 27

def self.run(key, options={}, &block)
  advisory = new(key, options)
  advisory.run(&block)
end

Instance Method Details

#run(&block) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/locker/advisory.rb', line 32

def run(&block)
  connection = ActiveRecord::Base.connection_pool.checkout
  connection.transaction :requires_new => true do
    ensure_unlocked(connection)

    while !get(connection) && @blocking
      sleep 0.5
    end

    if @locked
      begin
        parent_thread = Thread.current

        mutex = Mutex.new

        checker = Thread.new do
          while @locked
            10.times{ sleep 0.5 if @locked }
            mutex.synchronize do
              if @locked
                check(connection, parent_thread)
              end
            end
          end
        end

        block.call
      ensure
        release(connection) if @locked
        # Using a mutex to synchronize so that we're sure we're not
        # executing a query when we kill the thread.
        mutex.synchronize{}
        if checker.alive?
          checker.exit rescue nil
        end
      end
      true
    else
      false
    end
  end
ensure
  ActiveRecord::Base.connection_pool.checkin(connection) if connection
end