bloritsch 01/03/01 12:33:29
Modified: src/org/apache/cocoon/util Tag: xml-cocoon2
ComponentPool.java
Log:
Revert back to Dims' code.
Revision Changes Path
No revision
No revision
1.1.2.13 +240 -25
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.12
retrieving revision 1.1.2.13
diff -u -r1.1.2.12 -r1.1.2.13
--- ComponentPool.java 2001/03/01 20:12:23 1.1.2.12
+++ ComponentPool.java 2001/03/01 20:33:27 1.1.2.13
@@ -7,65 +7,280 @@
*/
package org.apache.cocoon.util;
+import java.util.Vector;
+
import org.apache.avalon.Poolable;
import org.apache.avalon.ThreadSafe;
-import org.apache.avalon.util.pool.ThreadSafePool;
+import org.apache.avalon.Loggable;
+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.util.pool.Resizable;
+import org.apache.avalon.Recyclable;
import org.apache.cocoon.ComponentFactory;
+import org.apache.log.Logger;
+
/**
* This is a implementation of <code>Pool</code> for SitemapComponents
* that is thread safe.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Giacomo Pati</a>
*/
-public class ComponentPool extends ThreadSafePool implements Resizable {
+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;
- public final static int DEFAULT_POOL_SIZE = 16;
+ /** 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 synchronized void grow(int amount) {
- if (m_currentCount >= m_max) {
- m_max += amount;
- } else {
- m_max = Math.max(m_currentCount + amount, m_max);
+ public void setLogger(Logger log) {
+ if (this.log == null) {
+ this.log = log;
}
+ }
- while (m_currentCount < m_max) {
- try {
- m_ready.add( m_factory.newInstance() );
- m_currentCount++;
- } catch (Exception e) {
- getLogger().debug("Error growing the pool", e);
+ /** 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) {
+ }
+ }
- notify();
+ /** 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);
}
- public synchronized void shrink(int amount) {
- m_max -= amount;
+ /** 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;
+ }
- while (m_currentCount > m_max) {
- m_ready.remove(0);
+ // 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);
+ }
}
- notify();
+ // 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);
}
}