struct SessionShaper {
plane: Option<Arc<ControlPlane>>,
classes: Vec<String>,
current: Mutex<CachedShaper>,
}Expand description
One session’s shaper, and the proxy profile it watches.
A session builds a Scheduler from the profile it was configured with
and shares it through the whole forwarding scope. That much has not
changed. What this adds is a place to notice that the proxy has been
given a different profile while the session runs, and a rule about when
the session is allowed to act on it.
§The swap happens between streams, never inside one
Self::current is read once per forwarded stream, and the
Arc<Scheduler> it hands back is what that stream classifies with, queues
under and paces against for the whole of its life. A stream that is
already forwarding keeps the scheduler it started with even after the
profile has moved on.
That is forced rather than chosen. A Class is an index into a
scheduler’s class list, and a stream’s egress queue holds the scheduler
its units were admitted under. Swapping mid-stream would classify a unit
against one profile’s rules and release it against another profile’s
buckets and demand rows — charging a class that is not the one that was
matched, or, where the new list is shorter, a class that does not exist.
Reading it per stream costs one Mutex acquisition where a PendingQueue
is already being built.
§A profile with a different class list is not taken up at all
The session’s ShapeRecorder has one row per configured class,
pre-sized when the session is constructed and never resized, and a class
is charged to its row by position. A profile whose class list differs
from the one those rows were named after would therefore keep every
number correct and make every label on it wrong. So a live profile is
taken up only when its class names match, in order, the ones this session
started with; otherwise the session keeps its own until it ends. Changing
the class list of a running session is done by ending it.
Fields§
§plane: Option<Arc<ControlPlane>>The proxy this session belongs to, or None for a session driven
directly rather than through an accept loop — which has no proxy, so
no profile can be installed on it and this never looks.
classes: Vec<String>The class names this session’s statistics rows were pre-sized from, and the test a live profile has to pass to be taken up.
current: Mutex<CachedShaper>The scheduler in force, and the profile generation it was built at.
Implementations§
Source§impl SessionShaper
impl SessionShaper
Sourcefn new(profile: ShapeProfile, plane: Option<Arc<ControlPlane>>) -> Self
fn new(profile: ShapeProfile, plane: Option<Arc<ControlPlane>>) -> Self
Build the shaper for a session configured with profile.
profile is what the session’s statistics rows were pre-sized from,
so its class list is the one every later swap is measured against. A
profile installed on the proxy between the session’s configuration
being copied and this call is taken up here, under the same rule a
later one would be — that window is short, but a session that ignored
it would run on a profile the proxy had already replaced with no way
to notice.
Sourcefn current(&self) -> Arc<Scheduler> ⓘ
fn current(&self) -> Arc<Scheduler> ⓘ
The scheduler the next stream should run under.
Takes up a profile installed since the last call when its class list matches; otherwise hands back what this session already had. Either way the generation is recorded, so a profile this session declined is not re-examined once per stream for the rest of the run — and a later profile that does match is still taken up, because the comparison is always against the class list the session started with.