the trick is to try to write first with the socket configured in non blocking mode, so if it's congestion controlled , the write will fail instantaneously so we en-queue the message and set the OP_WRITE flag on the selection key.
On Tue, Jan 8, 2013 at 3:24 AM, Chad Beaulac <[email protected]> wrote: > > On Jan 7, 2013, at 11:58 AM, Emmanuel Lécharny wrote: > > > Le 1/7/13 2:19 PM, Chad Beaulac a écrit : > >> If you don't push the data onto a queue and wait for the selector to > fire, you could be trying to write data to a socket that is congestion > controlled, which you shouldn't do. The writer should wait for the selector > to fire saying the socket is writable before trying to write. > > > > The thing is that in any case, we do try to write into the socket. If > > the socket internal buffer gets full, we won't be able to write any ore > > data into it, and we will have to wait for the socket to inform the > > selector when it's ready to accept more data. > > > > What I'm proposing is not any different, except that I bypass the queue > > *if* and only *if* the socket is ready to accept new data. In other > > words, the algorithm is : > > o if there is a queue containing messages waiting for the socket to be > > ready (OP_WRITE set ti true), then enqueue the new message. > > o else try to write the message into the socket > > - if we can't write the full message, set the SelectionKey to be > > interested in OP_WRITE, and enqueue the remaining data. > > - Otherwise, the data have already been written anyway, we are done > > > > This is the way MINA 2 works since it's inception. > > > > Is there anything wrong with that ? > > > > Potentially. You should not attempt to write to the socket unless the > OP_WRITE selector key says the socket is writable. If the selector has > fired and says the socket is writable before you try to write, it's not a > problem. Otherwise, you should queue the data, let the Selector fire and > then try to write. I don't see any way around queuing the data. > You never want to try to write to a socket that is writable. If it isn't > writable, it's closed or congestion controlled. This "edge-triggered" I/O > approach works well. You don't know what "edge" you're on if you haven't > registered for an event before you try to write. > > Pseudocode Algorithm. > > // Client provides data to this class to output onto the socket. > public synchronized void put(Data data) { > if (queue.isEmpty) { > register(key, OP_WRITE); // output queue is empty. We need to > register for the write event so the OS can tell us when it's ok to write. > enqueue(data); // Put the data onto the ConcurrentLinkedQueue > } > else { > enqueue(data); // Just put the data onto the queue. We're already > registered for the write event. > } > } > > public void runEventLoop() { > // handle events on Selector > } > > > // OP_WRITE fired for key > public synchronized void writeData(key) { > while (!queue.isEmpty()) { > Data data = queue.dequeue(); > writeForKey(key,data); > if (data.remaining() > 0) { > enqueue(data); > break; // socket is congestion controlled. We're still > registered for the write event. When the TCP queue drains, the write event > will fire again > } > } > if (queue.isEmpty()) { > unregister(key, OP_WRITE); // We don't have data to write to > this socket anymore. Unregister for the write event. > } > } > > > > > > -- > > Regards, > > Cordialement, > > Emmanuel Lécharny > > www.iktek.com > > > > Chad Beaulac > Objective Solutions, Inc. > www.objectivesolutions.com > [email protected] > > > > > > >
