Jump to: navigation, search

EclipseLink/Development/JPA 2.0/cache usaged

< EclipseLink‎ | Development‎ | JPA 2.0
Revision as of 12:37, 27 October 2009 by Karen.moore.oracle.com (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

JPA 2.0: Cache Usage Settings

JPA 2.0 Root | bug 277039

Discussion

Date Committer(s) Description
Feb 2, 2009 gyorke Initial feature template
June 15, 2009 gpelleti Feature implementation 3.7.1
July 14, 2009 gpelleti Feature implementation 3.7.2

Summary

The specification introduces cache usage controls in JPA 2.0. Users can use settings on the Entity and Query hints to control how the cache should be used. There are separate settings for how a provider can use the cache for query results and when the cache should be updated with database query results.

Functional Requirements

  • Support specification requirements.
  • Support a cacheable setting on a mapped superclass
  • Default for the "caching element" will be DISABLE_SELECTIVE

Section 3.7.1 - The shared-cache-mode element

Whether the entities and entity-related state of a persistence unit will be cached is determined by the value of the shared-cache-mode element of the persistence.xml file.

The shared-cache-mode element has four possible values: ALL, NONE, ENABLE_SELECTIVE, DISABLE_SELECTIVE.

Caching (persistence.xml) Behavior Code Log
<shared-cache-mode>ALL</shared-cache-mode> Causes all entities and entity related state and data to be cached. None as cache is on by default in EclipsLink Entities marked Cacheable(true) (or its XML equivalent) are ignored and a log warning is issued.
<shared-cache-mode>NONE</shared-cache-mode> Causes caching to be disable for the persistence unit and all cahing is turned off for all entities descriptor.setIsIsolated(true); Entities marked Cacheable(false) (or its XML equivalent) are ignored and a log warning is issued.

The values ENABLE_SELECTIVE and DISABLE_SELECTIVE are used in conjunction with the Cacheable annotation (or XML element). The Cacheable annotation specifies whether an entity should be cached if caching is enabled by the persistence.xml caching element. Cacheable(false) means that the entity and its state must not be cached by the provider. Note: if the user does not specify a caching value, EclipseLink will default to DISABLE_SELECTIVE. This allows them to then turn off the cache by specifying the Cacheable(false) and not having to modify their persistence.xml.

// From JPA 2.0 Specification
@Target({TYPE}) @Retention(RUNTIME)
public @interface Cacheable {
  boolean value() default true;
}
Caching (persistence.xml) Behavior Code Log
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> Enables the cache and causes entities for which Cacheable(true) (or its XML equivalent) is specified to be cached. Entities for which Cacheable(true) is not specified or for which Cacheable(false) is specified must not be cached. True (or no setting) - nothing, cache is on by default, False - descriptor.setIsIsolated(true); None.
<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode> Enables the cache and causes all entities to be cached except those for which Cacheable(false) is specified. Entities for which Cacheable(false) is specified must not be cached. True (or no setting) - nothing as cache is on by default. False, descriptor.setIsIsolated(true); None

EclipseLink will also go one step further and allow users to configure the Cacheable setting on a mapped superclass. The logic of this is similar to specifying an exclude-superclass-listener setting on a mapped superclass. To use this feature, the user can either specify annotations directly or use the eclipselink-orm schema. Note: a cacheable setting within an inheritance hierarchy applies to the given entity and its subclasses unless subsequently overridden by a subclass.

@MappedSuperclass
@Cacheable(true)
public class CacheableTrueMappedSuperclass {
    private int id;
    
    public CacheableTrueMappedSuperclass() {}
    
    @Id
    @GeneratedValue(strategy=TABLE, generator="CACHEABLE_TABLE_GENERATOR")
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
}

@Entity(name="JPA_SUB_CACHEABLE_FALSE")
@Cacheable(false)
public class SubCacheableFalseEntity extends CacheableTrueMappedSuperclass {
    public SubCacheableFalseEntity() {}
}

@Entity(name="JPA_SUB_CACHEABLE_NONE")
// Will pick up the Cacheable(true) setting from the mapped superclass.
public class SubCacheableNoneEntity extends CacheableTrueMappedSuperclass {
    public SubCacheableNoneEntity() {}
}

// These classes mapped in XML would look as follows:

<table-generator name="CACHEABLE_TABLE_GENERATOR" table="CACHEABLE_SEQ" pk-column-name="SEQ_NAME" value-column-name="SEQ_COUNT" pk-column-value="CACHEABLE_SEQ"/>
<mapped-superclass class="CacheableTrueMappedSuperclass" access="FIELD" cacheable="true">
  <attributes>
    <id name="id">
      <generated-value strategy="TABLE" generator="CACHEABLE_TABLE_GENERATOR"/>
    </id>
  </attributes>
</mapped-superclass>
<entity name="SUB_CACHEABLE_FALSE" class="SubCacheableFalseEntity" access="FIELD" cacheable="false"/>
<!-- Will pick up the Cacheable(true) setting from the mapped superclass. -->
<entity name="SUB_CACHEABLE_NONE" class="SubCacheableNoneEntity" access="FIELD"/>

Section 3.7.2 - Cache mode properties

Cache mode properties may be specified at the level of the persistence context by means of the EntityManager setProperties method. Cache mode properties may be specified for the EntityManager find and refresh methods and the Query setProperties method. Cache mode properties specified for the find, refresh, and Query setProperties methods override those specified for the persistence context for the specified find and refresh invocations, and for the execution of the specified queries respectively.

The existing EclipseLink property "eclipselink.cache-usage" will override any JPA cacheRetrieveMode and/or cacheStoreMode properties specified. Both can not be used in conjunction with one another.

Cache mode properties will not be applied to individual Entity Manager operations or query executions if the descriptor of the entity of that operation or query execution has been marked as Cacheable(false).

// From JPA 2.0 Specification
public enum CacheRetrieveMode {
 
    /**
     * Read entity data from the cache: this is
     * the default behavior.
     */
    USE,
 
    /**
     * Bypass the cache: get data directly from
     * the database.
     */
    BYPASS
}
 
public enum CacheStoreMode {
 
    /**
     * Insert/update entity data into cache when read
     * from database and when committed into database:
     * this is the default behavior. Does not force refresh
     * of already cached items when reading from database.
     */
    USE,
 
    /**
     * Don't insert into cache.
     */
    BYPASS,
 
    /**
     * Insert/update entity data into cache when read
     * from database and when committed into database:
     * Forces refresh of cache for items read from database.
     */
    REFRESH
}

Used as EntityManager properties

// To set individual properties (to overwrite existing or set new ones):
em.setProperty(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE);
em.setProperty(QueryHints.CACHE_STORE_MODE, CacheRetrieveMode.BYPASS);

// Or to overwrite the existing properties as a whole:
HashMap properties = new HashMap();
properties.put(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE);
properties.put(QueryHints.CACHE_STORE_MODE, CacheStoreMode.BYPASS);
em.setProperties(properties);

// EntityManager find operation (will use the value from the cache):
em.find(MyEntity.class, id);

// EntityManager find operation with properties (will read the entity from the DB and update the cache)
HashMap findProperties = new HashMap();
findProperties.put(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS);
findProperties.put(QueryHints.CACHE_STORE_MODE, CacheStoreMode.USE);
em.find(MyEntity.class, id, findProperties);

Used as NamedQuery properties

The queries may override EntityManager settings through their own setHint method or by the query definition itself (if defined in annotations or XML)


// Entity manager property settings:
em.setProperty(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE);
em.setProperty(QueryHints.CACHE_STORE_MODE, CacheRetrieveMode.BYPASS);


// A named query definition that will override the Entity Manager properties completely
// and use a retrieve mode of BYPASS and a store mode of USE.
@NamedQuery(
  name="findMyEntityByPK",
  query="SELECT OBJECT(e) FROM MYENTITY e WHERE e.id = :id",
  hints={
    @QueryHint(name=QueryHints.CACHE_RETRIEVE_MODE, value="BYPASS"),
    @QueryHint(name=QueryHints.CACHE_STORE_MODE, value="USE")
  }
)


// A named query definition that will override part of the EntityManager properties and will
// used a retrieve mode of BYPASS and a store mode of BYPASS (as specified by the EM)
@NamedQuery(
  name="findMyEntityByPK",
  query="SELECT OBJECT(e) FROM MYENTITY e WHERE e.id = :id",
  hints={
    @QueryHint(name=QueryHints.CACHE_RETRIEVE_MODE, value="BYPASS"),
  }
)

Design

3.7.1

Metadata processing will need to be expanded to include processing of the Cacheable annotation and the <cacheable> element from XML. Internally this will require changes to EntityAccessor. Since an EntityAccessor extends MappedSuperclassAccessor, it is fairly straight forward to expand this functionality to mapped superclasses. The metadata processing therefore, simply needs to:

  1. expand the existing OX mapping project to map the new cacheable xml element
  2. expand the existing metadata model to accept the xml value or discover one through annotations
  3. apply the necessary setting on the entity's descriptor (isolated or not)

3.7.2

New cache processing flags will be added to EclipseLink's DatabaseQuery to handle, shouldCacheRetrieveBypassCache and shouldCacheStoreBypassCache. By default this flags are false indicating to EclipseLink to operate as normal.

New API available to database queries:

public void setShouldRetrieveBypassCache(boolean shouldRetrieveBypassCache)
public void setShouldStoreBypassCache(boolean shouldStoreBypassCache)
public void retrieveBypassCache() // sets the flag to true
public boolean shouldRetrieveBypassCache()
public boolean shouldStoreBypassCache()
public void storeBypassCache() // sets the flag to true

Tying into the EclipseLink's dontMaintainCache setting was deemed too explicit, meaning we needed to separate EclipseLink's building object portion with the interaction to the cache during this build process. When building new objects, with a cacheStoreMode of BYPASS, we will build the objects in isolation meaning they will remain available only to the unit of work. This same setting is also checked to determine if merging into the parent is needed at commit time.

The cacheRetrieveMode of BYPASS will force the EclipseLink to ignore any cache hits and rebuild the object from the data retrieved from the database. This also avoids cloning any cached original and ensures we register the newly built object.

Note: a cacheStoreMode of REFRESH ties directly to the existing ObjectLevelReadQuery.refreshIdentityMapResult(); where it will refresh the attributes of the object(s) resulting from the query and if cascading is used, the private parts of the objects will also be refreshed.

Documentation

JPA Specification sections: 3.7, 3.7.1, 3.7.2, 11.1.7

Testing

New testing models using annotations and XML will be created.

Work Estimate

  1. Develop model for testing cache usage settings
    approx 3 days
  2. Update processing
    approx 3 days
  3. Implement Functionality
    approx 3 days