directory-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Colin Cullen" <colincul...@earthlink.net>
Subject ByteBuffer usage, performance, leak
Date Tue, 18 Apr 2006 04:18:48 GMT
Hi,

 

I am seeking some help regarding Mina.  I have completed development of a
server using Mina 0.8.2.  This server will be providing financial deal
ticket information to multiple clients.  Functionally everything works great
but I do seem to have a memory leak and slowly degrading performance.  I am
testing using a single production level client (not Mina based).  The server
protocol sends a deal ticket down to the client and then awaits a high level
acknowledgement from the client indicating whether the ticket has passed or
failed client side validation.  The performance degradation occurs between
the writing of the message object (deal ticket) at the protocol level and
the reception of the response message in its message handler.  BTW I am
using Mina's DemuxingProtocolCodecFactory and DemuxingProtocolHandler to
model the server and provide the codec/handler glue.  I am concerned about
whether I am using Mina's ByteBuffer properly.  I have also read on the
board that Mina will automatically place an allocated ByteBuffer in its
ByteBuffer pool.

 

My output buffer requirements are pretty minimal.  The deal ticket message
is around 1K bytes.  I allocate a single ByteBuffer for each session and
keep it in the session object, which is stored in Mina's session context
map, when a deal ticket needs to be written to the client the pre-allocated
ByteBuffer is retrieved from the session context object and used for
building the outbound data set.  Here are the actual code fragments:

 

This factory creates a session context object for each connection:

 

public class SessionContextFactory

{

    static private SessionContextFactory instance = new
SessionContextFactory();

    static public SessionContextFactory getInstance()

    {

        return SessionContextFactory.instance;

    }

    private SessionContextFactory()

    {

    }

    public SessionContext createSessionContext(ProtocolSession session)

    {

        return new SessionContext(session);

    }

    public final class SessionContext implements SessionContext,
LifeSpanControllable

    {

        ByteBuffer dataBuffer;

 

        private SessionContext(ProtocolSession session)

        {

            dataBuffer = ByteBuffer.allocate(1024);

        }

        public ByteBuffer getDataBuffer()

        {

            dataBuffer.acquire();'

            return dataBuffer;

        }

    }

}

 

This class performs the message encoding using the single ByteBuffer
retrieved from the session context object: 

 

public abstract class EasiAbstractMessageEncoder implements MessageEncoder

{

    private final String type;

 

    protected EasiAbstractMessageEncoder(String type)

    {

        this.type = type;

    }

    protected String getType()

    {

        return type;

    }

    public void encode(ProtocolSession session, Object message,
ProtocolEncoderOutput out) throws ProtocolViolationException

    {

        SessionContext sessCtx =
(SessionContext)session.getAttribute(ServerConstants.SESSION_CONTEXT);

        EasiAbstractMessage m = (EasiAbstractMessage)message;

 

        ByteBuffer buf = sessCtx.getDataBuffer();

        buf.clear();

        // Encode the header

        encodeHeader(session, m, buf); // will perform several buf.put()
calls

        // Encode the body

        encodeBody(session, m, buf); // will perform many buf.put() calls

        buf.flip();

        out.write(buf);

    }

    protected abstract void encodeMetadata(ProtocolSession session,
EasiAbstractMessage message, ByteBuffer buf);

    protected abstract void encodeHeader(ProtocolSession session,
EasiAbstractMessage message, ByteBuffer buf);

    protected abstract void encodeBody(ProtocolSession session,
EasiAbstractMessage message, ByteBuffer buf);

}

 

As you can see the buffer is acquired every time it is retrieved from the
session context object.  Apparently Mina is releasing the buffer in the
out.write(buf) call, is that true?

 

What is Mina going to do with this buffer with regard to pooling?

Is Mina going to add it to its ByteBuffer pool?

Is what I am doing reasonable?

Is there a way that I can pass a ByteBuffer to Mina without having Mina take
ownership of that ByteBuffer?

 

At a high level, what this server needs to do is to be able to send 40 - 50
1K deal ticket per second down to a single client (with the nagle algorithm
disabled).  BTW the client is very fast and almost always responds to the
deal ticket message within the same millisecond in which it was received.

Is it reasonable to expect this kind of performance from Mina?

 

Also worth noting is that the decoding, handling, retrieval of deal ticket
from the database, encoding and all of the related parsing etc. is very fast
and usually only takes around 10 to 20 milliseconds to complete.

 

Any help would be greatly appreciated!  (Sorry for being so long winded!)

 

Thanks for all who work on Mina, a very elegant design which renders NIO
much more approachable.

 

Colin Cullen

 

 

  _____  

The information contained in this e-mail is for the exclusive use of the
intended recipient(s) and may be confidential, proprietary, and/or legally
privileged.  Inadvertent disclosure of this message does not constitute a
waiver of any privilege.  If you receive this message in error, please do
not directly or indirectly use, print, copy, forward, or disclose any part
of this message.  Please also delete this e-mail and all copies and notify
the sender.  Thank you. 

  _____  

 


Mime
View raw message