On 04/28/2008 08:57 AM, Emmanuel Lecharny wrote:
"이희승 (Trustin Lee) <[EMAIL PROTECTED]>" wrote:
I thought about the current MINA API these days while I am idle, and got
some idea of improvements:
1) Split IoBuffer into two parts - array and buffer
IoBuffer is basically an improvement to ByteBuffer. Improvement here
means it inherited some bad asset from ByteBuffer - all the stateful
properties such as position, limit and mark. I think they should be
provided as a separate class, and there should be classes dedicated for
storing bytes only (something like ByteArray?)
I was also thinking about this class. ByteBuffers are allocated once,
with a specific size, and the JVM will optimize the way they are
handled. When dealing with IO, I don't see a lot of reasons to have
expandable BB.
Indeed. This was my motivation for opening DIRMINA-489.
I think that using a byte[] (for instance in the encoder), transform it
to a ByteBuffer, is another way to deal with the problem.
One important point is that ByteBuffers are just mean to contains a
fixed amount of data. It's a buffer, not a data structure. Transforming
ByteBuffer to make them able to expand twist their intrinsic semantic.
Yes, it makes far more sense to accumulate buffers until you can decode
your message from it.
So I would say that BB should be used on the very low level (reading
data and sending data), but then, the other layers should use byte[] or
a stream of bytes.
I don't see the advantage of using byte[] honestly - using at the least a
wrapper object seems preferable. And if you're going to use a wrapper
object, why not just use ByteBuffer.
This will lead to very intersting performances questions :
- how to handle large stream of data ?
One buffer at a time. :-)
- should we serialize the stream at some point ?
What do you mean by "serialize"?
- how to write an efficient decoder, when you may receive fractions of
what you are waiting for ?
An ideal decoder would be a state machine which can be entered and exited
at any state. This way, even a partial buffer can be fully consumed before
returning to wait for the next buffer.
However many decoders are not ideal due to various constraints. In the
worst case, you could accumulate ByteBuffer instances until you have a
complete message that can be handled. What I do at this point is to create
a DataInputStream that encapsulates all the received buffers.
Note that a buffer might contain data from more than one message as well.
So it's important to use only a slice of the buffer in this case.
- how to write an efficient encoder when you have no idea about the size
of the data you are going to send ?
Use a buffer factory, such as IoBufferAllocator, or use an even simpler
interface like this:
public interface BufferFactory {
ByteBuffer createBuffer();
}
which mass-produces pre-sized buffers. In the case of stream-oriented
systems like TCP or serial, you could probably send buffers as you fill
them. For message-oriented protocols like UDP, you can accumulate all the
buffers to send, and then use a single gathering write to send them as a
single message (yes, this stinks in the current NIO implementation, as
Trustin pointed out in DIRMINA-518, but it's no worse than the repeated
copying that auto-expanding buffers use; and APR and other possible
backends [and, if I have any say at all in it, future OpenJDK
implementations] would hopefully not suffer from this limitation).
For all these reasons, the mail I sent a few days ago express my
personnal opinion that IoBuffer may be a little bit overkilling
(remember that this class -and the associated tests- represent around
13% of all mina common code ! )
Yes, that's very heavy. I looked at resolving DIRMINA-489 more than once,
and was overwhelmed by the sheer number of methods that had to be
implemented, and the overly complex class structure.
One option could be to use ByteBuffer with some static support methods, and
streams to act as the "user interface" into collections of buffers. For
example, an InputStream that reads from a collection of buffers, and an
OutputStream that is configurable to auto-allocate buffers, performing an
action every time a buffer is filled:
public interface BufferSink {
void handleBuffer(ByteBuffer buffer);
}
Another option is to skip ByteBuffers and go with raw byte[] objects
(though this closes the door completely to direct buffers).
Yet another option is to have a simplified abstraction for byte arrays like
Trustin proposes, and use the stream cleasses for the buffer state
implementation.
This is all in addition to Trustin's idea of providing a byte array
abstraction and a buffer state abstraction class.
- DML