Crate mumble_server_runtime_shard

Crate mumble_server_runtime_shard 

Source
Expand description

A shard runtime: render once per shard, share the changes, not the views.

§The model in one page

The pipeline this crate replaces rendered the whole world as seen by one connection, once per connection. Everything else followed mechanically: N connections each holding an O(N) view means materializing every view costs Θ(N²), and no scheduler or cache fixes that, because it is in the type.

Here, a shard renders once. Each fact is held once, whoever ends up seeing it. What connections receive is the resulting delta, filtered:

  business state changes
       |  handle.wake()
       v
  render -> plan -> journal -> per-connection: filter, splice, collapse

A three-operation delta filtered N times costs O(N·|D|), not O(N·W). That property holds even when every view is different, which is what makes it robust rather than merely fast.

§Three independent mechanisms

Wanting to unify them is the mistake that breeds special cases.

mechanismshapewhat it solvescost
shared view + scopesa scope tree, one scope per element, a ScopeSet per observerparties, teams, spectators, staff - the 95%O(W) once + O(|D|) per connection
private overlaya few elements visible to one connectionvanish, private channel, per-observer placementO(|overlay|)
audio relationa directed relation per receiverall of the audioO(N + edges)

The rule that says which to use: a scope describes a group, an overlay describes an individual exception. A scope with one observer is an overlay in disguise. A role - player, host, spectator, staff - is a group by nature even when it has one member.

§The only coupling, and it is not ours

A receiver must see the sender.

The Mumble client discards audio whose sender session it does not know, so this is a protocol constraint rather than a design choice, and it is checked on the render’s output. A corollary worth stating: there is no separate “right to speak”. Speaking somewhere implies being visible there.

REF: docs/design/guide-implementation.md REF: references/mumble/src/mumble/ServerHandler.cpp : handleVoicePacket

Re-exports§

pub use build::BuildError;
pub use build::ChannelRef;
pub use build::MAX_ACTIONS;
pub use build::Narrow;
pub use build::PrivateBuilder;
pub use build::Rendered;
pub use build::ShardBuilder;
pub use build::UserRef;
pub use compose::collapse;
pub use compose::filter;
pub use compose::splice;
pub use emit::TextTarget;
pub use emit::action_key;
pub use emit::action_name;
pub use emit::actions;
pub use emit::denied_permission;
pub use emit::emit;
pub use emit::perm;
pub use emit::permission_query;
pub use emit::permissions_of;
pub use emit::relayed;
pub use emit::spoken;
pub use emit::user_stats;
pub use ids::ActionKey;
pub use ids::ChannelId;
pub use ids::ChannelKey;
pub use ids::ConnectionId;
pub use ids::Exhausted;
pub use ids::IdAllocator;
pub use ids::Occupant;
pub use ids::SessionId;
pub use ids::ShardId;
pub use ids::SharedIds;
pub use ids::SyntheticId;
pub use journal::Journal;
pub use journal::TooFarBehind;
pub use plan::ChannelPatch;
pub use plan::ElementId;
pub use plan::OverlayOps;
pub use plan::PlanOp;
pub use plan::PlannedOp;
pub use plan::UserPatch;
pub use plan::plan;
pub use plan::plan_elements;
pub use queue::MAX_DEPTH_FOR_VOICE;
pub use queue::OutboundQueue;
pub use queue::Refused;
pub use queue::VoiceAdmission;
pub use reply::Audience;
pub use reply::Effect;
pub use reply::Effects;
pub use reply::Reply;
pub use reply::Spoken;
pub use reply::Word;
pub use routing::AudioRelation;
pub use routing::AudioRouting;
pub use routing::DomainId;
pub use routing::Silence;
pub use routing::compile;
pub use scope::MAX_DEPTH;
pub use scope::MAX_OBSERVED;
pub use scope::Scope;
pub use scope::ScopeSet;
pub use scope::TooManyScopes;
pub use shard::ActionTarget;
pub use shard::AttachedConnection;
pub use shard::Handover;
pub use shard::MIN_INTERVAL;
pub use shard::ReconcileReport;
pub use shard::Shard;
pub use shard::ShardCommand;
pub use shard::ShardHandle;
pub use shard::ShardLogic;
pub use shard::VoiceEvent;
pub use shard::run;
pub use shard::spawn_parts;
pub use view::Action;
pub use view::Actions;
pub use view::Channel;
pub use view::On;
pub use view::Overlay;
pub use view::ShardView;
pub use view::User;
pub use view::UserFlags;

Modules§

build
The render builder: the only way a flavor produces a view.
compose
Composing one connection’s transition out of the shared delta.
emit
Translating a composed transition into Mumble control messages.
ids
Identifiers, and the allocator that keeps them stable.
journal
The shard’s delta journal.
plan
Planning a transition, with the scope as part of the element’s identity.
queue
One connection’s bounded output queue.
reply
What a flavor writes back while it observes an event.
routing
The audio relation, and the routing table compiled from it.
scope
Scopes: the shared-view visibility mechanism.
shard
The shard: one render, one journal, one task.
view
The rendered shard view, and the private overlays layered on top of it.