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]