Previous | Table of Contents | Next |
Processing of a time-independent invocation involves a series of roles played by various components of the distributed system.
These roles include:
• the invoking client
• an initial request router
• intermediate request routers
• a target router
• the target object
• intermediate reply routers
• a final reply router
• the response-receiving client.
Not all of these distinct roles are necessarily involved in every invocation, and more than one role can be played by the
same component of the distributed system. A router implementation is likely to be able to serve any of the router roles, and
may even serve multiple roles for the same invocation, such as when the initial request router also serves as the target router
with no intermediate request routers involved.
Routers can be collocated with client or server ORBs, or can be separate processes. Either way, routers must maintain persistent
state with transactional semantics.
22.14.3.1 Invoking Client
The client application makes an asynchronous invocation either by specifying a ReplyHandler object or by using the polling
API.
Depending on QoS requirements, the client ORB may try to synchronously invoke the operation on the target object, using IIOP
or some other synchronous protocol. This attempt will not be made if the client is part of an active transaction and the target
has a TransactionPolicy of Requires_unshared.
If the target is unreachable via a synchronous protocol, the client ORB tries to find an initial router to use. If the target
IOR has a TAG_MESSAGE_ROUTERS component, its list of routers may be tried, starting from the one closest to the target, which
is the last in the list. If none of these are reachable, or there is no TAG_MESSAGE_ROUTERS component, then the client ORB’s
default router closest to the target may be chosen. The order in which the client ORB attempts to contact an initial router
is not mandated by this specification. The client ORB may choose to send the request to any Router (such as its own closest
Router in all cases) according to implementation-specific configuration. If the client application used the polling interface
and a quality of service requiring the request to be persistent, the client ORB attempts to narrow the initial request router
to a PersistentRequestRouter, and if this fails, a different router must be selected. If no router can be found meeting the
required quality of service, the system exception CORBA::INV_POLICY is raised.
Once an initial request router is identified, the client ORB delivers the request to it by invoking send_request if a ReplyHandler
was specified, or create_persistent_request if the polling API and persistent QoS was used. The client application’s active
transaction context, if any, is used for this invocation. Only service context information that is meaningful to the target
in a time-independent invocation, such as CodeSets (but not TransactionContext), is included in the RequestMessage argument
to send_request. Future ORB service specifications must state whether their service contexts are to be considered end-to-end
(and therefore included within the RequestMessage) or are only for a single hop (and therefore used by the ORB when invoking
the initial router but not included with the RequestMessage).
An empty sequence is passed by the client ORB as the visited parameter. The list of routers from the target IOR’s TAG_MESSAGE_ROUTERS
component is used as the to_visit parameter. This list may have additional routers added to it by the client ORB depending
on administration of the network of routers. If the callback model is being used, the type-specific ReplyHandler is passed
as the reply_destination. If the request was originated using create_persistent_request, the untyped ReplyHandler is passed
as the reply_destination. For the reply to be able to be delivered asynchronously, these ReplyHandler IORs must contain enough
routing information (e.g., TAG_MESSAGE_ROUTERS component).
22.14.3.2 Initial Request Router
The initial request router’s role depends on whether the ReplyHandler or polling API was used by the client.
If the client ORB passed the request message, along with a ReplyHandler reference, to the initial router using the send_request
operation, the initial request router saves the request message to stable storage within the client application’s transaction
context, and then processes the request using the request routing algorithm described below.
If create_persistent_request was called, the initial request router must instantiate a PersistentRequest object and return
its reference to the client ORB, which will return it to the client application. Until the response for the request is delivered
to the client, or the request times out, such an initial request router must keep an association between the identity of this
PersistentRequest object and the state of the request. When routing the request (as described below), this first router passes
a reply_destination, which is an UntypedReplyHandler implemented by the first router itself. This UntypedReplyHandler may
be created either before or after the PersistentRequest and request state is committed to stable storage. After returning
the PersistentRequest object and committing the request state to stable storage, all within the transaction context of the
client application, the initial router processes the request using the routing algorithm described below. The routing process
does not continue until the client’s initial transaction has been committed.
22.14.3.3 Request Routing Algorithm
Any router that has received a request message and committed it to stable storage processes it in the same way. If it can
invoke the operation directly on the target object, the router serves as the target router for the invocation, as described
below. If not, it tries to deliver the request to another router closer to the target object. If it can’t do either of these,
it queues the request and tries again later, either after some period of time has elapsed, or in response to an announcement
of availability from another router
closer to the target as described in Section 22.15, “Router Administration,? on
page 22-58.
A router typically picks another router closer to the target by selecting from the list of routers passed to it as the to_visit
parameter to either send_request or create_persistent_request. Routers later in the list are given preference as being closer
to synchronous connection with the target. The next router can also be selected from some set of known Routers based on an
implementation-specific configuration. If QoS attributes of the request message require persistence of requests, a transaction
is first initiated. Then send_request is called on the selected router. The to_visit parameter is formed by removing the callee
from the to_visit list received with the original request. Any routers further from the target than the callee (earlier in
the to_visit list) are also removed. The target, reply_destination, selected_qos, and message parameters are copied from the
received request. After invoking send_request, the router removes the request message from its stable storage, and commits
the transaction if it initiated one.
A router must ensure that exactly-once semantics are preserved. If delivering a request message results in an exception with
a CompletionStatus of COMPLETED_NO, or in a transaction being aborted, it can retry. Since any invocation can raise a system
exception, all exception replies with a completion status other than COMPLETED_NO must be reported back to the client via
the reply message.
22.14.3.4 Intermediate Request Router
An intermediate router is simply a router that accepts a request message via send_request from one router and then, eventually,
delivers it to another router, again using send_request. The send_multiple_requests operation may also be used to allow batching
of requests between Routers. The intermediate routers may take a request’s QueueOrderPolicy (if present) into account when
prioritizing the delivery of requests to destination routers, but is not required to do so.
22.14.3.5 Target Router
The target router for an invocation is a router that accepts a request message, delivers it to the target object, and, if
a response is expected, routes the target’s reply back to the client. The target router may have to queue the request message
before the invocation and/or may have to queue the response message after the invocation.
The target router may be collocated with the target, or may deliver the request to the target via a synchronous GIOP-based
protocol. The target router is responsible for processing any LOCATION_FORWARD replies that may be generated in making the
invocation on the target, so only NO_EXCEPTION, USER_EXCEPTION, or SYSTEM_EXCEPTION replies are routed back to the client.
When making the synchronous GIOP request on the target, the TargetRouter must marshal its request with the same byte order
with which the original message body was marshaled. This byte order is recorded in the MessageBody structure. No Router is
expected to remarshal the request body with a new byte order.
If persistence of requests is required, the target router ensures that the request message is removed from stable storage
and the reply message is committed to stable storage within the scope of a single transaction. If the target object’s IOR
indicates that it supports time-independent transactions (through a TransactionPolicy of Allows_unshared, Allows_either, Requires_unshared,
or Requires_either), then that same transaction context is propagated to the server application. Otherwise no transaction
context is propagated to the target when the request is invoked.
When guaranteed delivery is required, there may be one, two, or three distinct transactions involved in the target router’s
processing of the invocation. The target router receives the request message within the context of a transaction initiated
by a previous router or possibly the client ORB. If the target is accessible at that time, the operation can be invoked on
the target and the reply message either stored or sent back toward the reply destination using the transaction context within
which the request was received. If the target is not accessible, the request message is committed to stable storage and queued
for later delivery to the target under a second transaction. When the target operation is invoked and its reply is received,
the target router may deliver the reply to another router, or possibly to the client ORB. The router may deliver the reply
in the same transaction as it invoked the operation, or the router may commit the reply to stable storage and later deliver
it in yet another transaction. The completion of the transaction in which the TargetRouter actually delivers the request to
the target is governed by the following cases:
• A NO_EXCEPTION reply is returned and the transaction commits. This committed reply is the one that will be returned to the client. Since the reply committed, the request is no longer waiting in some queue pending delivery.
• A NO_EXCEPTION reply is returned but the transaction raises TRANSACTION_ROLLEDBACK upon commit. In this case the router must ensure that the request not be considered pending delivery anymore (logically the request must be removed from some queue), and that a suitable reply be generated so that the client knows that the target’s transaction rolled back. The router starts a new transaction in which it removes the request from its “to be delivered? queue and generates a reply with the system exception TRANSACTION_ROLLEDBACK. This reply is then committed as the reply for the request.
• A user or system exception is returned. The Router should rollback the transaction so no work has been done in the target server. There are two subcases here:
• the target was unreachable. In this case, since the transaction has rolled back, the request is still waiting in the Router’s queue of pending requests. The retry policy is used to determine when next to attempt delivery. • the target was reachable but an exception was raised. As in the TRANSACTION_ROLLEDBACK case above, the Router starts a new transaction to remove the request from the queue of pending requests, and commits the exception reply that it received from the target as the reply for this operation.
If the request has a QueueOrderPolicy associated with it, the target router is responsible for making invocations in the proper
order. Depending on the Ordering requested (e.g., PRIORITY, TEMPORAL), the appropriate request is selected for delivery. Note
that end-to-end ordering guarantees cannot be made when client and target are decoupled, so this ordering is really only a
guideline. If multiple threads are used in the router for request delivery, it is certainly possible for delivery of requests
to be out of order. The specification of QueueOrderPolicy does not require a router or server ORB to limit its use of threads
in delivering requests.
Regardless of how many transactions, if any, are used, the target router must route the reply back to the reply destination
if and only if the response_expected flag was set to a non-zero value in the RequestMessage. The reply can take one of two
forms depending on whether the reply_destination is a type-specific ReplyHandler (the client uses the Callback model) or if
the reply_destination is an UntypedReplyHandler (a PersistentRequest was created such as when the client used the Polling
model).
Note – The type-specific reply handlers and the UntypedReplyHandler are both derived from the common base ReplyHandler interface,
but there is no other inheritance relationship between the UntypedReplyHandler and the type-specific reply handlers.
Regardless of destination, the new reply must be marshaled with the same byte order used by the target when the reply was
originally marshaled. The Target Router is not expected to remarshal the reply body.
22.14.3.6 Replying to a Type-specific ReplyHandler
If the client originally supplied a type-specific ReplyHandler, the reply must be converted into a typed request invocation
on the ReplyHandler. The Target Router determines this by verifying that the handler_type disposition of the reply_destination
argument has the value TYPED. The format of the generated request depends on the reply_status:
• NO_EXCEPTION - the generated reply operation has the same operation name as the request. Its RequestBody is exactly the same as the marshaled ReplyBody from the target’s GIOP reply.
• SYSTEM_EXCEPTION or USER_EXCEPTION - the generated reply operation has the same name as the request operation, with the string _excep appended. The single argument to this request is the Messaging::ExceptionHolder valuetype.
A reply with status LOCATION_FORWARD is handled as described below.
22.14.3.7 Replying to an UntypedReplyHandler
If the client originally created a PersistentRequest (such as by using the Polling model), the reply must be converted into
the generic request operation supported by the UntypedReplyHandler interface. The Target Router determines this by verifying
that the handler_type disposition of the reply_destination argument has the value UNTYPED. The generated reply operation has
the name “reply? and takes as arguments the original operation name, the reply_status (NO_EXCEPTION, SYSTEM_EXCEPTION or USER_EXCEPTION)
and a sequence of octet containing the reply data. The length is set to the size of the marshaled ReplyBody and the data is
the marshaled body itself.
22.14.3.8 Handling of Service Contexts
When a TargetRouter receives a Reply, it generates a request on some ReplyTarget as described previously in this section.
If the Reply contains service contexts, the TargetRouter must decide whether or not these contexts are to be used in its request
on the ReplyTarget. End-to-end service contexts, such as the CodeSets context, are propagated to the ReplyTarget. Single-hop
service contexts, such as the TransactionService context, are consumed by the TargetRouter. Unknown service contexts are propagated
from the reply to the generated request on the ReplyTarget.
22.14.3.9 Handling LOCATION_FORWARD Replies
When a TargetRouter receives a Reply with status LOCATION_FORWARD, it must either use the returned reference as the new target
for the request, or must return the new reference to the ReplyTarget. The Messaging protocol requires that the TargetRouter
continue processing the request by either directly invoking the new target or routing the request toward the new target as
has been described thus far.
22.14.3.10 Routing of Replies
As described above, the GIOP reply is turned into a request message targeted to the original reply_destination. Since this
reply is now a request, it may be sent to its destination using the message routing protocol described in this section. For
example, if the ReplyHandler’s reference contains Routing information, the TargetRouter may invoke the new request using some
Router’s send_request operation. In this case, the specified routing protocol should be followed for this new request, with
the response_expected flags all set to 0 and the reply_destination set to nil.
22.14.3.11 UntypedReplyHandler
When an UntypedReplyHandler’s reply operation is invoked, several things may happen. The specific correlation of a Router’s
UntypedReplyHandler with the PersistentRequests it supports is not visible to this interoperability layer, but at a high level
one of the following occurs:
• A type-specific ReplyHandler has been associated with the corresponding PersistentRequest. If a callback has been registered for this reply (the associated_handler is non-nil), the type-specific callback operation may be invoked directly as described in Section 22.14.3.6, “Replying to a Type-specific ReplyHandler,? on page 22-56. For persistent delivery of replies, the Router starts a transaction in which the reply is delivered. Once the client returns, the Router commits and the reply is deleted. As with any transactional request, the application’s ReplyHandler implementation may choose to invoke CosTransactions::Current::rollback_only or CosTransactions::coordinator::rollback_only and then raise the CORBA::TRANSACTION_ROLLEDBACK system exception if it wishes to rollback the Router’s transaction.
• A PersistentRequest::get_reply is pending for this request. The reply data may be immediately returned to the waiting client. The reply is returned within the client’s transaction context and when that transaction is committed the reply is deleted.
• The reply data may be saved to stable storage (for guaranteed delivery this is made durable when the sending Router commits the transaction in which the reply has been delivered) or recorded in-process (if the reply is not guaranteed). The UntypedReplyHandler::reply then returns. The reply is obtained by a client at a later time.