Hi,
Charles Oliver Nutter wrote:
> Oleksiy Stashok wrote:
>> Hello,
>>
>> please look at Grizzly's ByteBufferFactory class [1]. As I remember
>> correctly it's Jeanfrancois's idea... don't allocate small buffers
>> each time, but allocate the big one, and then "byte" chunks from it.
>
> That's a good idea. I may not look at it directly but implement one
> myself that can be licensed appropriately for JRuby...unless that's not
> a concern? Jeanfrancois...what would it take to co-opt this code into
> JRuby?
>
>>
>> And just one quick improvement I can propose. Please look at method
>> write(ByteList):
>> it does a lot of bad work: copying data, doing that *byte-by-byte*. Is
>> it possible to make change like that?
What licence are you using for your code? I think you can cut&paste the
class and save it into your workspace or bootstrap Grizzly 1.5 (33k).
The latter is easier as you don't have to maintains the code.
>>
> ...
>> In that case you will need to reload method flushOutBuffer() with
>> custom buffer flushOutBuffer(ByteBuffer), but you will avoid data
>> copying.
>
> That's certainly reasonable, and I agree the original write method is
> pretty inefficient. Do you see anything else that could be improved?
> Basically all the code in IOHandlerNio could be tossed if we can fulfill
> the same contracts with better code...we're open for any and all help
> here. This is a great start, thank you!
http://svn.codehaus.org/jruby/trunk/jruby/src/org/jruby/util/IOHandlerNio.java
This class will not work on all platform. Specially doing:
> public int syswrite(int c) throws BadDescriptorException, IOException {
> ByteBuffer buffer = ByteBuffer.allocate(1); // inefficient?
> buffer.put((byte)c);
>
> return syswrite(new ByteList(buffer.array(),false));
> }
You aren't guarantee that buffer.array() will works all the time and on
all platform. BB.wrap will be more efficient.
Also when reading, you might want to look at the Grizzly 1.5
ByteBufferInputStream:
https://grizzly.dev.java.net/source/browse/grizzly/trunk/modules/grizzly/src/main/java/com/sun/grizzly/util/
This class uses a temporary Selector to makes sure all the available
bytes are read without the needs to register the SelectionKey back to
the original Selector.
>
>> Think ByteList class also could be improved, but probably it will
>> require interface changing...
>
> Interface changing is not a problem, if there's a more optimal way to do
> it. We do have someone currently working on making ByteList
> copy-on-write to better simulate how StringBuffer works. Some history:
> ByteList is our byte[]-based StringBuffer, since Ruby uses raw byte[] to
> represent Strings. We moved to ByteList in hopes that it would help IO
> performance to not have to encode/decode String all the time...so now
> we're looking at the IO end of things.
Grizzly 1.5 has a class called ByteChunk and CharChunk that are
recyclable (no needs to re-create them, just pool them) that wraps
byte[] and allow easy addition/subtraction. If you want to take a look,
they might be a good candidate for replacing ByteList.
>
>> As for ByteBuffer.wrap(byte[])... it can not take much time and should
>> work fast, as doesn't perform any data copying.
>
> That's good to hear, someone else had reported it could be a bottleneck,
> but I'm not seeing that in profiling.
For me ByteBuffer.wrap(byte[]) perform extremely well, but the only
problem is you create a HeapByteBuffer everytime you call wrap. Under
small load it doesn't make a difference, but with 10 000 connection, it
can possibly means 10 000 HeapBB that will pack the heap and give some
work to the GC. Are you expecting this operation to occurs frequently?
More review to comes.....:-)
Thanks
-- Jeanfrancois
>
> - Charlie