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:tsavo@xxxxxxxxx]
> 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:aasmuts@xxxxxxxx]
> 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:tsavo@xxxxxxxxx]
> > 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:
turbine-jcs-dev-unsubscribe@xxxxxxxxxxxxxxxxxx
> > For additional commands, e-mail:
> turbine-jcs-dev-help@xxxxxxxxxxxxxxxxxx
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: turbine-jcs-dev-unsubscribe@xxxxxxxxxxxxxxxxxx
> For additional commands, e-mail:
turbine-jcs-dev-help@xxxxxxxxxxxxxxxxxx
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: turbine-jcs-dev-unsubscribe@xxxxxxxxxxxxxxxxxx
> For additional commands, e-mail:
turbine-jcs-dev-help@xxxxxxxxxxxxxxxxxx
|