pub struct Conversation {
window: Window,
rendered: Rendered,
compaction_count: u32,
dropped: usize,
watermark: u64,
dirty: bool,
folding: bool,
forged: HashSet<String>,
occupant: Option<SessionId>,
live: bool,
scan: TurnScan,
dropped_thinking: i64,
}Expand description
One seat’s conversation: the messages, where its turns sit and how many times it has compacted.
All three come out of one read and one fold, so a page cut on the fold’s
boundaries and a record built from messages cannot disagree about where a
turn begins, and the count cannot describe a different conversation than
the one held.
Fields§
§window: Window§rendered: RenderedThe fold’s boundaries and task endings, which a page is cut on.
Nothing but those is held, because the transport draws nothing: a client folds the frames a page hands it, so the boundaries are what a page here is cut on and the endings are what its turns carry.
compaction_count: u32§dropped: usizeThe messages the cap has dropped off the front, ever.
A page cursor is measured against this rather than against the held list. A cursor names a message in the conversation’s own numbering, which a drop does not move, so a cursor that outlived one still names the message it meant - and one naming a message the drop has taken is answered with the floor rather than with whatever now sits at its old place in the list.
watermark: u64The newest frame number this copy reflects, which a reseed resets.
An answer’s number is taken from it, because a reseed lands before the fold’s reset mark and a pre-seal number would have the client skip the new run’s first frames (#2443).
dirty: boolThe messages moved since the fold last ran.
Memoized rather than made incremental, because making it
incremental means deciding where a turn begins from the appended
message alone - a second turn-boundary rule, which is the drift
turn_ranges’ own doc exists to prevent. One rule in one place, and
it runs when the messages changed rather than once per request.
And it never runs under this lock. The socket folds the core’s
stream in ONE task for every seat, so a fold holding a seat’s lock
stalls update delivery for every client on every seat.
Held::fold is where it runs instead.
folding: boolThe messages are out being folded, so what is here is half a state.
A reader must wait rather than look. A fold takes the messages out in O(1), renders them off the lock, and puts them back with the spans, so between those two the seat reads as no messages against the PREVIOUS fold’s boundaries, and a page sliced on those walks off the end of an empty list. Two requests on one seat is the ordinary case for that, not an exotic one.
forged: HashSet<String>The uuids of the delivery rows this transport forged.
A forged row is a frame no transcript has, and nothing about its
shape says so - it is a user row like the prompt it draws. Only the
site that forged it knows, which is why the set lives here rather than
in the row rule. Conversation::has_a_row is what reads it: a walk
below the window names this seat’s oldest row TO THE FILE, and naming
one the file never wrote answers the read nothing - which reads as the
end of the history.
occupant: Option<SessionId>The occupant this copy was last seeded for.
What tells a copy of the previous run from the current one. A seal is minted by the fanout and applied by the fold, and a read landing between the two would otherwise pair the new epoch’s count with the old run’s rows: a copy whose occupant is not the seat’s is no copy at all.
live: boolWhether the seat’s turn is in flight right now, folded off the frames
this copy has seen (liveness_of - the delivered rule: the model’s
own frames open a turn, its Result or error closes it).
The fold’s caller carries this, because the frame that would say it
directly (session_state_changed) is never sent: the fold reads it as
“the open turn the frames describe is live”, which is what keeps a
mid-call delivery from being cut off from a result that has not
streamed yet (#2379).
scan: TurnScanWhere the stream opens turns, folded over every frame this copy has seen rather than over the window: a cut moves the window’s front, not the rule that says which frame opens a turn.
dropped_thinking: i64The thinking growth a cut took out of the turn open at the window’s end, which the page serving that turn carries back into its first counter.
It never crosses a turn. A Result closes the turn it belonged to,
and a frame that opens a turn starts the next one with nothing carried.
Implementations§
Source§impl Conversation
impl Conversation
Sourcepub fn new(
messages: Vec<Message>,
compaction_count: u32,
carried: usize,
) -> Self
pub fn new( messages: Vec<Message>, compaction_count: u32, carried: usize, ) -> Self
A conversation from the history a connect or a resume carried.
It does not fold. The spans come from the next
Held::fold, which runs on a blocking task; folding here would run
an 18 ms render on whatever task built this, and that task is the
socket’s single stream folder.
carried is the floor history arrives with: the messages the read it
came from left behind a window that was taken before the history
crossed (see Conversation::seed), so a window handed over on its
own still tells the whole conversation’s numbering.
Sourcepub fn set_occupant(&mut self, occupant: Option<SessionId>)
pub fn set_occupant(&mut self, occupant: Option<SessionId>)
Say which occupant this copy is for.
Sourcepub fn set_watermark(&mut self, seq: u64)
pub fn set_watermark(&mut self, seq: u64)
Say how far this copy is current, which a reseed resets and an applied frame advances.
Sourcepub fn seed(
&mut self,
messages: Vec<Message>,
compaction_count: u32,
carried: usize,
)
pub fn seed( &mut self, messages: Vec<Message>, compaction_count: u32, carried: usize, )
Replace the whole conversation, which is what a connect, a resume or a
/new says: the history it carries is the truth about this seat.
It marks the fold rather than running it, for the reason
Conversation::new gives: this is reached from the stream fold, and
a render there stalls every seat rather than this one.
carried is the floor the history arrives with - the messages the read
it came from left behind a window taken before it crossed, which
Connected and SessionReplaced carry beside the history they hand
over (a resume’s read is windowed at the emit). Without it a seat
reseeded from a window reports the window’s own front as the
conversation’s, and a client’s walk below it stops there instead of
crossing into the transcript.
The numbering restarts, because a connect or a resume carries a transcript READ - a row subset, not this copy’s frame sequence - so an index carried over it would be off by however far the two diverge. A cursor from before resolves by its own number again and is answered from the floor when that number falls below the front the new window starts at.
Sourcepub fn append_forged(&mut self, message: Message)
pub fn append_forged(&mut self, message: Message)
One row this transport forged for display, which no transcript holds.
Forged rows are frames the file counts no row for, and nothing
about their shape says so - a delivery row is a user row like the
prompt it draws. So the seat keeps their ids, and Self::has_a_row
answers with them: a walk below the floor names the seat’s oldest row
to the file, and one the file never wrote answers nothing.
Sourcepub fn has_a_row(&self, message: &Message) -> bool
pub fn has_a_row(&self, message: &Message) -> bool
Whether a transcript row carries message: the kinds the row rule
reads, and nothing this transport forged for display.
The seat’s own answer, because half of it is the seat’s. The rule knows the kinds a file writes; only the seat knows which of its own rows it minted, and a forged row is a user row like the prompt it draws. A walk below the window needs both halves: naming the file a row it does not carry answers the read nothing, which a client draws as the end of the history.
fn push(&mut self, message: Message)
Sourcefn take_dirty(&mut self) -> Option<Window>
fn take_dirty(&mut self) -> Option<Window>
The messages if the fold is behind them, taken in O(1).
Sourcefn merge_fold(&mut self, folded: Window, rendered: Rendered, complete: bool)
fn merge_fold(&mut self, folded: Window, rendered: Rendered, complete: bool)
Put a fold back, with whatever arrived while it ran appended.
complete is false when the render did not reach its end, which is the
guard’s path: the messages are back but the boundaries installed with
them describe nothing.
pub fn messages(&self) -> &[Message]
pub fn rendered(&self) -> &Rendered
pub fn compaction_count(&self) -> u32
Sourcepub fn dropped(&self) -> usize
pub fn dropped(&self) -> usize
How many messages the cap has dropped off the front, which is what turns a held index into the one a page’s cursor carries.
Sourcepub fn dropped_thinking(&self) -> i64
pub fn dropped_thinking(&self) -> i64
The thinking growth a cut took out of the turn open at the window’s end, which a page of that turn carries back into its first counter.
Auto Trait Implementations§
impl Freeze for Conversation
impl RefUnwindSafe for Conversation
impl Send for Conversation
impl Sync for Conversation
impl Unpin for Conversation
impl UnsafeUnpin for Conversation
impl UnwindSafe for Conversation
Blanket Implementations§
§impl<T> AnySync for T
impl<T> AnySync for T
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
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