Skip to main content

Server

Struct Server 

Source
pub struct Server {
    pub stats: Stats,
    /* private fields */
}
Expand description

Everything a server holds.

One of these per shard thread, not one per process: the databases inside are not Sync and are reached by sending their thread a command. What makes this a server rather than a shard is that it is the whole of what a connection can address.

Fields§

§stats: Stats

The numbers the reactor keeps for INFO.

Implementations§

Source§

impl Server

Source

pub fn now_ms(&self) -> u64

The clock reading this batch is working against.

Source

pub const fn waiters(&self) -> &Waiters

Who is parked, for the engine and for INFO.

Source

pub const fn waiters_mut(&mut self) -> &mut Waiters

The same, for the engine, which is what binds and forgets them.

Source

pub fn serve_waiter(&mut self, at: usize, now: u64, out: &mut Out) -> bool

Try to answer the waiter at at, writing into the buffer the engine found for it, and say whether it is finished with.

The engine cannot reach the databases and this cannot reach the connections, so the two meet here: the caller hands in one connection’s reply buffer and gets back whether to unpark the client behind it.

§Panics

If at is not a waiter.

Source§

impl Server

Source

pub fn new() -> Server

A server with DATABASES empty databases on the system clock.

Source

pub fn with_clock(clock: Clock) -> Server

A server on a clock the caller moves by hand, for tests.

Source

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

One database, by index.

§Panics

If i is not a database. SELECT is the only way a client changes the index and it checks, so an index that is out of range here is a bug in the caller and not something a client can ask for.

Source

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

One database, by index, without taking it mutably.

What the prefetch stage needs. It runs for all 64 commands in a batch before any of them executes, so it cannot hold the mutable borrow run is about to want, and it does not need one: warming a cache line reads nothing and changes nothing.

§Panics

As Server::db.

Source

pub fn refresh_clock(&mut self)

Take a new clock reading and give it to every database.

Once per turn of the event loop, which is the only place time moves. A command asking what the time is gets the answer the whole batch got, so two keys written by the same batch expire together (04 section 3).

Source

pub fn set_clock_ms(&mut self, ms: u64)

Move every clock here to ms by hand, for tests about expiry.

A test cannot wait a hundred seconds and a test that waits a hundred milliseconds is a test that fails on a loaded machine, so time moves on request. The system clock underneath will overwrite this on the next Server::refresh_clock, which is why this is only useful in a test that drives commands directly rather than through the event loop.

Source

pub fn uptime_secs(&self) -> u64

Seconds since this server was built.

Source

pub fn memory_bytes(&self) -> usize

Bytes held by every database’s index and arena, plus the read and reply buffers of every connection.

The buffers are in here because they are real and because Redis counts its own, so leaving them out would make the one number people compare flattering rather than true. They are not a database, so nothing in the keyspace can change them and the engine has to say when they move.

Source

pub fn dataset_bytes(&self) -> usize

What the keyspace itself is holding, live records only.

used_memory minus this is what the store costs to run: the index, the space dead records are sitting in until compaction gets to them, and the connections’ buffers.

Source

pub fn arena_bytes(&self) -> usize

Bytes the arenas are holding, live and dead together.

Source

pub fn index_bytes(&self) -> usize

Bytes the indexes are holding.

Source

pub fn segment_count(&self) -> usize

Arena segments whose pages are real, across every database.

Source

pub const fn conn_bytes(&self) -> usize

What the connections’ read and reply buffers are holding.

Source

pub fn note_conn_bytes(&mut self, delta: isize)

Note that the connections are holding delta bytes more than they were, or fewer when it is negative.

A delta and not a total because the alternative is a walk over every connection, and the walk would have to happen on a turn of the loop rather than when INFO asks, which puts the cost of a report on the command path of a server nobody is asking.

Source

pub fn expired_keys(&self) -> u64

Keys reclaimed by running into them after their deadline.

Source

pub fn evicted_keys(&self) -> u64

Keys thrown away to make room, which is the other number entirely.

Source

pub const fn maxmemory(&self) -> u64

The maxmemory limit in bytes, zero when there is not one.

Source

pub fn set_maxmemory(&mut self, bytes: u64)

Set the limit, and take a reading straight away.

The reading is here rather than left to the next maintenance turn because a client that sets the limit and sends a write in the same batch expects the write to be judged against the limit it just set, and because the cached number is meaningless until the first time there is a limit to compare it with.

Turning the limit on also turns on the running total every slab keeps of what its collections hold, and turning it off turns that back off, so a server with no limit is not paying to count something nobody reads. The first reading after switching it on is the walk that the total starts from, and it is the only walk.

Source

pub fn refresh_memory(&mut self)

Take a fresh memory reading, which the maintenance turn does once a batch.

Nothing at all when there is no limit, which is the default and is every server that has not asked for one.

Source

pub fn make_room(&mut self) -> bool

Make room under the maxmemory limit, throwing keys away if that is what it takes. Answers whether there is anything left it could throw away.

Redis runs the same thing from processCommand before every command and so does this: a client that writes has to be judged at the moment it writes, not a batch later, or the limit is a suggestion.

Three things happen in the loop and all three are needed. Eviction picks a key and drops it. Compaction gives the pages back, because dropping a key marks its record dead and returns nothing on its own, so a loop that only evicted would throw the whole keyspace away and watch the number stay where it was. The reading is taken again each time round, because the two of them together are the only thing that moves it.

§Why running out of budget is not a no

false means there was nothing left to evict, which is noeviction, or a volatile policy on a database where nothing has a deadline, or a keyspace that is already empty. It does not mean the server is still over its limit, and that difference is Redis’s: performEvictions answers EVICT_FAIL only when it has run out of things to delete, and processCommand refuses the client on that and on nothing else. Running out of time part way through a job it is doing well comes back as EVICT_RUNNING and the command goes through, because a server that is evicting steadily and refusing every write while it does it is worse for the client than a little overshoot.

§What the limit is worth

Space comes back a segment at a time and a segment is two megabytes, so this holds a server to its limit give or take a segment. A maxmemory of a few hundred megabytes gets what it asked for. A maxmemory of four megabytes is asking for a precision this store does not have.

Source

pub fn compact_step(&mut self) -> Option<usize>

Give one database’s dead space back, if any database has enough of it to be worth the move. None when no database had a candidate.

Once per batch, next to the clock. Overwriting a key writes a new record and counts the old one dead, so without this a server holds everything it has ever written: 400000 sets over 100000 keys measured at 742 bytes a key against Redis at 144 for the same load, and the whole difference was dead records nothing ever came back for.

At most one segment moves per call and the search starts one database further along each time, so the cost of asking is a comparison per database and the cost of acting is bounded by a segment.

Trait Implementations§

Source§

impl Default for Server

Source§

fn default() -> Server

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

Auto Trait Implementations§

§

impl !RefUnwindSafe for Server

§

impl !Send for Server

§

impl !Sync for Server

§

impl Freeze for Server

§

impl Unpin for Server

§

impl UnsafeUnpin for Server

§

impl UnwindSafe for Server

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, <T as TryFrom<U>>::Error>

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.