cziegeler 01/10/23 04:55:19
Modified: src/org/apache/cocoon cocoon.roles
src/org/apache/cocoon/components/store MRUMemoryStore.java
webapp cocoon.xconf
Added: src/org/apache/cocoon/components/store FilesystemQueue.java
FilesystemQueueImpl.java FilesystemQueueObject.java
Log:
New Store component: FilesystemQueue
Submitted by: Gerhard Froehlich [[EMAIL PROTECTED]]
Revision Changes Path
1.24 +4 -0 xml-cocoon2/src/org/apache/cocoon/cocoon.roles
Index: cocoon.roles
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/org/apache/cocoon/cocoon.roles,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- cocoon.roles 2001/10/10 20:53:56 1.23
+++ cocoon.roles 2001/10/23 11:55:19 1.24
@@ -100,6 +100,10 @@
shorthand="store-janitor"
default-class="org.apache.cocoon.components.store.StoreJanitorImpl"/>
+ <role name="org.apache.cocoon.components.store.FilesystemQueue"
+ shorthand="filesystem-queue"
+ default-class="org.apache.cocoon.components.store.FilesystemQueueImpl"/>
+
<role name="org.apache.cocoon.components.hsqldb.Server"
shorthand="hsqldb-server"
default-class="org.apache.cocoon.components.hsqldb.ServerImpl"/>
1.22 +47 -105
xml-cocoon2/src/org/apache/cocoon/components/store/MRUMemoryStore.java
Index: MRUMemoryStore.java
===================================================================
RCS file:
/home/cvs/xml-cocoon2/src/org/apache/cocoon/components/store/MRUMemoryStore.java,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- MRUMemoryStore.java 2001/10/10 09:23:08 1.21
+++ MRUMemoryStore.java 2001/10/23 11:55:19 1.22
@@ -7,6 +7,8 @@
*****************************************************************************/
package org.apache.cocoon.components.store;
+import org.apache.avalon.excalibur.collections.SynchronizedPriorityQueue;
+
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
@@ -37,8 +39,6 @@
import org.apache.cocoon.util.IOUtils;
-
-
import java.io.File;
import java.io.IOException;
@@ -51,14 +51,10 @@
import java.util.LinkedList;
-import java.util.Stack;
-
/**
* This class provides a cache algorithm for the requested documents.
* It combines a HashMap and a LinkedList to create a so called MRU
* (Most Recently Used) cache.
- * The objects can also be stored onto the filesystem to hold them in a
- * persitent state over jvm restarts.
*
* The idea was taken from the "Writing Advanced Application Tutorial" from
* javasoft. Many thanx to the writers!
@@ -67,25 +63,24 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
*/
-public class MRUMemoryStore extends AbstractLoggable implements Store, Configurable,
- ThreadSafe,
Runnable,
- Composable,
Contextualizable {
+public class MRUMemoryStore extends AbstractLoggable implements Store,
+ Configurable,
+ ThreadSafe,
+ Composable,
+ Contextualizable {
- private int priority;
private int maxobjects;
private boolean filesystem;
private HashMap cache;
private LinkedList mrulist;
- private Runtime jvm;
private File cachefile;
private Store fsstore;
private StoreJanitor storejanitor;
- private Stack writerstack;
- private Thread writer;
private File cachedir;
private File workdir;
private String cachedirstr;
+ private FilesystemQueue filesystemQueue;
protected ComponentManager manager;
/**
@@ -100,6 +95,8 @@
this.fsstore = (Store)manager.lookup(Store.ROLE + "/Filesystem");
getLogger().debug("Looking up " + StoreJanitor.ROLE);
this.storejanitor = (StoreJanitor)manager.lookup(StoreJanitor.ROLE);
+ getLogger().debug("Looking up " + FilesystemQueue.ROLE);
+ this.filesystemQueue = (FilesystemQueue)manager.lookup(FilesystemQueue.ROLE);
} catch(ComponentException e) {
getLogger().error("Error in compose()!", e);
}
@@ -118,8 +115,13 @@
this.workdir = (File)context.get(Constants.CONTEXT_WORK_DIR);
this.cachedirstr = IOUtils.getContextFilePath(this.workdir.getPath(),
this.cachedir.getPath());
+
+
- getLogger().debug("Context path="
+ this.getLogger().debug("cachedir=" + this.cachedir);
+ this.getLogger().debug("workdir=" + this.workdir);
+ this.getLogger().debug("cachedirstr=" + this.cachedirstr);
+ this.getLogger().debug("Context path="
+
IOUtils.getContextFilePath(this.workdir.getPath(),this.cachedir.getPath()));
} catch (Exception e) {
@@ -132,7 +134,6 @@
* A few options can be used :
* <UL>
* <LI>maxobjects = how many objects will be stored in memory (Default: 10
objects)</LI>
- * <LI>threadpriority = priority of the threads (1-10). (Default: 10)</LI>
* <LI>filesystem = use filesystem storage to keep object persistent (Default:
false)</LI>
* </UL>
*
@@ -140,57 +141,17 @@
* @exception ConfigurationException
*/
public void configure(Configuration conf) throws ConfigurationException {
- this.jvm = Runtime.getRuntime();
- this.mrulist = new LinkedList();
- this.writerstack = new Stack();
-
- this.storejanitor.register(this);
-
Parameters params = Parameters.fromConfiguration(conf);
- this.maxobjects = params.getParameterAsInteger("maxobjects",100);
- this.cache = new HashMap((int)(this.maxobjects * 1.2));
- this.priority =
params.getParameterAsInteger("threadpriority",Thread.currentThread().getPriority());
- this.filesystem = params.getParameterAsBoolean("filesystem",false);
- if ((this.priority < 1) || (this.priority > 10)) {
- throw new ConfigurationException("MRUMemoryStore cleanup thread priority must
be between 1 and 10!");
- }
+ this.maxobjects = params.getParameterAsInteger("maxobjects",100);
+ this.filesystem = params.getParameterAsBoolean("filesystem",false);
if ((this.maxobjects < 1)) {
throw new ConfigurationException("MRUMemoryStore maxobjects must be at least
1 milli second!");
}
-
- if (this.filesystem) {
- getLogger().debug("Intializing writer thread");
- writer = new Thread(this);
- writer.setPriority(this.priority);
- writer.setDaemon(true);
- writer.setName("writer");
- writer.start();
- }
- }
-
- /**
- * The writer thread writes objects from the writer stack onto the filesystem.
- */
- public void run() {
- while (true) {
- getLogger().debug("Writerthread awake!");
- while(!writerstack.empty()) {
- try {
- TmpStackObject tmp = (TmpStackObject)this.writerstack.pop();
- this.fsstore.store(getFileName(tmp.getKey().toString()), tmp.getObject());
- } catch(IOException e) {
- getLogger().error("Error in writer thread",e);
- } catch(Exception ex) {
- getLogger().error("Error in writer thread",ex);
- }
- }
- synchronized (this.writer) {
- try {
- writer.wait();
- } catch (InterruptedException ignored) {}
- }
- }
+ this.cache = new HashMap((int)(this.maxobjects * 1.2));
+ this.mrulist = new LinkedList();
+
+ this.storejanitor.register(this);
}
/**
@@ -225,12 +186,13 @@
/** put the object on the filesystem */
if(this.filesystem) {
- if(this.checkSerializable(value)) {
- getLogger().debug("Storing object on fs");
- this.writerstack.push(new TmpStackObject(key,value));
- getLogger().debug("Stack size=" + writerstack.size());
- synchronized (this.writer) {
- this.writer.notify();
+ if(this.checkSerializable(value) &&
+ !this.fsstore.containsKey(getFileName(key.toString()))) {
+ this.getLogger().debug("Storing object on fs");
+ try {
+ this.filesystemQueue.insert(new FilesystemQueueObject(key,value));
+ } catch(Exception e) {
+ this.getLogger().error("Error storing Object on fs",e);
}
}
}
@@ -238,7 +200,7 @@
this.cache.put(key, value);
this.mrulist.remove(key);
this.mrulist.addFirst(key);
- getLogger().debug("Cache size=" + cache.size());
+ this.getLogger().debug("Cache size=" + cache.size());
}
/**
@@ -248,7 +210,7 @@
* @return the requested object
*/
public Object get(Object key) {
- getLogger().debug("Getting object from memory. Key: " + key);
+ this.getLogger().debug("Getting object from memory. Key: " + key);
Object tmpobject = this.cache.get(key);
if ( tmpobject != null ) {
@@ -258,24 +220,27 @@
return tmpobject;
}
- getLogger().debug("Object not found in memory");
+ this.getLogger().debug("Object not found in memory");
/** try to fetch from filesystem */
if(this.filesystem) {
tmpobject = this.fsstore.get(getFileName(key.toString()));
if (tmpobject == null) {
- getLogger().debug( "Object was NOT found on fs. Looked for: " +
URLEncoder.encode(key.toString()) );
+ this.getLogger().debug( "Object was NOT found on fs. Looked for: "
+ + getFileName(key.toString()));
return null;
} else {
- getLogger().debug("Object was found on fs");
+ this.getLogger().debug("Object was found on fs");
try {
tmpobject = IOUtils.deserializeObject((File)tmpobject);
- this.hold(key,tmpobject);
+ if(!this.cache.containsKey(key)) {
+ this.hold(key,tmpobject);
+ }
return tmpobject;
} catch (ClassNotFoundException ce) {
- getLogger().error("Error in get()!", ce);
+ this.getLogger().error("Error in get()!", ce);
return null;
} catch (IOException ioe) {
- getLogger().error("Error in get()!", ioe);
+ this.getLogger().error("Error in get()!", ioe);
return null;
}
}
@@ -289,7 +254,7 @@
* @param the key of to be removed object
*/
public void remove(Object key) {
- getLogger().debug("Removing object from store");
+ this.getLogger().debug("Removing object from store");
this.cache.remove(key);
this.mrulist.remove(key);
if(this.filesystem && key != null) {
@@ -305,7 +270,7 @@
*/
public boolean containsKey(Object key) {
synchronized(this.cache) {
- return this.cache.containsKey(key);
+ return this.cache.containsKey(key);
}
}
@@ -329,10 +294,10 @@
this.getLogger().debug("Freeing cache");
this.cache.remove(this.mrulist.getLast());
this.mrulist.removeLast();
- getLogger().debug("Cache size=" + cache.size());
+ this.getLogger().debug("Cache size=" + cache.size());
}
} catch (Exception e) {
- getLogger().error("Error in free()", e);
+ this.getLogger().error("Error in free()", e);
}
}
@@ -346,7 +311,7 @@
*/
private boolean checkSerializable(Object object) {
try {
- getLogger().debug("Object=" + object);
+ this.getLogger().debug("Object=" + object);
if((object.getClass().getName().equals("org.apache.cocoon.caching.CachedEventObject"))
||
(object.getClass().getName().equals("org.apache.cocoon.caching.CachedStreamObject"))
||
(ClassUtils.implementsInterface(object.getClass().getName(),"org.apache.cocoon.caching.CacheValidity")))
{
@@ -355,7 +320,7 @@
return false;
}
} catch (Exception e) {
- getLogger().error("Error in checkSerializable()!", e);
+ this.getLogger().error("Error in checkSerializable()!", e);
return false;
}
}
@@ -367,7 +332,7 @@
*
* @param the key of the object
* @return the filename of the key
- */
+ */
private String getFileName(String key)
{
return new StringBuffer()
@@ -375,28 +340,5 @@
.append(File.separator)
.append(URLEncoder.encode(key.toString()))
.toString();
- }
-
- /**
- * Temporary container object for the writerstack
- */
- static class TmpStackObject {
- private Object object;
- private Object key;
-
- public TmpStackObject (Object key, Object object) {
- this.object = object;
- this.key = key;
- }
-
- public TmpStackObject() {}
-
- public Object getKey() {
- return this.key;
- }
-
- public Object getObject() {
- return this.object;
- }
}
}
1.1
xml-cocoon2/src/org/apache/cocoon/components/store/FilesystemQueue.java
Index: FilesystemQueue.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.components.store;
import org.apache.avalon.excalibur.collections.PriorityQueue;
import org.apache.avalon.framework.component.Component;
/**
* The interface for the filesystem queue
*
* @author <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
*/
public interface FilesystemQueue extends Component, PriorityQueue {
String ROLE = "org.apache.cocoon.components.store.FilesystemQueue";
}
1.1
xml-cocoon2/src/org/apache/cocoon/components/store/FilesystemQueueImpl.java
Index: FilesystemQueueImpl.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.components.store;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.util.IOUtils;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* This class provides a asynchron queue for storing objects on the filesystem.
* Every store component can uses this component to store object in the
* configured cache directory.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
*/
public class FilesystemQueueImpl extends AbstractLoggable implements FilesystemQueue,
Configurable,
Contextualizable,
Runnable,
ThreadSafe,
Composable {
private int handlerinterval;
private int threadpriority;
private int maxobjects;
private LinkedList linkedList;
private File cachedir;
private File workdir;
private String cachedirstr;
private Store fsstore;
private Thread fsQueueHandler;
/**
* Get the context
*
* @param the Context of the application
*/
public void contextualize(Context context) throws ContextException {
this.cachedirstr = new String();
try {
this.cachedir = (File)context.get(Constants.CONTEXT_CACHE_DIR);
this.workdir = (File)context.get(Constants.CONTEXT_WORK_DIR);
this.cachedirstr = IOUtils.getContextFilePath(this.workdir.getPath(),
this.cachedir.getPath());
this.getLogger().debug("Context path="
+
IOUtils.getContextFilePath(this.workdir.getPath(),this.cachedir.getPath()));
} catch (Exception e) {
this.getLogger().error("Error in contextualize()",e);
}
}
/**
* Get components of the ComponentManager
*
* @param the ComponentManager
*/
public void compose(ComponentManager manager) throws ComponentException {
try {
getLogger().debug("Looking up " + Store.ROLE + "/Filesystem");
this.fsstore = (Store)manager.lookup(Store.ROLE + "/Filesystem");
} catch(ComponentException e) {
getLogger().error("Error in compose()!", e);
}
}
/**
* Configure the Filesystem Queue:
* <UL>
* <LI>handlerinterval = Interval of the Queue Handler Thread</LI>
* <LI>threadpriority = Priority of the Queue Handler Thread</LI>
* >LI>maxobjects = Defines the max. numbers of Objects in the queue</LI>
* </UL>
*/
public void configure(Configuration conf) throws ConfigurationException {
this.getLogger().debug("Configure Filesystem Queue");
Parameters params = Parameters.fromConfiguration(conf);
this.handlerinterval = params.getParameterAsInteger("handlerinterval",10);
this.threadpriority = params.getParameterAsInteger("threadpriority",5);
this.maxobjects = params.getParameterAsInteger("maxobjects",100);
this.getLogger().debug("handlerinterval=" + handlerinterval);
this.getLogger().debug("threadpriority=" + threadpriority);
this.linkedList = new LinkedList();
this.fsQueueHandler = new Thread(this);
this.fsQueueHandler.setDaemon(true);
this.fsQueueHandler.setPriority(this.threadpriority);
this.fsQueueHandler.setName("fsQueueHandler");
this.fsQueueHandler.start();
}
public void run() {
while(true) {
while(!this.isEmpty()) {
FilesystemQueueObject filesystemQueueObject =
(FilesystemQueueObject)this.pop();
try {
this.fsstore.store(this.getFileName(filesystemQueueObject.getKey().toString()),
filesystemQueueObject.getObject());
} catch(IOException e) {
this.getLogger().error("Error in fsQueueHandler",e);
}
}
try {
Thread.currentThread().sleep(this.handlerinterval * 1000);
} catch (InterruptedException ignore) {}
}
}
/**
* Clear all elements from queue.
*/
public void clear() {
this.getLogger().debug("Clearing the FilesystemQueue");
ListIterator listIterator = linkedList.listIterator(0);
while(listIterator.hasNext()) {
this.linkedList.remove(listIterator.nextIndex());
}
}
/**
* Test if queue is empty.
*
* @return true if queue is empty else false.
*/
public boolean isEmpty() {
if (this.linkedList.size() > 0) {
return false;
} else {
return true;
}
}
/**
* Insert an element into queue.
*
* @param element the element to be inserted
*/
public void insert(Comparable element) {
if(this.linkedList.size() < maxobjects) {
this.getLogger().debug("Insert Element in FilesystemQueue");
this.linkedList.addFirst(element);
this.reportSize();
} else {
this.getLogger().warn("Filesystem Queue full!");
}
}
/**
* Return element on top of heap but don't remove it.
*
* @return the element at top of heap
* @exception NoSuchElementException if isEmpty() == true
*/
public Comparable peek() throws NoSuchElementException {
try {
this.getLogger().debug("Peek Element in FilesystemQueue");
return (Comparable)linkedList.getLast();
} catch (NoSuchElementException e) {
this.getLogger().error("Error peeking element from the queue",e);
return null;
}
}
/**
* Return element on top of heap and remove it.
*
* @return the element at top of heap
* @exception NoSuchElementException if isEmpty() == true
*/
public Comparable pop() throws NoSuchElementException {
try {
this.getLogger().debug("Pop Element in FilesystemQueue");
return (Comparable)linkedList.removeLast();
} catch (NoSuchElementException e) {
this.getLogger().error("Error popping element from the queue",e);
return null;
}
}
/**
* This method puts together a filename for
* the object, which shall be stored on the
* filesystem.
*
* @param the key of the object
* @return the filename of the key
*/
private String getFileName(String key)
{
return new StringBuffer()
.append(this.cachedirstr)
.append(File.separator)
.append(URLEncoder.encode(key.toString()))
.toString();
}
public void reportSize() {
this.getLogger().debug("Size of FilesystemQueue=" + this.linkedList.size());
}
}
1.1
xml-cocoon2/src/org/apache/cocoon/components/store/FilesystemQueueObject.java
Index: FilesystemQueueObject.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.components.store;
/**
* A "helper" container for the filesystem queue
*
* @author <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
*/
public class FilesystemQueueObject implements Comparable {
private Object object;
private Object key;
public FilesystemQueueObject (Object key, Object object) {
this.object = object;
this.key = key;
}
public FilesystemQueueObject() {}
public Object getKey() {
return this.key;
}
public Object getObject() {
return this.object;
}
public int compareTo(Object o) {
return 0;
}
}
1.38 +13 -15 xml-cocoon2/webapp/cocoon.xconf
Index: cocoon.xconf
===================================================================
RCS file: /home/cvs/xml-cocoon2/webapp/cocoon.xconf,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -r1.37 -r1.38
--- cocoon.xconf 2001/10/10 20:53:57 1.37
+++ cocoon.xconf 2001/10/23 11:55:19 1.38
@@ -34,13 +34,10 @@
maxobjects: Indicates how many objects will be hold in the cache.
When the number of maxobjects has been reached. The
last object in the cache will be thrown out.
- threadpriority: Indicates the priority of the writer thread.
- (1 is the lowest priority and 10 is the highest).
filesystem: Turns the filesystem storage for objects on or off.
-->
<store class="org.apache.cocoon.components.store.MRUMemoryStore"
logger="root.store">
<parameter name="maxobjects" value="100"/>
- <parameter name="threadpriority" value="5"/>
<parameter name="filesystem" value="true"/>
</store>
@@ -69,6 +66,19 @@
<parameter name="threadpriority" value="5"/>
</store-janitor>
+ <!-- Filesystem Queue
+ The Filesystem Queue is the central queue for writing objects onto the
filesystem:
+ handlerinterval = How often (seconds) is the queue checked for new objects.
+ threadpriority = The priority of the Handler Thread
+ maxobjects = Defines the max. numbers of objects in queue. If the queue is
full no objects
+ can be inserted.
+ -->
+ <filesystem-queue class="org.apache.cocoon.components.store.FilesystemQueueImpl"
logger="root.store">
+ <parameter name="handlerinterval" value="10"/>
+ <parameter name="threadpriority" value="5"/>
+ <parameter name="maxobjects" value="100"/>
+ </filesystem-queue>
+
<!-- Entity resolution catalogs:
catalog:
The default catalog is distributed at /resources/entities/catalog
@@ -331,22 +341,13 @@
pool-max="32" pool-min="16" pool-grow="4"/>
<!-- Caching of stream pipeline:
- freememory: Indicates how much memory should be left free in the
- JVM for normal operation.
- heapsize: Indicates how big the heap size can grow to before the
- cleanup thread kicks in.
- cleanupthreadinterval: Indicates the interval of the cleanup thread in
seconds.
maxobjects: Indicates how many objects will be hold in the cache.
When the number of maxobjects has been reached. The
last object in the cache will be thrown out.
- usecleanupthread: Indicates whether we use a cleanup thread or not.
- threadpriority: Indicates the priority of the cleanup thread.
- (1 is the lowest priority and 10 is the highest).
filesystem: Turns the filesystem storage for objects on or off.
-->
<stream-cache class="org.apache.cocoon.components.store.MRUMemoryStore"
logger="root.store">
<parameter name="maxobjects" value="100"/>
- <parameter name="threadpriority" value="5"/>
<parameter name="filesystem" value="true"/>
</stream-cache>
@@ -365,13 +366,10 @@
maxobjects: Indicates how many objects will be hold in the cache.
When the number of maxobjects has been reached. The
last object in the cache will be thrown out.
- threadpriority: Indicates the priority of the cleanup thread.
- (1 is the lowest priority and 10 is the highest).
filesystem: Turns the filesystem storage for objects on or off.
-->
<event-cache class="org.apache.cocoon.components.store.MRUMemoryStore"
logger="root.store">
<parameter name="maxobjects" value="100"/>
- <parameter name="threadpriority" value="5"/>
<parameter name="filesystem" value="true"/>
</event-cache>
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]