You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by vg...@apache.org on 2007/01/25 17:38:06 UTC

svn commit: r499840 - in /cocoon/trunk/core/cocoon-store/cocoon-store-impl: ./ src/main/java/org/apache/cocoon/components/store/impl/StoreJanitorImpl.java src/main/resources/META-INF/cocoon/spring/cocoon-core-store-janitor.xml

Author: vgritsenko
Date: Thu Jan 25 08:38:05 2007
New Revision: 499840

URL: http://svn.apache.org/viewvc?view=rev&rev=499840
Log:
    <action dev="VG" type="add">
      Core: In store janitor, add an option to cleanup all stores on each janitor
      run. Default behavior is to cleanup one store at a time.
    </action>


Modified:
    cocoon/trunk/core/cocoon-store/cocoon-store-impl/   (props changed)
    cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/java/org/apache/cocoon/components/store/impl/StoreJanitorImpl.java
    cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/resources/META-INF/cocoon/spring/cocoon-core-store-janitor.xml

Propchange: cocoon/trunk/core/cocoon-store/cocoon-store-impl/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Jan 25 08:38:05 2007
@@ -1,3 +1,4 @@
+*.iml
 .project
 .settings
 target

Modified: cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/java/org/apache/cocoon/components/store/impl/StoreJanitorImpl.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/java/org/apache/cocoon/components/store/impl/StoreJanitorImpl.java?view=diff&rev=499840&r1=499839&r2=499840
==============================================================================
--- cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/java/org/apache/cocoon/components/store/impl/StoreJanitorImpl.java (original)
+++ cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/java/org/apache/cocoon/components/store/impl/StoreJanitorImpl.java Thu Jan 25 08:38:05 2007
@@ -32,23 +32,36 @@
  * the StoreJanitor frees the registered caches until memory is normal.
  *
  * <p>A few parameters can be used:
- * <UL>
- *  <LI><B>freememory</B>: How many bytes shall be always free in the JVM (Default: 1mb)</LI>
- *  <LI><B>heapsize</B>: Maximum possible size of the JVM memory consumption (Default: 64mb)</LI>
- *  <LI><B>cleanupthreadinterval</B>: How often (sec) shall run the cleanup thread (Default: 10s)</LI>
- *  <LI><B>adaptivethreadinterval</B> (experimental): Enable adaptive algorithm to determine thread interval
+ * <ul>
+ *  <li><b>freememory</b>: How many bytes shall be always free in the JVM (Default: 1mb)</li>
+ *  <li><b>heapsize</b>: Maximum possible size of the JVM memory consumption (Default: 64mb)</li>
+ *  <li><b>cleanupthreadinterval</b>: How often (sec) shall run the cleanup thread (Default: 10s)</li>
+ *  <li><b>adaptivethreadinterval</b> (experimental): Enable adaptive algorithm to determine thread interval
  *      (Default: false) When true, <code>cleanupthreadinterval</code> defines the maximum cleanup interval.
  *      Cleanup interval then is determined based on the memory fill rate: the faster memory is filled in,
- *      and the less free memory is left, the shorter is the cleanup time.</LI>
- *  <LI><B>threadpriority</B>: priority of the thread (1-10). (Default: 10)</LI>
- *  <LI><B>percent_to_free</B>: What fraction of the store to free when memory is low (1-100). (Default: 10%)</LI>
- *  <LI><B>invokegc</B>: Invoke the gc on low memory first (true|false; default: false)</LI>
- * </UL></p>
+ *      and the less free memory is left, the shorter is the cleanup time.</li>
+ *  <li><b>threadpriority</b>: priority of the thread (1-10). (Default: current thread's priority)</li>
+ *  <li><b>percent_to_free</b>: What fraction of the store to free when memory is low (1-100). (Default: 10%)</li>
+ *  <li><b>invokegc</b>: Invoke the gc on low memory first (true|false; default: false)</li>
+ *  <li><b>freeingalgorithm</b>: Currently there are two algorithms available. (Default: round-robun)
+ *   <dl>
+ *    <dt>round-robin</dt>
+ *    <dd>The registered caches are cycled through,
+ *     and each time there is a low memory situation one of the
+ *     registered caches has objects freed from it.</dd>
+ *    <dt>all-stores</dt>
+ *    <dd>All registered stores have objects removed from them
+ *    each time there is a low memory situation.</dd>
+ * </ul></p>
  *
  * @version $Id$
  */
 public class StoreJanitorImpl implements StoreJanitor, Runnable {
 
+    // Cleaning Algorithms
+    private static final String ALG_ROUND_ROBIN = "round-robin";
+    private static final String ALG_ALL_STORES = "all-stores";
+
     // Note: this class doesn't need to be Startable. This allows the janitor thread to be
     // lazily created the first time a store registers itsefl
 
@@ -68,15 +81,17 @@
     private int minThreadInterval = 500;
     private boolean adaptiveThreadInterval = ADAPTIVE_THREAD_INTERVAL;
     private int priority = -1;
+    private String freeingAlgorithm = ALG_ROUND_ROBIN;
     private double fraction = PERCENT_TO_FREE / 100.0D;
 
+    /** Should the gc be called on low memory? */
+    protected boolean invokeGC;
+
+    // Runtime state
     private Runtime jvm;
     private ArrayList storelist;
     private int index = -1;
 
-    /** Should the gc be called on low memory? */
-    protected boolean invokeGC = false;
-
     private boolean doRun;
 
     /**
@@ -167,6 +182,10 @@
         this.priority = threadPriority;
     }
 
+    public void setFreeingAlgorithm(String algorithm) {
+        this.freeingAlgorithm = algorithm;
+    }
+
     public Log getLogger() {
         return this.logger;
     }
@@ -181,8 +200,9 @@
      */
     public void init() throws Exception {
         this.jvm = Runtime.getRuntime();
-        if (this.priority == -1) 
+        if (this.priority == -1) {
             this.priority = Thread.currentThread().getPriority();
+        }
 
         if (getMinFreeMemory() < 1) {
             throw new Exception("StoreJanitorImpl freememory parameter has to be greater then 1");
@@ -199,6 +219,9 @@
         if (fraction > 1 && fraction < 0.01) {
             throw new Exception("StoreJanitorImpl percentToFree, has to be between 1 and 100");
         }
+        if (!this.freeingAlgorithm.equals(ALG_ROUND_ROBIN) || !this.freeingAlgorithm.equals(ALG_ALL_STORES)) {
+            throw new Exception("StoreJanitorImpl freeingAlgorithm, has to be round-robin or all-stores.");
+        }
 
         this.storelist = new ArrayList();
 
@@ -211,6 +234,7 @@
             getLogger().debug("percent=" + fraction * 100);
             getLogger().debug("invoke gc=" + this.invokeGC);
         }
+
         doStart();
     }
 
@@ -249,6 +273,7 @@
             try {
                 Thread.sleep(this.interval);
             } catch (InterruptedException ignore) {
+                /* ignored */
             }
 
             // Ignore change in memory during the first run (startup)
@@ -400,12 +425,24 @@
     }
 
     /**
-     * Round Robin alghorithm for freeing the registered caches.
+     * Free configured percentage of objects from stores
+     * based on selected algorithm.
      */
     private void freeMemory() {
-        // TODO: Alternative to RR might be to free same fraction from every storage.
         try {
-            // Determine the store.
+            // What algorithm was selected?
+
+            // Option 1: Downsize all registered stores
+            if (this.freeingAlgorithm.equals(ALG_ALL_STORES)) {
+                for (Iterator i = iterator(); i.hasNext(); ) {
+                    removeStoreObjects((Store) i.next());
+                }
+
+                return;
+            }
+
+            // Option 2: Default to Round Robin
+            // Determine the store to clear this time around.
             if (getIndex() < getStoreList().size()) {
                 if (getIndex() == -1) {
                     setIndex(0);
@@ -418,20 +455,9 @@
                 setIndex(0);
             }
 
-            // Delete proportionate elements out of the store as configured.
-            Store store = (Store)getStoreList().get(getIndex());
-            int limit = calcToFree(store);
-            if (getLogger().isDebugEnabled()) {
-                getLogger().debug("Freeing " + limit + " items from store #" + getIndex());
-            }
+            // Remove the objects from this store
+            removeStoreObjects((Store) getStoreList().get(getIndex()));
 
-            for (int i = 0; i < limit; i++) {
-                try {
-                    store.free();
-                } catch (OutOfMemoryError e) {
-                    getLogger().error("OutOfMemoryError in freeMemory()");
-                }
-            }
         } catch (Exception e) {
             getLogger().error("Error in freeMemory()", e);
         } catch (OutOfMemoryError e) {
@@ -440,11 +466,35 @@
     }
 
     /**
-     * This method claculates the number of Elements to be freememory
-     * out of the Cache.
+     * This method clears the configured amount of objects from
+     * the provided store
+     *
+     * @param store the Store from which to release the objects
+     */
+    private void removeStoreObjects(Store store) {
+        // Calculate how many objects to release from the store
+        int limit = calcToFree(store);
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Freeing " + limit + " items from store " + store + " with "
+                              + store.size() + " items.");
+        }
+
+        // Remove the calculated number of objects from the current store
+        for (int i = 0; i < limit; i++) {
+            try {
+                store.free();
+            } catch (OutOfMemoryError e) {
+                getLogger().error("OutOfMemoryError while releasing an object from the store.");
+            }
+        }
+    }
+
+    /**
+     * This method calculates the number of items to free
+     * from the store.
      *
-     * @param store the Store which was selected as victim
-     * @return number of elements to be removed!
+     * @param store the Store which was selected as a victim
+     * @return number of items to be removed
      */
     private int calcToFree(Store store) {
         int cnt = store.size();
@@ -459,6 +509,7 @@
         if (getLogger().isDebugEnabled()) {
             getLogger().debug("Calculating size for store " + store + " with size " + cnt + ": " + res);
         }
+
         return res;
     }
 
@@ -482,7 +533,6 @@
         }
     }
 
-
     private int getMinFreeMemory() {
         return this.minFreeMemory;
     }
@@ -511,14 +561,14 @@
         return this.storelist;
     }
 
+    private int getIndex() {
+        return this.index;
+    }
+
     private void setIndex(int _index) {
         if (getLogger().isDebugEnabled()) {
             getLogger().debug("Setting index=" + _index);
         }
         this.index = _index;
-    }
-
-    private int getIndex() {
-        return this.index;
     }
 }

Modified: cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/resources/META-INF/cocoon/spring/cocoon-core-store-janitor.xml
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/resources/META-INF/cocoon/spring/cocoon-core-store-janitor.xml?view=diff&rev=499840&r1=499839&r2=499840
==============================================================================
--- cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/resources/META-INF/cocoon/spring/cocoon-core-store-janitor.xml (original)
+++ cocoon/trunk/core/cocoon-store/cocoon-store-impl/src/main/resources/META-INF/cocoon/spring/cocoon-core-store-janitor.xml Thu Jan 25 08:38:05 2007
@@ -15,16 +15,18 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-<!-- SVN $Id$ -->
-  <!-- Normally uses the org.apache.excalibur.store.impl.StoreJanitorImpl as
-       the default-class but as that uses its own Thread spawning there is
-       the org.apache.cocoon.components.store.impl.CocoonStoreJanitor class
-       to use a daemon thread from the org.apache.cocoon.components.thread.RunnableManager
-       component 
-       NOT: As soon as our patch has been accepted by the Excalibur community and an
-            excalibur-store has been release we can switch back to the original 
-            org.apache.excalibur.store.impl.StoreJanitorImpl class
-  -->
+
+<!-- Normally uses the org.apache.excalibur.store.impl.StoreJanitorImpl as
+     the default-class but as that uses its own Thread spawning there is
+     the org.apache.cocoon.components.store.impl.CocoonStoreJanitor class
+     to use a daemon thread from the org.apache.cocoon.components.thread.RunnableManager
+     component.
+     NOTE: As soon as our patch has been accepted by the Excalibur community and an
+           excalibur-store has been release we can switch back to the original
+           org.apache.excalibur.store.impl.StoreJanitorImpl class
+
+     $Id$
+-->
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
@@ -86,6 +88,16 @@
         +-->
     <property name="invokeGC" value="false"/>
     <!--+
+        | Algorithm describing how to clean caches in low memory situations.
+        |   round-robin: The registered caches are cycled through,
+        |                and each time there is a low memory situation one
+        |                of the registered caches has objects freed from it.
+        |   all-stores:  All registered stores have objects removed from
+        |                them each time there is a low memory situation.
+        | If not specified, defaults to 'round-robin'.
+        +-->
+    <property name="freeingAlgorithm" value="round-robin"/>
+    <!--+
         | Name of the thread pool to use.
         | If not specified, defaults to 'daemon'.
         +-->
@@ -101,4 +113,4 @@
         
     <property name="runnableManager" ref="org.apache.cocoon.components.thread.RunnableManager"/>
   </bean>
-</beans>
\ No newline at end of file
+</beans>