ROMP - The Ruby Object Message Proxy

(C) Copyright 2001 Paul Brannan (cout at rm-f.net)
ROMP is a set of classes for providing distributed object support to a
Ruby program.  You may distribute and/or modify it under the same terms as
Ruby (see http://www.ruby-lang.org/en/LICENSE.txt).  Example:

Client 
------
client = ROMP::Client.new('localhost', 4242)
obj = client.resolve("foo")
puts obj.foo("foo")
obj.oneway(:foo, "foo")

Server
------
class Foo
def foo(x); return x; end
end
obj = Foo.new
server = ROMP::Server.new('localhost', 4242)
server.bind(obj, "foo")
server.thread.join

You can do all sorts of cool things with ROMP, including passing blocks to
the functions, throwing exceptions and propogating them from server to
client, and more.  Unlike CORBA, where you must create an interface
definition and strictly adhere to it, ROMP uses marshalling, so you can
use almost any object with it.  But, alas, it is not as powerful as CORBA.

On a fast machine, you should expect around 7000 messages per second with
normal method calls, up to 10000 messages per second with oneway calls with
sync, and up to 40000 messages per second for oneway calls without sync.

The ROMP message format is broken into 3 components:
[ msg_type, obj_id, message ]
For each msg_type, there is a specific format to the message.  Additionally,
certain msg_types are only valid when being sent to the server, and others
are valid only when being sent back to the client.  Here is a summary:

msg_type         send to     meaning of obj_id       msg format
----------------------------------------------------------------------------
REQUEST          server      obj to talk to          [:method, *args]
REQUEST_BLOCK    server      obj to talk to          [:method, *args]
ONEWAY           server      obj to talk to          [:method, *args]
ONEWAY_SYNC      server      obj to talk to          [:method, *args] 
RETVAL           client      always 0                retval
EXCEPTION        client      always 0                $!
YIELD            client      always 0                [value, value, ...]
SYNC             either      0=request, 1=response   nil
NULL_MSG         either      always 0                n/a

BUGS:
- On a 2.2 kernel, oneway calls without sync is very slow.
- UDP support does not currently work.

Author: Paul Brannan
Version: 0.1


module ROMP


class Server < Object

The ROMP server class. Like its drb equivalent, this class spawns off a new thread which processes requests, allowing the server to do other things while it is doing processing for a distributed object. This means, though, that all objects used with ROMP must be thread-safe.

Methods

initialize(endpoint, acceptor=nil, debug=false)

endpointAn endpoint for the server to listen on; should be specified in URI notation.
acceptorA proc object that can accept or reject connections; it should take a Socket as an argument and returns true or false.
debugTurns on debugging messages if enabled.
Start a ROMP server.

create_reference(obj)

objThe object to register.
Returns: A new Object_Reference that should be returned to the client.

Register an object with the server. The object will be given an id of @next_id, and @next_id will be incremented. We could use the object's real id, but this is insecure. The supplied object must be thread-safe.

delete_reference(obj)

objThe object to unregister.
Find an object in linear time and unregister it. Be careful with this function, because the client may not know the object has gone away.

bind(obj, name)

objThe object to bind.
nameThe name of to bind the object to.
Register an object with the server and bind it to name.
This keeps the client from seeing our objects when they call inspect

Methods

inspect()


server_loop(session)

sessionThe session to run the loop with.
The server_loop function is the guts of the server. It takes in requests from the client and forwards them to already-registered objects.


class Client < Object

The ROMP client class. A ROMP server must be started on the given host and port before instantiating a ROMP client.

Methods

initialize(endpoint, sync=true)

endpointThe endpoint the server is listening on.
syncSpecifies whether to synchronize between threads; turn this off to get a 20% performance boost.
Connect to a ROMP server

resolve(object_name)

object_nameThe name of the object to resolve.
Returns: A Proxy_Object that can be used to make method calls on the object in the server.

Given a string, return a proxy object that will forward requests for an object on the server with that name.


class Null_Mutex < Object

In case the user does not want synchronization.

Methods

synchronize


lock


unlock



class Functions < Object

All the special functions we have to keep track of

Constants

GOOD
BAD
METHOD
RESPOND

class Object_Reference < Object

A ROMP::Object_Reference is created on the server side to represent an object in the system. It can be returned from a server object to a client object, at which point it is converted into a ROMP::Proxy_Object.

Methods

initialize(object_id)



class Proxy_Object < Object

A ROMP::Object acts as a proxy; it forwards most methods to the server for execution. When you make calls to a ROMP server, you will be making the calls through a Proxy_Object.

Methods

method_missing(function, *args)

The method_missing function is called for any method that is not defined on the client side. It will forward requests to the server for processing, and can iterate through a block, raise an exception, or return a value.

onweway(function, *args)

The oneway function is called to make a oneway call to the server without synchronization.

oneway_sync(function, *args)

The oneway_sync function is called to make a oneway call to the server with synchronization (the server will return a null message to the client before it begins processing). This is slightly safer than a normal oneway call, but it is slower (except on a linux 2.2 kernel; see the bug list above).

sync()

The sync function will synchronize with the server. It sends a sync request and waits for a response.

#{method}(*args)


#{method}(*args)


#{method}(*args)


#{method}(arg, *args)



class Resolve_Server < Object

The Resolve_Server class registers objects for the server. You will never have to use this class directly.

Methods

initialize


register(obj)


get_object(object_id)


unregister(obj)


bind(name, id)


resolve(name)


delete_obj_from_array_private(array, obj)



class Resolve_Obj < Object

The Resolve_Obj class handles resolve requests for the client. It is a special ROMP object with an object id of 0. You will never have to make calls on it directly, but will instead make calls on it through the Client object.

Methods

initialize(resolve_server)


resolve(name)



class Generic_Server < Object

A Generic_Server creates an endpoint to listen on, waits for connections, and accepts them when requested. It can operate on different kinds of connections. You will never have to use this object directly.

Methods

initialize(endpoint)


accept



class Generic_Client < Object

A Generic_Client connects to a Generic_Server on a given endpoint. You will never have to use this object directly.

Methods

self.new(endpoint)


self.print_exception(exc)

excThe exception object to print.
Print an exception to the screen. This is necessary, because Ruby does not give us access to its error_print function from within Ruby.


class Session < Object

The Sesssion class is defined in romp_helper.so. You should never have to use it directly.

Requires / Includes

socket
thread
fcntl
romp_helper