Class: GCRA::RedisStore
- Inherits:
-
Object
- Object
- GCRA::RedisStore
- Defined in:
- lib/gcra/redis_store.rb
Overview
Redis store, expects all timestamps and durations to be integers with nanoseconds since epoch.
Constant Summary collapse
- CAS_SCRIPT =
<<-EOF.freeze local v = redis.call('get', KEYS[1]) if v == false then return redis.error_reply("key does not exist") end if v ~= ARGV[1] then return 0 end redis.call('psetex', KEYS[1], ARGV[3], ARGV[2]) return 1 EOF
- CAS_SHA =
Digest::SHA1.hexdigest(CAS_SCRIPT)
"89118e702230c0d65969c5fc557a6e942a2f4d31".freeze
- CAS_SCRIPT_MISSING_KEY_RESPONSE =
'key does not exist'.freeze
- SCRIPT_NOT_IN_CACHE_RESPONSE =
'NOSCRIPT No matching script. Please use EVAL.'
Instance Method Summary collapse
-
#compare_and_set_with_ttl(key, old_value, new_value, ttl_nano) ⇒ Object
Atomically compare the value at key to the old value.
-
#get_with_time(key) ⇒ Object
Returns the value of the key or nil, if it isn’t in the store.
-
#initialize(redis, key_prefix) ⇒ RedisStore
constructor
A new instance of RedisStore.
-
#set_if_not_exists_with_ttl(key, value, ttl_nano) ⇒ Object
Set the value of key only if it is not already set.
Constructor Details
#initialize(redis, key_prefix) ⇒ RedisStore
Returns a new instance of RedisStore.
21 22 23 24 |
# File 'lib/gcra/redis_store.rb', line 21 def initialize(redis, key_prefix) @redis = redis @key_prefix = key_prefix end |
Instance Method Details
#compare_and_set_with_ttl(key, old_value, new_value, ttl_nano) ⇒ Object
Atomically compare the value at key to the old value. If it matches, set it to the new value and return true. Otherwise, return false. If the key does not exist in the store, return false with no error. If the swap succeeds, update the ttl for the key atomically.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/gcra/redis_store.rb', line 53 def compare_and_set_with_ttl(key, old_value, new_value, ttl_nano) full_key = @key_prefix + key retried = false begin ttl_milli = calculate_ttl_milli(ttl_nano) swapped = @redis.evalsha(CAS_SHA, keys: [full_key], argv: [old_value, new_value, ttl_milli]) rescue Redis::CommandError => e if e. == CAS_SCRIPT_MISSING_KEY_RESPONSE return false elsif e. == SCRIPT_NOT_IN_CACHE_RESPONSE && !retried @redis.script('load', CAS_SCRIPT) retried = true retry end raise end return swapped == 1 end |
#get_with_time(key) ⇒ Object
Returns the value of the key or nil, if it isn’t in the store. Also returns the time from the Redis server, with microsecond precision.
28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/gcra/redis_store.rb', line 28 def get_with_time(key) time_response, value = @redis.pipelined do @redis.time # returns tuple (seconds since epoch, microseconds) @redis.get(@key_prefix + key) end # Convert tuple to nanoseconds time = (time_response[0] * 1_000_000 + time_response[1]) * 1_000 if value != nil value = value.to_i end return value, time end |
#set_if_not_exists_with_ttl(key, value, ttl_nano) ⇒ Object
Set the value of key only if it is not already set. Return whether the value was set. Also set the key’s expiration (ttl, in seconds).
44 45 46 47 48 |
# File 'lib/gcra/redis_store.rb', line 44 def set_if_not_exists_with_ttl(key, value, ttl_nano) full_key = @key_prefix + key ttl_milli = calculate_ttl_milli(ttl_nano) @redis.set(full_key, value, nx: true, px: ttl_milli) end |