5 Managing a Pool of Connections

A connection pool manages a number of client side communication interfaces (e.g. active sockets), and allows choosing which one of them to use for a communication transfer by means of a portableCommAddress. This abstracts away the need to establish connections: whenever a connection as specified is available in the pool, we use it. Otherwise, such a connection will implicitly be established and added to the pool. If this process runs out of resources associated with these connections (e.g. file handles), it is possible to ask the pool to close the least recently used connection.

The connections are subject to concurrency control, so they must be used in a take-it, use-it, give-it-back fashion. This is achieved by the pattern communication. The concurrency control is necessary to prevent the situation where two users of the pool both transmit messages to some other party on one given connection, and randomly divide the incoming messages on that connection between them, both believing to have the other party for themselves. Using the pattern communication, at most one user of the pool communicates on any given connection at any given point of time.

By now, the only variant of connection pool implemented is the binaryConnectionPool. Instances of binaryConnectionPool are used for managing a number of binary socket connections. Before usage, initialize it. The user of a binaryConnectionPool gives a specification of the receiver, the type of connection, the quality of service etc. in a portableCommAddress to a (specialization of) the control pattern communication. This is used as follows (where bcPool is an instance of binaryConnectionPool):

addr[] -> bcPool.communication
  (# (* Extend error callbacks here *)
  do
    (* Within this dopart: use 'sock' to communicate *)
    (* Do not bring references to sock outside *)
  #);
If you want to leave the dopart of a specialization of a communication, use a construction like leaving(# do leave L #) in stead of leave L. Otherwise some resources may be rendered inaccessible.

Whenever the pool establishes a new connection, the hook onNewConnection of communication is executed. In a extending of this hook, a reference to the newly established connection is available, and by assigning a co-routine to actor, the connection gets associated with this co-routine. This is used to handle incoming messages to connections in the pool, which are not the immediate response to an outgoing message transmitted in a usage of communication: have the co-routine sit around waiting for the incoming messages. To support such things, one must specialize binaryConnectionPool.

If the connection delivered as sock within a specialization of communication is to be taken away from the pool and used outside, execute removeSock and bring out a reference to sock. If it is known that the connection will not be useful anymore, execute removeSock and sock.close.

The operation markAsDead is used to tell the pool that it certainly cannot have a connection like the one entered. If a communication partner closes a connection (or perhaps terminates unexpectedly), and the other end of that connection is in a connection pool, it could happen that this connection is not chosen in any communication for some time. If a new connection is created, the operating system may then reuse the local connection identifier (file handle, in case of UNIX sockets), giving a totally different connection, which is then administrated by some new BETA socket object. Now two BETA socket objects will talk to the same OS level connection (file handle), but this means that the first object (in the pool) has silently been redirected to a new communication partner. Of course, this leads to strange errors.

So, whenever creating a BETA socket object OUTSIDE a connection pool, please tell it by means of markAsDead, that any connections in the pool with the same OS level identifier must have died silently and thus should be removed from the pool. Internally, the connection pool handles this automatically.

Please note that this problem is not specific for connection pools, for the process library, or even for BETA programs, for that matter. But it occurs mainly in the presence of complicated and very dynamic communication topologies, which are more likely to appear with connection pools. It would actually be best to carry out similar checks (using sameConnection) also when using only simple socket objects in an application.

removeSomeConnection will seek through all unused connections in the pool. An unused connection is a connection such that no instance of communication in any co-routine of this process currently refers to it with its sock attribute. From this set of unused connections, it chooses the least recently used (as reported by its usageTimestamp), closes it, and removes it from the pool. If all connections are currently in use, application specific actions must be taken to free some of them. The callback noConnectionsRemovable is executed in this situation. It does not terminate the application by default, so beware of the possible infinite retry loop if removeSomeConnection is used in response to resourceError, and no connections could actually be removed.

When done with a connectionPool, close it to close all of the connections contained within it.


Process Libraries - Reference Manual
© 1994-2002 Mjølner Informatics
[Modified: Friday October 20th 2000 at 14:22]