Skip to main content

Server

Struct Server 

Source
pub struct Server { /* private fields */ }
Expand description

The context shared by the classes and the devices of a server, which every class of it owns, and which reaches what owns them, its Core, weakly.

§Ownership

                 ┌───────────────────────────┐                                     ┌─────────────────┐
                 │        ServerHandle       │                                     │ DevProxy        │
                 └─────────────┬─────────────┘                                     └─────┬───────────┘
                               │                                                         │
                               │core                                                     │backend: BackendDev
                               │1                                                        │0..1
         ┌─────────────────────┴─────────────────────┐      1┌───────────────────┐       │
         │ Core                                      ├───────┤ dyn BackendServer │       │
         └─┬──────┬──┬───┬──────┬────┬─────┬─────────┘backend└─────────┬──────┬──┘       │
           │ name │  │   │ name │    │     ╎1                          │ name │          │
           ╰──┬───╯  │   ╰──┬───╯    │     ╎core                       ╰──┬───╯          │
              │      │      │  server│     ╎                              │              │
              │      │      │       1│     ╎                              │              │
              │      │      │    ┌───┴─────┴───────┐                      │              │
              │      │      │    │ Server          │                      │              │
              │      │      │    └───────────────┬─┘                      │              │
              │      │      │classes: AnyClass   │1                       │              │
              │      │      │0..1                │server                  │              │
              │      │ ┌────┴────────────────────┴───────┐                │              │
              │      │ │ Class<M>                        │                │              │
              │      │ └─────────────────────────┬───────┘                │              │
              │      │                           │1                       │              │
              │      │                           │class                   │              │
  devs: AnyDev│      │pending: AnyDev            │        devs: BackendDev│              │
          0..1│      │*                          │                    0..1│              │
        ┌─────┴──────┴───────────────────────────┴────────────────────────┴──────────────┴─────────┐
        │ Dev<M>                                                                                   │
        └─┬──────┬─┬──────┬──┬────────────┬─────────────┬─────────────────────┬───────────┬────────┘
          │ name │ │ name │  │            │             │                 0..1╎           ╎0..1
          ╰──┬───╯ ╰─┬────╯  │            │             │      dev: BackendDev╎           ╎dev: BackendDev
             │       │       │            │             │                     ╎           ╎
     commands│       │attrs  │state_attr  │status_attr  │                     ╎           ╎
         0..1│       │0..1   │1           │1            │                     ╎           ╎
 ┌───────────┴┐  ┌───┴───────┴────────────┴────────┐    │                     ╎           ╎
 │ Command<M> │  │ Attr<M>                         │    │                     ╎           ╎
 └────────────┘  └─────────────────────────────────┘    │local_handle     ╭───┴───╮ ╭─────┴──────╮
                                                        │0..1             │  itr  │ │ port, name │
                                                ┌───────┴────────┐     1┌─┴───────┴─┴────────────┴─┐
                                                │ LocalDevHandle ├╌╌╌╌╌╌┤      local registry      │
                                                └────────────────┘  keys└──────────────────────────┘

A solid line is an Arc, a dashed one a Weak. An end of a line has a multiplicity, and the name of the field holding it, only when the class at the other end reaches it: an end without one is not reached through that line. A field holding the other end as a trait object is written field: Trait. A rounded box is the key of a map of the class it hangs from, which holds at most one of the other end per key. LocalDevHandle holds the keys of the entries of its device, which it takes out of the registry when dropped, and a weak reference to the device, not drawn, which only tells its entries from those of a device registered since.

The backend is given each device as a dyn BackendDev, which is the DevImpl<M> wrapper of a Dev<M>. A DevProxy holds the backend it reaches its device through as a dyn BackendDev too, which is the device itself when it is served by this process and found in the registry, and a client of the protocol of the backend otherwise.

The commands and attributes of a device, kept in its mutable field, each hold their definition, not drawn, which is shared with the ClassDef of its class.

Every solid line points down from the handle: the only links going back up are the weak core field and those of the local registry. Dropping the handle stops the backend, and frees everything once nothing else holds the core, which a request running a Self::sync_async or a Self::stop_async does until it ends, see ServerHandle.

The local registry only ever holds devices weakly, so it never keeps one alive, while a client of this process holds the device it found for as long as it is connected to it, which refuses its requests once withdrawn, see Dev::is_withdrawn. A device is taken out of the registry, by dropping its LocalDevHandle, before it is removed from the backend, so that local clients stop finding it first.

Implementations§

Source§

impl Server

Source

pub fn name(&self) -> &str

The exe/inst name of that server, under which it is registered in the database.

Source

pub fn admin_dev_name(&self) -> &str

The name of the admin device of that server, dserver/exe/inst.

Source

pub fn database(&self) -> &DatabaseProxy

The database that server is registered in.

Source

pub fn backend(&self) -> Option<Arc<dyn BackendServer>>

The backend serving the devices of that server, None once it is not served anymore, see ServerHandle.

Source

pub fn add_class<M: Model>(&self, def: ClassDef<M>) -> Result<Arc<Class<M>>>

Register a new class in this server, from its definition.

Source

pub fn get_class<M: Model>(&self, name: &str) -> Option<Arc<Class<M>>>

Get a class of this server from its name, if it is one of that model.

Source

pub fn add_dev(&self, class: &str, name: &str) -> Result<()>

Add a device to this server, as an instance of the class of that name, which is how the devices listed by the database are added, the database giving the class of each by its name. See Class::add_dev for the typed form.

The device is only registered: it is initialized, served and exported by the next Self::sync_async.

Source

pub fn remove_dev(&self, name: &str) -> bool

Remove the device of that name from this server, giving back whether it had one.

Its name is free again right away, but the device itself is only unexported, no longer served and deleted by the next Self::sync_async. A device removed before any synchronization reached it is simply dropped.

Source

pub async fn sync_async(&self) -> Result<()>

Apply what was done to the devices of this server since the last synchronization: the devices removed are unexported, no longer served and deleted, then the devices added are initialized, served and exported, which is what makes them reachable.

The devices added are initialized one after the other, class by class in the order the classes were made, and in the order they were added within a class. A device whose initialization adds devices has them initialized by this same synchronization, which is how the admin device boots a server. Each device is then served and exported on its own, which is what a Tango server always tells the database.

A device whose initialization failed is still served and exported, in FAULT, so that a client can ask it what went wrong. A device that could not be served or exported is retried by the next synchronization, and the first such error is given back once every other device is done.

Synchronizations never interleave: one waits for the one running to be done, so that everything done before calling it is applied once it returns. This is also why an init function must never call it, since it would wait for itself.

Source

pub fn sync(&self) -> Result<()>

The blocking form of Self::sync_async, which must therefore never run on the executor of a backend, in an asynchronous handler in particular.

Source

pub fn class_names(&self) -> Vec<Arc<str>>

The names of every class of this server, in the order they were made, the admin one first.

Source

pub fn dev_names(&self) -> Vec<Arc<str>>

The names of every device of this server, class by class in the order of Self::class_names, and by name within a class.

Source

pub fn has_dev(&self, name: &str) -> bool

Whether this server has a device of that name.

Source

pub fn get_dev<M: Model>(&self, name: &str) -> Option<Arc<Dev<M>>>

Get a device of this server from its name, if its class is one of that model.

Source

pub async fn stop_async(&self) -> Result<()>

Stop this server, which is only ever done once: it is unexported as a whole, so that clients stop finding it, then its backend is stopped, the requests in flight still being answered, and its devices are deleted, see Self::wait for what waits for the backend to be through. No synchronization runs after this, the devices still waiting for one never being served.

The devices are deleted one after the other, the classes in the reverse of their order, the admin device last, each once the requests still running on it are through, see Dev::is_withdrawn: a request that never ends therefore keeps this from ever returning. This is also why a request handler must never call it, since it would wait for itself; the Kill command of the admin device stops its server from the pool instead.

The backend is stopped and the devices deleted even if the server could not be unexported, and the first error met is given back.

Source

pub fn stop(&self) -> Result<()>

The blocking form of Self::stop_async, which must therefore never run on the executor of a backend, in an asynchronous handler in particular.

Source

pub async fn wait_async(&self)

Wait for this server to be stopped, see Self::stop_async, which is what the thread running a server spends its life in: for its backend to be through with every request, and for its devices to be deleted. A server that is not served anymore, see ServerHandle, is not waited for.

The backend is waited for first, which is only through once stopped, see BackendServer::wait, then the stop itself, which deletes the devices under the lock of the synchronizations. This waits for every request in flight, and must therefore never be called from a request handler, which would wait for itself.

Source

pub fn wait(&self)

The blocking form of Self::wait_async, which must therefore never run on the executor of a backend, in an asynchronous handler in particular. See Self::wait_timeout for a wait that gives up.

Source

pub fn wait_timeout(&self, timeout: Duration) -> Result<()>

Wait for this server to be stopped, see Self::wait_async, giving up with ErrorKind::TimedOut if the backend is still answering requests once the timeout has run out, which a request that never ends makes it, or a server never stopped.

The timeout only bounds the backend: once it is through, the deletion of the devices is waited for, however long that takes.

Trait Implementations§

Source§

impl Debug for Server

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Server

§

impl !RefUnwindSafe for Server

§

impl !UnwindSafe for Server

§

impl Forget for Server

§

impl Send for Server

§

impl Sync for Server

§

impl Unpin for Server

§

impl UnsafeUnpin 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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> Model for T
where T: Send + Sync + 'static,

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, !>

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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more