class Aws::SessionStore::DynamoDB::Locking::Pessimistic

This class implements a pessimistic locking strategy for the DynamoDB session handler. Sessions obtain an exclusive lock for reads that is only released when the session is saved.

Public Instance Methods

get_session_data(env, sid) click to toggle source

Gets session from database and places a lock on the session while you are reading from the database.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 13
def get_session_data(env, sid)
  handle_error(env) do
    get_session_with_lock(env, sid)
  end
end
set_session_data(env, sid, session, options = {}) click to toggle source

Saves the session.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 7
def set_session_data(env, sid, session, options = {})
  super(env, sid, session, set_lock_options(env, options))
end

Private Instance Methods

add_attr() click to toggle source

Option to delete lock.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 127
def add_attr
  { "locked_at" => {:action => "DELETE"} }
end
add_lock_attrs(env) click to toggle source

Attributes for locking.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 110
def add_lock_attrs(env)
  {
    :add_attrs => add_attr, :expect_attr => expect_lock_time(env)
  }
end
attempt_set_lock(sid) click to toggle source

Attempt to place a lock on the session.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 92
def attempt_set_lock(sid)
  @config.dynamo_db_client.update_item(obtain_lock_opts(sid, lock_expect))
end
bust_lock(sid, expires_at) click to toggle source

Attempt to bust the lock if the expiration date has expired.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 69
def bust_lock(sid, expires_at)
  if expires_at < Time.now.to_f
    @config.dynamo_db_client.update_item(obtain_lock_opts(sid))
  end
end
exceeded_wait_time?(max_attempt_date) click to toggle source

Determine if session has waited too long to obtain lock.

@raise [Error] When time for attempting to get lock has

been exceeded.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 44
def exceeded_wait_time?(max_attempt_date)
  lock_error = Aws::SessionStore::DynamoDB::LockWaitTimeoutError
  raise lock_error if Time.now.to_f > max_attempt_date
end
expect_lock_time(env) click to toggle source

Expectation of when lock was set.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 132
def expect_lock_time(env)
  { :expected => {"locked_at" => {
    :value => "#{env["locked_at"]}", :exists => true}} }
end
get_data(env, result) click to toggle source

@return [String] Session data.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 61
def get_data(env, result)
  lock_time = result[:attributes]["locked_at"]
  env["locked_at"] = (lock_time).to_f
  env['rack.initial_data'] = result[:item]["data"] if result.members.include? :item
  unpack_data(result[:attributes]["data"])
end
get_expire_date(sid) click to toggle source

Get the expiration date for the session

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 86
def get_expire_date(sid)
  lock_date = lock_time(sid)
  lock_date + (0.001 * @config.lock_expiry_time) if lock_date
end
get_lock_time_opts(sid) click to toggle source

@return [Hash] Options hash for placing a lock on a session.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 50
def get_lock_time_opts(sid)
  merge_all(table_opts(sid), lock_opts)
end
get_session_with_lock(env, sid) click to toggle source

Get session with implemented locking strategy.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 22
def get_session_with_lock(env, sid)
  expires_at = nil
  result = nil
  max_attempt_date = Time.now.to_f + @config.lock_max_wait_time
  while result.nil?
    exceeded_wait_time?(max_attempt_date)
    begin
      result = attempt_set_lock(sid)
    rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
      expires_at ||= get_expire_date(sid)
      next if expires_at.nil?
      result = bust_lock(sid, expires_at)
      wait_to_retry(result)
    end
  end
  get_data(env, result)
end
lock_attr() click to toggle source

Lock attribute - time stamp of when session was locked.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 97
def lock_attr
  {
    :attribute_updates => {"locked_at" => updated_at},
    :return_values => "ALL_NEW"
  }
end
lock_expect() click to toggle source

Lock expectation.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 122
def lock_expect
  { :expected => { "locked_at" => { :exists => false } } }
end
lock_opts() click to toggle source

Attributes to be retrieved via client

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 138
def lock_opts
  {:attributes_to_get => ["locked_at"],
  :consistent_read => @config.consistent_read}
end
lock_time(sid) click to toggle source

@return [Time] Time stamp for which the session was locked.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 55
def lock_time(sid)
  result = @config.dynamo_db_client.get_item(get_lock_time_opts(sid))
  (result[:item]["locked_at"]).to_f if result[:item]["locked_at"]
end
obtain_lock_opts(sid, add_opt = {}) click to toggle source

@return [Hash] Options hash for obtaining the lock.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 76
def obtain_lock_opts(sid, add_opt = {})
  merge_all(table_opts(sid), lock_attr, add_opt)
end
set_lock_options(env, options = {}) click to toggle source

Lock options for setting lock.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 117
def set_lock_options(env, options = {})
  merge_all(options, add_lock_attrs(env))
end
updated_at() click to toggle source

Time in which session was updated.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 105
def updated_at
  { :value => "#{(Time.now).to_f}", :action  => "PUT" }
end
wait_to_retry(result) click to toggle source

Sleep for given time period if the session is currently locked.

# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 81
def wait_to_retry(result)
  sleep(0.001 * @config.lock_retry_delay) if result.nil?
end