We have defined an Ibis-API, which can be implemented by an
Ibis-implementation. Every JVM may run multiple Ibis-implementations.
The user can specify the Ibis-implementation at startup. An
Ibis-implementation offers certain PortType properties. When creating
an Ibis-implementation, it can negotiate with the application to see
if it offers the required properties. When creating an
Ibis-implementation, a global unique name must be specified for it by
the application.
Communication
Communication is based on ReceivePorts and SendPorts of a certain
PortType. A PortType can be created using the Ibis.createPortType
method, where a name is given to the PortType (e.g. "satin porttype"
or "RMI porttype"). Port properties are given to the PortType (for
example ports are "totally-ordered" and "reliable" and support "NWS").
For each PortType there is a ReceivePort and a SendPort. Only
ReceivePorts and SendPorts of the same PortType can communicate. Any
number of ReceivePorts and SendPorts can be created on a JVM (even of
the same PortType).
SendPorts and ReceivePorts are created by their PortType using the
'createSendPort' and 'createReceivePort' methods.
When creating an ReceivePort it must be associated with an object. If
it is supplied by the user, the object must implement the
"handleMessage" interface. Upcalls are generated when messages arrive.
If it is not supplied by user explicit receive must be used to read
messages.
The system provides a globally unique ReceivePortIdentifier and
SendPortIdentifier for every RECEIVE and SendPort, these Identifiers
are implementation specific and serializable (and can be send over the
network/saved in a file etc.).
When a ReceivePort is created its ReceivePortIdentifier may be stored
in a registry. The application storing the ReceivePortIdentifier is
responsible for providing a globally unique name (key) that
identifies the ReceivePortIdentifier in the registry.
A SendPort takes the initiative to connect to or disconnect from
ReceivePorts (otherwise the one-way traffic scheme is violated).
A SendPort can be connected to one or more ReceivePorts using their
ReceivePortIdentifiers These ReceivePortIdentifiers may be obtained
using the registry, by sending them over the network, or any other
way. Additional ReceivePorts may be connected at any time.
A SendPort can be disconnected from one or more ReceivePorts using
their ReceivePortIdentifiers. Additional ReceivePorts may be
disconnected at any time
When a SendPort is no longer used it must be freed
using the 'free' method. All connections the SendPort has are
disconnected.
When a ReceivePort is no longer used it must be freed using the
'free' method. This call will block until
connections to SendPorts are disconnected (by the SendPorts).
A message can be send from an SendPort to the set of ReceivePorts it
is connected to. To do this, a Message is obtained from the SendPort
(this allows streaming, as the destination is known). Data can be
added to the message using "write" methods (this data may be
immediately streamed to the ReceivePorts). The Message can be send
using a 'send' method. After the send returns all data has been
copied (it now may be changed) and the Message may no longer be used.
When Message arrives at a ReceivePort, it depends on the associated
object how it is handled. If the object is provided by the user a
"new" thread is started (upcall), that runs Message handler on
object. When the Message is no longer used it MAY be returned to the
system using the 'free' method (after which the message may no longer
be used).
If no object is specified by the user, messages are delivered when the
"receive" method is called (explicit receipt). When the Message is
no longer used it MUST be returned to the system using the 'free'
method (after which the message may no longer be used). This is
done to free possible resources in the underlying implementation, as
waiting for the GC may take too long.
Ordering of Communication
Messages export a sequence number, which can be used to determine
their order. When a PortType specifies that the communication is not
ordered and explicit receipt is used, Message will be delivered in an
undefined order. When implicit receipt us used, more than one Message
may be delivered simultaneously with upcalls. When a PortType
specifies that the communication is uses some order and explicit
receipt is used, messages will be delivered in that order. When
implicit receipt is used, more than one Message may be delivered
simultaneously with upcalls, after which their sequence numbers can be
used to order them.
Adding and Removing Implementations
when an Ibis implementation is added to the pool, all other
implementations will receive an upcall, providing them with the
user-specified unique name of the new implementation. when an
Ibis-implementation wants to be removed from the pool, all other
implementations will receive an upcall, providing them with the
user-specified unique name of the implementation that wants to leave.
Rationale
With ReceivePorts and SendPorts we basically have a 'connection
oriented' message passing model, based on one-way connections (from
Sender to Receiver).
Why is this better then the TCP/IP model?
With our model we can support message passing (unicast and
multicast), and an RPC-style model (using two one-way connections).
TCP creates two-way connections and private channels, which is
inappropriate for multicast.
Why is it better then UDP or Panda?
Our model is connection oriented: when a message is created the
destination is known. This allows the implementation to stream data
to the destination, even while the message is being built (allowing
a better bandwidth and memory utilization, and flow control with
complex data structures).
Our model allows messages to be send to an object (instead of a
process). This is much better suited for the Java model (and SMP
machines).
Our model is less restrictive then Panda. An upcall is a real
thread. It is not restricted in any way. (multiple upcalls may
run simultaneously)
Our model does not have a closed world assumption. JVMs may be
added / removed during the computation.
In general:
Our model can be implemented efficiently, both on streams based
(TCP/IP) and message passing systems.
It allows the use of low-level optimizations such as hardware multicast
(or LFC).
It is flexible, because, using the Properties mechanism, it allows
the application to:
test if the implementation provides the desired primitives
select and configure the provided primitives at runtime
It is extensible, because, using the Properties mechanism, new functionality
can be exported by implementation, without changing the interface.