dev@grizzly.java.net

[Brainstorming] Grizzly 2 I/O API :)

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Tue, 27 Jan 2009 17:14:40 +0100

Hi,

wanted to share ideas John and myself came to, about changing current
Grizzly 2 I/O API.
The main idea is to make Grizzly 2.0 API to be based on StreamReader/
StreamWriter API, proposed by Ken. What does it mean?

Currently, to read something from Grizzly 2.0 Connection, we perform
following steps:

(1) Connect
Future<Connection> connectionFuture = transport.connect(...);
connection = connectionFuture.get();

(2) Allocate buffer
Buffer buffer = transport.getMemoryManager().allocate(size);

(3) Read data to buffer
Future<ReadResult> readFuture = connection.read(buffer);
ReadResult result = readFuture.get();

(4) Parse buffer
if (buffer.remaining() >= 4) {
         intValue = buffer.getInt();
}

Similar steps we do for writing.

Concerns?
IMHO, there is one. We always have to care about allocating Buffers
and then, if we use some smart buffer pool, don't forget to release it.

What John proposed and I like his idea is to use Streams for read and
write operations. This will let us hide Buffers complexity, developer
will not need to care about them anymore... and this should let us
make Buffers usage more optimal.
How read may look like with Streams?

(1) Connect
Future<Connection> connectionFuture = transport.connect(...);
connection = connectionFuture.get();

(2) Get StreamReader
StreamReader reader = connection.getStreamReader();

(3) Wait until data will become available
Future future = reader.notifyAvailable(4);
future.get();

(4) Parse data from stream
intValue = reader.getInt();

As you see in Stream-like case we don't allocate any Buffer, so
Grizzly has complete control over a Buffer inside StreamReader.

With write operation it's not so clear to me in terms of API, because
currently write works following way:

Buffer buffer = transport.getMemoryManager().allocate(size);
buffer.putInt(intValue);
buffer.putLong(longValue);
buffer.flip();

Future writeFuture = connection.write(buffer);
writeFuture.get();

here developer has full control over filling the buffer and flushing
it to network.
In Streams example:

StreamWriter writer = connection.getStreamWriter();
writer.putInt(intValue);
writer.putLong(longValue);

Future future = writer.flush();
future.get();

we can not guarantee that flush operation will be called just once,
because internal buffer could be overflowed before flush() will be
explicitly called. Not sure this is a big deal, but just possible issue.

I will appreciate feedback on API change proposal, and ideas, how it
could be improved.

Thanks.

WBR,
Alexey.