Le 05/01/15 16:41, pengchengliu a écrit :
> hello,
> I am very glad to write to you to discuss some of my doubts. Recently, I
> read the write processs of mina(source code). There is something really
> puzzled me.
> the flushNow function in mina is not so easy to understand.
You bet !!! ;-)
> the following are the origin source code and I add some comment at key point.
> finalboolean hasFragmentation =
> session.getTransportMetadata().hasFragmentation();
>
> finalWriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
>
> // Set limitation for the number of written bytes for read-write
> // fairness. I used maxReadBufferSize * 3 / 2, which yields best
> // performance in my experience while not breaking fairness much.
> finalint maxWrittenBytes = session.getConfig().getMaxReadBufferSize()
> +(session.getConfig().getMaxReadBufferSize()>>>1);
> int writtenBytes =0;
> WriteRequest req =null;
>
> try{
> // Clear OP_WRITE
> setInterestedInWrite(session,false);
>
> do{
> // Check for pending writes.
> req = session.getCurrentWriteRequest();// get the current write request
>
> if(req ==null){
> req = writeRequestQueue.poll(session); // each time will poll the first
> request from write request queue, and assign it
> // to current
> write request if current write request is null
>
> if(req ==null){
> break;
> }
>
> session.setCurrentWriteRequest(req);
> }
>
> int localWrittenBytes =0;
> Object message = req.getMessage();// get message from req
>
> if(message instanceofIoBuffer){
> // writeBuffer will write message out, there are two condition:
> // 1) hasFragmentation == true, then every time just
> write min((maxWrittenBytes - writtenBytes), buf.remaining())
> // 2) hasFragmentation == false, then write the whole
> message out
> localWrittenBytes = writeBuffer(session, req, hasFragmentation,
> maxWrittenBytes - writtenBytes,
> currentTime); // in writeBuffer, if message were totally written out, will
> setCurrentRequest(null)
>
> // why here after writeBuffer, localWrittenBytes >0 and message has
> Remaining() then jump out this flush and let Processor to process this
> session after next select ??? bad network state???
Ok, let me explain :
when you write some data in a socket, three things can happen :
- first, the socket might be closed. Ok, not interesting, you'll get an
exception, that the end of the game.
- second, most of the time you will be able to write everything you
want. Fine, we can process the next message in the queue.
- third, the most interesting case : you have written a part of the
message in the socket, but the socket buffer is full before you can
write the full message.
In this third case, you have to *wait* for the socket to be ready to
absorb some new data. In a blcoking mode, that's easy : when you do a
socket.write(data), you are blocked until all teh data is written (or
until a timeout occurs). In a non-blocking mode, you get back the number
of bytes actually written in the socket. It could happen that this
number is below the number you xwanted to write, and then you will have
to retry later.
Let's define "later" in a NIO context : this is when teh socket will
*inform* you that it can now accept more data. And this information
comes as an event processed by the main select loop.
So we do let the processor handle the next OP_WRITE event to try to
write the remaining bytes.
> // localWrittenBytes > 0 and message.hasRemaining()==
> true may happen when the message is huge, bigger then
> // maxWrittenBytes and network state is good, why not
> put it to then end of the flushingSessions queue but reinterest
> // it in writing?
Because we wanty to keep the order in which the messages are processed !
You don't want a piece of a message being written, then the remaining of
it pushed back at the end of the queue, for other meessages to be sent
before it ?
Let's say we have M1 = "hello", M2 = " World !"
we have a queue containing M1 and M2. We try to write M1, but we can
just write "He"
write M1 -> "He" remaining = "llo"
wait...
socket ready
write M1 remaining -> "llo"
socket ready
write M2 -> " World !"
The client will receive "Hello World!"
If you push the remaining bytes of MA at the end of the queue, teh
client will receive "He Wold!llo" (kind of)
> //
> if((localWrittenBytes >0)&&((IoBuffer) message).hasRemaining()){
> // the buffer isn't empty, we re-interest it in writing
> writtenBytes += localWrittenBytes;
> setInterestedInWrite(session,true);
> returnfalse;
> }
> }elseif{...}
>
> if(localWrittenBytes ==0){
> // Kernel buffer is full.
> setInterestedInWrite(session,true);
> returnfalse;
> }
>
> writtenBytes += localWrittenBytes;
>
> // if after serveral rounds writtenBytes >= maxWrittenBytes , put current
> session to queue end for fairness.
> if(writtenBytes >= maxWrittenBytes){
> // Wrote too much
> scheduleFlush(session);
> returnfalse;
> }
>
> if(message instanceofIoBuffer){
> ((IoBuffer) message).free();
> }
> }while(writtenBytes < maxWrittenBytes); // this round the cummulated
> writtenBytes still < maxWrittenBytes
> }catch(..){
> ....}
>
>
> it's hard to describe what i want to understand just though mail, but
> hope you can understand what i am saying, looking forward to your respond.
I hope I have responded...