pub struct Wire<S> { /* private fields */ }Expand description
The engine: connections on one side, the command layer on the other.
One per thread, and it is two halves rather than one thing. The front is the
connections and everything they own, which never leaves the thread that
accepted them. Server is the databases, and every thread has a handle on
the same one. This type is where the two meet, and every method on it that is
not a one line delegation is a method that genuinely needs both: running a
command, answering a client that blocked, and forgetting a client that has
gone.
Implementations§
Source§impl<S: Sink> Wire<S>
impl<S: Sink> Wire<S>
Sourcepub fn with_server(server: Server, sink: S) -> Wire<S>
pub fn with_server(server: Server, sink: S) -> Wire<S>
An engine over a server the caller built, which is how a test gives it a clock it can move by hand.
Sourcepub fn over(server: Arc<Server>, sink: S) -> Wire<S>
pub fn over(server: Arc<Server>, sink: S) -> Wire<S>
An engine over a server that already exists, which is how the second thread and every thread after it gets one.
Each thread builds its own front and they never see each other’s. What they share is behind the handle, and the reason the handle is counted rather than borrowed is that the threads outlive whichever call started them by design: a scope that borrows would tie the server’s lifetime to a frame that is meant to return.
Another handle on the same server, for building the next thread’s engine.
Sourcepub fn server_mut(&mut self) -> &mut Server
pub fn server_mut(&mut self) -> &mut Server
The server, for the few settings that have to be made before it is serving.
That is the directory and the thread count, both of which are read everywhere and written once at startup, so they are settings and not state. This works while this engine holds the only handle, which is the case from the moment the server is built until the threads are started, and it is the caller’s job to do its setting up in that window.
§Panics
If a second handle already exists, because there is no honest answer to give: changing the directory under a thread that is already serving out of it is the bug this would otherwise hide.
Sourcepub fn set_limits(&mut self, limits: Limits)
pub fn set_limits(&mut self, limits: Limits)
Change the protocol limits, which is proto-max-bulk-len and friends.
Sourcepub fn hangup(&mut self, conn: ConnId)
pub fn hangup(&mut self, conn: ConnId)
The peer went away.
Whatever is buffered for it is dropped rather than written, and the slot comes back as soon as the commands already framed out of its buffer have run, because those commands’ arguments still point into it.
Sourcepub fn owed(&self) -> usize
pub fn owed(&self) -> usize
Connections with a reply that has not gone out yet.
Non zero means a socket was full and what is left is being held for a later flush, which a driver waiting on readability needs to know: there is work here that no incoming byte will ever wake it up for.
Sourcepub fn waiting(&self) -> usize
pub fn waiting(&self) -> usize
Clients of this thread’s that are blocked on a key.
The other thing a driver waiting on readability needs to know, and for
the same reason owed is: there is work here that no incoming byte will
wake it for. A blocked client is answered by a write another thread made
or by its own deadline passing, and neither of those is a byte arriving
on this thread’s poller, so a driver that reads this keeps its wait short
while anybody is waiting on it.
Sourcepub fn posted(&self) -> usize
pub fn posted(&self) -> usize
Mail waiting for this thread, plus subscribers of its own that mail could arrive for.
The third thing a driver waiting on readability needs to know, and for the reason the other two are: a published message is a write another thread made and no byte arriving here will wake this thread for it. So a thread that has a subscriber keeps its wait short, and one that has none is not affected.
Sourcepub fn stopping(&self) -> bool
pub fn stopping(&self) -> bool
Whether a client has asked the server to stop.
The driver reads this once a turn, next to the flag a signal sets, and
leaves its loop when either is set. Asked after the batch rather than
during it, so the SHUTDOWN and everything that shared its batch is
finished and written out before anything closes.
Sourcepub fn decoders(&self) -> usize
pub fn decoders(&self) -> usize
Decoders in the pool, which is the high water mark of one batch.
Sourcepub fn buffer_bytes(&self) -> usize
pub fn buffer_bytes(&self) -> usize
What every connection’s read and reply buffers are holding.
Sourcepub fn feed(&mut self, conn: ConnId, bytes: &[u8])
pub fn feed(&mut self, conn: ConnId, bytes: &[u8])
Take bytes off a connection and frame whatever commands they complete.
Anything left over stays in the connection’s buffer, half a command included, so the caller hands over whatever the socket gave it without looking at it.
Sourcepub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize
pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize
Move up to max framed commands into into.
The reactor wants a batch it owns, and the front keeps the buffers, so what crosses between them is this: numbers, no borrows.
Sourcepub fn tick(&mut self)
pub fn tick(&mut self)
Take a clock reading for the whole batch.
04 section 5: once per turn, never per command, so every command in a
batch compares against the same millisecond and two keys written
together expire together.
Sourcepub fn maintain(&mut self) -> Option<usize>
pub fn maintain(&mut self) -> Option<usize>
Do one batch’s worth of housekeeping.
Today that is one segment of arena compaction at most, which is what
stops a server that rewrites the same keys from holding every version of
them. It is separate from Wire::tick because the clock has to move
before a batch runs and this does not: it can wait until the replies are
out, and the driver decides when that is.
Per batch and not per turn of the loop. A turn can carry one command or a thousand, so a per turn call means the rate at which garbage is collected has nothing to do with the rate at which it is made, and on a saturated server the second one wins. That was measured: with this on the loop’s turn the server settled at seven segments for six segments’ worth of keys, which is where an unloaded process running the same writes settled at six.
Trait Implementations§
Source§impl<S: Sink> Engine for Wire<S>
impl<S: Sink> Engine for Wire<S>
Source§fn key_hash(&self, cmd: &Cmd) -> Option<u64>
fn key_hash(&self, cmd: &Cmd) -> Option<u64>
None when it touches none. Read moreSource§fn prefetch(&self, cmd: &Cmd, hash: u64)
fn prefetch(&self, cmd: &Cmd, hash: u64)
run is about to load for this work. Read moreAuto Trait Implementations§
impl<S> !RefUnwindSafe for Wire<S>
impl<S> !UnwindSafe for Wire<S>
impl<S> Freeze for Wire<S>where
Front<S>: Freeze,
impl<S> Send for Wire<S>where
Front<S>: Send,
impl<S> Sync for Wire<S>where
Front<S>: Sync,
impl<S> Unpin for Wire<S>where
Front<S>: Unpin,
impl<S> UnsafeUnpin for Wire<S>where
Front<S>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more