If you have your cvs access worked out, you should modify the
project.xml and add yourself to the committer list.

Cheers,

Aaron

> -----Original Message-----
> From: Travis Savo [mailto:[EMAIL PROTECTED]
> Sent: Saturday, July 17, 2004 6:09 PM
> To: 'Turbine JCS Developers List'
> Subject: RE: CachingWorker
> 
> Some excellent suggestions. I'll refine my design and get back to you.
> 
> I'll also look into the group/key problem if I get a chance.
> 
> -T
> 
> -----Original Message-----
> From: Aaron Smuts [mailto:[EMAIL PROTECTED]
> Sent: Saturday, July 17, 2004 11:37 AM
> To: 'Turbine JCS Developers List'
> Subject: RE: CachingWorker
> 
> 
> This is interesting.  I don't like getting the region everytime you do
a
> get.  This slows things down dramatically.  I posted on the javaworld
> article on caching about this.  Their timings were way off because of
> it.  We might be able to make it more efficient.  I'd prefer issuing a
> get on a region I have has a static variable, and then calling
something
> like this if it returns null.  Would that work?
> 
> I see how it could be useful.  You can always put anything in the
> experiemental package or, maybe better, something like this in a
> subpackage of utils on the main src.  org.apache.jcs.utils.access or
> worker or something that makes sense, say org.apache.control.loader .
> 
> We should also look into the idea of implementing pluggable
cacheLoaders
> for a region.
> 
> Have you looked at the FutureResult in Doug Lea's util concurrent
> package.  It may be useful here.
> 
> I'm still looking over your idea.
> 
> On another issue, we need to make items in groups returnable by jus
the
> key, without referencing the group.  Otherwise a group is just an
> inefficient region.  To do this we need to create a CacheKey object
for
> the CacheElement.  The CacheKey and the GroupAttrName classes need
> equals methods that can match on the same key.
> 
> Cheers,
> 
> Aaron
> 
> > -----Original Message-----
> > From: Travis Savo [mailto:[EMAIL PROTECTED]
> > Sent: Friday, July 16, 2004 7:04 PM
> > To: 'Turbine JCS Developers List'
> > Subject: CachingWorker
> >
> > Did you want my CachingWorker?
> >
> > It's a wrapper around JCS to encapsulate the most common set of
> actions
> > performed with JCS.
> >
> > Given a region and a key, do the following psudo-code:
> >
> > if(region.get(key) != null)
> >   return region.get(key)
> > otherwise
> >   doTheWork()
> >   region.put(result)
> >   return result
> >
> > It also ensures that if a CachingWorker is in the middle of doing
the
> work
> > for the same region and key, the second (or Nth) CachingWorker will
> wait
> > and
> > use the results from that instead of doing the get/work/put again.
> >
> > Using JCS to do this might look like:
> >
> > final String key = "some:key";
> > MyObject myObject = null;
> > JCS myRegion = JCS.getInstance("myRegion");
> > if((myObject = (MyObject) myRegion.get(key)) == null){
> >   myObject = makeSomeObject(key);
> >   myRegion.put(key, myObject);
> > }
> >
> > With the caching worker it's:
> >
> > final String key = "some:key";
> > CachingWorker worker = new CachingWorker("myRegion", key) {
> >   public Object doWork() throws Exception {
> >       return makeSomeObject(key);
> >   }
> > };
> > MyObject myObject = (MyObject) worker.getResult();
> >
> > The advantage is with the CachingWorker, if two (or more) threads
> execute
> > this code in parallel, only one will do the work, while the second
> > CachingWorker waits, and mooches off the result of the first.
> >
> > I stuck it in the org.apache.jcs package in my project because it's
> just
> > an
> > advanced interface for org.apache.jcs.JCS and has no dependencies on
> > anything but org.apache.jcs.JCS and commons.logging.
> >
> > Here's the code. It's well javadoced. Of course I'd be happy to
commit
> it
> > myself if you want.
> >
> > /*
> >  * Created on Oct 8, 2003
> >  *
> >  */
> > package org.apache.jcs;
> > import java.io.Serializable;
> > import java.util.HashMap;
> > import java.util.Map;
> > import org.apache.commons.logging.Log;
> > import org.apache.commons.logging.LogFactory;
> > /**
> >  * Utility class to encapsulate doing a piece of work, and caching
the
> > results
> >  * in JCS. Simply implement this class and override protected Object
> > doWork(),
> >  * and do the work in there, returning the object to be cached. Then
> call
> >  * .getResult() to get the result of the work. If the object isn't
> > allready
> > in
> >  * the Cache, doWork() will get called, and the result will be put
> into
> > the
> >  * cache. If the object is allready in cache, the cached result will
> be
> > returned
> >  * instead. As an added bonus, multiple CachingWorkers with the same
> > region,
> >  * group, and key won't do the work multiple times: The first
> > CachingWorker
> > to
> >  * get started will do the work, and all subsequent workers with the
> same
> >  * region, group, and key will wait on the first one and use his
> resulting
> > work
> >  * instead of doing the work themselves.
> >  *
> >  * This is ideal when the work being done is a query to the database
> where
> > the
> >  * results may take time to be retrieved.
> >  *
> >  * For example: <br>
> >  *
> >  * <code>
> >  *     CachingWorker cachingWorker = new CachingWorker("example
> region",
> > aKey) {<br>
> >  *                  public Object doWork() throws Exception { <br>
> >  *          // Do some (DB?) work here which results in a list <br>
> >  *          // This only happens if the cache dosn't have a item in
> this
> > region for aKey <br>
> >  *          // Note this is especially useful with Hibernate, which
> will
> > cache indiviual <br>
> >  *          // Objects, but not entire query result sets. <br>
> >  *          List results = query.list(); <br>
> >  *          // Whatever we return here get's cached with aKey, and
> future
> > calls to <br>
> >  *          // getResult() on a CachedWorker with the same region
and
> key
> > will return that instead. <br>
> >  *          return results; <br>
> >  *        } <br>
> >  *      }; <br>
> >  *      List results = (List) cachingWorker.getResult();<br>
> >  *     </code>
> >  *
> >  * This is essentially the same as doing: JCS jcs =
> > JCS.getInstance("example
> >  * region"); List results = (List) jcs.get(aKey); if(results !=
null){
> > //do
> > the
> >  * work here results = query.list(); jcs.put(aKey, results); }
> >  *
> >  *
> >  * But has the added benifit of the work-load sharing; under normal
> >  * circumstances if multiple threads all tried to do the same query
at
> the
> > same
> >  * time, the same query would happen multiple times on the database,
> and
> > the
> >  * resulting object would get put into JCS multiple times.
> >  *
> >  * Using the Caching worker eliminates this senario entirely.
> >  *
> >  * @author Travis Savo
> >  */
> > public abstract class CachingWorker {
> >     private static final Log logger =
> > LogFactory.getLog(CachingWorker.class);
> >     /**
> >      * Object to hold the result of the work.
> >      */
> >     private Object result = null;
> >     public boolean wasCached = false;
> >     /**
> >      * Map to hold who's doing work presently.
> >      */
> >     private static volatile Map map = new HashMap();
> >     /**
> >      * Boolean to let us know if we need to wait or if it's
> finished.
> >      */
> >     private volatile boolean finished = false;
> >     /**
> >      * Region for the JCS cache.
> >      */
> >     private String region;
> >     /**
> >      * Key for caching the results with.
> >      */
> >     private Serializable key;
> >     /**
> >      * Optional Group to store the result under.
> >      */
> >     private String group = null;
> >     /**
> >      * Constructor which takes a region and a key, but no group.
> >      *
> >      * @param aName
> >      *          The Region to use for the JCS cache.
> >      * @param aKey
> >      *          The key to store the result under.
> >      */
> >     public CachingWorker(String aRegion, Serializable aKey) {
> >             this(aRegion, aKey, null);
> >     }
> >     /**
> >      * Constructor which takes a region, a key, and a group.
> >      *
> >      * @param aName
> >      *          The Region to use for the JCS cache.
> >      * @param aKey
> >      *          The key to store the result under.
> >      * @param aGroup
> >      *          The group to store the result under.
> >      */
> >     public CachingWorker(String aRegion, Serializable aKey, String
> > aGroup) {
> >             region = aRegion;
> >             key = aKey;
> >             group = aGroup;
> >             finished = false;
> >     }
> >     /**
> >      * Abstract method to implement for the case where the object
> has
> > not been
> >      * cached yet, and we need to get it from somewhere else and
> stick
> > the result
> >      * in the cache.
> >      *
> >      * You should not be calling this yourself! Call getResult()
> > instead.
> >      *
> >      * @return The result of doing the work to be cached and
> returned in
> >      *         getResult()
> >      * @throws Exception
> >      *           If something goes wrong, throw an Exception and
> nothing
> > will get
> >      *           cached.
> >      */
> >     protected abstract Object doWork() throws Exception;
> >     /**
> >      * Getter for the region of the JCS Cache.
> >      *
> >      * @return The JCS region in which the result will be cached.
> >      */
> >     public String getRegion() {
> >             return region;
> >     }
> >     /**
> >      * Getter for the key used to store the result of doing the work
> in
> > JCS.
> >      *
> >      * @return The key used to cache the result of the work.
> >      */
> >     public Serializable getKey() {
> >             return key;
> >     }
> >     /**
> >      * Getter for the group used to store the result of doing the
> work
> > in JCS.
> >      *
> >      * @return The key group used to cache the result of the work
> (could
> > be null).
> >      */
> >     public String getGroup() {
> >             return group;
> >     }
> >     /**
> >      * Gets the cached result for this region/key OR does the work
> and
> > caches the
> >      * result, returning the result. If the result has not been
> cached
> > yet, this
> >      * calls doWork() to do the work and cache the result.
> >      *
> >      * This is also an opertunity to do any post processing of the
> > result in your
> >      * CachedWorker implementation.
> >      *
> >      * @return The result of doing the work, or the cached result.
> >      * @throws Exception
> >      *           Throws an exception if anything goes wrong while
> doing
> > the work.
> >      */
> >     public Object getResult() throws Exception {
> >             return run();
> >     }
> >     /**
> >      * Try and get the object from the cache, and if it's not there,
> do
> > the work
> >      * and cache it. This also ensures that only one CachedWorker is
> > doing the
> >      * work and subsequent calls to a CachedWorker with identical
> > region/key/group
> >      * will wait on the results of this call.
> >      *
> >      * @return Either the result of doing the work, or the cached
> > result.
> >      * @throws Exception
> >      *           If something goes wrong while doing the work, throw
> an
> > exception.
> >      */
> >     private Object run() throws Exception {
> >             long start = 0;
> >             long dbTime = 0;
> >             CachingWorker thread = null;
> >             synchronized (map) {
> >                     //Check to see if we allready have a thread
> doing
> > this work.
> >                     thread = (CachingWorker) map.get(getRegion() +
> > getKey());
> >                     if (thread == null) {
> >                             //If not, add ourselves as the Worker so
> >                             //calls in another thread will use this
> > worker's result
> >                             map.put(getRegion() + getKey(), this);
> >                     }
> >             }
> >             if (thread != null) {
> >                     synchronized (thread) {
> >                             if (logger.isDebugEnabled()) {
> >                                     logger.debug("Found a worker
> > allready doing this work (" + thread.getRegion() + ":" +
> thread.getKey() +
> > ").");
> >                             }
> >                             if (!thread.finished) {
> >                                     thread.wait();
> >                             }
> >                             if (logger.isDebugEnabled()) {
> >                                     logger.debug("Another thread
> > finished our work for us. Using thoes results instead. (" +
> > thread.getRegion() + ":" + thread.getKey() + ").");
> >                             }
> >                             //Get the result and return it.
> >                             result = thread.result;
> >                             wasCached = thread.wasCached;
> >                             return result;
> >                     }
> >             }
> >             //Do the work
> >             try {
> >                     if (logger.isDebugEnabled()) {
> >                             logger.debug(getRegion() + " is doing
> the
> > work.");
> >                     }
> >                     result = null;
> >                     //Get the cache
> >                     JCS cache = JCS.getInstance(getRegion());
> >                     //Try to get the item from the cache
> >                     if (group != null) {
> >                             result = cache.getFromGroup(getKey(),
> > group);
> >                     } else {
> >                             result = cache.get(getKey());
> >                     }
> >                     //If the cache dosn't have it, do the work.
> >                     wasCached = true;
> >                     if (result == null) {
> >                             wasCached = false;
> >                             result = doWork();
> >                             if (logger.isDebugEnabled()) {
> >                                     logger.debug("Work Done,
> caching:
> > key:" + getKey() + ", group:" + getGroup() + ", result:" + result +
> ".");
> >                             }
> >                             //Stick the result of the work in the
> cache.
> >                             if (group != null) {
> >                                     cache.putInGroup(getKey(),
> group,
> > result);
> >                             } else {
> >                                     cache.put(getKey(), result);
> >                             }
> >                     }
> >                     //return the result
> >                     return result;
> >             } finally {
> >                     if (logger.isDebugEnabled()) {
> >                             logger.debug(getRegion() + ":" +
> getKey() +
> > " entered finally.");
> >                     }
> >                     synchronized (map) {
> >                             //Remove ourselves as the worker.
> >                             map.remove(getRegion() + getKey());
> >                             synchronized (this) {
> >                                     finished = true;
> >                                     //Wake everyone waiting on us
> >                                     notifyAll();
> >                             }
> >                     }
> >             }
> >     }
> > }
> >
> >
---------------------------------------------------------------------
> > To unsubscribe, e-mail:
[EMAIL PROTECTED]
> > For additional commands, e-mail:
> [EMAIL PROTECTED]
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail:
[EMAIL PROTECTED]
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail:
[EMAIL PROTECTED]


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

Reply via email to