Is it possible to setnx a key with a value and a ttl in single command in redis
I am trying to implement locking in redis and http://redis.io/commands/hsetnx seems like the best way to do that. It is atomic and returns 0 if a key is already present. Is it possible to HSETNX with TTL
e.g.
HSETNX myhash mykey "myvalue" 10
#and key expires after 10 seconds, and a subsequent HSETNX after 10 seconds returns a value 1 i.e. it behaves as if mykey is not present in myhash
The main problem is that Redis have no support for fields expiration in hashmaps.
You can only expire the entire hashmap by calling EXPIRE on myhash.
So, you should reconsider using ordinary Redis strings instead of hashmaps, because they support SETEX operation.
It'll work fine unless you want to take advantage of using HGETALL, HKEYS or HVALS on your hashmap myhash:
SETEX mynamespace:mykey 10 "myvalue"
mynamespace is not a hashmap here, it simply a prefix, but in most cases it works just as hashmaps do. The only difference is that there is no efficient way to tell which keys are stored in the given namespace or to get them all with a single command.
Related
I know there are several ways to set a specific ttl for a key, but is there a way to add some extra time for a key which has a counting down ttl?
There's no built-in way to extend TTL. You need to get the current TTL, and then add some more TTL to it.
Wrap these two steps into a Lua script:
-- extend 300 seconds
eval 'local ttl = redis.call("TTL", "key") + 300; redis.call("EXPIRE", "key", ttl)' 0
Good question
there is no such command
I think it is a bad idea to have a command like that, you have to be careful when you use it.
Probably end up adding more time to the ttl than we expect. If you set it like 5 mins, the actual expire time will be close to 5 mins even if setting it multiple times in that request. But if you add multiple 5 mins to it, then we can`t be sure of the actual expire time
I have case where i need to save values to redis SET structure under given key so i am using command from my code in the loop
SADD key value
EXPIRE KEY 100
However, i would like to set expiration time only on first save of the set key.
Is it possible to set expire time only at the moment of first set key creation ?
it is also should be noted that i can use EXISTS key call to redis to check if key exist and depending on that set expiration time or not - but this operation is not atomic.
To answer the question - no, there isn't such a command.
As you noted, this could be worked around with EXISTS. To address the atomicity (and save on network) requirement you can use a Lua script (see EVAL).
Redis 7.0 has a new option "NX -- Set expiry only when the key has no expiry". So, you could solve the problem with EXPIRE KEY 100 NX.
However, that it doesn't matter if you call EXPIRE KEY 100 1 or, let's say, 5 times. The key will expire after 100 seconds, thus checking EXISTS key is also an option.
Need to clear a concept about redis EXPIRE operation.
Imagine I write the following code:
HMSET myself name "Sam" age "21"
EXPIRE myself 60
This sets the hash myself={'name':'Sam','age':'21'} (using python dictionary to illustrate the concept). Moreover, it sets myself to expire after 60 seconds.
What happens to the EXPIRE setting if I perform a couple of operations on myself? E.g.:
HINCRBY myself age 1
HSET myself gender f
Will EXPIRE remain intact, or will it be removed? And taking it a step further, do us redis coders have any control on whether EXPIRE stays or not in such cases?
Expire will remain, and the TTL will continue to decrease.
From Redis doc :
altering the field value of a hash with HSET (...) will leave the timeout untouched
As Maurice Meyer said above, you can use TTL myself to get the remaining Time To Live of the key mysef, and so use it for your experiments.
In Redis Cache, is it possible to retrieve the original TimeOut that was set on a key? I know that there is a way to retrieve the pending TimeToLive of any key but I want the original value that was set while creating the key.
No, Redis doesn't store the original TTL for keys. It would be interesting to understand the use case that requires this.
You could, however, use a Sorted Set to keep track of the initial TTLs. The idea is that after each call to EXPIRE, call ZADD on that set with the member being the key's name. The score should be a decimal, where the part before the decimal point is the expiration timestamp and the fractional part is the TTL (padded with 0s according to your max TTL).
To retrieve the initial TTL, call ZSCORE on the set with the key's name and extract the part after the decimal point.
Note that by taking this approach you'll have to do some housekeeping, namely removing expired members from the set. To do that, periodically call ZREMBYSCORE from -inf to the current timestamp.
How do I set expiry for hashmaps in Redis like I do for regular values using SETX.
I want to provide TTL for a session for which I am storing a hasmap.
Can I create a Hashmap using SETEX itself ?
No, you can't create hash with SETEX (which is a strings methods). You can call EXPIRE on hash key, but that will expire the whole hash. There's no support at the moment for expiration of individual hash key/value pairs.
Update:
If you wanted to set expiration on the whole hash while setting its individual elements, you can achieve that in several ways.
Use pipelining. Pipelining is a special mode of operation where redis client issues several commands in quick succession, not waiting for a reply to send next one. Here's an example in ruby:
redis.pipelined do
redis.hset "foo", "bar", 1
redis.expire "foo", 300
end
Use transactions. Without watched keys this is similar to pipelining (for a transaction can't abort). The commands are guaranteed to run together and atomically (several pipelines can run interleaved, transactions are serialized)
redis.multi do
redis.hset "foo", "bar", 1
redis.expire "foo", 300
end
Use lua scripting to implement your custom HSETEX command. It will be executed atomically and you just have to send one command (instead of 2(pipelining) or 4 (transaction)).