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
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
Saves the session.
Aws::SessionStore::DynamoDB::Locking::Base#set_session_data
# 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
Option to delete lock.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 127 def add_attr { "locked_at" => {:action => "DELETE"} } end
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 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
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
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
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
@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 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
@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 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 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 expectation.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 122 def lock_expect { :expected => { "locked_at" => { :exists => false } } } end
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
@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
@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
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
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
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