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]






Reply via email to