class AWS::SessionStore::DynamoDB::Locking::Pessimistic
for reads that is only released when the session is saved.
DynamoDB session handler. Sessions obtain an exclusive lock
This class implements a pessimistic locking strategy for the
def add_attr
def add_attr { "locked_at" => {:action => "DELETE"} } end
def add_lock_attrs(env)
def add_lock_attrs(env) { :add_attrs => add_attr, :expect_attr => expect_lock_time(env) } end
def attempt_set_lock(sid)
def attempt_set_lock(sid) @config.dynamo_db_client.update_item(obtain_lock_opts(sid, lock_expect)) end
def bust_lock(sid, expires_at)
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
def exceeded_wait_time?(max_attempt_date)
-
(Error)
- When time for attempting to get lock has
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
def expect_lock_time(env)
def expect_lock_time(env) { :expected => {"locked_at" => { :value => {:n => "#{env["locked_at"]}"}, :exists => true}} } end
def get_data(env, result)
-
(String)
- Session data.
def get_data(env, result) lock_time = result[:attributes]["locked_at"][:n] env["locked_at"] = (lock_time).to_f env['rack.initial_data'] = result[:item]["data"][:s] if result[:item] unpack_data(result[:attributes]["data"][:s]) end
def get_expire_date(sid)
def get_expire_date(sid) lock_date = lock_time(sid) lock_date + (0.001 * @config.lock_expiry_time) if lock_date end
def get_lock_time_opts(sid)
-
(Hash)
- Options hash for placing a lock on a session.
def get_lock_time_opts(sid) merge_all(table_opts(sid), lock_opts) end
def get_session_data(env, sid)
Gets session from database and places a lock on the session
def get_session_data(env, sid) handle_error(env) do get_session_with_lock(env, sid) end end
def get_session_with_lock(env, sid)
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
def lock_attr
def lock_attr { :attribute_updates => {"locked_at" => updated_at}, :return_values => "ALL_NEW" } end
def lock_expect
def lock_expect { :expected => { "locked_at" => { :exists => false } } } end
def lock_opts
def lock_opts {:attributes_to_get => ["locked_at"], :consistent_read => @config.consistent_read} end
def lock_time(sid)
-
(Time)
- Time stamp for which the session was locked.
def lock_time(sid) result = @config.dynamo_db_client.get_item(get_lock_time_opts(sid)) (result[:item]["locked_at"][:n]).to_f if result[:item]["locked_at"] end
def obtain_lock_opts(sid, add_opt = {})
-
(Hash)
- Options hash for obtaining the lock.
def obtain_lock_opts(sid, add_opt = {}) merge_all(table_opts(sid), lock_attr, add_opt) end
def set_lock_options(env, options = {})
def set_lock_options(env, options = {}) merge_all(options, add_lock_attrs(env)) end
def updated_at
def updated_at { :value => {:n => "#{(Time.now).to_f}"}, :action => "PUT" } end
def wait_to_retry(result)
def wait_to_retry(result) sleep(0.001 * @config.lock_retry_delay) if result.nil? end