Remote Procedure Call (RPC) Within Transactions
One can execute RPCs within a lock-based critical section,
as well as from within an RCU read-side critical section.
What happens when you attempt to execute an RPC from within
a transaction?
If both the RPC request and its response are to be contained within
the transaction, and if some part of the transaction depends on the
result returned by the response, then it is not possible to use the
memory-buffer tricks that can be used in the case of buffered I/O.
Any attempt to take this buffering approach would deadlock the
transaction, as the request could not be transmitted until the transaction
was guaranteed to succeed, but the transaction's success might not be
knowable until after the response is received, as is the case in
the following example:
begin_trans();
rpc_request();
i = rpc_response();
a[i]++;
end_trans();
The transaction's memory footprint cannot be determined until after
the RPC response is received, and until the transaction's memory
footprint can be determined, it is impossible to determine whether
the transaction can be allowed to commit.
Here are some options available to TM:
- Prohibit RPC within transactions, so that any attempt to execute
an RPC operation aborts the enclosing transaction (and perhaps
multiple nested transactions).
Alternatively, enlist the compiler to enforce RPC-free transactions.
This approach does works, but will require TM to interact with
other synchronization primitives.
- Permit only one special
“inevitable” transaction
to proceed at any given time, thus allowing inevitable
transactions to contain RPC operations.
This works in general, but severely limits the scalability and
performance of RPC operations.
Given that scalability and performance is a first-class goal
of parallelism, this approach's generality seems a bit self-limiting.
- Identify special cases where the success of the transaction may be
determined before the RPC response is received, and automatically
convert these to inevitable transactions immediately before
sending the RPC request.
Of course, if several concurrent transactions attempt RPC calls
in this manner, it might be necessary to roll all but one of them
back, with consequent degradation of performance and scalability.
This approach nevertheless might be valuable given long-running
transactions ending with an RPC.
- Identify special cases where the RPC response may be moved out
of the transaction, and then proceed using techniques similar
to those used for buffered I/O.
- Extend the transactional substrate to include the RPC server as
well as its client.
This is in theory possible, as has been demonstrated by
distributed databases.
However, it is unclear whether the requisite performance
and scalability requirements can be met by distributed-database
techniques, given that memory-based TM cannot hide such latencies
behind those of slow disk drives.
As noted earlier, I/O is a known weakness of TM, and RPC is simply
an especially problematic case of I/O.