Skip to main content

Module keys

Module keys 

Source
Expand description

The keyspace itself: what is there, what type it is, and when it goes away.

Strings and Sets each hold the commands for one type. The commands here hold for all of them, because a deadline is not a string thing or a set thing. EXPIRE puts the moment in the key’s own record, so the same call works on a key holding a string, a set or a hash and costs the same on each.

use std::time::Duration;

let db = yo::open(yo::MEMORY)?;
let keys = db.keys();

db.set("online").add("alice")?;
keys.expire_in("online", Duration::from_secs(60))?;

assert_eq!(keys.kind("online")?, Some(yo::Kind::Set));
assert!(keys.ttl("online")?.left().is_some());

§What a deadline is not

It is not a property of the value. Giving a set a deadline rewrites five bytes of the key’s record and does not touch a single member, which is why Keys::expire_in on a set of a million members is the same call as on a set of one.

It is also not the same as the per field deadlines a hash can carry. Those are HEXPIRE and they live in the hash. A key can have a deadline while its fields have their own, and neither one knows about the other.

§The clock is only read when it matters

A database that has never been asked for a deadline never reads the clock on the data path, which Db::reads_the_clock reports. The first call here that creates one turns that on for good, so it is worth knowing that this is where the tens of nanoseconds come from.

§There is no touch

Redis has a TOUCH, and on a real server it counts the keys that are there and moves each of them up the eviction order. There is no eviction here, so all it could do is count, and Keys::count already does that. A second name for one call is worse than no second name, so the wire has TOUCH for the clients that send it and this does not.

§There is no cursor

The wire has SCAN because a server cannot stop and walk a keyspace for one client while every other client waits, so it hands out a number and does the walk in pieces. Nothing here is in that position. Keys::each holds the database for as long as it runs and nothing else can write to it in the meantime, so it is one walk, it sees one version of the keyspace, and there is no cursor to hold and no duplicate to filter out.

What that costs is that a walk of ten million keys is ten million calls before the next line of your program runs. That is the same trade KEYS makes and it is the right one here, because the thing on the other side of the call is your own code rather than a socket.

§The typed collections are somewhere else

A Map is a named collection and not a key in the keyspace, so it does not show up here and cannot be given a deadline. That is 15 section 3’s split and not an oversight: a map’s name is checked when it is opened, and a key’s name is whatever you pass.

Structs§

Keys
Every command that works on a key whatever the key holds.

Enums§

Ttl
What a key says about when it goes away.
When
Whether a deadline is allowed to move, which is EXPIRE’s NX, XX, GT and LT.