|
The multiplex transport provider is, as of now, Ubik's default provider implementation.
The provider uses a multiplexed socket to receive incoming remote method calls (RMCs) based on
Ubik's command protocol, as well as (potentially) other types of requests - following
different protocols wired through the same socket. More clearly, this simply means: a
Ubik server running "on" this provider can handle Ubik RMCs as well as other types
of requests on the same socket.
Design
The above is made possible through an acceptor/connector scheme: a single socket
server (based on the java.net.ServerSocket class) will be
started on a given port. This transport uses a special ServerSocket
implementation to do so: the MultiplexServerSocket
class (see the Javadoc, the class' inner workings are exhaustively described). To make a long story short:
acceptor threads pick up incoming requests and add them to an internal queue; selector threads process the
incoming requests; each request is processed by one selector thread; multiple selectors can act on the
request queue concurrently. For its "current" request, a selector goes through an internal list of connectors
(instances of MultiplexSocketConnector),
determining with the help of an application-specified StreamSelector
which connector can handle the current request. If a connector is found, the request is dispatched to it; if not, it is handed over
to the built-in, default connector - which, in our case, is Ubik's.
In the case of its own request handling, this transport provider keeps a configurable number of server threads to process the
requests given to it by its connector. Server threads block on the connector until a request is available; when that occurs, the connector (which actually acts
in the context of the selector thread) wakes up a server thread and dispatches the request to it.
| What you've just read implies that you can implement your own connectors and register them with this transport provider.
This would permit you to receive requests on the same server (port) as Ubik's. |
The key to performance is to find the proper balance between acceptor, selector, and server threads; by default, the Mplex transport provider
has one acceptor thread, one selector thread, and five server threads. This might very well not be optimal, and you should not judge Ubik's performance by these
default settings. Typically, there should be more server threads than threads of the other types.
Usage
Exporting an Object
When you use the Hub's export(Object o)
or export(Object o, int port) methods, Ubik uses the Mplex provider to start a server on a dynamic port, or on the user-specified
port. From then on, the object that you export can potentially receive remote method calls
Configuration
As was mentioned, you can set (and it is suggested that you do so) the number of acceptor, selector and servers threads using the following system
properties - and prior to exporting any objects:
- ubik.rmi.transport.mplex.acceptor-threads
- ubik.rmi.transport.mplex.selector-threads
- ubik.rmi.transport.socket.max-threads
If you export an object using the hub's export(Object o, Properties props) and you target this provider,
you can specify the above-mentioned configuration properties as part of the given Properties argument; and you
must specify the "type" identifier of this provider, with the following property (also in the properties passed in):
- ubik.rmi.transport.mplex.acceptor-threads (the property's value must be: tcp/socket).
|
When you bind an object to Ubik's JNDI implementation, and that object is not a stub corresponding to an already exported object, the
JNDI implementation will export that object automatically, using this transport provider (since it is the default).
|
Multiplexing
As was explained, you can leverage a single Ubik server over multiple connectors. To do so, you need to:
- Implement a StreamSelector;
- call the createSocketConnector(StreamSelector) on this provider;
- the above method returns a MultiplexSocketConnector that you use to process incoming requests (this in fact allows
implementing a server on top of a connector...);
- since most server implementations are based on the java.net.ServerSocket class, a connector is not very handy to adapt
an existing server implementation to Ubik's multiplexing; therefore, we have adapted connectors to the ServerSocket
class, with a ServerSocketAdapter.
The code below illustrates the above steps:
import java.net.ServerSocket;
import org.sapia.ubik.net.mplex.ServerSocketAdapter;
import org.sapia.ubik.rmi.server.transport.TransportManager;
import org.sapia.ubik.rmi.server.transport.socket
.MultiplexSocketTransportProvider;
...
// export has already taken place...
MultiplexSocketTransportProvider provider =
(MultiplexSocketTransportProvider)TransportManager.getProviderFor(
MultiplexSocketTransportProvider.TRANSPORT_TYPE);
MultiplexSocketConnector connector =
provider.createSocketConnector(new MyStreamSelector());
ServerSocket socket = new ServerSocketAdapter(connector);
MyServer server = new MyServer(socket);
server.start();
...
|
|