Summary |  Admin |  Home Page |  Forums |  Tracker |  Bugs |  Support |  Patches |  RFE |  Lists |  Tasks |  Docs |  News |  CVS |  Files

Table of Contents

1 Installation

Java Requirements

Ehcache 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 does not work with JDK1.1.

Dependencies

For JDK1.4 and JDK5, ehcache requires commons-logging and commons-collections 3.1 from Apache's Jakarta project.  The commons-collections library provided in hibernate is 2.1, so you will need to upgrade it if working with Hibernate.

For JDK1.2 and JDK 1.3, ehcache also requires Apache xerces (xml-apis.jar and xercesImpl.jar), version 2.5.

The dependencies are also Hibernate dependencies, so if you are using ehcache as a Hibernate plugin, dependency requirements are met.

Step-by-step Installation Instructions

For Use with Hibernate or Spring

There is nothing to do. Hibernate and Spring include ehcache.

For Use  as a General Purpose Cache

This assumes you do not have Hibernate installed.

The steps are:
  1. Place the ehcache-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.

2 CacheConcepts

ehcache consists of a CacheManager, which manages caches. Caches contain elements, which are essentially name value pairs. Caches are physically implemented either in-memory, or on disk.

CacheManager

The Cache Manager is made up of Caches which contain elements.  Creation of, access to and removal of caches is controlled by the CacheManager. You may only have one CacheManager per class loader, as it expects to be a singleton. If an application has more than one, ensure a separate configuration file is used for each. Otherwise disk caches will conflict.

Cache

A cache has a name and attributes. Each cache contains elements.

The JCACHE JSR also has groups, which is an association between objects in the same cache. They may be invalidated together or have the same element attributes. While groups may be useful, they are not used in Hibernate and has not been implemented in ehcache.

Cache elements are stored in the MemoryStore. Optionally they also overflow to a DiskStore.

Element

An element is an atomic entry in a cache. It has a key, a value and a record of accesses. Elements are put into and removed from caches. They can also expire and be removed by the Cache, depending on the Cache settings.

3 Storage Options

Ehcache has two physical stores:
  1. a MemoryStore and
  2. a DiskStore

Memory Store

The MemoryStore is always enabled. It is not directly manipulated, but is a component of every cache.

It has the following characteristics:

Safety

Thread safe for use by multiple concurrent threads.

Tested for memory leaks. See MemoryCacheTest#testMemoryLeak. This test passes for ehcache but exploits a number of memory leaks in JCS. JCS will give an OutOfMemory error with a default 64M in 10 seconds.

Backed By JDK LinkedHashMap

The MemoryStore for JDK1.4 and JDK 5 it is backed by an extended LinkedHashMap. This provides a combined linked list and a hash map, and is ideally suited for caching. Using this standard Java class simplifies the implementation of the memory cache.  It directly supports obtaining the least recently used element.

For JDK1.2 and JDK1.3, the LRUMap from Apache Commons is used. It provides similar features to LinkedHashMap.

The implementation is determined dynamically at runtime. LinkedHashMap is preferred if found in the classpath.

Fast

ehcache is faster than JCS. Here are some benchmarks from MemoryStoreTest.

Benchmark
ehcache
JCS Difference
insert 5 million typical CacheElements. Then get each of them by key.
 22.704s
42.176s
79% faster
insert 5,000,000 typical CacheElements and get each of them by key. Then remove them one at a time by key
14.999s
44.536s
293% faster

Memory Use, Spooling and Expiry Strategy

All caches specify their maximum in-memory size, in terms of the number of elements, at configuration time.

When an element is added to a cache and it goes beyond its maximum memory size, an existing element is either deleted, if overflowToDisk is false, or evaluated for spooling to disk, if overflowToDisk is true. In the latter case, a check for expiry is carried out. If it is expired it is deleted;  if not it is spooled. The eviction of an item from the memory store is based on an LRU algorithm.
or all the eviction policies there are also putQuiet and getQuiet methods which do not update the last used timestamp.

When there is a get or a getQuiet on an element, it is checked for expiry. If expired, it is removed and null is returned.

Note that at any point in time there will usually be some expired elements in the cache.  Memory sizing of an application must always take into account the maximum size of each cache. There is a convenience method which can provide an estimate of the size in bytes of the MemoryStore. See calculateInMemorySize(). It returns the serialized size of the cache. Do not use this method in production. It is very slow. It is only meant to provide a rough estimate.

The alternative would have been to have an expiry thread. This is a trade-off between lower memory use and short locking periods and cpu utilisation. The design is in favour of the latter. For those concerned with memory use, simply reduce the maxElementsInMemory.

DiskStore

The disk cache provides a disk spooling facility.

It has the following characteristics:

Storage Files

The disk cache creates one file per cache called "cache name.data".  if the DiskStore is configured to be persistent, a "cache name.index" file is also created.

Files are created in the directory specified by the diskStore configuration element. The default configuration is "java.io.tmpdir", which causes files to be created in the system's temporary directory.  Following is a list of Java system properties which are supported as values for diskStore:
Apart from these, any directory can be specified using syntax appropriate to the operating system. e.g. for Unix "/home/application/cache".

Expiry Strategy

One thread per cache is used to remove expired elements. The optional attribute  diskExpiryThreadIntervalSeconds sets the interval between runs of the expiry thread. Warning: setting this to a low value is not recommended. It can cause excessive DiskStore locking and high cpu utilisation. The default value is 120 seconds.

Serializable Objects Only

Only Serializable objects can be stored in a DiskStore. A NotSerializableException will be thrown if the object is not serializable.

Safety

DiskStores are thread safe.

Persistence

DiskStore persistence is controlled by the diskPersistent  configuration element. If false or omitted, DiskStores will not persist between CacheManager restarts. The data file for each cache will be deleted, if it exists, both on shutdown and startup. No data from a previous instance CacheManager is available.

If diskPersistent is true, the data file, and an index file, are saved. Cache Elements are available to a new CacheManager. This CacheManager may be in the same VM instance, or a new one.

The data file is updated continuously during operation of the Disk Store. New elements are spooled to disk, and deleted when expired. The index file is only written when dispose is called on the DiskStore. This happens when the CacheManager is shut down, a Cache is disposed, or the VM is being shut down.  It is recommended that the CacheManager shutdown() method be used. See Virtual Machine Shutdown Considerations for guidance on how to safely shut the Virtual Machine down.

When a DiskStore is persisted, the following steps take place:
  1. Any non-expired Elements of the MemoryStore are flushed to the DiskStore
  2. Elements awaiting spooling are spooled to the data file
  3. The free list and element list are serialized to the index file
On startup the following steps take place:
  1. An attempt is made to read the index file. If it does not exist or cannot be read successfully, due to disk corruption, upgrade of ehcache, change in JDK version etc, then the data file is deleted and the DiskStore starts with no Elements in it.
  2. If the index file is read successfully, the free list and element list are loaded into memory. Once this is done, the index file contents are removed. This way, if there is a dirty shutdown, when restarted, ehcache will delete the dirt index and data files.
  3. The DiskStore starts. All data is available.
  4. The expiry thread starts. It will delete Elements which have expired.
These actions favour safety over persistence. Ehcache is a cache, not a database. If a file gets dirty, all data is deleted. Once started there is further checking for corruption. When a get is done, if the Element cannot be successfully derserialized, it is deleted, and null is returned. These measures prevent corrupt and inconsistent data being returned.

Fragmentation

Expiring an element frees its space on the file. This space is available for reuse by new elements.  The element is also removed from the in-memory index of elements.

Speed

Spool requests are placed in-memory and then asynchronously written to disk. There is one thread per cache.  An in-memory index of elements on disk is maintained to quickly resolve whether a key exists on disk, and if so to seek it and read it.

Serialization

Writes to and from the disk use ObjectInputStream and the Java serialization mechanism. This is not required for the Memory Cache. So the disk cache will never be as fast.

Serialization speed is affected by the size of the objects being serialized and their type. It has been found in the ElementTest test that:
Byte arrays are 20 times faster to serialize. Make use of byte arrays to increase DiskStore performance.

RAMFS

However disks can be of different speeds. The disk cache can be sped up by using a faster disk. On some operating systems there are a plethora of file systems to choose from. For example, the Disk Cache has been successfully used with Linux' RAMFS file system. This file system simply consists of memory. Linux presents it as a file system. The Disk Cache treats it like a normal disk - it is just way faster. With this type of file system, object serialization becomes the limiting factor to performance.



4 Performance Considerations

Ehcache comes with a MemoryStore and a DiskStore. The MemoryStore is approximately an order of magnitude faster than the DiskStore. The reason is that the DiskStore incurs the following extra overhead: Note that writing to disk is not a synchronous performance overhead because it is handled by a separate thread.

A Cache should alway have its maximumSize attribute set to 1 or higher. A Cache with a maximum size of 1 has twice the performance of a disk only cache, i.e. one where the maximumSize is set to 0. For this reason a warning will be issued if a Cache is created with a 0 maximumSize.

5 Distributed Caching

Ehcache is not a distributed cache. There are no plans to make it a distributed cache. The key design goals of ehcache are simplicity and provability. Adding a distribution mechanism to ehcache conflicts with those goals. Moreover, a requirement for distribution is far less common than for requirements such as memory and disk storage.

Ehcache does however support distribution. Many of the open source distributed caches use the JGroups project for distribution framework. Or, if you are using J2EE it is straightforward to expose the CacheManager via an EJB session bean.

A CacheManager can access Caches and Elements. Elements are serializable. and can be sent over a network using RMI or another protocol.

6 Virtual Machine Shutdown Considerations

The DiskStore can optionally be configured to persist between CacheManager and Virtual Machine instances. See  documentation on the diskPersistent  cache attribute for information on how to do this.

When diskPersistent is turned on for a cache, a Virtual Machine shutdown hook is added to enable the DiskStore to persist itself. When the Virtual Machine shuts down, the the hook runs and, if the cache is not already disposed, it calls dispose. Any elements in the MemoryStore are spooled to the DiskStore. The DiskStore then flushes the spool, and writes the index to disk.

The cache shutdown hooks will run when:
The cache shutdown hooks will not run when:
If dispose was not called on the cache either by CacheManager.shutdown() or the shutdown hook, then the DiskStore will be corrupt when the application is next started. If this happens, it will be detected and the DiskStore file will be automatically truncated and a log warning level message is emitted. The cache will work normally, except that it will have lost all data.
 

7 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. 

8 Obtaining the Source Code

The source code is distributed in the root directory of the download. It is called ehcache-x.x.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

9 Cache Configuration

Declarative versus Programmatic Configuration

Declarative configuration refers to the practice of declaring configuration at design time. Programmatic configuration to the practice of configuring at runtime.

In ehcache the following must always be configured declaratively:
  1. The directory in which DiskStores are to be created. (diskStore element)
  2. Default configuration for caches created without declarative or programmatic configuration.  (defaultCache element)
Individual caches can be configured either declaratively or programmatically.

It is better practice to configure caches declaratively because:
  1. It is easy if you have all of your configuration in one place. Caches consume memory, and disk space. They need to be carefully tuned. You can see the total effect in a configuration file. You could do this code, but it would not as visible.
  2. It is possible to change configuration without doing a recompile.
  3. Common configuration errors can be checked for at start-up, rather than causing a runtime error.
The programmatic facility is provided primarily so that new caches can be dynamically created at runtime.

Declarative Configuration

The ehcache schema: ehcache.xsd

Ehcache looks for an ehcache.xml file. These must be configured in accordance with the following schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="ehcache">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="diskStore"/>
        <xs:element ref="defaultCache"/>
        <xs:element maxOccurs="unbounded" ref="cache"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="diskStore">
    <xs:complexType>
      <xs:attribute name="path" use="required" type="xs:NCName"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="defaultCache">
    <xs:complexType>
      <xs:attribute name="eternal" use="required" type="xs:boolean"/>
      <xs:attribute name="maxElementsInMemory" use="required" type="xs:integer"/>
      <xs:attribute name="overflowToDisk" use="required" type="xs:boolean"/>
      <xs:attribute name="timeToIdleSeconds" use="optional" type="xs:integer"/>
      <xs:attribute name="timeToLiveSeconds" use="optional" type="xs:integer"/>
      <xs:attribute name="diskPersistent" use="optional" type="xs:integer"/>
      <xs:attribute name="diskExpiryThreadIntervalSeconds" use="optional" type="xs:integer"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="cache">
    <xs:complexType>
      <xs:attribute name="eternal" use="required" type="xs:boolean"/>
      <xs:attribute name="maxElementsInMemory" use="required" type="xs:integer"/>
      <xs:attribute name="name" use="required" type="xs:NCName"/>
      <xs:attribute name="overflowToDisk" use="required" type="xs:boolean"/>
      <xs:attribute name="timeToIdleSeconds" use="optional" type="xs:integer"/>
      <xs:attribute name="timeToLiveSeconds" use="optional" type="xs:integer"/>
      <xs:attribute name="diskPersistent" use="optional" type="xs:integer"/>
      <xs:attribute name="diskExpiryThreadIntervalSeconds" use="optional" type="xs:integer"/>
    </xs:complexType>
  </xs:element>
</xs:schema>
The schema is also provided in the root directory of the ehcache distribution.

diskStore

The diskStore element is required, regardless of whether or not it is intended to use any DiskStores.

path

This is a required attribute.

It sets the path used by any DiskStore objects for creating data and index files.

Legal values must be a relative or absolute path to a directory with syntax legal for the operating system ehcache is running on.  If the directory does not exist an attempt is made to create it.

If the path value is a Java System Property (e.g. "user.home") it is replaced by its runtime value in the Virtual Machine.

The following Java System Properties are understood:
user.home      - User's home directory
user.dir       - User's current working directory
java.io.tmpdir - Default temporary directory

defaultCache

The defaultCache element contains configuration used by ehcache to create caches, where a cache element matching the cache name does not exist. It is a template.

An example of it use is in Hibernate. When you specify that a Domain Object is cacheable Hibernate creates a new cache using the fully qualified class name of the Domain Object as the cache name. No configuration information is provided. Ehcache automatically creates the new caches using the defaultCache settings as a template.

While the defaultCache is a great convenience, it is preferable for each Cache to be configured individually. For this reason a log warning level message is issued each time a cache is created based on the defaultCache values.  

cache

The cache element contains configuration used by ehcache to create each cache. When the CacheManager is created it parses ehcache.xml for cache elements and creates a cache for each one with the settings provided.

defaultCache and cache attributes

defaultCache and cache share the same attributes, except that an additional name attribute is required for the cache element.

name

This is a required attribute for cache elements only. The defaultCache does not have a name attribute.

Legal values are any legal String value. Names must be unique. Ehcache will throw a CacheException if an attempt is made to create two caches with the same name.

Hibernate users should use the fully qualified class name of the DomainObject being cached.  There are different rules for other types of Hibernate cache. For more on Hibernate naming see  Using ehcache as a Hibernate Plugin.

eternal

This is a required attribute.

Whether or not the cache is eternal. An eternal cache does not expire its elements.

Legal values are "true" or "false".

maxElementsInMemory

This is a required attribute.

Legal values are integers between 0 and Integer.MAX_VALUE.

It is the maximum number of elements to store in the MemoryStore. It is strongly recommended for performance reasons that this value is at least 1. If not a warning will be issued at Cache creation time.

overflowToDisk

This is a required attribute.

Legal values are "true" or "false".

Whether or not to use the DiskStore when the number of Elements has exceeded the maxElementsInMemory of the MemoryStore.

Entries to be removed from the MemoryStore, when it overflows, are determined using a least recently used algorithm ("LRU"). Used means inserted or accessed. If false, the LRU Element is discarded. If true, it is transferred to the DiskStore.

timeToIdleSeconds

This is an optional attribute.

Legal values are integers between 0 and Integer.MAX_VALUE.

It is the number of seconds that an Element should live since it was last used. Used means inserted or accessed.

0 has a special meaning, which is not to check the Element for time to idle, i.e. it will idle forever.

The default value is 0.

timeToLiveSeconds

This is an optional attribute.

Legal values are integers between 0 and Integer.MAX_VALUE.

It is the number of seconds that an Element should live since it was created. Created means inserted into a cache using the Cache.put method.

0 has a special meaning, which is not to check the Element for time to live, i.e. it will live forever.

The default value is 0.

diskPersistent

This is an optional attribute.

Legal values are "true" or "false".

Whether or not the DiskStore should be persisted between CacheManager shutdowns and Virtual Machine restarts.

diskExpiryThreadIntervalSeconds

This is an optional attribute.

Legal values are integers between 0 and Integer.MAX_VALUE.

It is how long to the disk expiry thread should sleep between successive runs. Setting this value too low could cause performance problems. A setting of 0 is not recommended. It will cause 100% cpu load.

The default value is 120 seconds.

Sample ehcache.xml

A sample ehcache.xml configuration file is included in the root directory of the ehcache distribution. It is reproduced below.

The sample includes a diskStore element, a defaultCache element and three cache elements.
       
<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="java.io.tmpdir"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required:

        maxElementsInMemory            - Sets the maximum number of objects that will be created in memory
        eternal                        - Sets whether elements are eternal. If eternal,  timeouts are ignored and the
                                         element is never expired.
        overflowToDisk                 - Sets whether elements can overflow to disk when the in-memory cache
                                         has reached the maxInMemory limit.

        The following attributes are optional:
        timeToIdleSeconds              - Sets the time to idle for an element before it expires.
                                         i.e. The maximum amount of time between accesses before an element expires
                                         Is only used if the element is not eternal.
                                         Optional attribute. A value of 0 means that an Element can idle for infinity.
                                         The default value is 0.
        timeToLiveSeconds              - Sets the time to live for an element before it expires.
                                         i.e. The maximum time between creation time and when an element expires.
                                         Is only used if the element is not eternal.
                                         Optional attribute. A value of 0 means that and Element can live for infinity.
                                         The default value is 0.
        diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine.
                                         The default value is false.
        diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
                                         is 120 seconds.
        -->

    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        />

    <!--Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required:

        name                           - Sets the name of the cache. This is used to identify the cache.
                                         It must be unique.
        maxElementsInMemory            - Sets the maximum number of objects that will be created in memory
        eternal                        - Sets whether elements are eternal. If eternal,  timeouts are ignored and the
                                         element is never expired.
        overflowToDisk                 - Sets whether elements can overflow to disk when the in-memory cache
                                         has reached the maxInMemory limit.

        The following attributes are optional:
        timeToIdleSeconds              - Sets the time to idle for an element before it expires.
                                         i.e. The maximum amount of time between accesses before an element expires
                                         Is only used if the element is not eternal.
                                         Optional attribute. A value of 0 means that an Element can idle for infinity.
                                         The default value is 0.
        timeToLiveSeconds              - Sets the time to live for an element before it expires.
                                         i.e. The maximum time between creation time and when an element expires.
                                         Is only used if the element is not eternal.
                                         Optional attribute. A value of 0 means that and Element can live for infinity.
                                         The default value is 0.
        diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine.
                                         The default value is false.
        diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
                                         is 120 seconds.
        -->

    <!-- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        overflowToDisk="true"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        />

    <!-- Sample cache named sampleCache2
        This cache has a maximum of 1000 elements in memory. There is no overflow to disk, so 1000
        is also the maximum cache size. Note that when a cache is eternal, timeToLive and timeToIdle
        are not used and do not need to be specified -->
    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        overflowToDisk="false"
        />

    <!-- Sample cache named sampleCache3. This cache overflows to disk. The disk store is persistent
         between cache and VM restarts. The disk expiry thread interval is set to 10 minutes, overriding
         the default of 2 minutes. -->

    <cache name="sampleCache3"
        maxElementsInMemory="500"
        eternal="false"
        overflowToDisk="true"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        diskPersistent="true"
        diskExpiryThreadIntervalSeconds="1"
        />

    <!-- Place configuration for your caches following -->

</ehcache>

Installing ehcache.xml


By default the CacheManager.create() method expects to find ehcache.xml as a resource in the classpath. It uses Configurator.getClass().getResource(/"ehcache.xml"). The ehcache.xml file should be placed at the root of the classpath, not in a package. If placed in a jar, it should be in the root level directory of the jar.

If ehcache cannot find ehcache.xml it will instead use the failsafe configuration.

The CacheManager can also obtain ehcache.xml in other ways. See Creating a CacheManager.

Failsafe Configuration

Ehcache comes with a failsafe configuration declared in the ehcache-failsafe.xml file, which is provided in the ehcache.jar. It is only used when no ehcache.xml configuration file is found in the classpath, and CacheManager is created without any arguments. If it is used a log warning level message will be issued.

Ehcache deliberately avoids placing an ehcache.xml configuration file in the JAR archive so as to avoid frustrating classpath precedence problems.

The failsafe configuration provides ehcache with the minimum to function: specified diskStore and defaultCache elements. It sets the DiskStore path attribute to the value given by the Java system property "java.io.tmpdir" (/tmp on Unix-like systems) and sets the default cache to reasonable values. ehcache-failsafe.xml is reproduced here:

<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="java.io.tmpdir"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required:

        maxElementsInMemory            - Sets the maximum number of objects that will be created in memory
        eternal                        - Sets whether elements are eternal. If eternal,  timeouts are ignored and the
                                         element is never expired.
        overflowToDisk                 - Sets whether elements can overflow to disk when the in-memory cache
                                         has reached the maxInMemory limit.

        The following attributes are optional:
        timeToIdleSeconds              - Sets the time to idle for an element before it expires.
                                         i.e. The maximum amount of time between accesses before an element expires
                                         Is only used if the element is not eternal.
                                         Optional attribute. A value of 0 means that an Element can idle for infinity.
                                         The default value is 0.
        timeToLiveSeconds              - Sets the time to live for an element before it expires.
                                         i.e. The maximum time between creation time and when an element expires.
                                         Is only used if the element is not eternal.
                                         Optional attribute. A value of 0 means that and Element can live for infinity.
                                         The default value is 0.
        diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine.
                                         The default value is false.
        diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
                                         is 120 seconds.
        -->

    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        overflowToDisk="true"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        />
</ehcache>

Programmatic Configuration

The configuration for a Cache can be specified programmatically in the Cache constructor:

 public Cache(String name,
                 int maxElementsInMemory,
                 boolean overflowToDisk,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds) {
   ...
}

Here is an example which creates a cache called test.
//Create a CacheManager using defaults
CacheManager manager = CacheManager.create();
//Create a Cache specifying its configuration.
Cache testCache = new Cache("test", maxElements, true, false, 60, 30, false, 0);
manager.addCache(cache);

Once the cache is created, add it to the list of caches managed by the CacheManager:

manager.addCache(testCache);
The cache is not usable until it has been added.

10 Code Samples

Ehcache comes with a comprehensive JUnit test suite. The test suite shows you how to use all the features of ehcache.

Following are code samples for the most common tasks.

For comprehensive code samples see the test source code:
  1. In CVS online with viewcvs
  2. In the source distributed with the download

Using the CacheManager


Create a CacheManager using defaults
CacheManager manager = CacheManager.create();


Create a CacheManager specifying a configuration file.
CacheManager manager = CacheManager.create("src/config/ehcache.xml");


Create a CacheManager from a configuration resource in the classpath.
URL url = getClass().getResource("/anothername.xml");
CacheManager manager = CacheManager.create(url);

Create a CacheManager from a configuration in an InputStream.
InputStream fis = new FileInputStream(new File("src/config/ehcache.xml").getAbsolutePath());
try {
    manager = CacheManager.create(fis);
} finally {
    fis.close();
}
   


Shutdown the CacheManager
manager.shutdown();


Using Caches


Obtain a Cache called "sampleCache1" which has been preconfigured in the configuration file
Cache cache = manager.getCache("sampleCache1");
Create a new Cache called "test" which does not exist, using defaults
CacheManager manager = CacheManager.create();
manager.addCache("test");

Create a new Cache called "test", specifying its properties.
CacheManager manager = CacheManager.create();
Cache cache = new Cache("test", 1, true, false, 5, 2);
manager.addCache(cache);

Put an element into a cache
Element element = new Element("key1", "value1"
cache.put(new Element(element);

Get an element from a cache
Element element = cache.get("key1");

11 Using ehcache as a Hibernate plugin

Ehcache easily integrates with  the Hibernate Object/Relational persistence and query service. Gavin King, the maintainer of Hibernate, is also a committer to the ehcache project. This ensures ehcache will remain a first class cache for Hibernate. Since Hibernate 2.1, ehcache has been the default cache, for Hibernate.

The net.sf.ehcache.hibernate package provides classes integrating ehcache with Hibernate. Hibernate is an application of ehcache. Ehcache is also widely used a general-purpose Java cache.

To use ehcache with Hibernate do the following:
  1. Ensure ehcache is enabled in the Hibernate configuration (it should already be)
  2. Add the cache element to the Hibernate mapping file, either manually, or via hibernatedoclet for each Domain Object you wish to cache
  3. Add the cache element to the Hibernate mapping file, either manually, or via hibernatedoclet for each Domain Object collection you wish to cache
  4. Add the cache element to the Hibernate mapping file, either manually, or via hibernatedoclet for each Hibernate query you wish to cache
  5. Create a cache element in ehcache.xml
Each of these steps is illustrated using a fictional Country Domain Object.

For more about cache configuration in Hibernate see the Hibernate documentation. Parts of this chapter are drawn from Hibernate documentation and source code comments. They are reproduced here for convenience in using ehcache.

Ensuring ehcache is enabled


To ensure ehcache is enabled, verify that the hibernate.cache.provider_class property is set to net.sf.ehcache.hibernate.Provider in the Hibernate configuration file; typically hibernate.cfg.xml. By default it should already be.

<property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.Provider</property>

The provider can also be set programmatically in Hiberante using Configuration.setProperty("hibernate.cache.provider_class", "net.sf.ehcache.hibernate.Provider").

Hibernate Mapping Files

In Hibernate, each domain object requires a mapping file.

For example to enable cache entries for the domain object com.somecompany.someproject.domain.Country there would be a mapping file something like the following:

<hibernate-mapping>
    <class
        name="com.somecompany.someproject.domain.Country"
        table="ut_Countries"
        dynamic-update="false"
        dynamic-insert="false"
    >                                                                                       
...

</hibernate-mapping>

To enable caching, add the following element.

<cache usage="read-write|nonstrict-read-write|read-only" />

e.g.

<cache usage="read-write" />

read-write

Caches data that is sometimes updated while maintaining the semantics of "read committed" isolation level. If the database is set to "repeatable  read", this concurrency strategy almost maintains the semantics.  Repeatable read isolation is compromised in the case of concurrent writes. 

This is an "asynchronous" concurrency strategy.

nonstrict-read-write

Caches data that is sometimes updated without ever locking the cache.  If concurrent access to an item is possible, this concurrency strategy  makes no guarantee that the item returned from the cache is the latest  version available in the database. Configure your cache timeout accordingly!
This is an "asynchronous" concurrency strategy.

This policy is the fastest. It does not use synchronized methods whereas read-write and read-only both do.

read-only

Caches data that is never updated.

Hibernate Doclet   

Hibernate Doclet, part of the XDoclet project, can be used to generate Hibernate mapping files from markup in JavaDoc comments.

Following is an example of a Class level JavaDoc which configures a read-write cache for the Country Domain Object:


/**
 * A Country Domain Object
 *
 * @hibernate.class table="COUNTRY"
 * @hibernate.cache usage="read-write"
 */
public class Country implements Serializable {                                    

...

}

The @hibernate.cache usage tag should be set to one of  read-write, nonstrict-read-write and read-only.

Configuration with ehcache.xml

Because ehcache.xml has a defaultCache, caches will always be created when required by Hibernate. However more control can be exerted by specifying a configuration per cache, based on its name.

In particular, because Hibernate caches are populated from databases, there is potential for them to get very large. This can be controlled by capping their maxElementsInMemory and specifying whether to overflowToDisk beyond that.

Hibernate uses a specific convention for the naming of caches of Domain Objects, Collections, and Queries.

Domain Objects

Hibernate creates caches named after the fully qualified name of Domain Objects.

So, for example to create a cache for com.somecompany.someproject.domain.Country create a cache configuration entry similar to the following in ehcache.xml.

<cache name="com.somecompany.someproject.domain.Country"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

Hibernate CacheConcurrencyStrategy

read-write, nonstrict-read-write and read-only policies apply to Domain Objects.

Collections

Hibernate creates collection caches named after the fully qualified name of the Domain Object followed by "." followed by the collection field name.

For example, a Country domain object has a set of advancedSearchFacilities.  The Hibernate doclet for the accessor looks like:


    /**
     * Returns the advanced search facilities that should appear for this country.
     * @hibernate.set cascade="all" inverse="true"
     * @hibernate.collection-key column="COUNTRY_ID"
     * @hibernate.collection-one-to-many class="com.wotif.jaguar.domain.AdvancedSearchFacility"
     * @hibernate.cache usage="read-write"
     */
    public Set getAdvancedSearchFacilities()  {
        return advancedSearchFacilities;
    }

You need an additional cache configured for the set. The ehcache.xml configuration looks like:

<cache name="com.somecompany.someproject.domain.Country"
        maxElementsInMemory="50"
        eternal="false"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
<cache name="com.somecompany.someproject.Country.advancedSearchFacilities"
        maxElementsInMemory="450"
        eternal="false"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

Hibernate CacheConcurrencyStrategy

read-write, nonstrict-read-write and read-only policies apply to Domain Object collections.

Queries

Hibernate allows the caching of query results. Two caches, one called "net.sf.hibernate.cache.StandardQueryCache" in version 2.1.4 and higher and  "net.sf.hibernate.cache.QueryCache" in versions 2.1.0 - 2.1.3, and one called "net.sf.hibernate.cache.UpdateTimestampsCache" are always used.

StandardQueryCache

This cache is used if you use a query  cache without setting a name. A typical ehcache.xml configuration is:

    <cache name="net.sf.hibernate.cache.StandardQueryCache"
        maxElementsInMemory="5"
        eternal="false"
        timeToLiveSeconds="120"
        overflowToDisk="true"/>


UpdateTimestampsCache


Tracks the timestamps of the most recent updates to particular tables. It is important that the cache timeout of the underlying cache implementation be set to a higher value than the timeouts of any of the query caches. In fact, it is recommend that the the underlying cache not be configured for expiry at all.

A typical ehcache.xml configuration is:

    <cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
        maxElementsInMemory="5000"
        eternal="true"
        overflowToDisk="true"/>

Named Query Caches

In addition, a QueryCache can be given a specific name in Hibernate using Query.setCacheRegion(String name). The name of the cache in ehcache.xml is then the name given in that method. The name can be whatever you want, but by convention you should use "query." followed by a descriptive name.

E.g.

<cache name="query.AdministrativeAreasPerCountry"
        maxElementsInMemory="5"
        eternal="false"
        timeToLiveSeconds="86400"
        overflowToDisk="true"/>


Using Query Caches

For example, let's say we have a common query running against the Country Domain.

Code to use a query cache follows:

public List getStreetTypes(final Country country) throws HibernateException {
        final Session session = createSession();
        try {
            final Query query = session.createQuery(
                    "select st.id, st.name"
                    + " from StreetType st "
                    + " where st.country.id = :countryId "
                    + " order by st.sortOrder desc, st.name");
            query.setLong("countryId", country.getId().longValue());
            query.setCacheable(true);
            query.setCacheRegion("query.StreetTypes");
            return query.list();
        } finally {
            session.close();
        }
    }

The query.setCacheable(true); line caches the query.

The query.setCacheRegion("query.StreetTypes"); line sets the name of the Query Cache.

Hibernate CacheConcurrencyStrategy

None of read-write, nonstrict-read-write and read-only policies apply to Domain Objects. Cache policies are not configurable for query cache. They act like a non-locking read only cache.

Hibernate Caching Performance Tips

To get the most out of ehcache with Hibernate, Hibernate's use of it's in-process cache is important to understand.

In-Process Cache

From Hibernate's point of view, Ehcache is an in-process cache. Cached objects are accessible across different sessions. They are common to the Java process.

Object Id

Hibernate identifies cached objects via an object id. This is normally the primary key of a database row.

Session.load

Session.load will always try to use the cache.

Session.find and Query.find

Session.find does not use the cache for the primary object. Hibernate will try to use the cache for any associated objects. Session.find does however cause the cache to be populated.

Query.find works in exactly the same way.

Use these where the chance of getting a cache hit is low.

Session.iterate and Query.iterate

Session.iterate always uses the cache for the primary object and any associated objects.

Query.iterate works in exactly the same way.

Use these where the chance of getting a cache hit is high.



SourceForge.net