that is, I'd like to append to a sorted-set something like:
"set1" -> [1371772258, 1371772265, 1371772299, etc.]
but I don't want to send in the time values from my server. I want to get a consistant timestamp from one server's clock, the server redis is running on.
The TIME command returns the current server time as a two items lists: a Unix timestamp and the amount of microseconds already elapsed in the current second. Basically the interface is very similar to the one of the gettimeofday system call.
Redis TTL command is used to get the remaining time of key expiry in seconds. Returns the remaining time to live of a key that has a timeout. This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset. Syntax: TTL KEY_NAME.
Redis expires allow keys to have a limited time to live (TTL). Such a feature depends on the ability of an instance to count the time, however Redis replicas correctly replicate keys with expires, even when such keys are altered using Lua scripts.
All string values are limited to 512 MiB. This is the size limit you probably care most about. EDIT: Because keys in Redis are strings, the maximum key size is 512 MiB. The maximum number of keys is 2^32 - 1 = 4,294,967,295.
This solution works since Redis version 2.6.0
There could be easy solution if Redis provide Lua os.time
function, but it doesn't.
So I've invented some hack. We can set EXPIREAT
in future, and then with TTL
we will know current unix timestamp.
Here is proof of concept. Of course you can do at least 2 optimizations: set future
key once in your redis database and then just read its ttl in lua script, and obviously use evalsha
instead of eval
.
zaddts.lua
local future_ts, cur_ts, zkey, zmember
future_ts = 2000000000
redis.call('setnx', 'future', 1)
redis.call('expireat', 'future', future_ts)
cur_ts = future_ts - redis.call('ttl', 'future')
zkey = KEYS[1]
zmember = KEYS[2]
return redis.call('zadd', zkey, cur_ts, zmember)
Example of oneliner with hardcoded timestamp:
return redis.call('zadd', KEYS[1], 2000000000 - redis.call('ttl', 'future'), KEYS[2])
example-client.php
<?php
ini_set('display_errors', true);
$r = new Redis();
$r->connect('localhost');
$script = file_get_contents('zaddts.lua');
$r->eval($script, array('events', 'event1'), 2);
sleep(1);
$r->eval($script, array('events', 'event2'), 2);
print_r($r->zrange('events', 0, -1, $withscore = true));
/* Output:
Array
(
[event1] => 1371777755
[event2] => 1371777756
)
*/
UPD: [facepalm] I didn't see TIME
command. With it lua script became much simpler:
zaddts.lua
local time_full, time_sec, zkey, zmember
zkey = KEYS[1]
zmember = KEYS[2]
time_full = redis.call('time')
time_sec = tonumber(time_full[1])
return redis.call('zadd', zkey, time_sec, zmember)
UPD 2: Code with time
call doesn't work due to the redis lua scripting restrictions (Scripts as pure functions):
redis 127.0.0.1:6379> eval "return redis.call('zadd', 'events', redis.call('time')[1], 'some-event')" 0
(error) ERR Error running script (call to f_426eeadf424497fc04eb8f06efac0553f3212660): Write commands not allowed after non deterministic commands
So first version of code (with ttl
) still makes sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With