bloritsch    01/03/27 06:30:03

  Modified:    src/org/apache/cocoon/components Tag: xml-cocoon2
                        ComponentPool.java
  Log:
  rearchitected component pool like JdbcConnectionPool
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.4   +126 -175  
xml-cocoon/src/org/apache/cocoon/components/Attic/ComponentPool.java
  
  Index: ComponentPool.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon/src/org/apache/cocoon/components/Attic/ComponentPool.java,v
  retrieving revision 1.1.2.3
  retrieving revision 1.1.2.4
  diff -u -r1.1.2.3 -r1.1.2.4
  --- ComponentPool.java        2001/03/19 17:08:39     1.1.2.3
  +++ ComponentPool.java        2001/03/27 14:30:02     1.1.2.4
  @@ -7,13 +7,17 @@
    */
   package org.apache.cocoon.components;
   
  -import java.util.Vector;
  +import java.util.List;
  +import java.util.ArrayList;
   
   import org.apache.avalon.Poolable;
   import org.apache.avalon.ThreadSafe;
  -//import org.apache.avalon.Loggable;
  +import org.apache.avalon.Initializable;
  +import org.apache.avalon.Disposable;
   import org.apache.avalon.util.pool.Pool;
   import org.apache.avalon.util.pool.ObjectFactory;
  +import org.apache.avalon.util.Lock;
  +import org.apache.avalon.util.LockException;
   import org.apache.avalon.Recyclable;
   import org.apache.cocoon.components.ComponentFactory;
   import org.apache.avalon.AbstractLoggable;
  @@ -24,29 +28,27 @@
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Giacomo Pati</a>
    */
  -public class ComponentPool extends AbstractLoggable implements Pool, 
ThreadSafe {
  +public class ComponentPool extends AbstractLoggable implements Pool, 
Initializable, Disposable, Runnable, ThreadSafe {
   
       public final static int DEFAULT_POOL_SIZE = 8;
   
  -    public final static int DEFAULT_WAIT_TIME = (5*100);
  -
       /** The resources that are currently free */
  -    protected Vector availableResources;
  +    protected List availableResources = new ArrayList();
   
       /** Resources that have been allocated out of the pool */
  -    protected Vector usedResources;
  +    protected List usedResources = new ArrayList();
   
  -    /** Flag to make sure at least one thread has received notification */
  -    boolean receivedWakeup;
  +    private boolean initialized = false;
  +    private boolean disposed = false;
   
  -    /** The number of threads waiting for notification */
  -    int numThreadsWaiting;
  +    private Lock lock = new Lock();
  +    private Thread initializationThread;
   
  -    protected ObjectFactory m_factory = null;
  +    protected ObjectFactory factory = null;
   
  -    protected int m_initial = DEFAULT_POOL_SIZE/2;
  +    protected int initial = DEFAULT_POOL_SIZE/2;
   
  -    protected int m_maximum = DEFAULT_POOL_SIZE;
  +    protected int maximum = DEFAULT_POOL_SIZE;
   
       public ComponentPool(final ObjectFactory factory) throws Exception {
           init(factory, DEFAULT_POOL_SIZE/2, DEFAULT_POOL_SIZE);
  @@ -66,157 +68,116 @@
       private void init(final ObjectFactory factory,
                         final int initial,
                         final int maximum) throws Exception {
  -        m_factory = factory;
  -        m_initial = initial;
  -        m_maximum = maximum;
  +        this.factory = factory;
  +        this.initial = initial;
  +        this.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());
  +        this.initializationThread = new Thread(this);
  +        this.initializationThread.start();
       }
   
  -    /** 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 = (Poolable)m_factory.newInstance();
  -        getLogger().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);
  +    public void run() {
  +        this.lock.lock(this.availableResources);
   
  -            // Remove the resource from the free list
  -            availableResources.removeElement(resource);
  +        for( int i = 0; i < this.initial; i++ ) {
  +            try {
  +                this.availableResources.add(this.factory.newInstance());
  +            } catch (Exception e) {
  +                getLogger().warn("Could not create poolable resource", e);
  +            }
  +        }
   
  -            // Add the resource and its associated info to the used list
  -            usedResources.addElement(resource);
  +        if ((this.availableResources.size() < this.initial) && 
(this.availableResources.size() > 0)) {
  +            while (this.availableResources.size() < this.initial) {
  +                try {
  +                    this.availableResources.add(this.factory.newInstance());
  +                } catch (Exception e) {
  +                    getLogger().warn("Could not create poolable resource", 
e);
  +                }
  +            }
  +        }
   
  -            return resource;
  +        if (this.availableResources.size() > 0) {
  +            this.initialized = true;
           }
   
  -        return null;
  +        this.lock.unlock(this.availableResources);
       }
   
  -    /** 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) {
  +    public void dispose() {
  +        this.lock.lock(this.availableResources);
  +        this.disposed = true;
  +
  +        while ( ! this.availableResources.isEmpty() ) {
  +            this.availableResources.remove(0);
           }
  +
  +        this.lock.unlock(this.availableResources);
       }
   
  -    /** 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
  +    /**
  +     * 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
        */
  -    public Poolable get()
  -        throws Exception
  -    {
  -        return get(DEFAULT_WAIT_TIME);
  +    protected Poolable getOverflowResource() throws Exception {
  +        Poolable poolable = (Poolable) this.factory.newInstance();
  +        getLogger().debug("Component Pool - creating Overflow Resource:"
  +                        + " Resource=" + poolable
  +                        + " Available=" + availableResources.size()
  +                        + " Used=" + usedResources.size() );
  +        return poolable;
       }
   
       /** 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
  +     * No extra information is associated with the allocated 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;
  -                    }
  -                }
  +    public Poolable get() throws Exception {
  +        if (! this.initialized) {
  +            if (this.initializationThread == null) {
  +                throw new IllegalStateException("You cannot get a resource 
before the pool is initialized");
  +            } else {
  +                this.initializationThread.join();
               }
  -
  -            // 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;
  +        if (this.disposed) {
  +            throw new IllegalStateException("You cannot get a resource after 
the pool is disposed");
  +        }
   
  -            // Indicate that there is a thread waiting for a wakeup
  -            numThreadsWaiting++;
  +        this.lock.lock(this.availableResources);
  +        // See if there is a resource in the pool already
  +        Poolable resource = null;
   
  -            // Wait for a wakeup
  -            doWait(maxWait);
  +        if (this.availableResources.size() > 0) {
  +            resource = (Poolable)this.availableResources.remove(0);
   
  -            numThreadsWaiting--;
  +            this.lock.lock(this.usedResources);
  +            this.usedResources.add(resource);
  +            this.lock.unlock(this.usedResources);
  +        } else {
  +            resource = this.getOverflowResource();
   
  -            // Only mention the received wakeup if the timeout hasn't expired
  -            if ((timeout < 0) || (System.currentTimeMillis() < maxWait)) {
  -                receivedWakeup = true;
  +            if (resource != null) {
  +                this.lock.lock(this.usedResources);
  +                this.usedResources.add(resource);
  +                this.lock.unlock(this.usedResources);
               }
  +        }
   
  -            // See if there is now a resource in the free pool
  -            resource = getResourceFromList();
  -            if (resource != null)
  -            {
  -                return resource;
  -            }
  +        this.lock.unlock(this.availableResources);
   
  -            // Keep looping while the timeout hasn't expired (loop forever 
if there is
  -            // no timeout.
  -        } while ((timeout < 0) || (System.currentTimeMillis() < endTime));
  +        if (resource == null) {
  +            throw new RuntimeException("Could not get the component from the 
pool");
  +        }
   
  -        return null;
  +        return resource;
       }
   
       /** Releases a resource back to the pool of available resources
  @@ -225,53 +186,43 @@
       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);
  -            }
  -        }
  +        this.lock.lock(this.usedResources);
   
  -        // If we released a resource, wake up any threads that may be waiting
  -        if (pos >= 0)
  -        {
  -            doWakeup();
  -        }
  -    }
  +        // Make sure the resource is in the used list
  +        pos = usedResources.indexOf(resource);
   
  -    /** Performs a notifyAll (which requires a synchronized method) */
  -    protected synchronized void doNotify()
  -    {
  -        try {
  -            notifyAll();
  +        if (resource instanceof Recyclable) {
  +            ((Recyclable)resource).recycle();
           }
  -        catch (Exception ignore) {
  -        }
  -    }
   
  -    protected void doWakeup()
  -    {
  -        // Wake up any threads waiting for the resource
  -        receivedWakeup = false;
  -        do {
  -            try {
  -                doNotify();
  -            }
  -            catch (Exception ignore) {
  +        // 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) {
  +            this.usedResources.remove(pos);
  +
  +            this.lock.lock(this.availableResources);
  +
  +            if (this.availableResources.size() < this.maximum) {
  +                // If the available resources are below the maximum add this 
back.
  +                this.availableResources.add(resource);
  +            } else {
  +                // If the available are above the maximum destroy this 
resource.
  +                try {
  +                    this.factory.decommission(resource);
  +                    getLogger().debug("Component Pool - decommissioning 
Overflow Resource:"
  +                                    + " Resource=" + resource
  +                                    + " Available=" + 
availableResources.size()
  +                                    + " Used=" + usedResources.size() );
  +                    resource = null;
  +                } catch (Exception e) {
  +                    throw new RuntimeException("caught exception 
decommissioning resource: " + resource);
  +                }
               }
  +
  +            this.lock.unlock(this.availableResources);
           }
  -        // Keep looping while there are threads waiting and none have 
received a wakeup
  -        while ((numThreadsWaiting > 0) && !receivedWakeup);
  +
  +        this.lock.unlock(this.usedResources);
       }
   }
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to