Jerome Louvel <jerome.louvel <at> noelios.com> writes:

> 
> 
> Hi Bruce,
> 
> Great news! 
> 
> Regarding the 40s delay I'm puzzled... Did you monitor the state of sockets?
> Are they all closed in a timely manner? 
> 
> Did you try using a profiler to detect which part of the code actually
> causes the delay?
> 
> Best regards,
> Jérôme Louvel
> --
> Restlet ~ Founder and Lead developer ~ http://www.restlet.org
> Noelios Technologies ~ Co-founder ~ http://www.noelios.com
> 

Hi Jerome,

Sorry I finally got some time to dig into this problem again and I think I've
found the cause of the round time delay.

In the ByteUtils, there's a SelectorFactory which is used when NIO
selectablechannel is used. Notice that the factory limits the total number of
active selectors to 20, and if the pool ever runs empty, it'll wait maximum of 2
periods of timeout before giving up. So the blocking we are seeing is coming
from this piece of code. (10s, 20s, 30s etc..)

The fix is relatively simple, since the selector (and selectionKey) is only
acquired in the NbChannelOutputStream when the channel is not available, the
code should release the selector at the finally block of the doWrite method
instead of waiting for the channel.close(). This will ensure that the limited
number of selector is never kept for a long period of time.

Ex:
} finally {
        this.bb.clear();
        release(this.selector, this.selectionKey);
}

With this piece of code change, I was able to run the following test code with
100 burst request at the same time without any problem.

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.restlet.Component;
import org.restlet.Restlet;
import org.restlet.data.MediaType;
import org.restlet.data.Protocol;
import org.restlet.data.Request;
import org.restlet.data.Response;

public class Test2 {

        private static Component component = new Component();

        public static void main(String[] args) throws Exception {

                // Create a new Restlet component and add a HTTP server
                // connector to it
                component.getServers().add(Protocol.HTTP, 1234);

                // Print the requested URI path
                StringBuffer message = new StringBuffer();
                // setup a response with 80k
                int size = 80000;
                char c = 'c';
                for (int i = 0; i < size; i++) {
                        message.append(c);
                }
                final String s = message.toString();
                
                // Create a new tracing Restlet
                Restlet restlet = new Restlet() {                       
                        @Override
                        public void handle(Request request, Response response) {
                                response.setEntity(s, MediaType.TEXT_PLAIN);
                        }
                };

                // Then attach it to the local host
                component.getDefaultHost().attach("/", restlet);

                // Now, let's start the component!
                // Note that the HTTP server connector is also automatically
                // started.
                component.start();

                BufferedReader in = null;
                String line;
                in = new BufferedReader(new InputStreamReader(System.in));
                while (true) {
                        System.out.print("> ");
                        System.out.flush();
                        line = in.readLine();
                        if (line.startsWith("quit") || line.startsWith("exit")) 
{
                                // quits the test client
                                break;
                        }
                }

                component.stop();
        }

}

Regards,

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1274115

Reply via email to