> ----- Forwarded message -----
>
> Date: Sat, 18 Feb 2017 22:21:19 -0500
> Subject: nbdkit async
>
> Hello,
>
> Hope this is the right person to contact regarding nbdkit design.
>
> I have a high latency massively parallel device that I am currently
> implementing as an nbdkit plugin in c++ and have run into some design
> limitations due to the synchronous callback interface nbdkit requires.
Is the concern that each client requires a single thread, consuming
memory (eg for stack space), but because of the high latency plugin
these threads will be hanging around not doing very much? And/or is
it that the client is blocked while servicing each request?
> Nbdkit is currently designed to call the plugin
> pread/pwrite/trim/flush/zero ops as synchronous calls and expects when the
> plugin functions return that it can then send the nbd reply to the socket.
>
> It's parallel thread model is also not implemented as of yet
I think this bit can be fixed fairly easily. One change which is
especially easy to make is to send back the NBD_FLAG_CAN_MULTI_CONN
flag (under control of the plugin).
Anyway this doesn't solve your problem ...
> but the
> current design still mandates a worker thread per parallel op in progress
> due to the synchronous design of the plugin calls.
And the synchronous / 1 thread per client design of the server.
> I would like to modify this to allow for an alternative operating mode
> where nbdkit calls the plugin functions and expects the plugin to callback
> to nbdkit when a request has completed rather than responding right after
> the plugin call returns to nbdkit.
>
> If you are familiar with fuse low level api design, something very similar
> to that.
>
> An example flow for a read request would be as follows:
>
> 1) nbdkit reads and validates the request from the socket
> 2) nbdkit calls handle_request but now also passing in the nbd request
> handle value
> 3) nbdkit bundles the nbd request handle value, bool flush_on_update, and
> read size into an opaque ptr to struct
> 4) nbdkit calls my_plugin.pread passing in the usual args + the opaque ptr
We can't change the existing API, so this would have to be exposed
through new plugin entry point(s).
> 5) my_plugin.pread makes an asynchronous read call with a handler set on
> completion to call nbdkit_reply_read(conn, opaque ptr, buf) or on error
> nbdkit_reply_error(conn, opaque_ptr, error)
> 6) my_plugin.pread returns back to nbdkit without error after it has
> started the async op but before it has completed
> 7) nbdkit doesn't send a response to the conn->sockout beause when the
> async op has completed my_plugin will callback to nbdkit for it to send the
> response
> 8) nbdkit loop continues right away on the next request and it reads and
> validates the next request from conn->sockin without waiting for the
> previous request to complete
> *) Now requires an additional mutex on the conn->sockout for writing
> responses
>
> The benefit of this approach is that 2 threads (1 thread for reading
> requests from the socket and kicking off requests to the plugin and 1
> thread (or more) in a worker pool executing the async handler callbacks)
> can service 100s of slow nbd requests in parallel overcoming high latency.
>
> The current design with synchronous callbacks we can provide async in our
> plugin layer for pwrites and implement our flush to enforce it but we can't
> get around a single slow high latency read op blocking the entire pipe.
>
> I'm willing to work on this in a branch and push this up as opensource but
> first wanted to check if this functionality extension is in fact something
> redhat would want for nbdkit and if so if there were suggestions to the
> implementation.
It depends on how much it complicates the internals of nbdkit (which
are currently quite simple). Would need to see the patches ...
You can help by splitting into simple changes which are generally
applicable (eg. supporting NBD_FLAG_CAN_MULTI_CONN), and other changes
which are more difficult to integrate.
> Initial implementation approach was going to be similar to the
> fuse_low_level approach and create an entirely separate header file for the
> asynchronous plugin api because the plugin calls now need an additional
> parameter (opaque ptr to handle for nbdkit_reply_). This header file
> nbdkit_plugin_async.h defines the plugin struct with slightly different
> function ptr prototypes that accepts the opaque ptr to nbd request handle
> and some additional callback functions nbdkit_reply_error, nbdkit_reply,
> and nbdkit_reply_read. The user of this plugin interface is required to
> call either nbdkit_reply_error or nbdkit_reply[_read] in each of the
> pread/pwrite/flush/trim/zero ops.
>
> If you got this far thank you for the long read and please let me know if
> there is any interest.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top