Summary |  Admin |  Home Page |  Forums |  Tracker |  Bugs |  Support |  Patches |  RFE |  Lists |  Tasks |  Docs |  News |  SVN |  Files
For Version 0.5

Table of Contents

1 Introduction

Ehcache-constructs provides implementations of common caching patterns. They can be used as they are or as a starting pointing for custom caching code. Ehcache-constructs uses ehcache for the backing cache.

Constructs

Doug Lea in his book Concurrent Programming in Java talks about concurrency support constructs. One meaning of a construct is "an abstract or general idea inferred or derived from specific instances".  Just like patterns emerge from noting the similarities of problems and gradually finding a solution to classes of them, so to constructs are general solutions to commond problems. With ehcache-constructs, concrete, extensible implementations are offered to solve these common problems.

Caching meets Concurrent Programming

All of the constructs use a combination of ehcache and concurrent programming. As Adam, a friend of mine says, "What could possibly go wrong?" Well in concurrent programming, the answer is: "A lot".

(The following section is based on Chapter 1.3 of Doug Lea's  Concurrent Programming in Java).

There are two often conflicting design goals at play in concurrent programming. They are:
  1. liveness, where something eventually happens within an activity.
  2. safety, where nothing bad ever happens to an object.

Safety Failures


Failures of safety include:
A cache is similar to a global variable. By its nature it is accessible to multiple threads. Because caching is often done for performance, cache entries can be highly contended for.

Liveness Failures


Failures of liveness include:
There are many different failures. Testing for all of them is tedious and time-consuming. It is sometimes hard to foresee all of them. The first BlockingCache implementation ran for almost a year on a very busy application before finally getting overwhelmed. It was using notifyAll(), and once the load on the cache got very high indeed, the threads started spending most of their time stampeding to the object lock and very little time doing anything else. The result was that server threads went to 1500 and server output dropped to almost nothing.

Ehcache-constructs provides high-quality, unit and production-tested implementations for developers to use.  All released constructs have had a minimum of several months production use. Some of them have several years of production time. In addition each one has tests in the test package. These tests include concurrency and scalability tests. See the tests here.

2 Provided Pattern Implementations

At present ehcache-constructs contains:

General Purpose Caching


Web Caching

Servlet 2.3 caching filters that cache HTTP/S responses:

3 Java Requirements

Ehcache-constructs supports JDK1.2, 1.3, 1.4 and 5 at runtime. When compiling from source, the build process requires JDK 1.4 or 5.

Ehcache-constructs does not work with JDK1.1.

4 Dependencies

Ehcache-constructs requires:

In addition For JDK1.2 and JDK 1.3, ehcache requires:

The dependencies are also required for ehcache and Hibernate, so if you already have either of those, your dependency requirements are met.

The filter constructs are designed to run in a Web Container which meets the Servlet 2.3 specification.

It has been reported that IBM Websphere 5.1 running on IBM JDK1.4 requires commons-collection.jar even though it does not use it.

5 Installation

The steps are:
  1. Place the ehcache-constructs-X.X.jar into your classpath.
  2. Ensure that any libraries required to satisfy dependencies are also in the classpath.
  3. As an optional step, configure an appropriate logging level.

6 Logging

Ehcache uses the Apache Commons Logging library. It acts as a thin bridge between logging statements in the code and logging infrastructure detected in the classpath. It will use in order of preference: log4j, JDK1.4 logging and then its own SimpleLog .  This enables ehcache to use logging infrastructures compatible with Java versions from JDK1.2 to JDK5. It does create a dependency on Apache Commons Logging, however many projects, including Hibernate, share the same dependency.

For normal production use, use the WARN level in log4J and the WARNING level for JDK1.4 logging. 

7 Obtaining the Source Code

The source code is distributed in the root directory of the download. It is called ehcache-constructs-x.x-src.zip. It is also available from SourceForge online or through cvs.

Online

The source code can be viewed online via viewcvs.

CVS

You can check out the sourcecode anonymously using cvs as follows:

1. cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/ehcache login
2. cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/ehcache co ehcache-constructs

8 Using The Constructs

In this section each construct is presented in a context of a pattern.

For each one, there are tests which show further examples of usage.  See the online  tests.

BlockingCache

Scenario

An expensive operation is required, say rendering a large web page, which takes 30 seconds. The page is not considered stale until it is 5 minutes old.  The page is hit very heavily and will be hit an average of 20 times per minute each 5 minutes.

Solution

You could use Cache directly here and do a Cache.put(Element element) to put it in after rendering and then a Cache.get(Serializable key) to get the cached versions out. This will work quite well. However once every five minutes the page will expire and it will need to be re-rendered. In the 30 seconds required to do so, 9 more requests will come in, each of which will be rendered. After that, the rendered page will be put in the cache and the cache will be hit with requests. So rather than doing only 1 render every 5 minutes 10 are required.

If, instead you use a BlockingCache, when the page is being rendered the other 9 requests that come in will be blocked. When the first rendering request finishes, the other 9 requests will be returned the cached page. This approach only requires 1 render each 5 minutes.

Implementation

Below is a code fragment showing the semantics for using a BlockingCache to implement the solution,


private BlockingCache blockingCache;

private PageInfo processRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    final String key = calculateKey(request);
    PageInfo pageInfo = (PageInfo) blockingCache.get(key);
    if (pageInfo == null) {
        try {
            //Page is not cached - build the response, cache it, and send to client
            pageInfo = buildPage(request, response, chain);
            blockingCache.put(key, pageInfo);
            return pageInfo
        } catch (final Throwable throwable) {
            // Must unlock the cache if the above fails
            blockingCache.put(key, null);
            throw new Exception("Could not build cached page.", throwable);
        }
}

SelfPopulatingCache

Scenario

A number of database queries need to be done to build a complicated collection of value objects to perform a search and generate search results.  A search takes 30 seconds to perform.  Search results can be no staler than 2 minutes. An average of 100 searches with the same queries are done per minute.

Solution

A Hibernate  Query Cache could be used. The cache could be configured to expire after two minutes. Once expired however, in the time taken for the Hibernate Query Cache to repopulate, 50 searches will have occurred. Over the 2 minutes, out of 200 searches performed, 50 will be uncached.

A BlockingCache will remove the extra searches, while the repopulate is being done. The uncached searches will drop to 1 out of 200. However, all search threads will block while the repopulate takes place.  A user will usually see fast responses but every two minutes 50 requests will take 30 seconds.

Implementation


  1. Extend SelfPopulatingCacheManager
  2. Create a SelfPopulatingCache
  3. Create a SelfPopulatingCacheEntryFactory
  4. Use a thread to call refresh. Perhpas JMX or a timing service such as Quartz.
  5. Configure the cache in ehcache.xml. The cache might be external because it is being refreshed.


SourceForge.net