expressions are a mix of :-) nd :-(

Next time just let me know when you folks plan a debugging marathon :-)
May be we can use some screen-sharing tool and I can also participate
means listen :-)

It would have been a good learning.

thanks
ashish

On Fri, Feb 19, 2010 at 8:04 PM, Emmanuel Lecharny <[email protected]> wrote:
> Hi,
>
> here is a memo describing the debugging session we did yesterday with
> Julien. I have added TODO each time I think we can do better.
>
>
>
> MINA analyze when processing one single message. The server receives "hello"
> and should return "HELLO".
>
> - We start in the main IoProcessor loop, after a select() returning 1 on a
> channel set with OP_READ, as we have just received the message.
> - the process() method is called. It does two things :
> 1) if the session is readable and not suspended, read the channel
> 2) is the session is writable and not suspended, add the session to the
> queue of session ready for flush, if not already there.
>
> TODO : at this point, we have no idea if the session has some pending
> writes. Check if the OP_WRTE flag has been set on the selectionKey
>
> - in the read() method, we allocate a buffer with the size configured for
> the session. Usually, it's way to big if you just have hundreds of bytes to
> read, and if you set the config to 65000…
>
> TODO : use smaller buffers
>
> - Then we call the chain's messageReceived() method
>
> - In the ProtocolCodecFilter, we grab the decoder instance, which is stored
> in the session's Attributes
>
> TODO : There is no good reason to store the instance in the attributes. It
> should be part of the session parameters.
>
> - then we create a new instance of a decoderOut.
>
> TODO : The only reason we have such an object created here is that we need
> to create a queue to store the result of the decoding.
>
> - We now decode the incoming data, until the buffer is empty. We may have
> more than one message in the buffer, so each one of them is decoded and
> enqueued in the encoderOut queue.
>
> - The doDecode() method is called. This is the user provided code. The
> decoded message is enqueued, and we do that until the doDecode() method
> returns false (meaning we don't have anymore message to decode)
>
> - We call the encodedOut.flush() method to go up in the chain
>
> TODO : it should be done directly here
>
> - For each decoded message in the queue, call the next filter
> messageReceived() event
>
> TODO : we went through the tail filter, which is updating some stats used by
> the idle session handler, but this should be done in another place. Everyone
> does not want to deal with idle sessions … My be an IdleFilter could help ?
>
> - In the handler, we process the message, and write the response calling
> session.write( response )
>
> - The session.write() method create a writeFuture and a WriteRequest object
> containing the response, the recipient's address and the future
>
> TODO : this WriteFuture is never used.
>
> - We go back to the chain in reverse order, firing the FilterWrite method
>
> TODO : This should be a separate chain
>
> - We get the encoded and we create an encoderOut instance, containing a
> queue
>
> TODO : here, unless the encoder creates more than one buffer to be sent,
> there is no need to create a queue. We can also call the encoder, get back
> the result and flush it, doing so receptively until all the encoded pieces
> has been generated (but I feel like we better get back a set of buffers
> instead as a response. No need of a queue)
>
> - The user's provided encoder method is called, the encoded buffer is
> enqueued. It can still be a plain Message, if we want to go though another
> encoder
>
> - At this point, we call the flushWithoutFuture() method which loop on the
> encoderOut queue to send all the encoded buffers
>
> - for each encoded message in the queue, we create an EncodedWriteRequest
> encapsulating the encoded buffer, and we go down in the chain
>
> - The WriteRequest is enqueued in the session WriteRequestQueue, and if the
> session is not suspended for write, we call the processor.flus() method
>
> TODO : there is no reason to call this method now. Also the
> session.getProcessor() method ask the processor pool for the session's
> processor, which is useless, as each session is attached to a single
> IoProtocol. We must store not the pool, but the processor
>
> - If the session is not already in the queue of session waiting to be
> flushed, we add it into this queue, then we wake up the selector
>
> TODO : Waking up the selector at this point is questionable. It's probably
> totally useless.
>
> - Ok, we go back, and call the filterWrite() method once again in the
> protocolCodecFilter, with a new MessageWriteRequest instance, encapsulating
> the response.
>
> TODO : WTF ??? Why do we process the same message twice ???
>
> - In the HeadFilter, we grab the message, which is empty. In fact, this
> empty message is used as a marker for the 'end of message'. Nevertheless, we
> add this empty message to the WriteRequestQueue
>
> - We ask the processor to flush again the session, but as the session has
> already been added into the scheduledForFlush queue, nothing is done
>
> - And we are done with all the process() method. We come back to the main
> select loop
>
> - Time to process the session waiting to be flushed now… This is done with a
> call to the flush(currentTime) method. We check that we have sessions ready
> to be flushed first. If so, we loop on all those sessions.
>
> Note : a session may be marked as ready to be flushed either because we just
> have some new message for it, or because a big message hasn't be written to
> the client completely n a previous loop.
>
> At first, we remove the session from the queue of scheduled sessions. We
> will put it back if the full message hasn't been written later. If the
> session is open, we call the pocessor.flushNow() method
>
> - There, we grab he WriteRequestQueue for this session. There is something
> obscure done here : we compute some number based on the max read and write
> buffer.
>
> TODO : remove all this crapity…
>
> We reset the OP_WRITE flag (it may have been set in a previous call).
>
> The session stores the current buffer being flushed in a special holder. if
> it's null, we take the first message from the queue and stores it into this
> session.
>
> TODO : This is absolutely useless. At this point, we know exactly where we
> left when we wrote it to the client. it's enough to keep the buffer in the
> queue, peeking it instead of polling it. We just remove it when the message
> has been completely sent.
>
> - We now call the writeBuffer() method, responsible for the writing of the
> data to the client.
>
> TODO : There is a totally useless loop in this method, where we try to write
> to the client up to 256 times, just in case the client is slow, I guess.
> This is overkilling. We have *no idea* why this loop exists, except that
> back in the past, some strange bug was fixed with such a 'workaround'
>
> - The buffer is written to the channel, and we get back the number of
> written bytes. If we have written all the bytes, we call the fireMessage()
> method. The currentWriteRequest is cleared in the session. The WriteFuture
> is now set to Written state (useless, as nobody uses this information).
>
> TODO : Get rid of useless tasks
>
> - In the PotocolCodecFilter, as the WriteRequest is the encodedWriteRequest,
> we immediately return.
>
> TODO Why the hell are we calling the messageSent() method at all as we just
> don't process the information here ??? probably because we have no clue
> about the fact that the WriteRequest is a message at this point. It has to
> be fixed, it's sucking useless CPU
>
> - Then we are back, and process the ext message in the queue, which is the
> empty message (used as a end-of-message marker)
>
> - The writeBuffer() method just do nothing, as this message is empty. It
> just call the messageSent() method to inform the handler that the message
> has been sent. So we go up in the chain to the handler, and back.
>
> - There is now a stupid things done (one more …) : as we didn't wrote
> anything, the number of written bytes is 0, so we consider that the socket
> is full, and we switch the OP_WRITE flag to true. This is a 100% guarantee
> that we will do a full select loop again, for nothing…
>
> TODO : FIX ME !!!
>
> - When we are back from the flushNow() method, we get a false, as we didn't'
> flushed the empty message. But we are done with the list of sessions
> scheduled for a flush.
>
> - and we get back to the select(), which will exit immediately with at least
> one selectionKey set with OP_WRITE, as wear still waiting to write the empty
> message !!!. That means we will process two reads for one write.
>
> - once we enter again in the mail select loop, the select() returns 1, we go
> back to the process() method, do nothing in the read part, but put back the
> session onto the scheduledForFlush queue, in order to be processed again in
> the flush() call.
>
> - In the flush() method, we reset the OP_WRITE flag, so that we aren't woke
> up again, and we are done.
>
>
>
> That's it !!! Lot of hacks, lot of useless things, lot of potential speedup
> expected !
>
>
>
>
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.nextury.com

Reply via email to