|  |  |  | License Codehaus OpenEJB OpenJMS OpenORB Tyrex

Old releases
General
Release 1.3
Release 1.3rc1
Release 1.2

Main
Home
About
Features
Download
Dependencies
Reference guide
Publications
JavaDoc
Maven 2 support
Maven 2 archetypes
DTD & Schemas
Recent HTML changes
News Archive
RSS news feed
Project Wiki

Development/Support
Mailing Lists
SVN/JIRA
Contributing
Support
Continuous builds
Prof. services

Related projects
Spring ORM support
Spring XML factories
WS frameworks

XML
XML

XML Code Generator
XML Code Generator

JDO
Introduction
First steps
Using JDO
JDO Config
Types
JDO Mapping
JDO FAQ
JDO Examples
JDO HOW-TOs
Tips & Tricks
Other Features
JDO sample JAR

Tools
Schema generator

Advanced JDO
Caching
OQL
Trans. & Locks
Design
KeyGen
Long Trans.
Nested Attrs.
Pooling Examples
LOBs
Best practice

DDL Generator
Using DDL Generator
Properties
Ant task
Type Mapping

More
The Examples
3rd Party Tools
JDO Tests
XML Tests
Configuration

About
License
User stories
Contributors
Marketplace
Status, Todo
Changelog
Library
Contact
Project Name

## Castor JDO - Caching concepts

Introduction
Caching and long transactions
Configuration
Configuration sample - count-limited
Configuration sample - time-limited
fifo and lru cache providers
Configuration sample - fifo
Configuration sample - lru
Configuration sample - fifo (custommized)
Caching and clustered environments
Configuration sample - Coherence
Configuration sample - Gigaspaces
Custom cache provider
Cache implementation
CacheFactory implementation
Configuration
CacheManager - monitoring and clearing caches

## Introduction

As explained at the introduction to Castor JDO, Castor has support for many advanced features such as caching. The below sections detail the features related to caching in Castor JDO, as their understanding is required to use Castor JDO in a performant and secure way.

In general, performance caches enhance the application performance by reducing the number of read operations against the persistence storage, by storing and reusing the last read or committed values of the object. Performance caches do not affect the behavior of short transactions or locking. It only affects persistence objects that have been released from any transactional context.

Starting from Castor 0.8.6, a performance cache implementation has been added. At a technical level, Castor maintains separate (performance) caches for each object type specified in the JDO mapping provided, allowing users to specify - for each object type individually - the type and capacity of the cache.

By default, the following cache types are available:

name | Vendor | Version | Distributable? | Open source/commercial | high volume/performance | Added inrelease
none | Built-in | - | No | Open Source | No |
unlimited | Built-in | - | No | Open Source | No |
count-limited | Built-in | - | No | Open Source | No |
time-limited | Built-in | - | No | Open Source | No |
coherence | Tangosol Coherence | 2.5 | Yes | Commercial | Yes | 0.9.9
jcs | JCS | 1.2.5 | Yes | Open source | Yes | 0.9.9
fkcache | FKCache | 1.0-beta6 | No | Open Source | No | 0.9.9
oscache | OSCache | 2.5 | Yes | Open Source | No | 1.0
fifo | Built-in | - | No | Open Source | Yes | 1.0
lru | Built-in | - | No | Open Source | Yes | 1.0
ehcache | Built-in | - | Yes | Open Source | ? | 1.0.1
gigaspaces | JCS | 5.0 | Yes | Commercial | Yes | 1.0.1

As some of these cache providers allow for allow you to use it in a distributed mode, this allows Castor JDO to be used in a clustered (multi-JVM) environment. Please see the section below for short summary of this feature.

Per definition, all build-in performance caches are write-through, because all changes to objects as part of a transaction should be persisted into the cache at commit time without delay.

For problems related to the use of performance caches, please consult with the relevant entries in the JDO F.A.Q..

## Caching and long transactions

As it stands currently, performance caches also serve a dual purpose as dirty checking caches for long-transactions. This limitation implies that the object's availability in the performance cache determines the allowed time span of a long transaction.

This might become an issue when performance caches of type 'count-limited' or 'time-limited' are being used, where objects will eventually be disposed. If an application tries to update an object that has been disposed from the dirty checking cache, an ObjectModifedException will be thrown.

## Configuration

The DTD declaration is as follows:

    <!ELEMENT cache-type  ( param* )>
    <!ATTLIST cache-type
        type           ( none | count-limited | time-limited | unlimited |
                         coherence | fkcache | jcache | jcs | oscache |
                         fifo | lru | ehcache | gigaspaces ) "count-limited"
        debug          (true|false) "false"
        capacity       NMTOKEN  #IMPLIED>

    <!ELEMENT param EMPTY>
    <!ATTLIST param
              name   NMTOKEN  #REQUIRED
              value  NMTOKEN  #REQUIRED>

With release 1.0 of Castor the DTD has changed but it is backward compatible to the old one and allows to enable debugging of cache access for a specific class as well as passing individual configuration parameters to each cache instance. Only count-limited and time-limited of the current build-in cache types support parameters. Parameter names are case sensitive and are silently ignored if they are unknown to a cache type.

It need to be noted that there are 3 parameter names that are reserved for internal use. If you specify a parameter with one of the names: type, name or debug their value will silently be overwritten with another one used internally.

### Configuration sample - count-limited

A count-limited least-recently-used cache (LRU) for 500 objects can be specified by:

    <cache-type type="count-limited" capacity="500"/>

or

    <cache-type type="count-limited"/>
        <param name="capacity" value="500"/>
    </cache-type>

If both, the capacity attribute and parameter with name="capacity" is specified, the parameter value takes precedence over the attribute value.

### Configuration sample - time-limited

A time-limited first-in-first-out cache (FIFO) that expires objects after 15 minutes can be specified by:

    <cache-type type="time-limited" capacity="900"/>

or

    <cache-type type="time-limited"/>
        <param name="ttl" value="900"/>
    </cache-type>

If both, the capacity attribute and parameter with name="ttl" is specified, the parameter value takes precedence over the attribute value.

The debug attribute can be used to enable debugging for objects of a single class. In addition to setting this attribut to true you also need to set logging level of org.castor.cache.Cache to debug.

Note

The default cache-type is `count-limited` with a capacity of 30. This will be used when no cache-type is specified in the mapping for a class.

## fifo and lru cache providers

The cache types fifo and lru are based on a set of articles in the O'Reilly Network by William Grosso, to implement a simplified and 1.3-compatible implementation of a Hashbelt algorithm.

Hashbelts are simple, in principle. Instead of walking all objects and finding out when they're supposed to expire, use a "conveyor belt" approach. At any particular point in time, objects going into the cache go into the front of the conveyor belt. After a certain amount of time or when the size limit of a container has been reached, move the conveyor belt - put a new, empty container at the front of the conveyor belt to catch new objects, and the one that drops off of the end of the conveyor belt is, by definition, ready for garbage collection.

As seen in his system, you can use a set of pluggable strategies to implement the actual hashbelt bits. A container strategy allows you to change out the implementation of the container itself - from simple hashtable-based implementations, up through more complex uses of soft referenced or hashset-based implementations, depending on what you need and what you want it to be used for. A pluggable "expire behavior" handler allows you to determine what action is taken on something which drops off of the bottom of the conveyor belt.

In difference to all other cache types the fifo and lru cache types offer various configuration options. Both of them have 6 parameters to configure their behaviour.

parameter | description

containers

The number of containers in the conveyor belt. For example: If a box will drop off of the conveyor belt every 30 seconds, and you want a cache that lasts for 5 minutes, you want 5 / 30 = 6 containers on the belt. Every 30 seconds, another, clean container goes on the front of the conveyor belt, and everything in the last belt gets discarded. If not specified 10 containers are used by default.
For systems with fine granularity, you are free to use a large number of containers; but the system is most efficient when the user decides on a "sweet spot" determining both the number of containers to be managed on the whole and the optimal number of buckets in those containers for managing. This is ultimately a performance/accuracy tradeoff with the actual discard-from-cache time being further from the mark as the rotation time goes up. Also the number of objects discarded at once when capacity limit is reached depends upon the number of containers.

capacity

Maximum capacity of the whole cache. If there are, for example, ten containers on the belt and the capacity has been set to 1000, each container will hold a maximum of 1000/10 objects. Therefore if the capacity limit is reached and the last container gets droped from the belt there are up to 100 objects discarted at once. By default the capacity is set to 0 which causes capacity limit to be ignored so the cache can hold an undefined number of objects.

ttl

The maximum time an object lifes in cache. If the are, for example, ten containers and ttl is set to 300 seconds (5 minutes), a new container will be put in front of the belt every 300/10 = 30 seconds while another is dropped at the end at the same time. Due to the granularity of 30 seconds, everything just until 5 minutes 30 seconds will also end up in this box. The default value for ttl is 60 seconds. If ttl is set to 0 which means that objects life in cache for unlimited time and may only discarded by a capacity limit.

monitor | The monitor intervall in minutes when hashbelt cache rports the current number of containers used and objects cached. If set to 0 (default) monitoring is disabled.

container-class

The implementation of org.castor.cache.hashbelt.container.Container interface to be used for all containers of the cache. Castor provides the following 3 implementations of the Container interface.

- | org.castor.cache.hashbelt.container.FastIteratingContainer
- | org.castor.cache.hashbelt.container.MapContainer
- | org.castor.cache.hashbelt.container.WeakReferenceContainer

If not specified the MapContainer will be used as default.

reaper-class

Specific reapers yield different behaviors. The GC reaper, the default, just dumps the contents to the garbage collector. However, custom implementations may want to actually do something when a bucket drops off the end; see the javadocs on other available reapers to find a reaper strategy that meets your behavior requirements. Apart of the default <api>org.castor.cache.hashbelt.reaper.NullReaper</api> we provide 3 abstract implementations of <api>org.castor.cache.hashbelt.reaper.Reaper</api> interface:

- | <api>org.castor.cache.hashbelt.reaper.NotifyingReaper</api>
- | <api>org.castor.cache.hashbelt.reaper.RefreshingReaper</api>
- | <api>org.castor.cache.hashbelt.reaper.ReinsertingReaper</api>

to be extended by your custom implementation.

### Configuration sample - fifo

A fifo cache with default values explained above is specified by:

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
           <cache-type type="fifo"/>
           ...
        </class>
        ...
    </mapping>

### Configuration sample - lru

A lru cache with capacity=300 and ttl=300 is defined by:

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
           <cache-type type="lru" capacity="300"/>
           ...
        </class>
        ...
    </mapping>

or better by:

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
           <cache-type type="lru">
              <param name="capacity" value="300"/>
              <param name="ttl" value="300"/>
           </cache-type>
           ...
        </class>
        ...
    </mapping>

### Configuration sample - fifo (custommized)

An example of a customized configuration of a fifo cache is:

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
           <cache-type type="fifo"/>
              <param name="container" value="10"/>
              <param name="capacity" value="1000"/>
              <param name="ttl" value="600"/>
              <param name="monitor" value="5"/>
              <param name="container-class" value="org.castor.cache.hashbelt.container.WeakReferenceContainer"/>
              <param name="reaper-class" value="org.castor.cache.hashbelt.reaper.NullReaper"/>
           </cache-type>
           ...
        </class>
        ...
    </mapping>

## Caching and clustered environments

All of the cache providers added with release 0.9.9 are distributed caches per se or can be configured to operate in such a mode. This effectively allows Castor JDO to be used in a clustered J2EE (multi-JVM) environment, where Castor JDO runs on each of the cluster instances, and where cache state is automatically snychronized between these instances.

In such an environment, Castor JDO wil make use of the underlying cache provider to replicate/distribute the content of a specific cache between the various JDOManager instances. Through the distribution mechanism of the cache provider, a client of a Castor JDO instance on one JVM will see any updates made to domain objects performed against any other JVM/JDO instance.

### Configuration sample - Coherence

The following class mapping, for example, ...

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
            <cache-type type="coherence" />
           ...
        </class>
        ...
    </mapping>

defines that for all objects of type `com.xyz.MyOtherObject` Tangosol's Coherence cache provider should be used.

### Configuration sample - Gigaspaces

The following class mapping, for example, ...

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
            <cache-type type="gigaspaces" />
           ...
        </class>
        ...
    </mapping>

defines that for all objects of type `com.xyz.MyOtherObject` the Gigaspaces cache provider should be used. As Gigspaces supports various cache and clsuer modes, this cache provider allows product-specific configuration as shown below:

    <mapping>
        ...
        <class name="com.xyz.MyOtherObject">
           ...
            <cache-type type="gigaspaces" >
               <param name="spaceURL" value="/./" />
               <param name="spaceProperties" value="useLocalCache" />
            </cache-type>
           ...
        </class>
        ...
    </mapping>

## Custom cache provider

As of release 0.9.6, Castor allows for the addition of user-defined cache implementations. Whilst Castor provides a set of pre-built cache providers, offering a variety of different cache algorithms, special needs still might require the application developer to implement a custom cache algorithm. Castor facilitates such need by making available standardized interfaces and an easy to understand recipe for integrating a custom cache provider with Castor.

As explained in API docs for the persists package, LockEngine implements a persistence engine that caches objects in memory for performance reasons and thus reduces the number of operations against the persistence storage.

The main component of this package is the interface Cache, which declares the external functionality of a (performance) cache. Existing (and future) cache implementations (have to) implement this interface, which is closely modelled after the `java.util.Map` interface.

Below is a summary of the steps required to build a custom cache provider and register it with Castor JDO:

1. Create a class that implements Cache.
2. Create a class that implements CacheFactory
3. Register your custom cache implementation with Castor JDO in the `castor.properties` file.

### Cache implementation

Please create a class that implements the interface Cache.

To assist users in this task, a AbstractBaseCache class has been supplied, which users should derive their custom Cache instances from, if they wish so. Please consult existing Cache implementations such as TimeLimited} or CountLimited for code samples.

    /**
     * My own cache implementation
     */
     public class CustomCache extends AbstractBaseCache {

        ...

     }

### CacheFactory implementation

Please add a class that imnplements the CacheFactory interface and make sure that you provide valid values for the two properties `name` and `className`.

To assist users in this task, a AbstractCacheFactory class has been supplied, which users should derive their custom CacheFactory instances from, if they wish so. Please consult existing CacheFactory implementations such as TimeLimitedFactory} or CountLimitedFactory for code samples.

    /**
     * My own cache factory implementation
     */
     public class CustomCacheFactory extends AbstractCacheFactory {

        /**
         * The name of the factory
         */
        private static final String NAME = "custom";

        /**
         * Full class name of the underlying cache implementation.
         */
        private static final String CLASS_NAME = "my.company.project.CustomCache";

        /**
         * Returns the short alias for this factory instance.
         * @return The short alias name.
         */
        public String getName() {
            return NAME;
        }

        /**
         * Returns the full class name of the underlying cache implementation.
         * @return The full cache class name.
         */
        public String getCacheClassName() {
            return CLASS_NAME;
        }

     }

### Configuration

The file `castor.properties` holds a property `org.castor.cache.Factories` that enlists the available cache types through their related CacheFactory instances.

    #
    # Cache implementations
    #
    org.castor.cache.Factories=\
      org.castor.cache.simple.NoCacheFactory,\
      org.castor.cache.simple.TimeLimitedFactory,\
      org.castor.cache.simple.CountLimitedFactory,\
      org.castor.cache.simple.UnlimitedFactory,\
      org.castor.cache.distributed.FKCacheFactory,\
      org.castor.cache.distributed.JcsCacheFactory,\
      org.castor.cache.distributed.JCacheFactory,\
      org.castor.cache.distributed.CoherenceCacheFactory,\
      org.castor.cache.distributed.OsCacheFactory,\
      org.castor.cache.hashbelt.FIFOHashbeltFactory,\
      org.castor.cache.hashbelt.LRUHashbeltFactory

To add your custom cache implementation, please append the fully-qualified class name to this list as shown below:

    #
    # Cache implementations
    #
    org.castor.cache.Factories=\
      org.castor.cache.simple.NoCacheFactory,\
      org.castor.cache.simple.TimeLimitedFactory,\
      org.castor.cache.simple.CountLimitedFactory,\
      org.castor.cache.simple.UnlimitedFactory,\
      org.castor.cache.distributed.FKCacheFactory,\
      org.castor.cache.distributed.JcsCacheFactory,\
      org.castor.cache.distributed.JCacheFactory,\
      org.castor.cache.distributed.CoherenceCacheFactory,\
      org.castor.cache.distributed.OsCacheFactory,\
      org.castor.cache.hashbelt.FIFOHashbeltFactory,\
      org.castor.cache.hashbelt.LRUHashbeltFactory,\
      org.whatever.somewhere.nevermind.CustomCache

## CacheManager - monitoring and clearing caches

Sometimes it is necessary to interact with Castor's (performance) caches to e.g. (selectively) clear a Castor cache of its content, or inquire about whether a particular object instance (as identified by its identity) is cached already.

For this purpose a CacheManager can be obtained from a Database instance by issuing the following code:

    JDO jdo = ....;
    Database db = jdo.getDatabase();
    CacheManager manager = db.getCacheManager();

This instance can subsequently be used to selectively clear the Castor performance cache using one of the following methods:

- | expireCache()
- | expireCache(Class,Object)
- | expireCache(Class,Object[])
- | expireCache(Class[])

To inquire whether an object has already been cached, please use the following method:

- | isCached (Class, Object);

Please note that once you have closed the Database instance from which you have obtained the CacheManager, the CacheManager cannot be used anymore and will throw a PersistenceException.

<notice> Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved. </notice>
<notice> Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners. </notice>