On Tue, Mar 5, 2013 at 1:50 PM, Michael Goulish <mgoul...@redhat.com> wrote:
> > > ----- Original Message ----- > > On Tue, Mar 5, 2013 at 3:20 PM, Rafael Schloming <r...@alum.mit.edu> > > wrote: > > > On Tue, Mar 5, 2013 at 11:33 AM, Rajith Attapattu > > > <rajit...@gmail.com>wrote: > > > > > >> On Tue, Mar 5, 2013 at 2:24 PM, Ted Ross <tr...@redhat.com> wrote: > > >> > > > >> > On 03/05/2013 02:14 PM, Rajith Attapattu wrote: > > >> >> > > >> >> > > >> >> This is a good explanation that we need to put in the docs, as > > >> >> Application developers certainly need to know how it behaves. > > >> >> If one were to use the current C impl, it certainly gives the > > >> >> impression that put() is meant to write messages into your > > >> >> internal > > >> >> buffer and send() will actually write it to the wire. > > >> >> Unfortunately some applications will depend on this behaviour, > > >> >> even > > >> >> though it's not advisable > > >> >> > > >> >> If we are to change from say #2 to #1 or even #3 we need to > > >> >> release > > >> >> note it prominently. > > >> >> > > >> >> I think the best solution is to make this behaviour > > >> >> configurable, and > > >> >> advertise the default very prominently. > > >> >> This way application developers will know exactly what they are > > >> >> getting instead of us making changes underneath. > > >> >> > > >> >> Rajith > > >> >> > > >> > > > >> > Making this configurable multiplies the size of the test matrix. > > >> > Can't > > >> we > > >> > make this simpler? > > >> > > >> I do understand your concern here, but the Java impl already does > > >> both > > >> #1 and #2 and Rafi wants to do #3 in the future. > > >> The old JMS client does something similar. > > >> > > >> I agree that if we just do option #2 (as you suggest below), then > > >> the > > >> application can easily do #1 and #3 on top of that. > > >> But I'm sure they will like if the library implements those > > >> strategies > > >> for them and they have the ability to pick a strategy. > > >> > > > > > > I don't see why we'd make this configurable. All three options > > > actually > > > fit the same general semantics. Even if you're optimistically > > > trying to > > > transmit every single time put is called it's entirely possible for > > > the > > > socket to be blocked every single time you try. If this were to > > > happen the > > > implementation of #1 would appear to behave precisely the same as > > > #2 > > > behaves. > > > > > > In other words if you're coding correctly against the API you can't > > > assume > > > that put will or won't have transmitted anything regardless of > > > which > > > strategy is used internally. > > > > > > > I agree with you. You make a very good point. > > Perhaps we should explicitly make that clear in our docs to avoid > > applications written against wrong assumptions. > > > I can certainly do that, but it seems to me that semantics should be > simple, obvious, and orthogonal. > > What seems non-simple and non-obvious to me so far is: > > put() might send, or not. It doesn't send now, but it > might later. > This behaviour is fundamental to an asynchronous API. You're not actually doing things, you're scheduling things to be done asynchronously. This is why put() returns a tracker so you can come back and check on the status of your asynchronous operation. recv() can cause messages to be sent. > > send() can cause messages to be received. > I don't think that's a correct way of describing what is going on. You scheduled an asynchronous operation via put(). That means it can occur at any point later on. The fact that it happens to be trigger by the recv() in the example I gave is simply because recv() is blocking waiting for the reply and so it is inevitably going to end up blocking until the request is sent because the reply won't be triggered until after the request is sent. As for send(), it's simply inaccurate to say that send causes messages to be received. Messages can be spontaneously sent by remote parties at any time (given sufficient credit has been previously granted). What caused them to be received is the other party actually sending them, and if message data happens to arrived while we're inside a call to send(), we can't simply throw those messages away, so they go onto the incoming queue just as if they had arrived during a call to recv(). > I would think that > > 1. every verb should only mean one thing > > 2. there should be a simple mental model, > against which every verb performs a > predictable action. > > so for example: > > put ( messenger, message ); // enqueue for sending > send ( messenger, BLOCK ); // block till all sent. > send ( messenger, DONT_BLOCK ); // send what you can. > credit ( messenger, 10 ); // limit incoming queue size > recv ( messenger, BLOCK ); // block till I get a message > recv ( messenger, DONT_BLOCK ); // if no messages incoming, return. > I'm not sure how your example is meaningfully different from the current API. Your short descriptions are only positive. If you intend to "simplify" by allowing one and only one action per call then you need to document that recv prevents messages from being sent, and send prevents messages from being received. Regardless I think you may be missing an asynchronous component from your mental model. Events can happen spontaneously, such as messages being sent/received over the wire, but that doesn't invalidate the semantics of send as "block until all the messages are sent" or recv as "block until there is a message to get". The only thing we've been discussing is the granularity of that asynchronousness. One extreme is a fully lazy implementation that never bothers doing any asynchronous work until it has to block for something. At the other end of the spectrum is an implementation with a background thread that constantly tries to do any outstanding work. For both these implementations though (and any in between implementations) the programming semantics are identical: "put" is requesting that a message be asynchronously sent, and send/recv are blocking until a specific condition is met. --Rafael