Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can I set a value in redis from the redis server's current system time?

Tags:

redis

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.

like image 366
Andrew Arrow Avatar asked Jun 20 '13 23:06

Andrew Arrow


People also ask

Does Redis have timestamp?

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.

What is TTL in Redis?

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.

Does Redis allow duplicate keys?

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.

How big can a Redis value be?

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.


1 Answers

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.

like image 165
kgtk Avatar answered Sep 27 '22 21:09

kgtk