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);
+ }
}