Skip to main content

Db

Struct Db 

Source
pub struct Db { /* private fields */ }
Expand description

One database.

Holds the keys a client sees under one SELECT, spread over one or more keyspaces. A caller that knows which key it wants asks Db::at and gets the one keyspace that key can be in. A caller that wants the whole database walks Db::stripes_mut, and the answers it adds up are the same answers a single keyspace would have given.

Implementations§

Source§

impl Db

Source

pub fn bitop<'k, I>(&self, op: Op, dest: &'k [u8], srcs: I) -> Result<usize>
where I: Iterator<Item = &'k [u8]> + Clone,

BITOP op dest src [src ...] over a database of any width.

Every key on one stripe is that one stripe’s BITOP, which is every BITOP on a database of one stripe and every BITOP whose keys were hash tagged into the same place. That path is the old one, byte for byte.

The rest is the same work with the reads spread out. Every stripe the command names is held for the whole of it, the sources are copied into a buffer this database owns rather than one a stripe owns, and they are combined there and written to whichever stripe the destination is on. Held together rather than one after the other, because an operand that was written to after it had been read would leave a result that no arrangement of these keys ever had.

§Panics

As Keyspace::bitop.

Source§

impl Db

Source

pub fn with_clock(clock: Clock, stripes: usize) -> Db

A database of stripes empty keyspaces on clock.

The count is rounded up to a power of two and clamped to MAX_STRIPES, and zero means one. Rounding rather than refusing because the number arrives from --threads and from available_parallelism, and neither of those has any reason to be a power of two, while a mask is the only stripe lookup worth having.

Source

pub fn new() -> Db

A database of one keyspace on the system clock, which is a database exactly as it was before there were stripes.

Source

pub fn width(&self) -> usize

How many stripes this database is cut into.

Source

pub fn stripe_of(&self, key: &[u8]) -> usize

Which stripe key lives on.

A function of the key and the width and nothing else, so the same key always answers the same stripe and a caller can work out where a key is without holding the database.

Source

pub fn stripe_of_hash(&self, hash: u64) -> usize

The same, for a caller that already has the hash.

The engine hashes the first key of every command before it runs it, to prefetch the record, so on the command path the hash is in hand already and hashing it again would be the second most expensive thing in a GET.

The hash must be Keyspace::hash_of of the key. Anything else picks the wrong stripe, and the wrong stripe is a key that cannot be found rather than an error, so this is not something to hand a number that came from somewhere else.

Source

pub fn at(&mut self, key: &[u8]) -> &mut Keyspace

The stripe key is on.

§Panics

Never. The mask cannot select a stripe that is not there.

Source

pub fn hold(&self, key: &[u8]) -> Held<'_, Keyspace>

The stripe key is on, held.

For a caller that has the database shared, which is every caller once there is more than one thread. The stripe is released when the answer is dropped, so a caller that wants it for the length of a command has to keep the answer for the length of the command rather than write it into the middle of a larger expression.

Source

pub fn at_hashed(&mut self, hash: u64) -> &mut Keyspace

The stripe a key with this hash is on.

As Db::stripe_of_hash for what the hash has to be.

Source

pub fn hold_hashed(&self, hash: u64) -> Held<'_, Keyspace>

The stripe a key with this hash is on, held.

As Db::stripe_of_hash for what the hash has to be.

Source

pub fn prefetch_hashed(&self, hash: u64)

Warm the line a key with this hash is going to be read from, if the stripe it is on is not busy.

What the prefetch stage uses, and the one place a lock is not worth waiting for. A prefetch is a hint about a command that has not started yet, so a stripe that somebody else is holding is a stripe whose lines are being pulled about anyway, and waiting for it would turn a hint into a wait for another thread. It is skipped instead.

Source

pub fn one_stripe<'k>( &self, keys: impl Iterator<Item = &'k [u8]>, ) -> Option<usize>

The one stripe every one of keys is on, or None when they are spread over more than one.

This is what a command that names several keys asks first. A database of one stripe always answers Some(0), so the old path stays the path, and a wide database answers it often enough to be worth asking: a client that hash tags its keys the way a cluster makes it does it so that its multi key commands land in one place, and this is that place.

Source

pub fn stripe_mut(&mut self, i: usize) -> &mut Keyspace

Stripe i.

§Panics

If i is not a stripe. Callers get their index from Db::stripe_of or from a walk over Db::width, so an index out of range here is a bug in the caller.

Source

pub fn hold_stripe(&self, i: usize) -> Held<'_, Keyspace>

Stripe i, held.

§Panics

As Db::stripe_mut, and also if the calling thread is already holding this stripe, in a debug build. Holding one twice is a wait for yourself and the lock says so rather than stopping.

Source

pub fn hold_many(&self, homes: impl Iterator<Item = usize>) -> Holds<'_>

Every stripe named, each one once, held, in stripe order.

The order is what makes this safe to call while another database is being held elsewhere and what makes two commands that want the same pair of stripes want them the same way round. The names are deduplicated because two keys of a multi key command land on one stripe often enough, and asking for a stripe twice is the mistake the lock panics about.

Source

pub fn hold_keys<'k>(&self, keys: impl Iterator<Item = &'k [u8]>) -> Holds<'_>

The same, for a command that has keys rather than stripe numbers.

Which is most of them: a multi key command is handed the names off the wire and works out where they live here. Two keys on one stripe hold it once, so MGET a a and MGET a b where both land in the same place are one hold and not two.

Source

pub fn stripes_mut(&mut self) -> impl Iterator<Item = &mut Keyspace>

Every stripe, in order, mutably.

Free, because an exclusive reference to the database is already an exclusive reference to every stripe in it.

Source

pub fn now_ms(&self) -> u64

What time every stripe here thinks it is.

One reading and not one per stripe. The clock is set on all of them together at the top of a turn of the loop, so a command that asks two stripes what the time is has to get the same answer from both or two keys written by the same command would expire at different moments. The reading is kept here as well as in the stripes so that asking the time does not mean taking one of them.

Source

pub fn len(&self) -> usize

How many keys are in the database.

One stripe at a time and never two at once, so this is a sum of counts that were each true when it was read rather than a count of the database at one moment. DBSIZE on a server that is being written to was already that answer.

Source

pub fn is_empty(&self) -> bool

Whether there are none.

Source

pub fn expires(&self) -> usize

How many of the keys have a deadline on them.

Source

pub fn clear(&self)

Throw the whole database away, which is what FLUSHDB does.

One stripe at a time, the same as every other walk here. A reader on another thread can see a database that is half thrown away, which is the same thing it can see of a FLUSHDB on any server that does not stop the world for one.

Source

pub fn set_clock_ms(&self, ms: u64)

Move every clock in the database to ms.

One store, because every stripe of a database and the database itself hold handles onto one reading rather than copies of it. It used to be a walk that wanted the database exclusively, which is a thing no thread could do while another was serving.

Source

pub fn swap_with(&self, other: &Db)

Trade this database’s contents with another’s, which is SWAPDB.

Stripe by stripe rather than by exchanging the two databases where they sit, because a caller holding a server shared has references out to the databases and those have to go on pointing at the database the client selected. What moves is what is in the stripes, which is a handful of words each whatever they are holding, so this is still O(1) in the number of keys and still the two pointer sized writes per stripe that make SWAPDB fast and dangerous at the same time.

The pair is held in address order and not in the order the client named them, so two clients swapping the same two databases in opposite directions take turns rather than each holding what the other is waiting for. Swapping a database with itself does nothing, which is the answer a real server gives too.

A reader on another thread can see one stripe swapped and the next one not, the same as it can see a half finished Db::clear.

Source

pub fn track_memory(&self, on: bool)

Turn the running memory total on or off in every stripe.

Source

pub fn scan( &self, from: KeyCursor, budget: usize, ty: Option<Kind>, out: impl FnMut(&[u8]), ) -> KeyCursor

A batch of keys and where the next batch starts, over the whole database.

This is SCAN, and it is one stripe at a time. The cursor carries the stripe it had got to as well as the place in that stripe, which is what the spare field in yo_index::Cursor is for.

The promise a single keyspace makes survives being made one stripe at a time, and it survives it for one reason: a key never changes stripe. So a key that is there for the whole walk is on a stripe this walk has not reached yet or on the one it is in the middle of, and either way it is still coming. Nothing a writer does while the walk is going can move a key from a stripe that is still to come to a stripe that is already done.

budget is spent per stripe rather than per call, so a call that finishes a stripe exactly on the budget stops there rather than starting the next one. What it will do is walk past any number of empty stripes, because a stripe with nothing in it is a walk of one segment and stopping to hand the client a cursor for it would be the more expensive of the two.

Source

pub fn keys(&self, out: impl FnMut(&[u8]))

Every key in the database, once each.

This is KEYS, and it is every key of every stripe. The order is the order the stripes are in and then whatever order each one walks in, which is no order at all as far as a client is concerned, the same as it was with one stripe.

Source

pub fn random_key(&self, f: impl FnOnce(&[u8])) -> bool

One key from anywhere in the database, or None if there are none.

This is RANDOMKEY. The stripe is drawn first, weighted by how many keys each one holds, so a database whose stripes came out uneven does not answer the small ones as often as the big ones. Then that stripe picks a key the way it always did.

A stripe can still answer nothing, because its count includes keys whose deadline has gone and which nothing has collected yet. The stripes after it are asked in turn when that happens, so an answer of None here means every stripe was asked and none of them had a live key.

The key is handed to f while its stripe is still held rather than answered, because the stripe it came out of is what it is borrowed from and letting go of that stripe is the end of the borrow. The caller writes it into a reply, which is not part of this database and is therefore still there afterwards. false means no stripe had one.

Source§

impl Db

Source

pub fn geosearchstore( &self, dest: &[u8], src: &[u8], from: Option<&[u8]>, shape: &Shape, limit: Limit, dist: bool, ) -> Result<usize>

GEOSEARCHSTORE and the two GEORADIUS store forms, when the source and the destination are not on the same stripe.

The search runs on the source’s stripe and leaves its hits in that stripe’s scratch, which is where they are read from while the result is built. The sorted set that comes out is put on the destination’s stripe under that stripe’s promotion thresholds, the same way every other store form works.

from is the member the centre comes from, for the forms that take it from one rather than from a pair of coordinates. It is read here, with the stripes already held, so that the centre and the members it is measured against are the same key at the same moment. A caller that read it beforehand would be handing in a point the member may have moved away from since.

§Errors

WRONGTYPE from the source, which is checked before the destination is touched, and the missing member complaint when from names a member the source does not have.

Source§

impl Db

Source

pub fn pfcount<'k, I>(&self, keys: I) -> Result<u64>
where I: Iterator<Item = &'k [u8]> + Clone,

PFCOUNT key [key ...] over a database of any width.

Every key on one stripe is that one stripe’s PFCOUNT, which is every PFCOUNT on a database of one stripe and every single key one wherever that key is. That matters more here than it does for the other multi key commands: one key is the form that answers out of the header cache without touching a register, and it stays that form.

Keys on several stripes are taken together, checked, and then merged into one set of registers. Together rather than one after the other, because a count over four keys is one answer about four keys and a key that was added to while the merge walked past it would make it an answer about no moment at all.

Source

pub fn pfmerge<'k, I>(&self, dest: &'k [u8], srcs: I) -> Result<()>
where I: Iterator<Item = &'k [u8]> + Clone,

PFMERGE dest [source ...] over a database of any width.

One stripe is the old path. Otherwise every stripe the command names is held for the whole of it and the checks run in the order a single keyspace runs them, the destination first and then the sources, so the sentence a client gets for a bad key is the sentence it would have got. Then every input is read and the destination is written, with no moment in the middle where a source could be added to after it was read.

Source§

impl Db

Source

pub fn lmove<F>( &self, src: &[u8], dst: &[u8], from: End, to: End, f: F, ) -> Result<bool>
where F: FnOnce(&[u8]),

LMOVE, and RPOPLPUSH with it, over a database of any width.

Two keys on one stripe is the whole command handed to that stripe, which is what a width one database always does and what makes LMOVE k k LEFT RIGHT a rotation here as much as it is there.

Two keys on two stripes is the same three steps with the element passing through this database’s own buffer rather than a stripe’s. The element has to be copied for the reason the one stripe version gives, that it has no structure to borrow from once it has moved, and the copy costs no allocation after the first call for the same reason too.

Source

pub fn lmovem<F>(&self, src: &[u8], dst: &[u8], b: Movem, f: F) -> Result<usize>
where F: FnMut(&[u8]),

LMOVEM src dst LEFT|RIGHT LEFT|RIGHT [COUNT|EXACTLY n OBO|BULK].

Db::lmove for a block of elements, and everything is taken out of the source before anything is put in the destination, which is what the one stripe version does and for the same reason: the destination is allowed to be the source.

The ordering the elements end up in is worked out by Keyspace::lmovem, and rather than write it out a second time this hands the block to that method on the destination’s stripe. The source stripe has already given the elements up by then, so what is left is a push into one stripe, which is a move whose source is not there.

Source§

impl Db

Source

pub fn smove( &self, source: &[u8], destination: &[u8], member: &[u8], ) -> Result<bool>

SMOVE source destination member over a database of any width.

The two keys on one stripe are that stripe’s SMOVE, which is the whole command on a database of one. Otherwise the member is taken out of one stripe and put into another, in the order the single stripe version moves it: the destination is filled before the source is emptied, and the source is only deleted once it is known to be empty.

The checks are in Redis’s order, which is not the order they look like they should be in. A source that is not there answers zero without ever looking at the destination, so a destination holding a string is not a WRONGTYPE until the source turns out to be a set.

Source

pub fn sinter<'k, F>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, f: F, ) -> Result<usize>
where F: FnMut(&[u8]),

SINTER key [key ...], and SINTERCARD’s limit.

Source

pub fn sintercard<'k>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, ) -> Result<usize>

SINTERCARD numkeys key [key ...] [LIMIT limit].

Source

pub fn sunion<'k, F>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, f: F, ) -> Result<usize>
where F: FnMut(&[u8]),

SUNION key [key ...], and SUNIONCARD’s limit.

Source

pub fn sunioncard<'k>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, ) -> Result<usize>

SUNIONCARD numkeys key [key ...] [LIMIT limit].

Source

pub fn sdiff<'k, F>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, f: F, ) -> Result<usize>
where F: FnMut(&[u8]),

SDIFF key [key ...], and SDIFFCARD’s limit.

Source

pub fn sdiffcard<'k>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, ) -> Result<usize>

SDIFFCARD numkeys key [key ...] [LIMIT limit].

Source

pub fn sinterstore<'k>( &self, destination: &'k [u8], keys: impl Iterator<Item = &'k [u8]> + Clone, ) -> Result<usize>

SINTERSTORE destination key [key ...]. Answers the size of the result.

The result is built whole before the destination is touched, exactly as it is on one stripe, which is what makes a destination that is also a source work. The limits and the slab the answer goes into are the destination’s stripe’s, since that is where the set is going to live.

Source

pub fn sunionstore<'k>( &self, destination: &'k [u8], keys: impl Iterator<Item = &'k [u8]> + Clone, ) -> Result<usize>

SUNIONSTORE destination key [key ...].

Source

pub fn sdiffstore<'k>( &self, destination: &'k [u8], keys: impl Iterator<Item = &'k [u8]> + Clone, ) -> Result<usize>

SDIFFSTORE destination key [key ...].

Source§

impl Db

Source

pub fn sort(&self, key: &[u8], opts: &Sort<'_>) -> Result<Vec<Option<Vec<u8>>>>

SORT key [BY pattern] [LIMIT offset count] [GET pattern ...] [ASC|DESC] [ALPHA], and the whole of SORT_RO.

One row per element that survived the LIMIT, or one row per GET pattern per element if there were any. A row is None where a GET pattern missed, which is a nil on the wire, and GET # never misses.

This allocates the elements, which nothing else on the read path does. It has to: the ordering is decided by reading other keys, and reading another key needs the database that the elements are borrowed from. Redis has the same problem and solves it by holding refcounted pointers, which is the same copy with the copy moved to whoever wrote the value. The copy is also what lets a BY or a GET reach a stripe other than the one the elements came from.

Source

pub fn sort_store( &self, key: &[u8], dest: &[u8], opts: &Sort<'_>, ) -> Result<usize>

SORT key ... STORE destination, which answers the length of the list it wrote.

An empty result deletes the destination rather than leaving an empty list behind, because a list is never empty and a key that holds one that is would be a key TYPE answers list for and LLEN answers zero for.

A GET pattern that missed stores an empty string, where the same miss sent to a client is a nil. There is no nil in a list, so this is the only thing it could be, and it is what Redis stores.

The destination is on its own stripe, which is not generally the stripe the elements came from, and it is held from the start alongside the rest rather than reached for once the sort is done, so that nothing can write into it between the read and the store.

Source§

impl Db

Source

pub fn zsetop<'k, F>( &self, op: Op, keys: impl Iterator<Item = &'k [u8]> + Clone, weights: &[f64], agg: Aggregate, f: F, ) -> Result<usize>
where F: FnMut(Member<'_>, f64),

ZUNION, ZINTER and ZDIFF over a database of any width.

The keys are asked whether they share a stripe before anything else, and when they do the whole command is handed to that stripe. A width one database always takes that path and so does a hash tagged group on a wide one, so only keys that are genuinely spread out pay for the two passes below.

Source

pub fn zsetop_store<'k>( &self, op: Op, destination: &'k [u8], keys: impl Iterator<Item = &'k [u8]> + Clone, weights: &[f64], agg: Aggregate, ) -> Result<usize>

ZUNIONSTORE, ZINTERSTORE and ZDIFFSTORE.

The destination is allowed to be one of the sources here too, and for the same reason: the whole result is built before the destination is touched, so no body is written over while it is still being read, whichever stripe it is on.

Source

pub fn zintercard<'k>( &self, keys: impl Iterator<Item = &'k [u8]> + Clone, limit: usize, ) -> Result<usize>

ZINTERCARD numkeys key [key ...] [LIMIT limit].

Source

pub fn zrangestore( &self, destination: &[u8], source: &[u8], q: &Query<'_>, ) -> Result<usize>

ZRANGESTORE destination source <the arguments of ZRANGE>.

Two keys and one window, so when they are on different stripes the window is walked out of the source’s stripe into a table of its own and the sorted set that comes of it is put on the destination’s. The source keeps its members either way, which is what makes the copy the right shape even when the two keys are the same key.

Trait Implementations§

Source§

impl Default for Db

Source§

fn default() -> Db

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !Freeze for Db

§

impl !RefUnwindSafe for Db

§

impl !UnwindSafe for Db

§

impl Send for Db

§

impl Sync for Db

§

impl Unpin for Db

§

impl UnsafeUnpin for Db

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.