You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by di...@apache.org on 2001/03/01 16:45:40 UTC

cvs commit: xml-cocoon/src/org/apache/cocoon/util ComponentPool.java

dims        01/03/01 07:45:39

  Modified:    src/org/apache/cocoon Tag: xml-cocoon2
                        CocoonComponentSelector.java
               src/org/apache/cocoon/components/language/generator Tag:
                        xml-cocoon2 ProgramGeneratorImpl.java
               src/org/apache/cocoon/util Tag: xml-cocoon2
                        ComponentPool.java
  Log:
  1. A slightly better ComponentPool implementation till the Avalon guys come up
     with a better one. Does not impose any resource limit right now, expands the
     pool but does not shrink it.
  2. Remove leaks in Life-Cycle for XSPGenerator components.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.25  +4 -1      xml-cocoon/src/org/apache/cocoon/Attic/CocoonComponentSelector.java
  
  Index: CocoonComponentSelector.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon/src/org/apache/cocoon/Attic/CocoonComponentSelector.java,v
  retrieving revision 1.1.2.24
  retrieving revision 1.1.2.25
  diff -u -r1.1.2.24 -r1.1.2.25
  --- CocoonComponentSelector.java	2001/02/28 17:40:24	1.1.2.24
  +++ CocoonComponentSelector.java	2001/03/01 15:45:26	1.1.2.25
  @@ -43,7 +43,7 @@
   /** Default component manager for Cocoon's non sitemap components.
    * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
    * @author <a href="mailto:paul@luminas.co.uk">Paul Russell</a>
  - * @version CVS $Revision: 1.1.2.24 $ $Date: 2001/02/28 17:40:24 $
  + * @version CVS $Revision: 1.1.2.25 $ $Date: 2001/03/01 15:45:26 $
    */
   public class CocoonComponentSelector implements Contextualizable, ComponentSelector, Composer, Configurable, ThreadSafe, Loggable {
       protected Logger log;
  @@ -225,6 +225,7 @@
   
           if ( pool == null ) {
               try {
  +                log.debug("Creating new pool for:" + componentClass);
                   ComponentFactory cf = new ComponentFactory(componentClass, (Configuration)configurations.get(hint), this.manager, this.context);
                   cf.setLogger(this.log);
   
  @@ -263,6 +264,8 @@
   
               if (pool != null) {
                   pool.put((Poolable) component);
  +            } else {
  +                log.debug("Could not find pool for:" + component.getClass());
               }
           } else if (component instanceof Recyclable) {
               ((Recyclable) component).recycle();
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.38  +20 -7     xml-cocoon/src/org/apache/cocoon/components/language/generator/Attic/ProgramGeneratorImpl.java
  
  Index: ProgramGeneratorImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon/src/org/apache/cocoon/components/language/generator/Attic/ProgramGeneratorImpl.java,v
  retrieving revision 1.1.2.37
  retrieving revision 1.1.2.38
  diff -u -r1.1.2.37 -r1.1.2.38
  --- ProgramGeneratorImpl.java	2001/02/22 19:07:41	1.1.2.37
  +++ ProgramGeneratorImpl.java	2001/03/01 15:45:33	1.1.2.38
  @@ -46,7 +46,7 @@
   /**
    * The default implementation of <code>ProgramGenerator</code>
    * @author <a href="mailto:ricardo@apache.org">Ricardo Rocha</a>
  - * @version CVS $Revision: 1.1.2.37 $ $Date: 2001/02/22 19:07:41 $
  + * @version CVS $Revision: 1.1.2.38 $ $Date: 2001/03/01 15:45:33 $
    */
   public class ProgramGeneratorImpl extends AbstractLoggable implements ProgramGenerator, Contextualizable, Composer, Configurable, ThreadSafe {
   
  @@ -152,7 +152,7 @@
   
           // Attempt to load program object from cache
           try {
  -            programInstance = (CompiledComponent) this.cache.select(normalizedName);
  +            programInstance = (CompiledComponent) select(normalizedName);
           } catch (Exception e) {
               getLogger().debug("The instance was not accessible, creating it now.");
           }
  @@ -165,7 +165,7 @@
               }
   
               try {
  -                programInstance = (CompiledComponent) this.cache.select(normalizedName);
  +                programInstance = (CompiledComponent) select(normalizedName);
               } catch (Exception cme) {
                   getLogger().debug("Can't load ServerPage", cme);
               }
  @@ -183,22 +183,29 @@
            */
   
           if (programInstance != null && programInstance.modifiedSince(file.lastModified())) {
  +            // Release the component.            
  +            release(programInstance);
  +
               // Unload program
               programmingLanguage.unload(program, normalizedName, this.workDir);
  +            
               // Invalidate previous program/instance pair
               program = null;
               programInstance = null;
           }
   
           if (programInstance == null) {
  -            program = generateResource(file, normalizedName, markupLanguage, programmingLanguage, resolver);
  +            if (program == null) {
  +                program = generateResource(file, normalizedName, markupLanguage, programmingLanguage, resolver);
  +            }
  +            // Instantiate
  +            programInstance = (CompiledComponent) select(normalizedName);
           }
   
           this.markupSelector.release((Component) markupLanguage);
           this.languageSelector.release((Component) programmingLanguage);
   
  -        // Instantiate
  -        return (CompiledComponent) this.cache.select(normalizedName);
  +        return programInstance;
       }
   
       private Class generateResource(File file,
  @@ -227,7 +234,7 @@
   
           if (markupLanguage.getClass().getName().equals(SitemapMarkupLanguage.class.getName())) {
               try {
  -                this.cache.select("sitemap");
  +                select("sitemap");
               } catch (Exception e) {
                   // If the root sitemap has not been compiled, add an alias here.
                   this.cache.addGenerator("sitemap", program);
  @@ -235,6 +242,12 @@
           }
   
           return program;
  +    }
  +
  +    public CompiledComponent select(String componentName) 
  +        throws Exception {
  +        CompiledComponent component = (CompiledComponent)this.cache.select(componentName);
  +        return component;
       }
   
       public void release(CompiledComponent component) {
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.10  +240 -6    xml-cocoon/src/org/apache/cocoon/util/Attic/ComponentPool.java
  
  Index: ComponentPool.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon/src/org/apache/cocoon/util/Attic/ComponentPool.java,v
  retrieving revision 1.1.2.9
  retrieving revision 1.1.2.10
  diff -u -r1.1.2.9 -r1.1.2.10
  --- ComponentPool.java	2001/02/28 17:40:29	1.1.2.9
  +++ ComponentPool.java	2001/03/01 15:45:37	1.1.2.10
  @@ -7,12 +7,14 @@
    */
   package org.apache.cocoon.util;
   
  +import java.util.Vector;
  +
   import org.apache.avalon.Poolable;
   import org.apache.avalon.ThreadSafe;
   import org.apache.avalon.Loggable;
  -import org.apache.avalon.util.pool.ThreadSafePool;
  +import org.apache.avalon.util.pool.Pool;
   import org.apache.avalon.util.pool.ObjectFactory;
  -import org.apache.avalon.util.pool.PoolController;
  +import org.apache.avalon.Recyclable;
   import org.apache.cocoon.ComponentFactory;
   
   import org.apache.log.Logger;
  @@ -23,30 +25,262 @@
    *
    * @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a>
    */
  -public class ComponentPool extends ThreadSafePool implements ThreadSafe, Loggable {
  +public class ComponentPool implements Pool, ThreadSafe, Loggable {
   
       public final static int DEFAULT_POOL_SIZE = 8;
   
  +    public final static int DEFAULT_WAIT_TIME = (5*100);
  +
       private Logger log;
   
  +    /** The resources that are currently free */
  +	protected Vector availableResources;
  +
  +    /** Resources that have been allocated out of the pool */
  +	protected Vector usedResources;
  +
  +    /** Flag to make sure at least one thread has received notification */
  +	boolean receivedWakeup;
  +
  +    /** The number of threads waiting for notification */
  +	int numThreadsWaiting;
  +
  +    protected ObjectFactory m_factory = null;
  +
  +    protected int m_initial = DEFAULT_POOL_SIZE/2;
  +
  +    protected int m_maximum = DEFAULT_POOL_SIZE;
  +
       public ComponentPool(final ObjectFactory factory) throws Exception {
  -        super(factory, DEFAULT_POOL_SIZE/2, DEFAULT_POOL_SIZE);
  +        init(factory, DEFAULT_POOL_SIZE/2, DEFAULT_POOL_SIZE);
       }
   
       public ComponentPool(final ObjectFactory factory,
                            final int initial) throws Exception {
  -        super(factory, initial, initial);
  +        init(factory, initial, initial);
       }
   
       public ComponentPool(final ObjectFactory factory,
                            final int initial,
                            final int maximum) throws Exception {
  -        super(factory, initial, maximum);
  +        init(factory, initial, maximum);
       }
   
  +    private void init(final ObjectFactory factory, 
  +                      final int initial, 
  +                      final int maximum) throws Exception {
  +        m_factory = factory;
  +        m_initial = initial;
  +        m_maximum = maximum;
  +    }
  +
  +    public void init() throws Exception {
  +		availableResources = new Vector();
  +		usedResources = new Vector();
  +		receivedWakeup = true;
  +		numThreadsWaiting = 0;
  +
  +        for( int i = 0; i < m_initial; i++ )
  +            availableResources.addElement(m_factory.newInstance());
  +    }
  +
       public void setLogger(Logger log) {
           if (this.log == null) {
               this.log = log;
           }
       }
  +
  +    /** Allocates a resource when the pool is empty. By default, this method
  +     *	returns null, indicating that the requesting thread must wait. This
  +     *	allows a thread pool to expand when necessary, allowing for spikes in
  +     *	activity.
  +     *	@return A new resource, or null to force the requester to wait
  +     */ 
  +	protected synchronized Poolable getOverflowResource()
  +        throws Exception
  +	{
  +		Poolable poolable = m_factory.newInstance();
  +        log.debug("Component Pool - creating Overflow Resource:" 
  +                        + " Resource=" + poolable
  +                        + " Available=" + availableResources.size()
  +                        + " Used=" + usedResources.size() );
  +        return poolable;
  +	}
  +
  +    /** Grabs a resource from the free list and moves it to the used list.
  +     * This method is really the core of the resource pool. The rest of the class
  +     * deals with synchronization around this method.
  +     * @return The allocated resource
  +     */
  +	protected synchronized Poolable getResourceFromList()
  +	{
  +        // See if there is a resource available.
  +		if (availableResources.size() > 0) {
  +
  +            // Get the first resource from the free list
  +			Poolable resource = (Poolable) availableResources.elementAt(0);
  +
  +            // Remove the resource from the free list
  +	   	    availableResources.removeElement(resource);
  +
  +            // Add the resource and its associated info to the used list
  +			usedResources.addElement(resource);
  +
  +			return resource;
  +		}
  +
  +		return null;
  +	}
  +
  +    /** Performs a wait for a specified number of milliseconds.
  +     * @param timeout The number of milliseconds to wait
  +     * (wait forever if timeout < 0)
  +     */
  +	protected synchronized void doWait(long timeout)
  +	{
  +		try {
  +			if (timeout < 0) {
  +				wait();
  +			}
  +			else {
  +				wait(timeout);
  +			}
  +		}
  +		catch (Exception ignore) {
  +		}
  +	}
  +
  +    /** Requests a resource from the pool, waiting forever if one is not available.
  +     * No extra information is associated with the allocated resource.
  +     * @return The allocated resource
  +     */
  +	public Poolable get()
  +        throws Exception
  +	{
  +		return get(DEFAULT_WAIT_TIME);
  +	}
  +
  +    /** Requests a resource from the pool, waiting forever if one is not available.
  +     * @param timeout The maximum amount of time (in milliseconds)
  +     * to wait for the resource
  +     * @return The allocated resource
  +     */
  +	public Poolable get(long timeout) 
  +        throws Exception
  +	{
  +        // See if there is a resource in the pool already
  +		Poolable resource = getResourceFromList();
  +		if (resource != null)
  +		{
  +			return resource;
  +		}
  +
  +        // Figure out when to stop waiting
  +		long endTime = System.currentTimeMillis() + timeout;
  +
  +		do {
  +
  +			synchronized(this) {
  +                // See if there are any available resources in the pool
  +				if (availableResources.size() == 0) {
  +
  +                    // Allow subclasses to provide overflow resources
  +		   	 	    resource = getOverflowResource();
  +
  +                    // If there was a resource allocated for overflow, add it to the used list
  +			   	    if (resource != null) {
  +				        usedResources.addElement(resource);
  +       	 	  	        return resource;
  +		   		    }
  +				}
  +			}
  +
  +            // Wait for a resource to be allocated
  +
  +            // Figure out the longest time to wait before timing out
  +			long maxWait = endTime - System.currentTimeMillis();
  +			if (timeout < 0) maxWait = -1;
  +
  +            // Indicate that there is a thread waiting for a wakeup
  +			numThreadsWaiting++;
  +
  +            // Wait for a wakeup
  +			doWait(maxWait);
  +
  +			numThreadsWaiting--;
  +
  +            // Only mention the received wakeup if the timeout hasn't expired
  +			if ((timeout < 0) || (System.currentTimeMillis() < maxWait)) {
  +				receivedWakeup = true;
  +			}
  +
  +            // See if there is now a resource in the free pool
  +	   	    resource = getResourceFromList();
  +		    if (resource != null)
  +			{
  +				return resource;
  +	   	    }
  +
  +            // Keep looping while the timeout hasn't expired (loop forever if there is
  +            // no timeout.
  +		} while ((timeout < 0) || (System.currentTimeMillis() < endTime));
  +
  +		return null;
  +	}
  +
  +    /** Releases a resource back to the pool of available resources
  +     * @param resource The resource to be returned to the pool
  +     */
  +	public void put(Poolable resource)
  +	{
  +		int pos = -1;
  +
  +		synchronized(this) {
  +            // Make sure the resource is in the used list
  +	    	pos = usedResources.indexOf(resource);
  +
  +            if( resource instanceof Recyclable )
  +            {
  +                ((Recyclable)resource).recycle();
  +            }
  +
  +            // If the resource was in the used list, remove it from the used list and
  +            // add it back to the free list
  +			if (pos >= 0) {
  +				usedResources.removeElementAt(pos);
  +				availableResources.addElement(resource);
  +			}
  +		}
  +
  +        // If we released a resource, wake up any threads that may be waiting
  +		if (pos >= 0)
  +		{
  +			doWakeup();
  +		}
  +	}
  +
  +    /** Performs a notifyAll (which requires a synchronized method) */
  +	protected synchronized void doNotify()
  +	{
  +		try {
  +			notifyAll();
  +		}
  +		catch (Exception ignore) {
  +		}
  +	}
  +
  +	protected void doWakeup()
  +	{
  +        // Wake up any threads waiting for the resource
  +		receivedWakeup = false;
  +		do {
  +			try {
  +		   		doNotify();
  +			}
  +			catch (Exception ignore) {
  +			}
  +		}
  +        // Keep looping while there are threads waiting and none have received a wakeup
  +		while ((numThreadsWaiting > 0) && !receivedWakeup);
  +	}
   }