bug-hurd
[Top][All Lists]
Advanced

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

Re: Channel sessions


From: Carl Fredrik Hammar
Subject: Re: Channel sessions
Date: Tue, 14 Aug 2007 14:15:46 +0200
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.1.50 (gnu/linux)

Hello,

<olafBuddenhagen@gmx.net> writes:

> Hi,
>
> On Mon, Aug 13, 2007 at 03:08:27PM +0200, Carl Fredrik Hammar wrote:
>> <olafBuddenhagen@gmx.net> writes:
>
>> I will use channel for the object that a client interacts with, i.e.
>> one is created whenever the translator is opened.
>
> That is what I call a channel instance. You can also call it a channel
> session; but referring to an individual instance only as "channel" would
> be very confusing IMHO.

I have found the opposite very confusing or at least it has misguided
me in the past.  The word channel suggest that their is a only single
stream of data (in both directions) transferred between the two
end-points.  Associating it with the translator, gives the idea that
every client will receive the same data, i.e. opening a channel
subscribes a client to the channel.  I was under the impression that
this was the case for quite some time.

But I think we both agree is not always the desired behavior.  Instead
opening the translator should give the client a *new* communication
channel to the end-point.

>> > A channel module is a single unit implementing the channel
>> > interface, running within libchannel or in a channel translator. It
>> > has a client side, which can be access through a filesystem node or
>> > through libchannel; and a device side, which can access either a
>> > Mach device, or the client side of another channel module. A channel
>> > stack is a layering of several channel translators/modules.
>> 
>> This object I have opted to call a hub, ``module'' would perhaps be a
>> bit better.  However, I don't want to stray to much from libstore's
>> terminology.  And in libstore module is the shared object containing a
>> class that can be loaded dynamically.
>
> Hm... Haven't distinguished between these up till now. Is it necessary
> to avoid ambiguity?...
>
> [...]
>
> Well, I can't make much of OO terminology; I'm still not really sure
> what you actually mean by a channel class... I hope you don't mind if I
> don't use these terms :-)

Lets take it from the top and see if it clears things up.

I addition to its normal usage, a type is simply a name of a class,
and is pretty much only used to look up the class it names.  Of course
the term is used for channels and hubs created from the class.

A class' main purpose is simply to create hubs of its type, i.e. it
supplies a pointer to a function that can fill in any type-specific
parts of a hub.  Their is only one class per type and is static and
constant object.  As an auxiliary service, it also holds any constant
data shared by all hubs and channels of the same type, which is mostly
a bunch of function hooks that determines the behavior of the
channels, these are referred to as methods.

A class is resides in a module, which is simply an archive that is
either already linked into the translator or is dynamically loadable.

A hub's purpose is to open channels and to coordinate them if they
need to access a shared resource.  Unlike a class, there may be
several and they are not constant nor static.  Parameters given when
it was created determines which end-point channels are connected to,
e.g. one hub of type ``device'' may open channels to /dev/dsp, while
another might open channels to /dev/eth0.

Our discussion is not on a low enough level to warrant use of some of
these, but hopefully it will explain my reluctance to use them in any
other sense.  For our discussion type and class can be considered
synonymous.  If you'd like you can use module instead of hub, since
it's likely not to be confused with its other use, but I won't (for
now.)

>> > Why can't --buffer or --no-buffer be used? In storeio, you also have
>> > a number of optional flags, and if you give several of them, you get
>> > implicit layering, although you only set a single translator --
>> > without using the "unwieldy" layering syntax...
>> 
>> Yes, that is an option in many cases.  But for buffering, position in
>> the stack may be crucial.  Consider a tee, buffer, device stack, where
>> the tee will only open a single channel to the buffer.
>
> Well, when implicitely selecting several modules where order is relevant
> (which I think can happen with storeio as well), simply establish a
> fixed order; if for some reason a different order is necessary, one can
> still stack several translators, or use the layering syntax...
>
> BTW, I think junctions probably should never be specified with some
> options, but rather always by explicit translator stacking.

When combining both of your statements there isn't a problem.  Buffer
position will probably only matter in stacks with junctions.

But you must acknowledge that stacks containing junctions can be
mighty complicated to specify.

>> If the buffer were on top, there would have to be one buffer per
>> channel, which is redundant since the same stream is passing through
>> all of them.
>
> I think there are cases where having individual buffers per instance
> could be desirable.

Well yes, that was my point, since a buffer should be per channel
(instance), a buffer hub's location in the stack matters in some
cases.

>> > Also, I thing there still might be some confusion here. It seems
>> > very important that we get a common understanding of the topology.
>> >
>> > There are basically two kinds of junctions regarding the topology:
>> > Multi-client junctions and multi-device junctions. Those are two
>> > totally different things, serving very different purposes, and
>> > usually not used together.
>> 
>> In not sure if this is what you were getting at, but your talk of
>> topology got me thinking.  When faced with a back-end junction I was
>> assuming that one only wants one channel per back-end, leaving only
>> one channel to be shared by clients.  This forced me to choose
>> front-end junction as well, an arbitrary choice, with in-tee being the
>> closest at hand.
>> 
>> However, it is now clear to me that when a back-end junction channel
>> is opened, new channels to all back-ends should be opened.  By
>> layering a front-end junction over the back-end junction one can still
>> have only one channel per back-end.
>
> Yes, that's exactly what I was getting at. Good to have this sorted out
> at last :-)

Indeed. :-)

>> For a general purpose front-end junction, the simplest and most
>> neutral way would be used, which would be a fifo (or perhaps it should
>> be called a fofi. ;-))
>
> I think there might be some cases, where some variant of fifo is most
> appropriate; but I'm not at all convinced that it's the most useful in
> the general case. In fact, my point was that there might not be such a
> thing as a general case here... Useful behaviour is just too
> type-specific I think.

Hmmm... yes, I think it might be best to simply make junctions read or
write only, and force the user to handle it appropriately.

>> > Now what about the out-tee? This is somewhat confusing: While the
>> > in-tee is a multi-client input junction, the out-tee is a
>> > multi-device output junction -- something totally unrelated with
>> > very different use cases. Also, althouh the basic idea of
>> > duplicating streams is the same, forwarding from one client to
>> > multiple devices is totally different implementation-wise than
>> > forwarding from one device to multiple clients...
>> 
>> Yes, I am well aware of the differences.  The out-tee is much, much
>> simpler.  Handling the case when some channels of an in-tee aren't so
>> that other channels don't stall is tricky.
>
> I'm not sure there is any difference in this regard. I don't see why
> backends should provide any more guarantees about not stalling than
> frontends...

The difference is in the difficulty in handling stalling, not whether
they stall or not.  The problem is more that the client has control,
the server can only wait for all clients initiates a transfer or
time-out.  A client can simply specify a time-out when doing an RPC to
handle stalling servers.

>> > The situation is even more confusing for fifo. There are two
>> > distinct kinds: A split-fifo (with a topology like the tee), and a
>> > merge-fifo; each having in- and out-variants. (Maybe better leave
>> > out the "fifo" alltogether and give them totally distinct names
>> > instead, to reduce confusion...)
>> 
>> What would a merge-fifo be?  I don't think we've brought that one up
>> before.  I have always been referring to split-fifo (I think.)
>
> Well, if we want to do network load balancing over multiple devices for
> example, we'd need some variant of a multi-backend out-fifo, which is a
> splitting fifo, as it takes packets from one stream and distributes them
> to several. When receiving packets from multiple devices, we need a
> multi-backend in-fifo, which is a merging fifo, as it interleaves
> packets from several streams into one.

Ok, now I see.  I've been pairing them together, since they actually
are each-others inverse, unlike pairing tee and merge fifo.  This
pairing makes sense so I think I would keep it in the general purpose
front-end and back-end fifos.

For a general purpose fifo I would split and merge requests,
e.g. merging two reads or splitting a write in two.  Of course this
would break up packets.  One way to get around it might be to
introduce packeting channels, that simply makes sure that each request
is in whole packets, buffering if that is not the case.

>> One more thing to think about is making sure that when a in and out
>> channel is rejoined that they belong to the same client.  This might
>> very well happen in a naive implementation of a joiner, that simply
>> pairs the last in channel with the next out channel or vice versa.
>> Considering that it is possible to open read or write only channels.
>> 
>> In fact I think this rules out option one and three.  A modified
>> version of three might work though, where the split and join is in a
>> single module that maintains two separate stacks.  Lets call this
>> option four.
>> 
>> Another way to tackle this would be to supply a client id along with
>> the channel when it is opened, allowing the relevant party to pair up
>> channels.  This would allow option one and three to be implemented.
>> But the client id can't be forwarded across translators (unless we
>> expand the IPC protocol,) so channel would have to be paired up before
>> this point.
>
> Indeed, I haven't considered this issue at all so far. I'll have to
> think more about it I guess. Client IDs seem like a reasonable approach
> at first glance at least...

For now I will go with option four, since it will work without adding
functionality to libchannel.  But client IDs should be definitely be
explored as an alternative.

>> libchannel also handles control interfaces, analogous to ioctls.  This
>> just means that channels can handle any IPC messages not recognized by
>> the translator.  It just occurred to me that one might want to split
>> them into separate paths as well.  But this can be handled similarly
>> to in/out splitting.
>
> Right. I'm not sure how useful this might be in practice, but the
> generalization should certainly help thinking about the pairing issue.
>
> -antrik-

Such a splitter would mostly be to get around general purpose
junctions, as they can't possibly know how to deal with them.  A
layers in a chain of channels can simply pass them down the line
without a problem.

Cheers,
  Fredrik




reply via email to

[Prev in Thread] Current Thread [Next in Thread]