Hi there,
I've been following this thread with quite some interest.

I like the idea of one monitoring thread that checks memory
and then calls on the different stores to free some up if 
necessary.

As an attachment I included a (very rough, first version, pre-alpha...
you get it;-) StoreJanitor.

To get this to run in your environment do the following:
1) add a new role named "janitor" to org/apache/cocoon/cocoon.roles
2) add an <janitor> element to cocoon.xconf, 
   similar to the MRUMemoryStore ones
3) Expand the Store interface by a "public void free()" method.
4) Add the Store to the Janitor surveillance, i.e.:
    StoreJanitor janitor = (StoreJanitor)manager.lookup(StoreJanitor.ROLE);
    janitor.addToSurveillance(this);

As mentioned above, this is far from complete. I'm sending this in
so people that are more knowledgable than I am can take a look at
it.

I'd appreciate any (rocks!, sucks) feedback.


Thanks,
Christian

On Wed, Aug 29, 2001 at 12:18:46AM +0200, Gerhard Froehlich wrote:
> >> >Wow, where have you been before? :)))
> Always there watching and learning much through this project and its
> participants :). But most of the time in the dungeons of commercial
> software development and its deadlines.
> >> >Yes, you are right - that's not necessary and this might be the
> >> >performance issue.
> >> >Reducing checker threads amount down to one would decrease amount of
> >> >runFinalization()/gc()
> >> >calls in two times - giving better performance.
> >> >
> >> >Could we use just one static checker thread?
> We have to test this. When static, we have namely one cleanup thread but
> still two stores to free(). For the moment I don't know if this work.
> But I have the strong feeling that it won't. Too bad that Carsten is
> away for a couple of weeks. He would certainly have some good ideas for
> the pipline configuration. But I will test this with a static thread.
> >> >There is an issue with configuration though... Which
> >configuration to use,
> >> >from what store...
> Maybe we can add a sample configuration to the cocoon.xconf according
> to a reference config for the Xms Xmx parameters. Berin made some
> good suggestions some threads below. I can add it to the cocoon.xconf.
> >> How about a separate component to do the checking?
> >(MRUMemoryStoreJanitor?)
> >> Each MRUMemoryStore would register its requested heapsize &
> >freememory with
> >> the janitor, and it would be responsible for the worker thread. It would
> >
> >Good suggestion and I kind of like this name ;)
> >Gerhard, what do you think?
> Good suggestion. But I would name it StoreJanitor. Because the
> MRUMemoryStore
> is *only* a component. Maybe there will be a LRUMemoryStore or combination
> of
> both in nearer future :). Every store component implements the store
> interface, so
> the StoreJanitor would have access to the free() method of every store
> component.
> Then we would have a seperate cleanup component for every store
> implementation.
> I would implement the stores as singelton classes with one instance for
> better
> control about the memory. Because, how do you decide from which store
> instance
> to free memory. Maybe there is one with many small objects and another with
> less
> but huge objects. You can't determine, like in C, the byte size of each
> object in java easy.
> >> try to keep the JVM totalMemory below the sum of all the registered
> >> heapsizes, and freeMemory below the sum of all registered freememories.
> >Here I think that idea (originally) was that heapsize specifies
> >heapsize of the JVM,
> >but not the size of the store (because it is (almost) impossible
> >to determine), so my
> >understanding is that these parameters (heapsize and freememory)
> >should also
> >go into janitor configuration.
> Yeah, thats right. But I had the opinion that there is only one store
> instance.
> (I tested it too carelessly :( )
> This gc()->jvm.FreeMemory()->gc()->jvm.FreeMemory() is the proposed
> implementation (hack) from javasoft to determine memory consumption
> of objects in java.
> >> If runFinalization/gc isn't enough to create the free memory, a
> >round-robin
> >> approach (or other algorithm) could be used to select a
> >MRUMemoryStore to
> >> free an object from.
> Yes, that would be a possible approach to decide from which store to free().
> But
> I still don't understand why 2 or more stores?
> >> Just my .02 :)
> Mine too :)
> 
> Cheers
> Gerhard
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, email: [EMAIL PROTECTED]
> 
/*****************************************************************************
 * 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.Component;
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.parameters.Parameters;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.thread.ThreadSafe;

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ListIterator;

/**
 * This class monitors memory usage of thr JVM.
 * It calls the <code>free()</code> method in <code>Store</code>s
 * when memory gets low to free up some.
 *
 * @author <a href="mailto:[EMAIL PROTECTED]";>Gerhard Froehlich</a>
 * @author <a href="mailto:[EMAIL PROTECTED]";>Davanum Srinivas</a>
 * @author <a href="mailto:[EMAIL PROTECTED]";>Christian Schmitt</a>
 *
*/
public class StoreJanitor extends AbstractLoggable
    implements Component, Configurable, Runnable, ThreadSafe {

    /**
     * The Avalon role name
     */
    final static String ROLE = "org.apache.cocoon.components.store.StoreJanitor";

    /**
     * Indicates how much memory should be left free in the JVM for
     * normal operation.
     */
    private int freememory;

    /**
     * Indicates how big the heap size can grow to before the cleanup thread kicks in.
     * The default value is based on the default maximum heap size of 64Mb.
     */
    private int heapsize;

    /**
     * Indicates the time in seconds to sleep between memory checks.
     */
    private long cleanupthreadinterval;

    /**
     * Indicates the daemon thread priority.
     */
    private int priority;

    /**
     * Store of stores
     */
    private List stores = Collections.synchronizedList(new ArrayList());

    /**
     * The Runtime
     */
    private Runtime jvm;
    
    public void configure(Configuration config) throws ConfigurationException {
        getLogger().debug("About to be configured!");
        Parameters params = Parameters.fromConfiguration(config);
        this.freememory            = params.getParameterAsInteger("freememory", 1000000);
        this.heapsize              = params.getParameterAsInteger("heapsize", 60000000);
        this.cleanupthreadinterval = params.getParameterAsInteger("cleanupthreadinterval", 10);
        this.priority              = params.getParameterAsInteger("threadpriority",Thread.currentThread().getPriority());

        if ((this.priority < 1) || (this.priority > 10)) {
          throw new ConfigurationException("StoreJanitor cleanup thread priority must be between 1 and 10!");
        }
        if ((this.cleanupthreadinterval < 1)) {
          throw new ConfigurationException("StoreJanitor cleanup thread interval must be at least 1 second!");
        }

        Thread janitor = new Thread(this);
        janitor.setDaemon(true);
        janitor.setPriority(this.priority);
        janitor.setName("janitor");
        janitor.start();
    }
    
    /**
     * The background thread that monitors memory.
     * If memory is getting low, appropriate actions have to be taken.
     */
    public void run() {
        while(true) {
            if (memoryLow()) {
                ListIterator li = stores.listIterator();
                while (li.hasNext()) {
                    Store s = (Store)li.next();
                    getLogger().debug("Calling " + s.toString() + " to free some memory");
                    s.free();
                }
            }
            try {
              Thread.currentThread().sleep(this.cleanupthreadinterval * 1000);
            } catch (InterruptedException ignore) {}
        }
    }
    
    /**
     * Add a Store to be watched.
     */  
    public void addToSurveillance(Store store) {
        stores.add(store);
        getLogger().debug(store.toString() + " added to surveillance");
    }

    /**
     * Remove a Store from being watched.
     */
    public void removeFromSurveillance(Store store) {
        stores.remove(store);
        getLogger().debug(store.toString() + " removed from surveillance");
    }

    /**
     * Method to check if memory is running low in the jvm.
     */
    private boolean memoryLow() {
      return jvm.totalMemory() > heapsize && jvm.freeMemory() < freememory;
    }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to