pub/sub zero copy message dispatch

Skip to first unread message

Gyorgy Miru

Aug 11, 2022, 10:02:09 AM8/11/22
to Cap'n Proto

I am implementing a publisher/subscriber RPC interface with a large volume of messages.
The server receives the incoming published messages and dispatches them to the subscribers after filtering without modifying the original message content. The filtering is done on separate worker threads.

My question is whether this can be done with zero copy? The worst case is marshalling the received message struct into a native struct than building a struct parameter for each subscriber. That would be 1 + N copies.

I tried to keep the original MyStruct::Reader around (that is received as a parameter upon publishing) but my understanding and experience is that it only holds a weak reference to the underlying data which is released as soon as the original context goes out of scope. See the code below for clarity.

kj::Promise<void> server::Server::publish(PublishContext context) {

    Event::Reader event = context.getParams().getEvent();
    // Is there a way to make Event::Reader-s data outlive this scope?
    // Or a convenient way to make a deep copy?

    return kj::READY_NOW;

The other part of the question is if I manage to keep the reader and its data (or I just make a new Event::Builder) can I reuse those to craft multiple subscriber dispatch requests. After all, the +N copies is that I really want to avoid. If i do something like below, would that work and would that result in N copies?

Event::Builder/Reader event;
for (auto client: subscribers) {
   auto req = client.dispatchRequest();

Thank you for your time and help,

Kenton Varda

Aug 12, 2022, 3:35:57 PM8/12/22
to Gyorgy Miru, Cap'n Proto
Hi Gym,

There's no way to do true zero-copy from one RPC to another. You will have to copy. And yes, if the outgoing messages have to be built after the incoming RPC has completed, then you have to make two copies, once into a temporary in-memory structure.

Note that, if you have a complex structure, using `capnp::clone(reader)` to create the temporary copy is likely more efficient than using tree of plain C++ objects, as `capnp::clone` makes sure to do only one allocation where the entire message is stored together. Also, copying between capnp messages is generally very efficient compared to converting to a different style of representation and back.

If your message contains very large Text or Data values, you might be able to avoid copying those by making use of `Orhpanage::referenceExternalData()`. However, there's no equivalent that lets you reference whole message trees.


You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
To view this discussion on the web visit
Reply all
Reply to author
0 new messages