admin@glassfish.java.net

Re: CODE REVIEW: LifecycleModuleService threaded startup (but #1975)

From: Lloyd L Chambers <Lloyd.Chambers_at_Sun.COM>
Date: Tue, 16 Jan 2007 12:30:32 -0800

Please review these diffs instead, which include threading of the
onStartup() and onReady() methods, for a total reduction in startup
time of 11.5% on a dual core MacBook Pro. The modified file is also
attached.

-----------


-----------
Index: src/java/com/sun/appserv/server/LifecycleModuleService.java
===================================================================
RCS file: /cvs/glassfish/appserv-core/src/java/com/sun/appserv/server/
LifecycleModuleService.java,v
retrieving revision 1.7
diff -u -w -r1.7 LifecycleModuleService.java
--- src/java/com/sun/appserv/server/LifecycleModuleService.java 1 Dec
2006 09:55:32 -0000 1.7
+++ src/java/com/sun/appserv/server/LifecycleModuleService.java 16
Jan 2007 20:28:35 -0000
@@ -25,6 +25,7 @@
import java.util.HashSet;
import java.util.Set;
+import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
@@ -47,6 +48,10 @@
import com.sun.enterprise.server.ServerContext;
+import com.sun.appserv.management.util.misc.TimingDelta;
+import com.sun.appserv.management.util.misc.RunnableBase;
+import com.sun.appserv.management.helper.AMXDebugHelper;
+
/**
   * Support class to assist in firing LifecycleEvent notifications to
   * registered LifecycleListeners.
@@ -57,30 +62,39 @@
public class LifecycleModuleService implements ServerLifecycle {
+ private OneTimeIniter mOneTimeIniter;
+ private OneTimeStartup mOneTimeStartup;
+
+ private final AMXDebugHelper mDebug = new AMXDebugHelper
( "LifecycleModuleService" );
+ private void debug( final Object...args ) { mDebug.println
( args ); }
+
      /**
       * The set of registered LifecycleListeners for event
notifications.
       */
- private ArrayList listeners = new ArrayList();
+ private final List<ServerLifecycleModule> mLifecycleModules =
new ArrayList<ServerLifecycleModule>();

+ private final class OneTimeIniter extends RunnableBase {
+ private final ServerContext mServerContext;
- public synchronized void onInitialization(ServerContext context)
- throws
ServerLifecycleException {
+ public OneTimeIniter( final ServerContext serverContext ) {
+ mServerContext = serverContext;
+ }
- try {
+ protected void doRun() throws ConfigException,
ServerLifecycleException {
              //ROB: config changes
              //Applications apps =
- //ServerBeansFactory.getServerBean
(context.getConfigContext()).getApplications();
- Applications apps =
ServerBeansFactory.getApplicationsBean(context.getConfigContext());
+ //ServerBeansFactory.getServerBean
(mServerContext.getConfigContext()).getApplications();
+ final Applications apps =
ServerBeansFactory.getApplicationsBean(mServerContext.getConfigContext
());
              if (apps == null) return;
- LifecycleModule[] lcms = apps.getLifecycleModule();
+ final LifecycleModule[] lcms = apps.getLifecycleModule();
              if(lcms == null) return;
- HashSet listenerSet = new HashSet();
+ final Set<ServerLifecycleModule> listenerSet = new
HashSet<ServerLifecycleModule>();
              for(int i=0;i<lcms.length;i++) {
- LifecycleModule next = lcms[i];
+ final LifecycleModule next = lcms[i];

- if ( isEnabled(next, context.getConfigContext()) ) {
+ if ( isEnabled(next, mServerContext.getConfigContext
()) ) {
                      int order = Integer.MAX_VALUE;
                      String strOrder = next.getLoadOrder();
                      if (strOrder != null) {
@@ -90,14 +104,13 @@
                              nfe.printStackTrace();
                          }
                      }
- ServerLifecycleModule slcm =
- new ServerLifecycleModule(context,
- next.getName(), next.getClassName
());
+ final ServerLifecycleModule slcm =
+ new ServerLifecycleModule(mServerContext,
next.getName(), next.getClassName());
                      slcm.setLoadOrder(order);
                      slcm.setClasspath(next.getClasspath());
                      slcm.setIsFatal(next.isIsFailureFatal());

- ElementProperty[] s = next.getElementProperty();
+ final ElementProperty[] s =
next.getElementProperty();
                      if(s != null) {
                          for(int j=0;j< s.length;j++) {
                              ElementProperty next1 = s[j];
@@ -105,17 +118,55 @@
                          }
                      }
- LifecycleListener listener =
slcm.loadServerLifecycle();
+ final LifecycleListener listener =
slcm.loadServerLifecycle();
                      listenerSet.add(slcm);
                  }
              }
              sortModules(listenerSet);
- } catch(Exception ce1) {
- // FIXME eat it?
- ce1.printStackTrace();
+
+ initialize(mServerContext);
          }
+ };
+
- initialize(context);
+ private void sortModules( final Set<ServerLifecycleModule>
listenerSet) {
+ // FIXME: use a better sorting algorithm, this one is O( N^2 )
+ for( final ServerLifecycleModule next : listenerSet ) {
+ final int order = next.getLoadOrder();
+
+ int i = 0;
+ for( ; i < this.mLifecycleModules.size(); i++) {
+ if( mLifecycleModules.get(i).getLoadOrder() > order) {
+ break;
+ }
+ }
+
+ mLifecycleModules.add(i,next);
+ }
+ }
+
+ private void initialize( final ServerContext context)
+ throws ServerLifecycleException {
+ final ClassLoader cl = Thread.currentThread
().getContextClassLoader();
+ for( final ServerLifecycleModule next : mLifecycleModules ) {
+ next.onInitialization(context);
+ }
+ // set it back
+ resetClassLoader(cl);
+ }
+
+
+
+ public LifecycleModuleService() {
+ }
+
+
+ public synchronized void onInitialization( final ServerContext
context)
+ throws
ServerLifecycleException {
+ mOneTimeIniter = new OneTimeIniter( context );
+
+ mOneTimeIniter.submit( RunnableBase.SUBMIT_ASYNC );
+ // leave it running; we'll sync up with it in start()
      }
      /**
@@ -128,7 +179,6 @@
       * @return true if life cycle module is enabled
       */
      private boolean isEnabled(LifecycleModule lcm, ConfigContext
config) {
-
          try {
              // return false if arguments are null
              if (lcm == null || config == null) {
@@ -136,8 +186,8 @@
              }
              // find the ref to the life cycle module
- Server server = ServerBeansFactory.getServerBean(config);
- ApplicationRef appRef=server.getApplicationRefByRef
(lcm.getName());
+ final Server server = ServerBeansFactory.getServerBean
(config);
+ final ApplicationRef appRef=server.getApplicationRefByRef
(lcm.getName());
              // true if enabled in both lifecyle module and in the ref
              return ((lcm.isEnabled()) &&
@@ -160,84 +210,68 @@
          );
      }

- private void sortModules(HashSet listenerSet) {
- // FIXME: use a better sorting algo
- for(Iterator iter = listenerSet.iterator(); iter.hasNext();) {
- ServerLifecycleModule next = (ServerLifecycleModule)
iter.next();
- int order = next.getLoadOrder();
- int i=0;
- for(;i<this.listeners.size();i++) {
- if(((ServerLifecycleModule)listeners.get
(i)).getLoadOrder() > order) {
- break;
- }
- }
- this.listeners.add(i,next);
- }
- }
-
- private void initialize(ServerContext context)
- throws ServerLifecycleException {
-
- if (listeners.isEmpty())
- return;
+ /**
+ Note that both the onStartup() and onReady() phases
+ are performed (in sequence) by this thread.
+ */
+ private final class OneTimeStartup extends RunnableBase {
+ private final ServerContext mServerContext;
- final ClassLoader cl = Thread.currentThread
().getContextClassLoader();
- for(Iterator iter = listeners.iterator(); iter.hasNext();) {
- ServerLifecycleModule next = (ServerLifecycleModule)
iter.next();
- next.onInitialization(context);
+ public OneTimeStartup( final ServerContext serverContext ) {
+ mServerContext = serverContext;
          }
- // set it back
- resetClassLoader(cl);
- }
-
- public void onStartup(ServerContext context) throws
ServerLifecycleException {
-
- if (listeners.isEmpty())
- return;
+ protected void doRun() throws ServerLifecycleException {
          final ClassLoader cl = Thread.currentThread
().getContextClassLoader();
- for(Iterator iter = listeners.iterator(); iter.hasNext();) {
- ServerLifecycleModule next = (ServerLifecycleModule)
iter.next();
-
+ for( final ServerLifecycleModule next :
mLifecycleModules ) {
              // the SERVLET invocation context so J2EE invocations from
              // lifecycle modules get a legal ComponentInvocation.
              // create an invocation context that is of the type
              // SERVLET_INVOCATION
- Context invocationContext = new StandardContext();
+ final Context invocationContext = new StandardContext
();
- WebBundleDescriptor wbd = new WebBundleDescriptor();
+ final WebBundleDescriptor wbd = new
WebBundleDescriptor();
              Application.createApplication(next.getName(),
                  wbd.getModuleDescriptor());
              invocationContext.setRealm(new RealmAdapter(wbd, false));
- next.onStartup(context, invocationContext);
+ next.onStartup( mServerContext, invocationContext);
          }
          // set it back
          resetClassLoader(cl);
+
+ // do the onReady() phase now instead of waiting
+ for( final ServerLifecycleModule next :
mLifecycleModules ) {
+ next.onReady( mServerContext );
      }

- public void onReady(ServerContext context) throws
ServerLifecycleException {
+ resetClassLoader(cl);
+ }
+ };
- if (listeners.isEmpty())
- return;
- final ClassLoader cl = Thread.currentThread
().getContextClassLoader();
- for(Iterator iter = listeners.iterator(); iter.hasNext();) {
- ServerLifecycleModule next = (ServerLifecycleModule)
iter.next();
- next.onReady(context);
- }
- // set it back
- resetClassLoader(cl);
+ public void onStartup(ServerContext context) throws
ServerLifecycleException {
+ final TimingDelta delta = new TimingDelta();
+ // wait for initialization to finish
+ mOneTimeIniter.waitDoneThrow();
+ debug( "Millis for initer to run: ",
(mOneTimeIniter.getNanosFromSubmit() / (1000*1000)), ", wait time =
", delta.elapsedMillis() );
+ mOneTimeIniter = null;
+
+ mOneTimeStartup = new OneTimeStartup( context );
+ mOneTimeStartup.submit( RunnableBase.SUBMIT_ASYNC );
+ // we'll sync up with this thread in onReady()
      }
- public void onShutdown() throws ServerLifecycleException {
+ public void onReady(ServerContext context) throws
ServerLifecycleException {
+ mOneTimeStartup.waitDoneThrow();
+ debug( "Millis for onStartup+onReady to run: ",
(mOneTimeStartup.getNanosFromSubmit() / (1000*1000)));
+ mOneTimeStartup = null;
- if (listeners.isEmpty())
- return;
+ }
+ public void onShutdown() throws ServerLifecycleException {
          final ClassLoader cl = Thread.currentThread
().getContextClassLoader();
- for(Iterator iter = listeners.iterator(); iter.hasNext();) {
- ServerLifecycleModule next = (ServerLifecycleModule)
iter.next();
+ for( final ServerLifecycleModule next : mLifecycleModules ) {
              next.onShutdown();
          }
          // set it back
@@ -245,16 +279,16 @@
      }

      public void onTermination() throws ServerLifecycleException {
-
- if (listeners.isEmpty())
- return;
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader
();
- for(Iterator iter = listeners.iterator(); iter.hasNext();) {
- ServerLifecycleModule next = (ServerLifecycleModule)
iter.next();
+ final ClassLoader cl = Thread.currentThread
().getContextClassLoader();
+ for( final ServerLifecycleModule next : mLifecycleModules ) {
              next.onTermination();
          }
          // set it back
          resetClassLoader(cl);
      }
}
+
+
+
+
+



On Jan 16, 2007, at 11:53 AM, Lloyd L Chambers wrote:

> See: https://glassfish.dev.java.net/issues/show_bug.cgi?id=1975
>
> This change offers a reduction of 6% in startup time on my MacBook
> Pro Core 2 Duo 2.33GHz. It works by running the onInitialization
> work in a separate thread. No change in load order or
> initialization is made with respect to modules.
>
> I also need a volunteer to run QuickLook enterprise on Linux. I
> will run it on Mac OS X and Solaris.
>
> The modified file is attached, and diffs are found below.
>
> ---------------
>
> <LifecycleModuleService.java>
>
> -----------------
> cvs server: Diffing src/java/com/sun/appserv/server
> Index: src/java/com/sun/appserv/server/LifecycleModuleService.java
> ===================================================================
> RCS file: /cvs/glassfish/appserv-core/src/java/com/sun/appserv/
> server/LifecycleModuleService.java,v
> retrieving revision 1.7
> diff -u -w -r1.7 LifecycleModuleService.java
> --- src/java/com/sun/appserv/server/LifecycleModuleService.java 1
> Dec 2006 09:55:32 -0000 1.7
> +++ src/java/com/sun/appserv/server/LifecycleModuleService.java 16
> Jan 2007 19:49:06 -0000
> @@ -25,6 +25,7 @@
> import java.util.HashSet;
> import java.util.Set;
> +import java.util.List;
> import java.util.ArrayList;
> import java.util.Iterator;
> @@ -47,6 +48,10 @@
> import com.sun.enterprise.server.ServerContext;
> +import com.sun.appserv.management.util.misc.TimingDelta;
> +import com.sun.appserv.management.util.misc.RunnableBase;
> +import com.sun.appserv.management.helper.AMXDebugHelper;
> +
> /**
> * Support class to assist in firing LifecycleEvent notifications to
> * registered LifecycleListeners.
> @@ -57,30 +62,38 @@
> public class LifecycleModuleService implements ServerLifecycle {
> + private OneTimeIniter mOneTimeIniter;
> +
> + private final AMXDebugHelper mDebug = new AMXDebugHelper
> ( "LifecycleModuleService" );
> + private void debug( final Object...args ) { mDebug.println
> ( args ); }
> +
> /**
> * The set of registered LifecycleListeners for event
> notifications.
> */
> - private ArrayList listeners = new ArrayList();
> + private final List<ServerLifecycleModule> listeners = new
> ArrayList<ServerLifecycleModule>();
>
> + private final class OneTimeIniter extends RunnableBase {
> + private final ServerContext mServerContext;
> - public synchronized void onInitialization(ServerContext context)
> - throws
> ServerLifecycleException {
> + public OneTimeIniter( final ServerContext serverContext ) {
> + mServerContext = serverContext;
> + }
> - try {
> + protected void doRun() throws ConfigException,
> ServerLifecycleException {
> //ROB: config changes
> //Applications apps =
> - //ServerBeansFactory.getServerBean
> (context.getConfigContext()).getApplications();
> - Applications apps =
> ServerBeansFactory.getApplicationsBean(context.getConfigContext());
> + //ServerBeansFactory.getServerBean
> (mServerContext.getConfigContext()).getApplications();
> + final Applications apps =
> ServerBeansFactory.getApplicationsBean
> (mServerContext.getConfigContext());
> if (apps == null) return;
> - LifecycleModule[] lcms = apps.getLifecycleModule();
> + final LifecycleModule[] lcms = apps.getLifecycleModule();
> if(lcms == null) return;
> - HashSet listenerSet = new HashSet();
> + final HashSet listenerSet = new HashSet();
> for(int i=0;i<lcms.length;i++) {
> - LifecycleModule next = lcms[i];
> + final LifecycleModule next = lcms[i];
>
> - if ( isEnabled(next, context.getConfigContext()) ) {
> + if ( isEnabled(next,
> mServerContext.getConfigContext()) ) {
> int order = Integer.MAX_VALUE;
> String strOrder = next.getLoadOrder();
> if (strOrder != null) {
> @@ -90,14 +103,13 @@
> nfe.printStackTrace();
> }
> }
> - ServerLifecycleModule slcm =
> - new ServerLifecycleModule(context,
> - next.getName(),
> next.getClassName());
> + final ServerLifecycleModule slcm =
> + new ServerLifecycleModule(mServerContext,
> next.getName(), next.getClassName());
> slcm.setLoadOrder(order);
> slcm.setClasspath(next.getClasspath());
> slcm.setIsFatal(next.isIsFailureFatal());
>
> - ElementProperty[] s = next.getElementProperty();
> + final ElementProperty[] s =
> next.getElementProperty();
> if(s != null) {
> for(int j=0;j< s.length;j++) {
> ElementProperty next1 = s[j];
> @@ -105,17 +117,57 @@
> }
> }
> - LifecycleListener listener =
> slcm.loadServerLifecycle();
> + final LifecycleListener listener =
> slcm.loadServerLifecycle();
> listenerSet.add(slcm);
> }
> }
> sortModules(listenerSet);
> - } catch(Exception ce1) {
> - // FIXME eat it?
> - ce1.printStackTrace();
> +
> + initialize(mServerContext);
> + }
> + };
> +
> +
> + private void sortModules( final HashSet listenerSet) {
> + // FIXME: use a better sorting algo
> + for( final Iterator iter = listenerSet.iterator();
> iter.hasNext();) {
> + final ServerLifecycleModule next =
> (ServerLifecycleModule) iter.next();
> + final int order = next.getLoadOrder();
> + int i=0;
> + for(;i<this.listeners.size();i++) {
> + if( listeners.get(i).getLoadOrder() > order) {
> + break;
> + }
> + }
> + this.listeners.add(i,next);
> }
> + }
> +
> + private void initialize( final ServerContext context)
> + throws ServerLifecycleException {
> + if (listeners.isEmpty())
> + return;
> - initialize(context);
> + final ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> + for( final ServerLifecycleModule next : listeners ) {
> + next.onInitialization(context);
> + }
> + // set it back
> + resetClassLoader(cl);
> + }
> +
> +
> +
> + public LifecycleModuleService() {
> + }
> +
> +
> + public synchronized void onInitialization( final ServerContext
> context)
> + throws
> ServerLifecycleException {
> + mOneTimeIniter = new OneTimeIniter( context );
> +
> + mOneTimeIniter.submit( RunnableBase.SUBMIT_ASYNC );
> + // leave it running; we'll sync up with it in start()
> }
> /**
> @@ -128,7 +180,6 @@
> * @return true if life cycle module is enabled
> */
> private boolean isEnabled(LifecycleModule lcm, ConfigContext
> config) {
> -
> try {
> // return false if arguments are null
> if (lcm == null || config == null) {
> @@ -136,8 +187,8 @@
> }
> // find the ref to the life cycle module
> - Server server = ServerBeansFactory.getServerBean(config);
> - ApplicationRef appRef=server.getApplicationRefByRef
> (lcm.getName());
> + final Server server = ServerBeansFactory.getServerBean
> (config);
> + final ApplicationRef
> appRef=server.getApplicationRefByRef(lcm.getName());
> // true if enabled in both lifecyle module and in the ref
> return ((lcm.isEnabled()) &&
> @@ -159,46 +210,18 @@
> }
> );
> }
> -
> - private void sortModules(HashSet listenerSet) {
> - // FIXME: use a better sorting algo
> - for(Iterator iter = listenerSet.iterator(); iter.hasNext
> ();) {
> - ServerLifecycleModule next = (ServerLifecycleModule)
> iter.next();
> - int order = next.getLoadOrder();
> - int i=0;
> - for(;i<this.listeners.size();i++) {
> - if(((ServerLifecycleModule)listeners.get
> (i)).getLoadOrder() > order) {
> - break;
> - }
> - }
> - this.listeners.add(i,next);
> - }
> - }
> -
> - private void initialize(ServerContext context)
> - throws ServerLifecycleException {
> -
> - if (listeners.isEmpty())
> - return;
> -
> - final ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> - for(Iterator iter = listeners.iterator(); iter.hasNext();) {
> - ServerLifecycleModule next = (ServerLifecycleModule)
> iter.next();
> - next.onInitialization(context);
> - }
> - // set it back
> - resetClassLoader(cl);
> - }
> -
> public void onStartup(ServerContext context) throws
> ServerLifecycleException {
> + final TimingDelta delta = new TimingDelta();
> + // wait for initialization to finish
> + mOneTimeIniter.waitDoneThrow();
> + debug( "Millis for initer to run: ",
> (mOneTimeIniter.getNanosFromSubmit() / (1000*1000)), ", wait time =
> ", delta.elapsedMillis() );
> + mOneTimeIniter = null;
> if (listeners.isEmpty())
> return;
> final ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> - for(Iterator iter = listeners.iterator(); iter.hasNext();) {
> - ServerLifecycleModule next = (ServerLifecycleModule)
> iter.next();
> -
> + for( final ServerLifecycleModule next : listeners ) {
> // the SERVLET invocation context so J2EE invocations
> from
> // lifecycle modules get a legal ComponentInvocation.
> @@ -222,8 +245,7 @@
> return;
> final ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> - for(Iterator iter = listeners.iterator(); iter.hasNext();) {
> - ServerLifecycleModule next = (ServerLifecycleModule)
> iter.next();
> + for( final ServerLifecycleModule next : listeners ) {
> next.onReady(context);
> }
> // set it back
> @@ -236,8 +258,7 @@
> return;
> final ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> - for(Iterator iter = listeners.iterator(); iter.hasNext();) {
> - ServerLifecycleModule next = (ServerLifecycleModule)
> iter.next();
> + for( final ServerLifecycleModule next : listeners ) {
> next.onShutdown();
> }
> // set it back
> @@ -249,12 +270,16 @@
> if (listeners.isEmpty())
> return;
> - ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> - for(Iterator iter = listeners.iterator(); iter.hasNext();) {
> - ServerLifecycleModule next = (ServerLifecycleModule)
> iter.next();
> + final ClassLoader cl = Thread.currentThread
> ().getContextClassLoader();
> + for( final ServerLifecycleModule next : listeners ) {
> next.onTermination();
> }
> // set it back
> resetClassLoader(cl);
> }
> }
> +
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: admin-help_at_glassfish.dev.java.net