users@grizzly.java.net

Re: Should I use Context to store the clients references ?

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Thu, 17 Jul 2008 15:59:21 +0200

Great!!!

One more think it could make sense to improve in your code (IMHO) -
it's place, where you try to decode ByteBuffer to CharBuffer, then
check the string for [eoq]... This operation could be expensive and
not optimal.
Just, as idea, you can try to find [eoq] in the ByteBuffer directly
and make ByteBuffer -> CharBuffer conversion only if [eoq] was found.
If you didn't find [eoq] in the current ByteBuffer - you can save
current position and when next portion of data will come - start to
search for [eoq] not from beginning but from last position.

But these are just possible ways of optimization :)

Thanks.

WBR,
Alexey.

On Jul 17, 2008, at 14:23 , Survivant 00 wrote:

> thanks for your explanation.. it helped.
>
> I did return true when the buffer is full, but I still got a
> exception (buffer full) (I was able to fix that by clearing the
> buffer).
>
>
> It could be done by returning true from hasNextMessage().
> And parser's getNextMessage() method implementation should return
> some Error message, so your next filter will get it and be able to
> parse.
>
> here the changes that I made :
>
> I check if the buffer size reach the max value, and if it's YES, I
> return true. and in the function getNextMessage() I return a
> string MAX that I will evaluate in the next filter.
>
> // Check if buffer is full
> if (processingBuffer.remaining() ==
> processingBuffer.capacity()) {
> // If full - reallocate
>
> // but check if the max length is attein
> if(processingBuffer.capacity() +
> processingBuffer.remaining()<LIMITBB){
> ByteBuffer newBB =
> ByteBufferFactory.allocateView(
> processingBuffer.capacity() * 2,
> processingBuffer.isDirect());
> newBB.put(processingBuffer);
> processingBuffer = newBB;
> WorkerThread workerThread = (WorkerThread)
> Thread.currentThread();
> workerThread.setByteBuffer(processingBuffer);
> } else {
> System.out.println("BUFFER MAX ATTEIND.. LE
> CLIENT ENVOYE DE LA JUNK OU LE BUFFER EST TROP PETIT!");
>
> processingBuffer.clear();
>
> maxBufferReached = true;
>
> return maxBufferReached;
> }
> }
>
>
> public String getNextMessage() {
> //System.out.println("getNextMessage");
> if(maxBufferReached){
> return "MAX";
> }
> return query;
> }
>
>
> in the next filter in the excute(...) I add that
>
>
> public boolean execute(Context context) throws IOException {
> String query = (String)
> context.removeAttribute(ProtocolParser.MESSAGE);
>
> if(query==null || query.trim().length()==0){
> return false;
> }
>
> System.out.println("query = " + query);
>
> if(query.equals("MAX")){
> clientConnectionHandler.close(); // close the
> connection because the client issending junk
> return false;
> }
>
>
>
> now I think I have a more complete example that's actually works.
>
>
> 2008/7/17 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
> Hi,
>
> On Jul 16, 2008, at 21:14 , Survivant 00 wrote:
>
>> just one more question.
>>
>> suppose this case.
>>
>> a client go rampage.. it send invalid data for X reason..
>>
>> with the actual code, when the capacity is reach, it will create a
>> new buffer (2x size), but I want to aloid a max size.. like 20
>> 000. the default is 8192(somthing like that) I did a system,out
>> of processingbuffer.capacity
>>
>> what is the clean way to exit the parsing loop and return a state
>> or exception to the next filter ? The next filter should be able
>> to detect this error and close the client connection.
> It could be done by returning true from hasNextMessage().
> And parser's getNextMessage() method implementation should return
> some Error message, so your next filter will get it and be able to
> parse.
>
>
>> and just for my information.
>>
>> I tought the the buffer could be flush between the loop in the
>> filter. That's why I put the remaining data in the buffer into the
>> WorkerThread.
> With ParserProtocolFilter you don't need to care about ByteBuffer...
> Once isExpectingMoreData() returns true - filter will save the
> ByteBuffer and reuse it only with current connection next time.
>
>
>> but I suppose it's only when we create a new buffer (like double
>> size) right ?
>>
>> WorkerThread workerThread = (WorkerThread) Thread.currentThread();
>> workerThread.setByteBuffer(processingBuffer);
> startBuffer() method is called first, where we associate current
> Thread's ByteBuffer with parser's processingBuffer...
> So we need this:
>> WorkerThread workerThread = (WorkerThread) Thread.currentThread();
>> workerThread.setByteBuffer(processingBuffer);
>
> only, when we create new ByteBuffer.
>
> Thanks.
>
> WBR,
> Alexey.
>
>>
>>
>>
>>
>> 2008/7/16 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> Ok, once it works, I can describe the changes.
>>
>> + First of all I don't use internal buffer in the parser to store
>> temporary data there.
>> + Fixed parser logic... I know we don't have good tutorial on that
>> yet, so your blog could help
>> hasMoreBytesToParse: should return true only if one message
>> was parsed successfully, but there is still some remaining data in
>> the buffer.
>> releaseBuffer(): should compact the buffer, not clear... as
>> possibly there is some remaining. Buffer should become ready for
>> next read operation (unflipped).
>>
>>
>>>
>>> do you have a good link or documentation about the code behind the
>>> ByteBufferFactory ?
>> ByteBufferFactory is Factory class for creating ByteBuffers. It's
>> actually wrapper on top of ByteBuffer.allocate(...)/
>> allocateDirect()...
>> But it also implements ByteBuffer views functionality. It means
>> ByteBufferFactory preallocates very big ByteBuffer(4M) and then,
>> when ByteBufferFactory.allocateView(...) is called - it basically
>> doesn't allocate new buffer, but just cuts the chunk of big
>> preallocated buffer and returns this chunk.
>>
>> Seems that's it.
>>
>> Thanks.
>>
>> WBR,
>> Alexey.
>>
>>> I want to know what it's done under the hood, suppose that I want
>>> to do it in a project that doesn't use grizzly.. could be usefull
>>> to understand that.
>>>
>>> and thanks again for your help.
>>>
>>> now I'm almost ready to blog all about this.
>>>
>>>
>>> 2008/7/16 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>>> Pls. try attached version.
>>>
>>> WBR,
>>> Alexey.
>>>
>>>
>>>
>>> On Jul 16, 2008, at 15:45 , Survivant 00 wrote:
>>>
>>>> I got a exception when I send the second request
>>>>
>>>> it's really simple to reproduce
>>>>
>>>> start the main class
>>>>
>>>> GrizzlyGateway
>>>>
>>>> it will listen on the port 5000
>>>>
>>>>
>>>> open a telnet localhost 5000
>>>>
>>>> in the console.. send theses 2 requests.. One by one
>>>>
>>>> feed|aaa[eoq]
>>>> feed|bbb[eoq]
>>>>
>>>>
>>>> you will see that in the server console
>>>>
>>>>
>>>> GrizzlyGateway started
>>>> Simulate a disconnection from the 3th party
>>>> Reconnecting...
>>>> listening for incomming TCP Connections on port : 5000
>>>> query = feed|aaa
>>>> SENDING FEED TO CLIENT = [SYMBOL=[aaa] BID = 31.46111239671892|
>>>> ASK = 41.85483961272104]
>>>> SENDING FEED TO CLIENT = [SYMBOL=[aaa] BID = 19.410604221055426|
>>>> ASK = 40.98782811588009]
>>>> 2008-07-16 09:41:07 com.sun.grizzly.DefaultProtocolChain
>>>> executeProtocolFilter
>>>> GRAVE: ProtocolChain exception
>>>> java.lang.IllegalStateException: ByteBuffer is full:
>>>> java.nio.HeapByteBuffer[pos=0 lim=0 cap=8192]
>>>> at com.sun.grizzly.filter.ReadFilter.execute(ReadFilter.java:
>>>> 120)
>>>> at com.sun.grizzly.filter.ReadFilter.execute(ReadFilter.java:
>>>> 95)
>>>> at
>>>> com
>>>> .sun
>>>> .grizzly
>>>> .filter.ParserProtocolFilter.execute(ParserProtocolFilter.java:108)
>>>> at
>>>> com
>>>> .sun
>>>> .grizzly
>>>> .DefaultProtocolChain
>>>> .executeProtocolFilter(DefaultProtocolChain.java:137)
>>>> at
>>>> com
>>>> .sun
>>>> .grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:
>>>> 104)
>>>> at
>>>> com
>>>> .sun
>>>> .grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
>>>> at
>>>> com
>>>> .sun
>>>> .grizzly
>>>> .ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:67)
>>>> at
>>>> com
>>>> .sun
>>>> .grizzly
>>>> .SelectionKeyContextTask.call(SelectionKeyContextTask.java:56)
>>>> at
>>>> com.sun.grizzly.util.WorkerThreadImpl.run(WorkerThreadImpl.java:
>>>> 169)
>>>> SENDING FEED TO CLIENT = [SYMBOL=[aaa] BID = 10.932414591862527|
>>>> ASK = 25.136572649558214]
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> 2008/7/16 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>>>> Hi,
>>>>
>>>> I made some changes to the parser code - please try it.
>>>> The idea is to not use internal bytebuffer in the parser, but
>>>> reuse one from WorkerThread...
>>>> Let me know if it works, if not - please provide some unit test,
>>>> using which I can test the parser myself.
>>>>
>>>> Thank you.
>>>>
>>>> WBR,
>>>> Alexey.
>>>>
>>>>
>>>>
>>>> <
>>>> nio_quotestock_demo_v3
>>>> .zip
>>>> >
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>
>>>
>>>
>>
>>
>
>