Hah! I think I get it! Your comments about asynchronicity were the key. Rewriting now.....
----- Original Message ----- > 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 >