dev@grizzly.java.net

SVN diff of changes for the Grizzly - JRuby Contrib part

From: Pramod Gopinath <Pramod.Gopinath_at_Sun.COM>
Date: Wed, 12 Mar 2008 18:23:56 -0700

Hi
  Changes that are specific for the grizzly -jruby contrib part.

The changes that are listed below deal with the following :

The current code was reading the dispatcher.rb script and parsing the
script on every request. This was having the impact on the performance.
In the current changes, based on suggestion from Thomas Enebo (of the
JRuby team), have ensured that we do this activity once during the
creation of the runtime. Once the object is created am saving it into
the runtime, so that we could reuse this for each request.

1. RubyObjectPool : Moved the reading of the dispatch.rb code here and
save the object into the runtime.
                                  Have changed the code to block on the
pool. This is a temporary change until JFA adds the suspend/resume of
request code to v3.
2. RailsSelectorThread : Set the webappRootPath to railsRoot + "/public"
to ensure that static content is found from the correct location
3. RailsAdapter : Changes to reflect the reuse of the responder object
from the runtime.
4. dispatch.rb : Defined a Grizzlet class for the code. This could
would get gitted by JRuby 1.1RC2+ versions.

Thanks
Pramod




Property changes on: .
___________________________________________________________________
Name: svn:ignore
   + target


Index: src/main/java/com/sun/grizzly/jruby/RubyObjectPool.java
===================================================================
--- src/main/java/com/sun/grizzly/jruby/RubyObjectPool.java (revision 889)
+++ src/main/java/com/sun/grizzly/jruby/RubyObjectPool.java (working copy)
@@ -24,6 +24,9 @@
 
 import com.sun.grizzly.http.SelectorThread;
 
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ExecutorService;
@@ -34,17 +37,19 @@
 
 import org.jruby.Ruby;
 import org.jruby.javasupport.JavaEmbedUtils;
+import org.jruby.runtime.builtin.IRubyObject;
 import org.jruby.runtime.load.LoadService;
 
 /**
  * An object pool for ruby runtime.
  *
  * @author TAKAI Naoto
+ * @author Pramod Gopinath
  */
 public class RubyObjectPool {
 
     /** How long to wait before given up. */
- private static long DEFAULT_TIMEOUT = 1000L;
+ private static long DEFAULT_TIMEOUT = 360L;
 
     /** JRUBY_LIB directory */
     private String jrubyLib = null;
@@ -70,9 +75,9 @@
      * @return JRuby runtime.
      */
     public Ruby borrowRuntime() {
- if (!isAsyncEnabled()){
+ if (isAsyncEnabled()){
             try {
- return queue.poll(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ return queue.poll(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
@@ -136,8 +141,7 @@
                 exec.execute(new Runnable(){
                     public void run() {
                         long startTime = System.currentTimeMillis();
- Ruby runtime = initializeRubyRuntime();
- loadRubyLibraries(runtime);
+ Ruby runtime = createRubyRuntimeInstance();
                         SelectorThread.logger().log(Level.INFO,
                             "Rails instance instantiation took : " +
                             (System.currentTimeMillis() - startTime) + "ms");
@@ -162,8 +166,22 @@
         queue.clear();
     }
 
+ private Ruby createRubyRuntimeInstance() {
+ Ruby runtime = initializeRubyRuntime();
+ loadRubyLibraries(runtime);
+
+// IRubyObject loggerObj = JavaEmbedUtils.javaToRuby(runtime, SelectorThread.logger());
+// runtime.defineReadonlyVariable("$logger", loggerObj);
+
+ IRubyObject responder = (JavaEmbedUtils.newRuntimeAdapter()).eval(runtime, getDispatcherString());
+ runtime.defineReadonlyVariable("$responder", responder);
+
+ return runtime;
+ }
+
     protected Ruby initializeRubyRuntime() {
         ArrayList<String> libs = new ArrayList<String>();
+// libs.add(railsRoot);
         libs.add("META-INF/jruby.home/lib/ruby/site_ruby/1.8");
         return JavaEmbedUtils.initialize(libs);
     }
@@ -172,7 +190,9 @@
         LoadService loadService = runtime.getLoadService();
 
         // load rails
- loadService.require(railsRoot + "/config/environment.rb");
+ loadService.require(railsRoot + "/config/environment");
+ loadService.require("cgi/force_nph");
+ loadService.require("dispatcher");
     }
 
     /**
@@ -213,4 +233,24 @@
     public void setAsyncEnabled(boolean asyncEnabled) {
         this.asyncEnabled = asyncEnabled;
     }
+
+
+ private String getDispatcherString() {
+ String str;
+ StringBuffer completeText = new StringBuffer();
+ try {
+ InputStream is = getClass().getResourceAsStream("/dispatch.rb");
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ str = br.readLine();
+ while (str != null) {
+ completeText.append(str + "\n");
+ str = br.readLine();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return completeText.toString();
+ }
+
 }
Index: src/main/java/com/sun/grizzly/jruby/RailsSelectorThread.java
===================================================================
--- src/main/java/com/sun/grizzly/jruby/RailsSelectorThread.java (revision 889)
+++ src/main/java/com/sun/grizzly/jruby/RailsSelectorThread.java (working copy)
@@ -33,6 +33,7 @@
  * JRuby on rails implementation of Grizzly SelectorThread
  * @author TAKAI Naoto
  * @author Jeanfrancois Arcand
+ * @author Pramod Gopinath
  */
 public class RailsSelectorThread extends SelectorThread {
     
@@ -55,7 +56,7 @@
     public void initEndpoint() throws IOException, InstantiationException {
         setupSystemProperties();
         initializeRubyRuntime();
-
+ setWebAppRootPath(railsRoot + "/public");
         setBufferResponse(false);
         
         asyncExecution = true;
Index: src/main/java/com/sun/grizzly/jruby/RailsAdapter.java
===================================================================
--- src/main/java/com/sun/grizzly/jruby/RailsAdapter.java (revision 889)
+++ src/main/java/com/sun/grizzly/jruby/RailsAdapter.java (working copy)
@@ -22,10 +22,6 @@
  */
 package com.sun.grizzly.jruby;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.util.Map;
 
@@ -33,18 +29,17 @@
 import org.jruby.RubyException;
 import org.jruby.RubyIO;
 import org.jruby.RubyHash;
-import org.jruby.ast.Node;
 import org.jruby.exceptions.RaiseException;
 import org.jruby.javasupport.JavaEmbedUtils;
-import org.jruby.runtime.DynamicScope;
 import org.jruby.runtime.builtin.IRubyObject;
 
 import com.sun.grizzly.http.SelectorThread;
-import com.sun.grizzly.standalone.DynamicContentAdapter;
+import com.sun.grizzly.tcp.DynamicContentAdapter;
 import com.sun.grizzly.tcp.Adapter;
 import com.sun.grizzly.tcp.Request;
 import com.sun.grizzly.tcp.Response;
 import com.sun.grizzly.tcp.http11.InternalOutputBuffer;
+import java.io.IOException;
 import java.util.HashMap;
 
 /**
@@ -52,6 +47,7 @@
  *
  * @author TAKAI Naoto
  * @author Jean-Francois Arcand
+ * @author Pramod Gopinath
  */
 public class RailsAdapter extends DynamicContentAdapter
         implements Adapter{
@@ -64,7 +60,7 @@
     private Map environment;
     
     public RailsAdapter( RubyObjectPool pool) {
- super(pool.getRailsRoot() + "/public");
+ super(pool.getRailsRoot() + "public");
         this.pool = pool;
         
     }
@@ -93,45 +89,52 @@
                 throw new IllegalStateException(
                     "No Rails Instances available to satisfy the current request");
             }
- loadRuntimeEnvironment(runtime, res, rt);
- (JavaEmbedUtils.newRuntimeAdapter()).eval(runtime, getDispatcherString());
- } catch (RaiseException e) {
- RubyException exception = e.getException();
-
- System.err.println(e.getMessage());
- exception.printBacktrace(System.err);
-
- throw e;
+ dispatchRailsRequest(runtime, res, rt);
         } finally {
             rt.recycle();
             req.setNote(RAILS_TOKEN,rt);
             if (runtime != null) {
                 pool.returnRuntime(runtime);
- asyncFilter.resume();
+ if (asyncFilter != null) {
+ asyncFilter.resume();
+ }
             }
         }
     }
     
- private String getDispatcherString() {
- String str;
- StringBuffer completeText = new StringBuffer();
+ private void dispatchRailsRequest(Ruby runtime, Response res,
+ DynamicContentAdapter.RequestTupple rt) throws IOException {
         try {
- InputStream is = getClass().getResourceAsStream("/dispatch.rb");
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- str = br.readLine();
- while (str != null) {
- completeText.append(str + "\n");
- str = br.readLine();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
+ Request req = rt.req;
+ req.doRead(rt.readChunk);
 
- return completeText.toString();
+ ((InternalOutputBuffer)res.getOutputBuffer()).commit();
+ res.setCommitted(true);
+
+ RubyIO iObj = new RubyIO(runtime, rt.inputStream);
+ runtime.defineReadonlyVariable("$stdin", iObj);
+
+ OutputStream os =
+ ((InternalOutputBuffer)res.getOutputBuffer()).getOutputStream();
+ RubyIO oObj = new RubyIO(runtime, os);
+ runtime.defineReadonlyVariable("$stdout", oObj);
+
+ loadRuntimeEnvironment(runtime);
+
+ IRubyObject[] args = {JavaEmbedUtils.javaToRuby(runtime, req)};
+ IRubyObject responder = runtime.getGlobalVariables().get("$responder");
+ JavaEmbedUtils.invokeMethod(runtime, responder, "service", args, IRubyObject.class);
+ } catch (RaiseException e) {
+ RubyException exception = e.getException();
+
+ System.err.println(e.getMessage());
+ exception.printBacktrace(System.err);
+
+ throw e;
+ }
     }
 
- private void loadRuntimeEnvironment(Ruby runtime, Response res,
- DynamicContentAdapter.RequestTupple rt) {
+ private void loadRuntimeEnvironment(Ruby runtime) {
         RubyHash env = (RubyHash) runtime.getObject().getConstant("ENV");
         if (environment == null) {
             IRubyObject loggerObj = JavaEmbedUtils.javaToRuby(runtime, SelectorThread.logger());
@@ -148,27 +151,6 @@
             env.clear();
             env.putAll(environment);
         }
-
- try {
- RubyIO iObj = new RubyIO(runtime, rt.inputStream);
- runtime.defineReadonlyVariable("$stdin", iObj);
-
- ((InternalOutputBuffer)res.getOutputBuffer()).commit();
- res.setCommitted(true);
-
- Request req = rt.req;
- req.doRead(rt.readChunk);
- IRubyObject reqObj = JavaEmbedUtils.javaToRuby(runtime, req);
- runtime.defineReadonlyVariable("$req", reqObj);
-
- OutputStream os =
- ((InternalOutputBuffer)res.getOutputBuffer()).getOutputStream();
- RubyIO oObj = new RubyIO(runtime, os);
- runtime.defineReadonlyVariable("$stdout", oObj);
- } catch (java.io.IOException e) {
- System.err.println(e.getMessage());
- e.printStackTrace(System.err);
- }
     }
 
 }
Index: src/main/resources/dispatch.rb
===================================================================
--- src/main/resources/dispatch.rb (revision 889)
+++ src/main/resources/dispatch.rb (working copy)
@@ -20,45 +20,47 @@
 #
 # Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 #
-require 'cgi/force_nph'
+class Grizzlet
+ def service(req)
+ info = req.getRequestProcessor()
+ request_uri = req.requestURI.to_s
+ headers = req.getMimeHeaders()
 
-info = $req.getRequestProcessor()
+ # RFC3875 The Common Gateway Interface (CGI) Version 1.1
+ #ENV['AUTH_TYPE'] = req.getAuthType().to_s
+ ENV['CONTENT_LENGTH'] = info.getContentLength().to_s
+ ENV['CONTENT_TYPE'] = req.getContentType()
 
-request_uri = $req.requestURI.to_s
-headers = $req.getMimeHeaders()
+ ENV['GATEWAY_INTERFACE'] = 'CGI/1.1'
+ ENV['PATH_INFO'] = request_uri
+ ENV['PATH_TRANSLATED'] = request_uri.split('?', 2).first
+ ENV['QUERY_STRING'] = req.queryString().to_s
+ ENV['REMOTE_ADDR'] = info.getRemoteAddr()
+ ENV['REMOTE_HOST'] = req.remoteHost().to_s
+ ENV['REMOTE_USER'] = req.getRemoteUser().to_s
 
-# RFC3875 The Common Gateway Interface (CGI) Version 1.1
-#ENV['AUTH_TYPE'] = $req.getAuthType().to_s
-ENV['CONTENT_LENGTH'] = info.getContentLength().to_s
-ENV['CONTENT_TYPE'] = $req.getContentType()
+ ENV['REQUEST_METHOD'] = info.getMethod()
+ ENV['SCRIPT_NAME'] = ''
 
-ENV['GATEWAY_INTERFACE'] = 'CGI/1.1'
-ENV['PATH_INFO'] = request_uri
-ENV['PATH_TRANSLATED'] = request_uri.split('?', 2).first
-ENV['QUERY_STRING'] = $req.queryString().to_s
-ENV['REMOTE_ADDR'] = info.getRemoteAddr()
-ENV['REMOTE_HOST'] = $req.remoteHost().to_s
-ENV['REMOTE_USER'] = $req.getRemoteUser().to_s
+ ENV['SERVER_NAME'] = req.serverName().to_s
+ ENV['SERVER_PORT'] = req.getServerPort().to_s
+ ENV['SERVER_PROTOCOL'] = req.protocol().to_s
+ ENV['SERVER_SOFTWARE'] = 'Grizzly/1.7'
+ ENV['REQUEST_URI'] = request_uri
 
-ENV['REQUEST_METHOD'] = info.getMethod()
-ENV['SCRIPT_NAME'] = ''
+ for i in 0 ... headers.size
+ name = headers.getName(i).to_s
+ value = headers.getValue(i).to_s
+ ENV['HTTP_' + name.upcase.tr('-','_')] = value
+ end
 
-ENV['SERVER_NAME'] = $req.serverName().to_s
-ENV['SERVER_PORT'] = $req.getServerPort().to_s
-ENV['SERVER_PROTOCOL'] = $req.protocol().to_s
-ENV['SERVER_SOFTWARE'] = 'Grizzly/1.7'
-ENV['REQUEST_URI'] = request_uri
+ if !$root.nil?
+ ActionController::AbstractRequest.relative_url_root = $root
+ ActionController::CgiRequest.relative_url_root = $root
+ end
 
-for i in 0 ... headers.size
- name = headers.getName(i).to_s
- value = headers.getValue(i).to_s
- ENV['HTTP_' + name.upcase.tr('-','_')] = value
+ Dispatcher.dispatch
+ end
 end
 
-if !$root.nil?
- ActionController::AbstractRequest.relative_url_root = $root
- ActionController::CgiRequest.relative_url_root = $root
-end
-require "dispatcher"
-
-Dispatcher.dispatch
+Grizzlet.new