[Xorp-hackers] XRL call serialization
Bruce Simpson
bms at incunabulum.net
Thu Oct 29 11:02:07 PDT 2009
Hi Ben,
Just saw this... sorry for the delay.
Ben Greear wrote:
> With regard to XRL, I've a question:
>
> If an application makes 3 XRL calls:
>
> do_a()
> do_b()
> commit_all()
>
> Is there any guarantee that these are strictly delivered to
> the peer process in the order called? Code appears to expect
> this to be true, but I'm suspicious that perhaps it does not.
XORP processes are intended to be asynchronous; this is realized using
explicit coroutines, with no additional C++ runtime support other than
UNIX system calls.
XRL is intended to be an asynchronous IPC layer. The calls in your
example won't be guaranteed to be serialized, unless you explicitly
serialize them in your process.
You can see this in XORP processes and tools in the form of a ping-pong
between callback routines.
An example of forcing serialization can be found in
contrib/olsr/tools/print_databases.cc, where you can see the EventLoop
being run whilst the Getter does its thing. get() is called, this fires
off an XRL, and the list_cb() will successively be called for each
fetch, until Getter::_done is set to true by the final fetch.
BTW: One example of what NOT to do would be the
XrlIO::register_rib() function in contrib/olsr/xrl_io.cc. The semantics
behind those two XRL calls are co-dependent, and will be different
depending on whether or not an OLSR origin table is already registered
with the RIB. But you can see that two different XRLs can be fired off
'in parallel'.
Class Xrl has no notion of call/reply sequence numbers, which are
necessary in order to deal with out-of-order delivery, as well as
identifying individual method calls on-the-wire.
However, the XORP application code is written with the expectation
that XRL is async. The fact that a few things 'under the hood' in XRL
prevent it being fully async, is largely academic -- the tutorial
materials are pretty clear you shouldn't assume serial method call
returns, etc.
In practice, what happens is that the XRL transport(s) themselves
will stamp each call with a sequence ID. You can see this happening in
XrlPFSTCPSender::send(). Although it *does* expect delivery in sequence
(you can see this in XrlPFSTCPSender::read_event()), this is purely how
it's been done here.
In this respect, XRL is totally tied to TCP semantics in its
implemention, and RPCs should not be reordered, given that their
dispatch in the XRL target is synchronous with their delivery -- there
is no intermediate queueing, apart from the kernel's socket buffers.
But there should be no expectation of this by application
developers. Indeed, if you look at the stubs which Thrift generates, the
client code only allows 1 request in-flight; it always sets the sequence
number to 0. In practice, this isn't a problem, because in Thrift, the
servers tell clients apart per session.
In XRL, we tell calls apart by method name. Something tells me this
gets really interesting if we try to thread the RIB or otherwise move it
into another process. I should point out that XRL targets never actually
get to see the Xrl itself -- they just get passed a bunch of arguments
by the XrlRouter, and their handler function invoked.
On a Grim Code Reaper's note:
This makes it pretty much impossible, using the existing code, to
implement any serialization or parallelism policy within each XORP
process, as well as making it impossible to decentralize the method call
disposition, because it's tied to TCP streams.
Therefore:
Synchronous dispatch of method calls doesn't change in a Thrifted
XORP to begin with -- too much of the existing router code is written
around this expectation.
cheers,
BMS
More information about the Xorp-hackers
mailing list