|
YAMI Home
Concept
Specification
Implementation
What next?
Questions & Answers
Comments
|
Implementation
[Downloads] [Internal model] [Connection modes] [Performance]
This page contains an explanation of the YAMI Agent
internal structure.
All the information here is valid for the YAMI C (and C++) library and
(by inclusion) for libraries available for other languages (with
appropriate limitations).
Note, that YAMI does not mandate any internal structure, only
communication protocol is defined (see Specification).
If any other YAMI implementation will be developed and published, this
page will be restructured.
[Static structure] [Dynamic model]
Static structure
The figure below presents the Agent's static structure:
The Agent manages internally four kinds of control
objects (each control object is active):
- Sender. There is one Sender in the Agent. Its
responsibility is to manage all the outgoing network traffic, which
covers message sending, replying to incoming messages and sending out
all controlling packets and notifications. The Sender uses a connection
pool for best performance where the number of remote domains (to which
the Sender sends packets) is small. Also, the Sender uses the Agent's
internal address book to resolve domain names to network addresses and
IP port numbers.
- Receiver. There is one Receiver in the Agent.
It is supposed to manage all the incoming network traffic. In essence,
the Receiver has one listening socket (the IP port for the listening
socket is given when the Agent is constructed), but each accepted
connection is added to the connection pool (up to some limited number
of connections). The Receiver can accept two kinds of packets: the
incoming messages - they are queued for appropriate registered object,
and the replies, rejections and other control packets that are received
concerning the messages sent out earlier - these packets are
appropriately converted into the status of the message.
- Waker. There is one Waker in the Agent. Its
responsibility is to wake (set their status) the messages sent
out previously, if the user wishes so. The purpose for this
functionality is to help the client code recover from the situation
when there is no reply for the outgoing message and the client decided
to wait for some change in the message's status. The Waker works with
resolution of approximately 1s.
- Dispatcher. There can be many Dispatchers in
the Agent. For those objects that were registered as passive, the
Dispatcher takes each incoming message and calls the external (external
to the Agent) servant, with the incoming message as the parameter. The
presence of Dispatcher allows to develop servers that are driven by
messages coming from clients.
The figure above shows also entity objects managed internally by the
Agent, which are (the address book already described):
- Registered Object. The Receiver accepts
incoming messages only for properly registered objects. If there is
none, then the Agent does not accept any incoming messages. It is
possible to register the object as passive, in which case the Agent
delivers its incoming message to the client code.
- IncomingMsg. Each incoming message is stored
in the queue for one of the registered objects.
- Message. This represents all the resources
managed for the needs of message sent to some remote domain. Note, that
the Message is not linked to any registered objects, which
means that there is no need to register any object in order to sent out
some message.
The IncomingMsg and Message are internal resources that
are accesible to the client code via handles. The client code is
responsible for their lifetime management, which means that the
resources should be released by the client code, otherwise the resource
leak may occur. Note, that even while the resource management is
automatic for C++ or Python client code, it is still external to the
Agent.
Dynamic model
The following sections describe the Agent's behavior in
different Use Cases.
[Send New Message]
[Receive Message]
[Reply]
[Receive Response]
[Time Out]
[Dispatch]
Send New Message
When the client code asks the Agent to send a new message, the Agent
creates the new message entity object (allocates all the resources and
so on), posts the request to the Sender and returns the message handle
to the client. Note, that the Sender performs its actions
asynchronously and the client does not have to wait (although it can)
for the message to be actually sent or replied to.
The SendManager object is not depicted on the static model, since its
only role is to provide ordering for all the actions required to send a
message.
[up]
Receive Message
When the network module accepts new connection or discovers new packet
on any connection in the pool, it reads the packet and hands it to the
Receiver. If the packet is of type message, the Receiver tries
to locate a registered object with appropriate name. If it finds one,
it stores the message in the queue associated with the registered
object. Otherwise (there is no such object) the unknown object
notification is sent back to the remote Agent.
Similar notification mechanism is used when the Receiver discovers that
the new message would overflow the queue set up for the registered
object or when the parameter set has Level 2 and the local Agent is of
Level 1 (but this indicates that the local Agent is badly registered at
the remote site).
[up]
Reply
The Reply collaboration shows that it is asynchronous action, too. The
client code gives to the Sender all the necessary information
(including parameter set, if any) and immediately returns. The Sender
is responsible for delivering the response.
[up]
Receive Response
When the network packet arrives that was sent as a response (or
rejection) to the message sent previously, the Receiver just updates
the status of the Message object. In case of response, the parameter
set (if any) is also stored with the Message object.
[up]
Time Out
If the client code wishes to wait until the response arrives for some
message, it can subscribe the Message object to the Waker module. When
the specified time out expires, the Waker module notifies the Message
object so that the client code waiting for any change in the message's
status can proceed. Usually client code decides to perform some
recovery action if it discovers that after waiting the status is timed
out.
[up]
Dispatch
The Dispatcher module (there can be many of them) repeatedly asks
objects registered as passive for any new incoming message and upcalls
the appropriate servant (the one that was provided when the passive
object was registered) provided by the client code (the upcall is
performed through the PassiveObject interface, which is
implemented by the servant).
The diagram above shows only one Dispatcher module collaborating with
one registered object, but this collaboration is in fact much wider:
one Dispatcher is not assigned to any of the passive objects and it can
dispatch messages for any object registered. Also, when more than one
Dispatcher is involved, a couple of messages (even for the same passive
object, if there are many waiting in the same queue) can be upcalled at
the same time.
[up]
|