dev@grizzly.java.net

Re: Async HTTP responses

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Fri, 28 Nov 2008 10:37:19 -0500

Salut,

Oleksiy Stashok wrote:
>>>>>>>>>
>>>>>>>>> * Output buffer.
>>>>>>>>> @@ -54,16 +65,60 @@
>>>>>>>>> * * @author Jean-Francois Arcand
>>>>>>>>> * @author Scott Oaks
>>>>>>>>> + * @author Alexey Stashok
>>>>>>>>> */
>>>>>>>>> -public class SocketChannelOutputBuffer extends
>>>>>>>>> InternalOutputBuffer{
>>>>>>>>> +public class SocketChannelOutputBuffer extends
>>>>>>>>> InternalOutputBuffer {
>>>>>>>>> + private static Logger logger = SelectorThread.logger();
>>>>>>>>> + private static final int DEFAULT_BUFFER_POOL_SIZE = 16384;
>>>>>>>>> +
>>>>>>>>> + private static int maxBufferPoolSize =
>>>>>>>>> DEFAULT_BUFFER_POOL_SIZE;
>>>>>>>>> +
>>>>>>>>> /**
>>>>>>>>> + * ByteBuffer pool to be used with async write
>>>>>>>>> + */
>>>>>>>>> + private static Queue<ByteBuffer> bufferPool =
>>>>>>>>> + new
>>>>>>>>> ArrayBlockingQueue<ByteBuffer>(maxBufferPoolSize);
>>>>>>>>
>>>>>>>> Can you instead have a pool per instance, and limit the size of
>>>>>>>> the pool based on the number of maxThreads? Take a look at AIO
>>>>>>>>
>>>>>>>> http-aio/src/main/java/com/sun/grizzly/aio/http/AsyncSocketChannelOutputBuffer.java
>>>>>>>>
>>>>>>>>
>>>>>>>> there I avoid synchronized on a single queue.
>>>>> Per instance - yes we can. It will probably improve the perf, but
>>>>> increase memory consumption, so it's trade off here.
>>>>
>>>> Why would it? The idea is to have:
>>>>
>>>> size per instance * instance_number == overall size
>>>>
>>>> Right now you have overall_size shared amongst all instance.
>>> But we don't create the ByteBuffers at startup. We add them by
>>> demand. And shared pool will grow slower than pool per instance. So
>>> memory consumption will be less.
>>
>> Hum ;-) I'm not sure I agree :-) Eventually you will reach the max
>> memory anyway.
> That's right. What I'm saying, is that pool per instance is less
> economic than global one and it will reach the maximum much faster than
> global pool.

It is hard to say who is right without numbers...so I might be wrong :-)

>
>> Plus you need to sync on the 'global' cache ;-) All threads will
>> eventually dead ends there, trying to get one ByteBuffer.
> Well they will not dead. But for sure synchronization cost should be paid.
>
> One more thing is that ProcessorTask count is not directly dependent on
> the number of worker threads.

The number of ProcessorTask must be the same as WorkerThread. The logic
there might be confusing (some left over from 1.0). Only when ARP is
enabled that there is more ProcessorTask than WorkerThread.

The processor task pool represents
> unbounded linked queue. In this case It means we can not control the
> real amount of pooled buffers.
>
> Basically I agree with you, that pool per instance will perform faster,
> because less threads will be synchronized on it, but the idea looks
> dangerous for me.
>
> We can use concurrent linked queue as 'global' ByteBuffer cache, instead
> of BlockingQueue. ConcurrentLinkedQueue is not synchronized (thread safe
> though). And we can control the size of this pool with weak (non
> synchronized) checking, which means the limits will not be strictly
> honored. And pool could get larger than max-size. Actually the real
> limit for this queue with weak checking will be max-size +
> worker-threads-number.
>
> What do you think?

I think that's a pretty good trade off. +1

Thanks!

-- Jeanfrancois


>
> Thanks.
>
> WBR,
> Alexey.
>
>> At least this is what I've measured with AIO ;-)
>>
>> :-)
>>
>> -- Jeanfrancois
>>
>>
>>>>> As for limit size, based on max threads number - not sure it's
>>>>> right solution. These values are completely independent, or I
>>>>> missed something?
>>>>>>>>> + }
>>>>>>>>> +
>>>>>>>>> + + /**
>>>>>>>>> + * Sets the underlying selection key of the output channel.
>>>>>>>>> + * @param selectionKey the underlying selection key of the
>>>>>>>>> output channel.
>>>>>>>>> + */
>>>>>>>>> + public void setSelectionKey(SelectionKey selectionKey) {
>>>>>>>>> + this.selectionKey = selectionKey;
>>>>>>>>> + channel = selectionKey.channel();
>>>>>>>>> + }
>>>>>>>>
>>>>>>>> setChannel() is always invoked by DefaultProcessorTask
>>>>> Now it invokes setSelectionKey(), cause we need it for async write.
>>>>>>>>>
>>>>>>>>> }
>>>>>>>>> @@ -278,4 +507,20 @@
>>>>>>>>> public static void setMaxBufferedBytes(int aMaxBufferedBytes) {
>>>>>>>>> maxBufferedBytes = aMaxBufferedBytes;
>>>>>>>>> }
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> + public static void setMaxBufferPoolSize(int size) {
>>>>>>>>> + int poolSize = (size >= 0) ? size :
>>>>>>>>> DEFAULT_BUFFER_POOL_SIZE;
>>>>>>>>> +
>>>>>>>>> + if (maxBufferPoolSize == poolSize) return;
>>>>>>>>> + + maxBufferPoolSize = poolSize;
>>>>>>>>> +
>>>>>>>>> + bufferPool = new
>>>>>>>>> ArrayBlockingQueue<ByteBuffer>(maxBufferPoolSize);
>>>>>>>>> }
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Hum I don't like set method that does works :-) Can we change
>>>>>>>> the name to ajustMaxBufferPoolSize()?
>>>>> Hmm, and what is the difference? :))
>>>>
>>>> just working. Usually when invoking setXXX, you just the value
>>>> without logic. Just cosmetics
>>> ok.
>>> Thanks.
>>> WBR,
>>> Alexey.
>>>>
>>>>
>>>> A+
>>>>
>>>> -- Jeanfrancois
>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>