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
26
27
# 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
  @block_timeout   = options[:block_timeout]
  @block_spin_wait = options[:block_spin_wait] || 0.005

  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



29
30
31
32
# File 'lib/locker/advisory.rb', line 29

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

Instance Method Details

#run(&block) ⇒ Object



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
76
77
78
79
80
81
# File 'lib/locker/advisory.rb', line 34

def run(&block)
  connection = ActiveRecord::Base.connection_pool.checkout
  connection.transaction :requires_new => true do
    if @blocking && @block_timeout
      break_at = Time.now + @block_timeout
    end

    while !get(connection) && @blocking
      break if break_at && break_at < Time.now
      sleep @block_spin_wait
    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
        @locked = false
        # Using a mutex to synchronize so that we're sure we're not
        # executing a query when we kill the thread.
        mutex.synchronize do
          if checker.alive?
            checker.exit rescue nil
          end
        end
      end
      true
    else
      false
    end
  end
ensure
  ActiveRecord::Base.connection_pool.checkin(connection) if connection
end