Class: Redpear::Store::Lock

Inherits:
Base
  • Object
show all
Defined in:
lib/redpear/store/lock.rb

Defined Under Namespace

Classes: LockTimeout

Constant Summary

Constants inherited from Base

Base::IS_NIL, Base::IS_ONE, Base::IS_TRUE, Base::IS_ZERO, Base::PICK_FIRST, Base::TO_INT, Base::TO_SET

Instance Attribute Summary

Attributes inherited from Base

#conn, #key

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#clear, #exists?, #expire, #expire_at, #expire_in, #initialize, #inspect, #purge!, temporary, #ttl, #type, #watch

Constructor Details

This class inherits a constructor from Redpear::Store::Base

Class Method Details

.default_optionsHash

Default lock options. Override via e.g.:

Redpear::Store::Lock.default_options[:lock_timeout] = 5

Returns:

  • (Hash)

    default options



11
12
13
# File 'lib/redpear/store/lock.rb', line 11

def default_options
  @default_options ||= { lock_timeout: 2, wait_timeout: 2 }
end

Instance Method Details

#currentFloat

Returns the current lock timestamp.

Returns:

  • (Float)

    the current lock timestamp



18
19
20
# File 'lib/redpear/store/lock.rb', line 18

def current
  value.to_f
end

#lock(options = {}) { ... } ⇒ Object

Creates a lock and yields a transaction.

Examples:


sender    = Redpear::Store::Hash.new "accounts:sender", connection
recipient = Redpear::Store::Hash.new "accounts:recipient", connection
lock      = Redpear::Store::Lock.new "locks:transfer", connection

lock.lock do
  sender.decrement 'balance', 100
  recipient.increment 'balance', 100
end

Parameters:

  • options (Hash) (defaults to: {})
  • [Integer] (Hash)

    a customizable set of options

Yields:

  • processes the block within the lock

Raises:



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
# File 'lib/redpear/store/lock.rb', line 47

def lock(options = {})
  options   = self.class.default_options.merge(options)
  result    = nil
  timestamp = nil
  timeout   = to_time(options[:wait_timeout])

  while !timestamp && timeout > Time.now
    timestamp = to_time(options[:lock_timeout]).to_f

    if lock_obtained?(timestamp) || expired_lock_obtained?(timestamp)
      result = yield
    else
      timestamp = nil # Unset
      sleep 0.1
    end
  end

  unless timestamp
    raise LockTimeout, "Could not acquire lock on '#{key}'. Timed out."
  end

  result
ensure
  purge! if timestamp && timestamp > Time.now.to_f
end

#lock?(options = {}) { ... } ⇒ Boolean

Conditional locking. Performs a transaction if lock can be acquired.

Parameters:

  • options (Hash) (defaults to: {})
    • see #lock

Yields:

  • processes the block within the lock

Returns:

  • (Boolean)

    true if successful



77
78
79
80
81
82
# File 'lib/redpear/store/lock.rb', line 77

def lock?(options = {}, &block)
  lock(options, &block)
  true
rescue LockTimeout
  false
end

#reserve(seconds, options = {}) { ... } ⇒ Object

Reserves a lock and yields a transaction, but only if not reserved by someone else. This is useful when processes can be triggered by concurrent threads, but should only be executed once.

Examples:

Calling ‘execute_once` method only once


def execute_once
  # Do something
end

t1 = Thread.new do
  lock = Redpear::Store::Lock.new "locks:reservation", connection
  lock.reserve(60) { execute_once } # Reserve for max. 60 seconds
end

t2 = Thread.new do
  lock = Redpear::Store::Lock.new "locks:reservation", connection
  lock.reserve(60) { execute_once }
end

t1.join
t2.join

Parameters:

  • seconds (Integer)

    the number of seconds

  • options (Hash) (defaults to: {})
  • [Boolean] (Hash)

    a customizable set of options

Yields:

  • processes the block within the lock



122
123
124
125
126
# File 'lib/redpear/store/lock.rb', line 122

def reserve(seconds, options = {})
  yield if reserve?(seconds)
ensure
  purge! if options[:clear]
end

#reserve?(seconds) ⇒ Boolean

Tries to reserve a lock. Low-level method, please see #reserve for the high-level API.

Parameters:

  • seconds (Integer)

    the number of seconds

Returns:

  • (Boolean)

    true if lock was reserved



89
90
91
92
# File 'lib/redpear/store/lock.rb', line 89

def reserve?(seconds)
  timestamp = to_time(seconds).to_f
  lock_obtained?(timestamp) || expired_lock_obtained?(timestamp)
end

#valueString

Returns the current lock value.

Returns:

  • (String)

    the current lock value



23
24
25
# File 'lib/redpear/store/lock.rb', line 23

def value
  conn.get key
end