Problems with the Stream interface



I'd like to point out a very urgent issue that I have noticed in the
design of Bonobo. The Bonobo::Stream interface is inherently
synchronous by design. This is a problem, because it means that when a
component is slow to load (because the Stream data is coming over the
network, because it's loading a lot of data, or just because it's slow
for some reason) it completely blocks the UI of the containing
application.

This is a problem for applications in general. If we want to be able
to handle large data sets, and have everything be network-transparent,
we need this kind of loading to be async. I've been told it's not a
problem for evolution because the relevant data sets are small, but I
imagine in the future someone might send a 300-page Word document
attachment, and the poor recipient will have to see the whole UI block
while it gets streamed into the view component.

It is a showstopper bug for Nautilus right now
(http://bugzilla.eazel.com/show_bug.cgi?id=1994) - when you view text
documents, images, or anything else handled by an ordinary Bonobo
control or embeddable that does not implement the special Nautilus
view interface, the whole Nautilus UI blocks while the component
loads.

Note that this problem cannot be solved just by adding a new
interface.  If a component provides only the synchronous Stream
interface, it can stil block the UI, so just making some kind of Async
interface available (ProgressiveDataSink is sort of a step in this
direction), it will still block the UI; it doesn't help that some
other components might implement an async interface instead or in
addition. So we actually need to remove this synchronous interface.

I'd like to point out, as an aside, why this problem arises in Bonobo
but not in Microsoft COM, even though we copied their design. On
Windows, threads are used heavily to avoid blocking, so if you want a
component to load a stream without blocking the app's UI, you just
start a new thread. In GNOME, we use asynchronicity and callbacks as
the basis of our application architecture; for this to work, all the
interfaces you need must be async.

I have a proposal for how to solve this problem. Essentially, we need
to make the Stream interface asynchronous by design. We can start with
the current Stream interface and convert all calls to not return a
value and take some sort of response listener object to which they
will deliver the results when ready. This is much like the gnome-vfs
CORBA interface for asynchronous I/O.

If we don't want to force components to be bother with the complexity
of handling asynchronous I/O (an understandable goal), it should
actually be possible to emulate the current synchronous stream
interface in terms of the async calls (so the only IDL would be for
the async stream interface, but the bonobo client-side wrappers would
provide emulated synchronous calls). This way, containers can be safe
from having components block their UI while loading, but components
are still free to be written in a hasty way that will make their own
UI completely block while loading (granted, this is far less harmful).

I am willing to commit my personal time to fixing this interface
soon. Does my proposed plan of action sound reasonable? I'd like to
start working out a detailed design on this list as soon as possible.

 - Maciej




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]