HHH-11356 - Adjust the 2nd-Cache SPIs to better reflect supported uses

HHH-12323 - Update Statistics API and SPI based on changes to 2nd level caching changes
This commit is contained in:
Steve Ebersole 2018-03-13 17:54:24 -05:00
parent 24a078732c
commit f432ecea68
267 changed files with 7878 additions and 5477 deletions

View File

@ -26,10 +26,9 @@ import org.hibernate.cache.ehcache.EhCacheRegionFactory;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.CacheRegionStatistics;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.FailureExpected;
import org.junit.Ignore;
import org.junit.Test;
@ -188,8 +187,8 @@ public class SecondLevelCacheTest extends BaseEntityManagerFunctionalTestCase {
Session session = entityManager.unwrap( Session.class );
//tag::caching-statistics-example[]
Statistics statistics = session.getSessionFactory().getStatistics();
SecondLevelCacheStatistics secondLevelCacheStatistics =
statistics.getSecondLevelCacheStatistics( "query.cache.person" );
CacheRegionStatistics secondLevelCacheStatistics =
statistics.getDomainDataRegionStatistics( "query.cache.person" );
long hitCount = secondLevelCacheStatistics.getHitCount();
long missCount = secondLevelCacheStatistics.getMissCount();
double hitRatio = (double) hitCount / ( hitCount + missCount );

View File

@ -8,7 +8,6 @@ package org.hibernate.userguide.persister;
import org.hibernate.MappingException;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.mapping.Collection;
import org.hibernate.persister.collection.OneToManyPersister;
import org.hibernate.persister.spi.PersisterCreationContext;

View File

@ -7,8 +7,6 @@
package org.hibernate.userguide.persister;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.persister.spi.PersisterCreationContext;

View File

@ -18,6 +18,7 @@ import java.io.Serializable;
*
* @author Steve Ebersole
*/
@SuppressWarnings( {"UnusedDeclaration"})
public interface Cache extends javax.persistence.Cache {
/**
* Access to the SessionFactory this Cache is bound to.
@ -26,6 +27,11 @@ public interface Cache extends javax.persistence.Cache {
*/
SessionFactory getSessionFactory();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Entity data
/**
* Determine whether the cache contains data for the given entity "instance".
* <p/>
@ -58,59 +64,83 @@ public interface Cache extends javax.persistence.Cache {
*
* @param entityClass The entity class.
* @param identifier The entity identifier
*
* @since 5.3
*/
void evictEntity(Class entityClass, Serializable identifier);
void evictEntityData(Class entityClass, Serializable identifier);
/**
* Evicts the entity data for a particular entity "instance".
*
* @param entityName The entity name.
* @param identifier The entity identifier
*
* @since 5.3
*/
void evictEntity(String entityName, Serializable identifier);
void evictEntityData(String entityName, Serializable identifier);
/**
* Evicts all entity data from the given region (i.e. for all entities of
* type).
*
* @param entityClass The entity class.
*
* @since 5.3
*/
void evictEntityRegion(Class entityClass);
void evictEntityData(Class entityClass);
/**
* Evicts all entity data from the given region (i.e. for all entities of
* type).
*
* @param entityName The entity name.
*
* @since 5.3
*/
void evictEntityRegion(String entityName);
void evictEntityData(String entityName);
/**
* Evict data from all entity regions.
*/
void evictEntityRegions();
/**
* Evicts all naturalId data from the given region (i.e. for all entities of
* type).
*
* @param naturalIdClass The naturalId class.
* @since 5.3
*/
@SuppressWarnings( {"UnusedDeclaration"})
void evictNaturalIdRegion(Class naturalIdClass);
void evictEntityData();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Natural-id data
/**
* Evicts all naturalId data from the given region (i.e. for all entities of
* type).
* Evict cached data for the given entity's natural-id
*
* @param naturalIdName The naturalId name.
* @param entityClass The entity class.
*
* @since 5.3
*/
void evictNaturalIdRegion(String naturalIdName);
void evictNaturalIdData(Class entityClass);
/**
* Evict data from all naturalId regions.
* Evict cached data for the given entity's natural-id
*
* @param entityName The entity name.
*
* @since 5.3
*/
void evictNaturalIdRegions();
void evictNaturalIdData(String entityName);
/**
* Evict cached data for all natural-ids (for all entities)
*
* @since 5.3
*/
void evictNaturalIdData();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Collection data
/**
* Determine whether the cache contains data for the given collection.
@ -128,26 +158,38 @@ public interface Cache extends javax.persistence.Cache {
@SuppressWarnings( {"UnusedDeclaration"})
boolean containsCollection(String role, Serializable ownerIdentifier);
/**
* Evicts the cache data for the given identified collection instance.
* Evicts the cache data for the given identified collection "instance"
*
* @param role The "collection role" (in form [owner-entity-name].[collection-property-name]).
* @param ownerIdentifier The identifier of the owning entity
*
* @since 5.3
*/
void evictCollection(String role, Serializable ownerIdentifier);
void evictCollectionData(String role, Serializable ownerIdentifier);
/**
* Evicts all entity data from the given region (i.e. evicts cached data
* for all of the specified collection role).
* Evicts cached data for the given collection role
*
* @param role The "collection role" (in form [owner-entity-name].[collection-property-name]).
*
* @since 5.3
*/
void evictCollectionRegion(String role);
void evictCollectionData(String role);
/**
* Evict data from all collection regions.
* Evict cache data for all collections
*
* @since 5.3
*/
void evictCollectionRegions();
void evictCollectionData();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Query result data
/**
* Determine whether the cache contains data for the given query.
@ -159,7 +201,6 @@ public interface Cache extends javax.persistence.Cache {
*
* @return True if the underlying cache contains corresponding data; false otherwise.
*/
@SuppressWarnings( {"UnusedDeclaration"})
boolean containsQuery(String regionName);
/**
@ -178,9 +219,181 @@ public interface Cache extends javax.persistence.Cache {
* Evict data from all query regions.
*/
void evictQueryRegions();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Misc
/**
* Evict all data from the cache.
* Evict all data from the named cache region
*
* @since 5.3
*/
void evictAllRegions();
void evictRegion(String regionName);
/**
* {@inheritDoc}
*
* @apiNote Hibernate impl - we only evict entity data here in keeping
* with the JPA intent (JPA only defines caching for entity data). For
* evicting all cache regions (collections, natural-ids and query results),
* use {@link #evictAllRegions} instead.
*/
@Override
default void evictAll() {
// Evict only the "JPA cache", which is purely defined as the entity regions.
evictEntityData();
}
/**
* Evict data from all cache regions.
*/
default void evictAllRegions() {
evictEntityData();
evictNaturalIdData();
evictCollectionData();
evictDefaultQueryRegion();
evictQueryRegions();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deprecations (5.3)
/**
* Evicts the entity data for a particular entity "instance".
*
* @param entityClass The entity class.
* @param identifier The entity identifier
*
* @deprecated Use {@link Cache#evictEntityData(Class, Serializable)} instead
*/
@Deprecated
default void evictEntity(Class entityClass, Serializable identifier) {
evictEntityData( entityClass, identifier );
}
/**
* Evicts the entity data for a particular entity "instance".
*
* @param entityName The entity name.
* @param identifier The entity identifier
*
* @deprecated Use {@link Cache#evictEntityData(String, Serializable)} instead
*/
@Deprecated
default void evictEntity(String entityName, Serializable identifier) {
evictEntityData( entityName, identifier );
}
/**
* Evicts all entity data from the given region (i.e. for all entities of
* type).
*
* @param entityClass The entity class.
*
* @deprecated Use {@link Cache#evictEntityData(Class)} instead
*/
@Deprecated
default void evictEntityRegion(Class entityClass) {
evictEntityData( entityClass );
}
/**
* Evicts all entity data from the given region (i.e. for all entities of
* type).
*
* @param entityName The entity name.
*
* @deprecated Use {@link Cache#evictEntityData(String)} instead
*/
@Deprecated
default void evictEntityRegion(String entityName) {
evictEntityData( entityName );
}
/**
* Evict data from all entity regions.
*
* @deprecated Use {@link Cache#evictEntityData()} instead
*/
@Deprecated
default void evictEntityRegions() {
evictEntityData();
}
/**
* Evicts all naturalId data from the given region (i.e. for all entities of
* type).
*
* @param entityClass The entity class.
*
* @deprecated Use {@link Cache#evictNaturalIdData(Class)} instead
*/
@Deprecated
default void evictNaturalIdRegion(Class entityClass) {
evictNaturalIdData( entityClass );
}
/**
* Evicts all naturalId data from the given region (i.e. for all entities of
* type).
*
* @param entityName The entity name.
*
* @deprecated Use {@link Cache#evictNaturalIdData(String)} instead
*/
@Deprecated
default void evictNaturalIdRegion(String entityName) {
evictNaturalIdData( entityName );
}
/**
* Evict data from all naturalId regions.
*
* @deprecated Use {@link Cache#evictNaturalIdData()} instead
*/
@Deprecated
default void evictNaturalIdRegions() {
evictNaturalIdData();
}
/**
* Evicts the cache data for the given identified collection instance.
*
* @param role The "collection role" (in form [owner-entity-name].[collection-property-name]).
* @param ownerIdentifier The identifier of the owning entity
*
* @deprecated Use {@link Cache#evictCollectionData(String, Serializable)} instead
*/
@Deprecated
default void evictCollection(String role, Serializable ownerIdentifier) {
evictCollectionData( role, ownerIdentifier );
}
/**
* Evicts all entity data from the given region (i.e. evicts cached data
* for all of the specified collection role).
*
* @param role The "collection role" (in form [owner-entity-name].[collection-property-name]).
*
* @deprecated Use {@link Cache#evictCollectionData(String)} instead
*/
@Deprecated
default void evictCollectionRegion(String role) {
evictCollectionData( role );
}
/**
* Evict data from all collection regions.
*
* @deprecated Use {@link Cache#evictCollectionData()} instead
*/
@Deprecated
default void evictCollectionRegions() {
evictCollectionData();
}
}

View File

@ -16,9 +16,9 @@ import org.hibernate.HibernateException;
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.action.spi.Executable;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -62,10 +62,15 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
spacesList.addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
if ( persister.canWriteToCache() ) {
entityCleanups.add( new EntityCleanup( persister.getCacheAccessStrategy() ) );
final EntityDataAccess entityDataAccess = factory.getCache()
.getEntityRegionAccess( persister.getNavigableRole() );
if ( entityDataAccess != null ) {
entityCleanups.add( new EntityCleanup( entityDataAccess ) );
} entityCleanups.add( new EntityCleanup( entityDataAccess ) );
}
if ( persister.hasNaturalIdentifier() && persister.hasNaturalIdCache() ) {
naturalIdCleanups.add( new NaturalIdCleanup( persister.getNaturalIdCacheAccessStrategy() ) );
naturalIdCleanups.add( new NaturalIdCleanup( factory.getCache().getNaturalIdRegionAccess( persister.getNavigableRole() ) ) );
}
final Set<String> roles = factory.getMetamodel().getCollectionRolesByEntityParticipant( persister.getEntityName() );
@ -73,7 +78,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
for ( String role : roles ) {
final CollectionPersister collectionPersister = factory.getMetamodel().collectionPersister( role );
if ( collectionPersister.hasCache() ) {
collectionCleanups.add( new CollectionCleanup( collectionPersister.getCacheAccessStrategy() ) );
collectionCleanups.add( new CollectionCleanup( factory.getCache().getCollectionRegionAccess( collectionPersister.getNavigableRole() ) ) );
}
}
}
@ -200,10 +205,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
private static class EntityCleanup implements Serializable {
private final EntityRegionAccessStrategy cacheAccess;
private final EntityDataAccess cacheAccess;
private final SoftLock cacheLock;
private EntityCleanup(EntityRegionAccessStrategy cacheAccess) {
private EntityCleanup(EntityDataAccess cacheAccess) {
this.cacheAccess = cacheAccess;
this.cacheLock = cacheAccess.lockRegion();
cacheAccess.removeAll();
@ -215,10 +220,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
private static class CollectionCleanup implements Serializable {
private final CollectionRegionAccessStrategy cacheAccess;
private final CollectionDataAccess cacheAccess;
private final SoftLock cacheLock;
private CollectionCleanup(CollectionRegionAccessStrategy cacheAccess) {
private CollectionCleanup(CollectionDataAccess cacheAccess) {
this.cacheAccess = cacheAccess;
this.cacheLock = cacheAccess.lockRegion();
cacheAccess.removeAll();
@ -230,10 +235,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
private static class NaturalIdCleanup implements Serializable {
private final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy;
private final NaturalIdDataAccess naturalIdCacheAccessStrategy;
private final SoftLock cacheLock;
public NaturalIdCleanup(NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy) {
public NaturalIdCleanup(NaturalIdDataAccess naturalIdCacheAccessStrategy) {
this.naturalIdCacheAccessStrategy = naturalIdCacheAccessStrategy;
this.cacheLock = naturalIdCacheAccessStrategy.lockRegion();
naturalIdCacheAccessStrategy.removeAll();

View File

@ -12,7 +12,7 @@ import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.action.spi.Executable;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -76,7 +76,7 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
// bidirectional association and it is one of the earlier entity actions which actually updates
// the database (this action is responsible for second-level cache invalidation only)
if ( persister.hasCache() ) {
final CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final CollectionDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
key,
persister,
@ -129,7 +129,7 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
protected final void evict() throws CacheException {
if ( persister.hasCache() ) {
final CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final CollectionDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
key,
persister,
@ -173,7 +173,7 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
@Override
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) {
final CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final CollectionDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
key,
persister,

View File

@ -10,7 +10,7 @@ import java.io.Serializable;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
@ -87,7 +87,7 @@ public class EntityDeleteAction extends EntityAction {
final Object ck;
if ( persister.canWriteToCache() ) {
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
ck = cache.generateCacheKey( id, persister, session.getFactory(), session.getTenantIdentifier() );
lock = cache.lockItem( session, ck, version );
}
@ -188,7 +188,7 @@ public class EntityDeleteAction extends EntityAction {
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException {
EntityPersister entityPersister = getPersister();
if ( entityPersister.canWriteToCache() ) {
EntityRegionAccessStrategy cache = entityPersister.getCacheAccessStrategy();
EntityDataAccess cache = entityPersister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
getId(),
entityPersister,

View File

@ -102,7 +102,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
postInsert();
if ( session.getFactory().getStatistics().isStatisticsEnabled() && !isVeto() ) {
session.getFactory().getStatisticsImplementor().insertEntity( getPersister().getEntityName() );
session.getFactory().getStatistics().insertEntity( getPersister().getEntityName() );
}
markExecuted();

View File

@ -10,7 +10,7 @@ import java.io.Serializable;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.EntityEntry;
@ -116,7 +116,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
session
);
cacheEntry = persister.getCacheEntryStructure().structure( ce );
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey( id, persister, factory, session.getTenantIdentifier() );
final boolean put = cacheInsert( persister, ck );
@ -211,20 +211,20 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException {
final EntityPersister persister = getPersister();
if ( success && isCachePutEnabled( persister, getSession() ) ) {
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
SessionFactoryImplementor sessionFactoryImplementor = session.getFactory();
final Object ck = cache.generateCacheKey( getId(), persister, sessionFactoryImplementor, session.getTenantIdentifier() );
final boolean put = cacheAfterInsert( cache, ck );
if ( put && sessionFactoryImplementor.getStatistics().isStatisticsEnabled() ) {
sessionFactoryImplementor.getStatisticsImplementor()
sessionFactoryImplementor.getStatistics()
.secondLevelCachePut( cache.getRegion().getName() );
}
}
postCommitInsert( success );
}
private boolean cacheAfterInsert(EntityRegionAccessStrategy cache, Object ck) {
private boolean cacheAfterInsert(EntityDataAccess cache, Object ck) {
SharedSessionContractImplementor session = getSession();
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
try {

View File

@ -11,7 +11,7 @@ import java.io.Serializable;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.engine.internal.Versioning;
@ -128,7 +128,7 @@ public final class EntityUpdateAction extends EntityAction {
final Object ck;
if ( persister.canWriteToCache() ) {
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
ck = cache.generateCacheKey(
id,
persister,
@ -311,7 +311,7 @@ public final class EntityUpdateAction extends EntityAction {
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws CacheException {
final EntityPersister persister = getPersister();
if ( persister.canWriteToCache() ) {
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
getId(),
persister,
@ -337,7 +337,7 @@ public final class EntityUpdateAction extends EntityAction {
postCommitUpdate( success );
}
private boolean cacheAfterUpdate(EntityRegionAccessStrategy cache, Object ck) {
private boolean cacheAfterUpdate(EntityDataAccess cache, Object ck) {
final SharedSessionContractImplementor session = getSession();
SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
try {

View File

@ -15,7 +15,7 @@ import org.hibernate.MultiTenancyStrategy;
import org.hibernate.NullPrecedence;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
@ -491,7 +491,7 @@ public interface SessionFactoryBuilder {
*
* @see org.hibernate.cfg.AvailableSettings#QUERY_CACHE_FACTORY
*/
SessionFactoryBuilder applyQueryCacheFactory(QueryCacheFactory factory);
SessionFactoryBuilder applyTimestampsRegionAccessFactory(TimestampsRegionAccessFactory factory);
/**
* Apply a prefix to prepended to all cache region names for this SessionFactory.

View File

@ -38,7 +38,7 @@ import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.convert.internal.AttributeConverterManager;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
import org.hibernate.boot.model.convert.internal.InstanceBasedConverterDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterAutoApplyHandler;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.ImplicitForeignKeyNameSource;
@ -50,13 +50,13 @@ import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
import org.hibernate.boot.model.convert.spi.ConverterAutoApplyHandler;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.MetadataBuildingOptions;
import org.hibernate.boot.spi.NaturalIdUniqueKeyBinder;
import org.hibernate.cache.cfg.internal.DomainDataRegionConfigImpl.Builder;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.CopyIdentifierComponentSecondPass;
import org.hibernate.cfg.CreateKeySecondPass;
import org.hibernate.cfg.FkSecondPass;
@ -143,6 +143,8 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
private final Map<String, FetchProfile> fetchProfileMap = new HashMap<String, FetchProfile>();
private final Map<String, IdentifierGeneratorDefinition> idGeneratorDefinitionMap = new HashMap<String, IdentifierGeneratorDefinition>();
private final Map<String, Builder> regionConfigBuilders = new ConcurrentHashMap<>();
private Map<String, SQLFunction> sqlFunctionMap;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -276,8 +278,28 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
throw new DuplicateMappingException( DuplicateMappingException.Type.ENTITY, entityName );
}
entityBindingMap.put( entityName, persistentClass );
final AccessType accessType = AccessType.fromExternalName( persistentClass.getCacheConcurrencyStrategy() );
if ( accessType != null ) {
if ( persistentClass.isCached() ) {
locateCacheRegionConfigBuilder( persistentClass.getRootClass().getCacheRegionName() ).addEntityConfig(
persistentClass,
accessType
);
}
if ( persistentClass.hasNaturalId() && persistentClass.getNaturalIdCacheRegionName() != null ) {
locateCacheRegionConfigBuilder( persistentClass.getNaturalIdCacheRegionName() ).addNaturalIdConfig(
(RootClass) persistentClass,
accessType
);
}
}
}
private Builder locateCacheRegionConfigBuilder(String regionName) {
return regionConfigBuilders.computeIfAbsent( regionName, Builder::new );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Collection handling
@ -299,6 +321,14 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
throw new DuplicateMappingException( DuplicateMappingException.Type.COLLECTION, collectionRole );
}
collectionBindingMap.put( collectionRole, collection );
final AccessType accessType = AccessType.fromExternalName( collection.getCacheConcurrencyStrategy() );
if ( accessType != null ) {
locateCacheRegionConfigBuilder( collection.getCacheConcurrencyStrategy() ).addCollectionConfig(
collection,
accessType
);
}
}
@ -2213,6 +2243,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
sqlResultSetMappingMap,
namedEntityGraphMap,
sqlFunctionMap,
regionConfigBuilders.values(),
getDatabase()
);
}

View File

@ -28,6 +28,7 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.MetadataBuildingOptions;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryBuilderFactory;
import org.hibernate.cache.cfg.internal.DomainDataRegionConfigImpl;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.dialect.function.SQLFunction;
@ -77,6 +78,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final Map<String, ResultSetMappingDefinition> sqlResultSetMappingMap;
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;
private final Map<String, SQLFunction> sqlFunctionMap;
private final java.util.Collection<DomainDataRegionConfigImpl.Builder> cacheRegionConfigBuilders;
private final Database database;
public MetadataImpl(
@ -98,6 +100,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
Map<String, ResultSetMappingDefinition> sqlResultSetMappingMap,
Map<String, NamedEntityGraphDefinition> namedEntityGraphMap,
Map<String, SQLFunction> sqlFunctionMap,
java.util.Collection<DomainDataRegionConfigImpl.Builder> cacheRegionConfigBuilders,
Database database) {
this.uuid = uuid;
this.metadataBuildingOptions = metadataBuildingOptions;
@ -117,6 +120,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
this.sqlResultSetMappingMap = sqlResultSetMappingMap;
this.namedEntityGraphMap = namedEntityGraphMap;
this.sqlFunctionMap = sqlFunctionMap;
this.cacheRegionConfigBuilders = cacheRegionConfigBuilders;
this.database = database;
}

View File

@ -23,7 +23,7 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryBuilderImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
@ -283,8 +283,8 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
}
@Override
public SessionFactoryBuilder applyQueryCacheFactory(QueryCacheFactory factory) {
this.optionsBuilder.applyQueryCacheFactory( factory );
public SessionFactoryBuilder applyTimestampsRegionAccessFactory(TimestampsRegionAccessFactory factory) {
this.optionsBuilder.applyTimestampsRegionAccessFactory( factory );
return this;
}

View File

@ -32,9 +32,9 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.internal.StandardQueryCacheFactory;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.internal.StandardTimestampsRegionAccessFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
@ -197,7 +197,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
// Caching
private boolean secondLevelCacheEnabled;
private boolean queryCacheEnabled;
private QueryCacheFactory queryCacheFactory;
private TimestampsRegionAccessFactory timestampsCacheFactory;
private String cacheRegionPrefix;
private boolean minimalPutsEnabled;
private boolean structuredCacheEntriesEnabled;
@ -331,10 +331,10 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.secondLevelCacheEnabled = cfgService.getSetting( USE_SECOND_LEVEL_CACHE, BOOLEAN, true );
this.queryCacheEnabled = cfgService.getSetting( USE_QUERY_CACHE, BOOLEAN, false );
this.queryCacheFactory = strategySelector.resolveDefaultableStrategy(
QueryCacheFactory.class,
this.timestampsCacheFactory = strategySelector.resolveDefaultableStrategy(
TimestampsRegionAccessFactory.class,
configurationSettings.get( QUERY_CACHE_FACTORY ),
StandardQueryCacheFactory.INSTANCE
StandardTimestampsRegionAccessFactory.INSTANCE
);
this.cacheRegionPrefix = ConfigurationHelper.extractPropertyValue(
CACHE_REGION_PREFIX,
@ -804,8 +804,8 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
}
@Override
public QueryCacheFactory getQueryCacheFactory() {
return queryCacheFactory;
public TimestampsRegionAccessFactory getTimestampsRegionAccessFactory() {
return timestampsCacheFactory;
}
@Override
@ -1102,8 +1102,8 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.queryCacheEnabled = enabled;
}
public void applyQueryCacheFactory(QueryCacheFactory factory) {
this.queryCacheFactory = factory;
public void applyTimestampsRegionAccessFactory(TimestampsRegionAccessFactory factory) {
this.timestampsCacheFactory = factory;
}
public void applyCacheRegionPrefix(String prefix) {

View File

@ -17,6 +17,7 @@ import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.cache.cfg.internal.DomainDataRegionConfigImpl;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.dialect.function.SQLFunction;

View File

@ -17,7 +17,7 @@ import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
@ -279,8 +279,8 @@ public abstract class AbstractDelegatingSessionFactoryBuilder<T extends SessionF
}
@Override
public T applyQueryCacheFactory(QueryCacheFactory factory) {
delegate.applyQueryCacheFactory( factory );
public SessionFactoryBuilder applyTimestampsRegionAccessFactory(TimestampsRegionAccessFactory factory) {
delegate.applyTimestampsRegionAccessFactory( factory );
return getThis();
}

View File

@ -17,7 +17,7 @@ import org.hibernate.SessionFactoryObserver;
import org.hibernate.boot.SchemaAutoTooling;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.function.SQLFunction;
@ -252,8 +252,8 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
}
@Override
public QueryCacheFactory getQueryCacheFactory() {
return delegate.getQueryCacheFactory();
public TimestampsRegionAccessFactory getTimestampsRegionAccessFactory() {
return delegate.getTimestampsRegionAccessFactory();
}
@Override

View File

@ -6,10 +6,12 @@
*/
package org.hibernate.boot.spi;
import java.util.Collection;
import java.util.Set;
import org.hibernate.MappingException;
import org.hibernate.boot.Metadata;
import org.hibernate.cache.cfg.internal.DomainDataRegionConfigImpl;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.mapping.MappedSuperclass;

View File

@ -6,6 +6,10 @@
*/
package org.hibernate.boot.spi;
import java.util.Map;
import java.util.TimeZone;
import java.util.function.Supplier;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.CustomEntityDirtinessStrategy;
import org.hibernate.EntityMode;
@ -18,7 +22,7 @@ import org.hibernate.SessionFactoryObserver;
import org.hibernate.boot.SchemaAutoTooling;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.function.SQLFunction;
@ -31,10 +35,6 @@ import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
import java.util.Map;
import java.util.TimeZone;
import java.util.function.Supplier;
/**
* Aggregator of special options used to build the SessionFactory.
*
@ -182,7 +182,7 @@ public interface SessionFactoryOptions {
boolean isQueryCacheEnabled();
QueryCacheFactory getQueryCacheFactory();
TimestampsRegionAccessFactory getTimestampsRegionAccessFactory();
String getCacheRegionPrefix();

View File

@ -0,0 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.internal;
import org.hibernate.cache.cfg.spi.DomainDataCachingConfig;
import org.hibernate.cache.spi.access.AccessType;
/**
* @author Steve Ebersole
*/
public abstract class AbstractDomainDataCachingConfig implements DomainDataCachingConfig {
private final AccessType accessType;
public AbstractDomainDataCachingConfig(AccessType accessType) {
this.accessType = accessType;
}
@Override
public AccessType getAccessType() {
return accessType;
}
}

View File

@ -0,0 +1,56 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.internal;
import java.util.Comparator;
import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.mapping.Collection;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.type.VersionType;
/**
* @author Steve Ebersole
*/
public class CollectionDataCachingConfigImpl
extends AbstractDomainDataCachingConfig
implements CollectionDataCachingConfig {
private final Collection collectionDescriptor;
private final NavigableRole navigableRole;
public CollectionDataCachingConfigImpl(
Collection collectionDescriptor,
AccessType accessType) {
super( accessType );
this.collectionDescriptor = collectionDescriptor;
this.navigableRole = new NavigableRole( collectionDescriptor.getRole() );
}
@Override
public boolean isMutable() {
return collectionDescriptor.isMutable();
}
@Override
public boolean isVersioned() {
return collectionDescriptor.getOwner().isVersioned();
}
@Override
public Comparator getOwnerVersionComparator() {
if ( !isVersioned() ) {
return null;
}
return ( (VersionType) collectionDescriptor.getOwner().getVersion().getType() ).getComparator();
}
@Override
public NavigableRole getNavigableRole() {
return navigableRole;
}
}

View File

@ -0,0 +1,163 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig;
import org.hibernate.cache.cfg.spi.DomainDataCachingConfig;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.cfg.spi.EntityDataCachingConfig;
import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.type.VersionType;
/**
* DomainDataRegionConfig implementation
*
* @author Steve Ebersole
*/
public class DomainDataRegionConfigImpl implements DomainDataRegionConfig {
private final String regionName;
private final List<EntityDataCachingConfig> entityConfigs;
private final List<NaturalIdDataCachingConfig> naturalIdConfigs;
private final List<CollectionDataCachingConfig> collectionConfigs;
private DomainDataRegionConfigImpl(
String regionName,
List<EntityDataCachingConfig> entityConfigs,
List<NaturalIdDataCachingConfig> naturalIdConfigs,
List<CollectionDataCachingConfig> collectionConfigs) {
this.regionName = regionName;
this.entityConfigs = entityConfigs;
this.naturalIdConfigs = naturalIdConfigs;
this.collectionConfigs = collectionConfigs;
}
@Override
public String getRegionName() {
return regionName;
}
@Override
public List<EntityDataCachingConfig> getEntityCaching() {
return entityConfigs;
}
@Override
public List<NaturalIdDataCachingConfig> getNaturalIdCaching() {
return naturalIdConfigs;
}
@Override
public List<CollectionDataCachingConfig> getCollectionCaching() {
return collectionConfigs;
}
public static class Builder {
private final String regionName;
private Map<NavigableRole,EntityDataCachingConfigImpl> entityConfigsByRootName;
private List<NaturalIdDataCachingConfig> naturalIdConfigs;
private List<CollectionDataCachingConfig> collectionConfigs;
public Builder(String regionName) {
this.regionName = regionName;
}
@SuppressWarnings("UnusedReturnValue")
public Builder addEntityConfig(PersistentClass bootEntityDescriptor, AccessType accessType) {
if ( entityConfigsByRootName == null ) {
entityConfigsByRootName = new HashMap<>();
}
// todo (5.3) : this is another place where having `BootstrapContext` / `TypeConfiguration` helps
// would allow us to delay the attempt to resolve the comparator (usual timing issues wrt Type resolution)
final NavigableRole rootEntityName = new NavigableRole( bootEntityDescriptor.getRootClass().getEntityName() );
final EntityDataCachingConfigImpl entityDataCachingConfig = entityConfigsByRootName.computeIfAbsent(
rootEntityName,
x -> new EntityDataCachingConfigImpl(
rootEntityName,
bootEntityDescriptor.isVersioned()
? (Supplier<Comparator>) () -> ( (VersionType) bootEntityDescriptor.getVersion().getType() ).getComparator()
: null,
bootEntityDescriptor.isMutable(),
accessType
)
);
if ( bootEntityDescriptor == bootEntityDescriptor.getRootClass() ) {
entityDataCachingConfig.addCachedType( rootEntityName );
}
else {
entityDataCachingConfig.addCachedType( new NavigableRole( bootEntityDescriptor.getEntityName() ) );
}
return this;
}
// todo (6.0) : `EntityPersister` and `CollectionPersister` references here should be replaces with `EntityHierarchy` and `PersistentCollectionDescriptor`
//
// todo : although ^^, couldn't this just be the boot-time model? Is there a specific need for it to be the run-time model?
// that would alleviate the difference between 5.3 and 6.0 from the SPI POV
@SuppressWarnings("UnusedReturnValue")
public Builder addNaturalIdConfig(RootClass rootEntityDescriptor, AccessType accessType) {
if ( naturalIdConfigs == null ) {
naturalIdConfigs = new ArrayList<>();
}
naturalIdConfigs.add( new NaturalIdDataCachingConfigImpl( rootEntityDescriptor, accessType ) );
return this;
}
@SuppressWarnings("UnusedReturnValue")
public Builder addCollectionConfig(Collection collectionDescriptor, AccessType accessType) {
if ( collectionConfigs == null ) {
collectionConfigs = new ArrayList<>();
}
collectionConfigs.add( new CollectionDataCachingConfigImpl( collectionDescriptor, accessType ) );
return this;
}
public DomainDataRegionConfigImpl build() {
return new DomainDataRegionConfigImpl(
regionName,
finalize( entityConfigsByRootName ),
finalize( naturalIdConfigs ),
finalize( collectionConfigs )
);
}
@SuppressWarnings("unchecked")
private <T extends DomainDataCachingConfig> List<T> finalize(Map configs) {
return configs == null
? Collections.emptyList()
: Collections.unmodifiableList( new ArrayList( configs.values() ) );
}
private <T extends DomainDataCachingConfig> List<T> finalize(List<T> configs) {
return configs == null
? Collections.emptyList()
: Collections.unmodifiableList( configs );
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.internal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import org.hibernate.cache.cfg.spi.EntityDataCachingConfig;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* @author Steve Ebersole
*/
public class EntityDataCachingConfigImpl
extends AbstractDomainDataCachingConfig
implements EntityDataCachingConfig {
private final NavigableRole navigableRole;
private final Supplier<Comparator> versionComparatorAccess;
private final boolean isEntityMutable;
private final Set<NavigableRole> cachedTypes = new HashSet<>();
public EntityDataCachingConfigImpl(
NavigableRole rootEntityName,
Supplier<Comparator> versionComparatorAccess,
boolean isEntityMutable,
AccessType accessType) {
super( accessType );
this.navigableRole = rootEntityName;
this.versionComparatorAccess = versionComparatorAccess;
this.isEntityMutable = isEntityMutable;
}
@Override
public Supplier<Comparator> getVersionComparatorAccess() {
return versionComparatorAccess;
}
@Override
public boolean isMutable() {
return isEntityMutable;
}
@Override
public boolean isVersioned() {
return getVersionComparatorAccess() != null;
}
@Override
public NavigableRole getNavigableRole() {
return navigableRole;
}
@Override
public Set<NavigableRole> getCachedTypes() {
return cachedTypes;
}
public void addCachedType(NavigableRole typeRole) {
cachedTypes.add( typeRole );
}
}

View File

@ -0,0 +1,64 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.internal;
import java.util.Iterator;
import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.RootClass;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* @author Steve Ebersole
*/
public class NaturalIdDataCachingConfigImpl
extends AbstractDomainDataCachingConfig
implements NaturalIdDataCachingConfig {
private final RootClass rootEntityDescriptor;
private final NavigableRole navigableRole;
private final boolean mutable;
public NaturalIdDataCachingConfigImpl(
RootClass rootEntityDescriptor,
AccessType accessType) {
super( accessType );
this.rootEntityDescriptor = rootEntityDescriptor;
this.navigableRole = new NavigableRole( rootEntityDescriptor.getEntityName() );
// sucks that we need to do this here. persister does the same "calculation"
this.mutable = hasAnyMutableNaturalIdProps();
}
private boolean hasAnyMutableNaturalIdProps() {
final Iterator itr = rootEntityDescriptor.getDeclaredPropertyIterator();
while ( itr.hasNext() ) {
final Property prop = (Property) itr.next();
if ( prop.isNaturalIdentifier() && prop.isUpdateable() ) {
return true;
}
}
return false;
}
@Override
public NavigableRole getNavigableRole() {
return navigableRole;
}
@Override
public boolean isMutable() {
return mutable;
}
@Override
public boolean isVersioned() {
return false;
}
}

View File

@ -0,0 +1,11 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
/**
* Package used to model various aspects of caching configuration
*/
package org.hibernate.cache.cfg;

View File

@ -0,0 +1,22 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.spi;
import java.util.Comparator;
/**
* Specialized DomainDataCachingConfig describing the requested
* caching config for a particular persistent collection's data
*
* @author Steve Ebersole
*/
public interface CollectionDataCachingConfig extends DomainDataCachingConfig {
/**
* The comparator to be used with the owning entity's version (if it has one).
*/
Comparator getOwnerVersionComparator();
}

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.spi;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* Configuration for a specific type of data to be stored in the
* region
*
* @author Steve Ebersole
*/
public interface DomainDataCachingConfig {
/**
* The requested AccessType
*/
AccessType getAccessType();
/**
* Is the data marked as being mutable?
*/
boolean isMutable();
/**
* Is the data to be cached considered versioned?
*/
boolean isVersioned();
/**
* The {@link NavigableRole} of the thing to be cached
*/
NavigableRole getNavigableRole();
}

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.spi;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/**
* A "parameter object" for {@link RegionFactory#buildDomainDataRegion}
* calls, giving it access to information it needs.
*
* @author Steve Ebersole
*/
public interface DomainDataRegionBuildingContext {
/**
* The CacheKeyFactory explicitly specified as part of the
* bootstrap by the user, by some "container", etc.
*
* If this method returns a non-null value, it is expected
* that RegionFactory implementors will use to be its
* CacheKeyFactory and return it when asked later.
*/
CacheKeysFactory getEnforcedCacheKeysFactory();
/**
* Access to the SessionFactory for which a Region is
* being built.
*/
SessionFactoryImplementor getSessionFactory();
}

View File

@ -0,0 +1,33 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.spi;
import java.util.List;
/**
* Configuration for a named region for caching domain data
*
* @author Steve Ebersole
*/
public interface DomainDataRegionConfig {
String getRegionName();
/**
* Retrieve the list of all entity to be stored in this region
*/
List<EntityDataCachingConfig> getEntityCaching();
/**
* Retrieve the list of all natural-id data to be stored in this region
*/
List<NaturalIdDataCachingConfig> getNaturalIdCaching();
/**
* Retrieve the list of all collection data to be stored in this region
*/
List<CollectionDataCachingConfig> getCollectionCaching();
}

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.spi;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* Specialized DomainDataCachingConfig describing the requested
* caching config for a particular entity hierarchy's state data
*
* @author Steve Ebersole
*/
public interface EntityDataCachingConfig extends DomainDataCachingConfig {
/**
* Mainly here to allow optimization of not having to know the
* actual comparator instance to use here yet. If this method
* returns {@code true}, then users can safely assume that
* accessing {@link #getVersionComparatorAccess()} will
* not produce a null Comparator later
*
*/
boolean isVersioned();
/**
* Access to the comparator to be used with the entity's
* version. If the entity is not versioned, then this method
* returns {@code null}.
*/
Supplier<Comparator> getVersionComparatorAccess();
/**
* The list of specific subclasses of the root that are actually
* written to cache.
*/
Set<NavigableRole> getCachedTypes();
// todo (5.3) : what else is needed here?
}

View File

@ -0,0 +1,16 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.cfg.spi;
/**
* Specialized DomainDataCachingConfig describing the requested
* caching config for the natural-id data of a particular entity (hierarchy)
*
* @author Steve Ebersole
*/
public interface NaturalIdDataCachingConfig extends DomainDataCachingConfig {
}

View File

@ -1,106 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.internal;
import java.util.Comparator;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
import org.hibernate.type.descriptor.java.IncomparableComparator;
/**
* Standard CacheDataDescription implementation.
*
* @author Steve Ebersole
*/
public class CacheDataDescriptionImpl implements CacheDataDescription {
private final boolean mutable;
private final boolean versioned;
private final Comparator versionComparator;
private final Type keyType;
/**
* Constructs a CacheDataDescriptionImpl instance. Generally speaking, code should use one of the
* overloaded {@link #decode} methods rather than direct instantiation.
* @param mutable Is the described data mutable?
* @param versioned Is the described data versioned?
* @param versionComparator The described data's version value comparator (if versioned).
* @param keyType
*/
public CacheDataDescriptionImpl(boolean mutable, boolean versioned, Comparator versionComparator, Type keyType) {
this.mutable = mutable;
this.versioned = versioned;
this.versionComparator = versionComparator;
if ( versioned &&
( versionComparator == null || IncomparableComparator.class.isInstance( versionComparator ) ) ) {
throw new IllegalArgumentException(
"versionComparator must not be null or an instance of " + IncomparableComparator.class.getName()
);
}
this.keyType = keyType;
}
@Override
public boolean isMutable() {
return mutable;
}
@Override
public boolean isVersioned() {
return versioned;
}
@Override
public Comparator getVersionComparator() {
return versionComparator;
}
@Override
public Type getKeyType() {
return keyType;
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of an entity class.
*
* @param model The mapping model.
*
* @return The constructed CacheDataDescriptionImpl
*/
public static CacheDataDescriptionImpl decode(PersistentClass model) {
return new CacheDataDescriptionImpl(
model.isMutable(),
model.isVersioned(),
model.isVersioned()
? ( (VersionType) model.getVersion().getType() ).getComparator()
: null,
model.getIdentifier().getType()
);
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of a collection
*
* @param model The mapping model.
*
* @return The constructed CacheDataDescriptionImpl
*/
public static CacheDataDescriptionImpl decode(Collection model) {
return new CacheDataDescriptionImpl(
model.isMutable(),
model.getOwner().isVersioned(),
model.getOwner().isVersioned()
? ( (VersionType) model.getOwner().getVersion().getType() ).getComparator()
: null,
model.getKey().getType()
);
}
}

View File

@ -194,5 +194,7 @@ public class CollectionCacheInvalidator
beforeExecutions();
return getAfterTransactionCompletionProcess();
}
}
}

View File

@ -0,0 +1,230 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import java.io.Serializable;
import java.util.Collections;
import java.util.Set;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.cache.spi.QueryResultRegionAccess;
import org.hibernate.cache.spi.Region;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegionAccess;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* CacheImplementor implementation for disabled caching
*
* @author Steve Ebersole
*/
public class DisabledCaching implements CacheImplementor {
private final SessionFactoryImplementor sessionFactory;
private final RegionFactory regionFactory;
public DisabledCaching(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
this.regionFactory = sessionFactory.getServiceRegistry().getService( RegionFactory.class );
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public RegionFactory getRegionFactory() {
return regionFactory;
}
@Override
public void prime(Set<DomainDataRegionConfig> cacheRegionConfigs) {
// nothing to do
}
@Override
public boolean containsEntity(Class entityClass, Serializable identifier) {
return false;
}
@Override
public boolean containsEntity(String entityName, Serializable identifier) {
return false;
}
@Override
public void evictEntityData(Class entityClass, Serializable identifier) {
// nothing to do
}
@Override
public void evictEntityData(String entityName, Serializable identifier) {
// nothing to do
}
@Override
public void evictEntityData(Class entityClass) {
// nothing to do
}
@Override
public void evictEntityData(String entityName) {
// nothing to do
}
@Override
public void evictEntityData() {
// nothing to do
}
@Override
public void evictNaturalIdData(Class entityClass) {
// nothing to do
}
@Override
public void evictNaturalIdData(String entityName) {
// nothing to do
}
@Override
public void evictNaturalIdData() {
// nothing to do
}
@Override
public boolean containsCollection(String role, Serializable ownerIdentifier) {
return false;
}
@Override
public void evictCollectionData(String role, Serializable ownerIdentifier) {
// nothing to do
}
@Override
public void evictCollectionData(String role) {
// nothing to do
}
@Override
public void evictCollectionData() {
// nothing to do
}
@Override
public boolean containsQuery(String regionName) {
return false;
}
@Override
public void evictDefaultQueryRegion() {
// nothing to do
}
@Override
public void evictQueryRegion(String regionName) {
// nothing to do
}
@Override
public void evictQueryRegions() {
// nothing to do
}
@Override
public void evictRegion(String regionName) {
// nothing to do
}
@Override
public Region getRegion(String fullRegionName) {
return null;
}
@Override
public TimestampsRegionAccess getTimestampsRegionAccess() {
return null;
}
@Override
public QueryResultRegionAccess getDefaultQueryResultsRegionAccess() {
return null;
}
@Override
public QueryResultRegionAccess getQueryResultsRegionAccess(String regionName) {
return null;
}
@Override
public QueryResultRegionAccess getQueryResultsRegionAccessStrictly(String regionName) {
return null;
}
@Override
public void close() {
}
@Override
public String[] getSecondLevelCacheRegionNames() {
return new String[0];
}
@Override
public Set<String> getCacheRegionNames() {
return null;
}
@Override
public EntityDataAccess getEntityRegionAccess(NavigableRole rootEntityName) {
return null;
}
@Override
public NaturalIdDataAccess getNaturalIdRegionAccess(NavigableRole rootEntityName) {
return null;
}
@Override
public CollectionDataAccess getCollectionRegionAccess(NavigableRole collectionRole) {
return null;
}
@Override
public boolean contains(Class cls, Object primaryKey) {
return false;
}
@Override
public void evict(Class cls, Object primaryKey) {
}
@Override
public void evict(Class cls) {
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> cls) {
return (T) this;
}
@Override
public Set<NaturalIdDataAccess> getNaturalIdAccessesInRegion(String regionName) {
return Collections.emptySet();
}
}

View File

@ -0,0 +1,599 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.PersistenceException;
import org.hibernate.HibernateException;
import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig;
import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.cfg.spi.EntityDataCachingConfig;
import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.DomainDataRegion;
import org.hibernate.cache.spi.QueryResultRegionAccess;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.cache.spi.Region;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegion;
import org.hibernate.cache.spi.TimestampsRegionAccess;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.descriptor.java.StringTypeDescriptor;
/**
* @author Steve Ebersole
* @author Strong Liu
*/
public class EnabledCaching implements CacheImplementor, DomainDataRegionBuildingContext {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EnabledCaching.class );
private final SessionFactoryImplementor sessionFactory;
private final RegionFactory regionFactory;
private final Map<String,Region> regionsByName = new ConcurrentHashMap<>();
private final Map<NavigableRole,EntityDataAccess> entityAccessMap = new ConcurrentHashMap<>();
private final Map<NavigableRole,NaturalIdDataAccess> naturalIdAccessMap = new ConcurrentHashMap<>();
private final Map<NavigableRole,CollectionDataAccess> collectionAccessMap = new ConcurrentHashMap<>();
private final TimestampsRegionAccess timestampsRegionAccess;
private final QueryResultRegionAccess defaultQueryResultsRegionAccess;
private final Map<String, QueryResultRegionAccess> namedQueryResultsRegionAccess = new ConcurrentHashMap<>();
private final Set<String> legacySecondLevelCacheNames = new LinkedHashSet<>();
private final Map<String,Set<NaturalIdDataAccess>> legacyNaturalIdAccessesForRegion = new ConcurrentHashMap<>();
public EnabledCaching(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
this.regionFactory = getSessionFactory().getSessionFactoryOptions().getServiceRegistry().getService( RegionFactory.class );
if ( getSessionFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
final TimestampsRegion timestampsRegion = regionFactory.buildTimestampsRegion(
TimestampsRegion.class.getName(),
sessionFactory
);
timestampsRegionAccess = sessionFactory.getSessionFactoryOptions()
.getTimestampsRegionAccessFactory()
.buildTimestampsRegionAccess( this, timestampsRegion );
final QueryResultsRegion queryResultsRegion = regionFactory.buildQueryResultsRegion(
QueryResultRegionAccessImpl.class.getName(),
sessionFactory
);
regionsByName.put( queryResultsRegion.getName(), queryResultsRegion );
defaultQueryResultsRegionAccess = new QueryResultRegionAccessImpl(
queryResultsRegion,
timestampsRegionAccess
);
}
else {
timestampsRegionAccess = new TimestampsRegionAccessDisabledImpl();
defaultQueryResultsRegionAccess = null;
}
}
@Override
public void prime(Set<DomainDataRegionConfig> cacheRegionConfigs) {
for ( DomainDataRegionConfig regionConfig : cacheRegionConfigs ) {
final DomainDataRegion region = getRegionFactory().buildDomainDataRegion( regionConfig, this );
regionsByName.put( region.getName(), region );
if ( !StringTypeDescriptor.INSTANCE.areEqual( region.getName(), regionConfig.getRegionName() ) ) {
throw new HibernateException(
String.format(
Locale.ROOT,
"Region returned from RegionFactory was named differently than requested name. Expecting `%s`, but found `%s`",
regionConfig.getRegionName(),
region.getName()
)
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Entity caching
for ( EntityDataCachingConfig entityAccessConfig : regionConfig.getEntityCaching() ) {
final EntityDataAccess entityDataAccess = entityAccessMap.put(
entityAccessConfig.getNavigableRole(),
region.getEntityDataAccess( entityAccessConfig.getNavigableRole() )
);
legacySecondLevelCacheNames.add(
StringHelper.qualifyConditionally(
getSessionFactory().getSessionFactoryOptions().getCacheRegionPrefix(),
region.getName()
)
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Natural-id caching
if ( regionConfig.getNaturalIdCaching().isEmpty() ) {
legacyNaturalIdAccessesForRegion.put( region.getName(), Collections.emptySet() );
}
else {
final HashSet<NaturalIdDataAccess> accesses = new HashSet<>();
for ( NaturalIdDataCachingConfig naturalIdAccessConfig : regionConfig.getNaturalIdCaching() ) {
final NaturalIdDataAccess naturalIdDataAccess = naturalIdAccessMap.put(
naturalIdAccessConfig.getNavigableRole(),
region.getNaturalIdDataAccess( naturalIdAccessConfig.getNavigableRole() )
);
accesses.add( naturalIdDataAccess );
}
legacyNaturalIdAccessesForRegion.put( region.getName(), accesses );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Collection caching
for ( CollectionDataCachingConfig collectionAccessConfig : regionConfig.getCollectionCaching() ) {
final CollectionDataAccess collectionDataAccess = collectionAccessMap.put(
collectionAccessConfig.getNavigableRole(),
region.getCollectionDataAccess( collectionAccessConfig.getNavigableRole() )
);
legacySecondLevelCacheNames.add(
StringHelper.qualifyConditionally(
getSessionFactory().getSessionFactoryOptions().getCacheRegionPrefix(),
region.getName()
)
);
}
}
}
@Override
public CacheKeysFactory getEnforcedCacheKeysFactory() {
// todo (6.0) : allow configuration of this
return null;
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public RegionFactory getRegionFactory() {
return regionFactory;
}
@Override
public TimestampsRegionAccess getTimestampsRegionAccess() {
return timestampsRegionAccess;
}
@Override
public Region getRegion(String regionName) {
return regionsByName.get( regionName );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Entity data
@Override
public boolean containsEntity(Class entityClass, Serializable identifier) {
return containsEntity( entityClass.getName(), identifier );
}
@Override
public boolean containsEntity(String entityName, Serializable identifier) {
final EntityPersister entityDescriptor = sessionFactory.getMetamodel().entityPersister( entityName );
final EntityDataAccess cacheAccess = entityDescriptor.getCacheAccessStrategy();
if ( cacheAccess == null ) {
return false;
}
final Object key = cacheAccess.generateCacheKey( identifier, entityDescriptor, sessionFactory, null );
return cacheAccess.contains( key );
}
@Override
public void evictEntityData(Class entityClass, Serializable identifier) {
evictEntityData( entityClass.getName(), identifier );
}
@Override
public void evictEntityData(String entityName, Serializable identifier) {
final EntityPersister entityDescriptor = sessionFactory.getMetamodel().entityPersister( entityName );
final EntityDataAccess cacheAccess = entityDescriptor.getCacheAccessStrategy();
if ( cacheAccess == null ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Evicting second-level cache: %s",
MessageHelper.infoString( entityDescriptor, identifier, sessionFactory )
);
}
final Object key = cacheAccess.generateCacheKey( identifier, entityDescriptor, sessionFactory, null );
cacheAccess.evict( key );
}
@Override
public void evictEntityData(Class entityClass) {
evictEntityData( entityClass.getName() );
}
@Override
public void evictEntityData(String entityName) {
evictEntityData( getSessionFactory().getMetamodel().entityPersister( entityName ) );
}
protected void evictEntityData(EntityPersister entityDescriptor) {
EntityPersister rootEntityDescriptor = entityDescriptor;
if ( entityDescriptor.isInherited()
&& ! entityDescriptor.getEntityName().equals( entityDescriptor.getRootEntityName() ) ) {
rootEntityDescriptor = getSessionFactory().getMetamodel().entityPersister( entityDescriptor.getRootEntityName() );
}
evictEntityData(
rootEntityDescriptor.getNavigableRole(),
rootEntityDescriptor.getCacheAccessStrategy()
);
}
private void evictEntityData(NavigableRole navigableRole, EntityDataAccess cacheAccess) {
if ( cacheAccess == null ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting entity cache: %s", navigableRole.getFullPath() );
}
cacheAccess.evictAll();
}
@Override
public void evictEntityData() {
sessionFactory.getMetamodel().entityPersisters().values().forEach( this::evictEntityData );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Natural-id data
@Override
public void evictNaturalIdData(Class entityClass) {
evictNaturalIdData( entityClass.getName() );
}
@Override
public void evictNaturalIdData(String entityName) {
evictNaturalIdData(
sessionFactory.getMetamodel().entityPersister( entityName )
);
}
private void evictNaturalIdData(EntityPersister rootEntityDescriptor) {
evictNaturalIdData( rootEntityDescriptor.getNavigableRole(), rootEntityDescriptor.getNaturalIdCacheAccessStrategy() );
}
@Override
public void evictNaturalIdData() {
naturalIdAccessMap.forEach( this::evictNaturalIdData );
}
private void evictNaturalIdData(NavigableRole rootEntityRole, NaturalIdDataAccess cacheAccess) {
if ( cacheAccess == null ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting natural-id cache: %s", rootEntityRole.getFullPath() );
}
cacheAccess.evictAll();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Collection data
@Override
public boolean containsCollection(String role, Serializable ownerIdentifier) {
final CollectionPersister collectionDescriptor = sessionFactory.getMetamodel()
.collectionPersister( role );
final CollectionDataAccess cacheAccess = collectionDescriptor.getCacheAccessStrategy();
if ( cacheAccess == null ) {
return false;
}
final Object key = cacheAccess.generateCacheKey( ownerIdentifier, collectionDescriptor, sessionFactory, null );
return cacheAccess.contains( key );
}
@Override
public void evictCollectionData(String role, Serializable ownerIdentifier) {
final CollectionPersister collectionDescriptor = sessionFactory.getMetamodel()
.collectionPersister( role );
final CollectionDataAccess cacheAccess = collectionDescriptor.getCacheAccessStrategy();
if ( cacheAccess == null ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Evicting second-level cache: %s",
MessageHelper.collectionInfoString( collectionDescriptor, ownerIdentifier, sessionFactory )
);
}
final Object key = cacheAccess.generateCacheKey( ownerIdentifier, collectionDescriptor, sessionFactory, null );
cacheAccess.evict( key );
}
@Override
public void evictCollectionData(String role) {
final CollectionPersister collectionDescriptor = sessionFactory.getMetamodel()
.collectionPersister( role );
evictCollectionData( collectionDescriptor );
}
private void evictCollectionData(CollectionPersister collectionDescriptor) {
evictCollectionData(
collectionDescriptor.getNavigableRole(),
collectionDescriptor.getCacheAccessStrategy()
);
}
private void evictCollectionData(NavigableRole navigableRole, CollectionDataAccess cacheAccess) {
if ( cacheAccess == null ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting second-level cache: %s", navigableRole.getFullPath() );
}
cacheAccess.evictAll();
}
@Override
public void evictCollectionData() {
collectionAccessMap.forEach( this::evictCollectionData );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Query-results data
@Override
public boolean containsQuery(String regionName) {
final QueryResultRegionAccess cacheAccess = getQueryResultsRegionAccessStrictly( regionName );
return cacheAccess != null;
}
@Override
public void evictDefaultQueryRegion() {
evictQueryResultRegion( defaultQueryResultsRegionAccess );
}
@Override
public void evictQueryRegion(String regionName) {
final QueryResultRegionAccess cacheAccess = getQueryResultsRegionAccess( regionName );
if ( cacheAccess == null ) {
return;
}
evictQueryResultRegion( cacheAccess );
}
private void evictQueryResultRegion(QueryResultRegionAccess cacheAccess) {
if ( cacheAccess == null ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting query cache, region: %s", cacheAccess.getRegion().getName() );
}
cacheAccess.clear();
}
@Override
public void evictQueryRegions() {
if ( LOG.isDebugEnabled() ) {
LOG.debug( "Evicting cache of all query regions." );
}
evictQueryResultRegion( defaultQueryResultsRegionAccess );
for ( QueryResultRegionAccess cacheAccess : namedQueryResultsRegionAccess.values() ) {
evictQueryResultRegion( cacheAccess );
}
}
@Override
public QueryResultRegionAccess getDefaultQueryResultsRegionAccess() {
return defaultQueryResultsRegionAccess;
}
@Override
public QueryResultRegionAccess getQueryResultsRegionAccess(String regionName) throws HibernateException {
if ( !getSessionFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
return null;
}
if ( regionName == null || regionName.equals( getDefaultQueryResultsRegionAccess().getRegion().getName() ) ) {
return getDefaultQueryResultsRegionAccess();
}
final QueryResultRegionAccess existing = namedQueryResultsRegionAccess.get( regionName );
if ( existing != null ) {
return existing;
}
return makeQueryResultsRegionAccess( regionName );
}
@Override
public QueryResultRegionAccess getQueryResultsRegionAccessStrictly(String regionName) {
if ( !getSessionFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
return null;
}
return namedQueryResultsRegionAccess.get( regionName );
}
protected QueryResultRegionAccess makeQueryResultsRegionAccess(String regionName) {
final QueryResultsRegion region = (QueryResultsRegion) regionsByName.computeIfAbsent(
regionName,
this::makeQueryResultsRegion
);
final QueryResultRegionAccessImpl regionAccess = new QueryResultRegionAccessImpl(
region,
timestampsRegionAccess
);
namedQueryResultsRegionAccess.put( regionName, regionAccess );
return regionAccess;
}
protected QueryResultsRegion makeQueryResultsRegion(String regionName) {
// make sure there is not an existing domain-data region with that name..
final Region existing = regionsByName.get( regionName );
if ( existing != null ) {
if ( !QueryResultsRegion.class.isInstance( existing ) ) {
throw new IllegalStateException( "Cannot store both domain-data and query-result-data in the same region [" + regionName );
}
throw new IllegalStateException( "Illegal call to create QueryResultsRegion - one already existed" );
}
return regionFactory.buildQueryResultsRegion( regionName, getSessionFactory() );
}
@Override
public Set<String> getCacheRegionNames() {
return regionsByName.keySet();
}
@Override
public void evictRegion(String regionName) {
getRegion( regionName ).clear();
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> cls) {
if ( org.hibernate.Cache.class.isAssignableFrom( cls ) ) {
return (T) this;
}
if ( RegionFactory.class.isAssignableFrom( cls ) ) {
return (T) regionFactory;
}
throw new PersistenceException( "Hibernate cannot unwrap Cache as " + cls.getName() );
}
@Override
public void close() {
for ( Region region : regionsByName.values() ) {
region.destroy();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA-defined methods
@Override
public boolean contains(Class cls, Object primaryKey) {
// JPA
return containsEntity( cls, (Serializable) primaryKey );
}
@Override
public void evict(Class cls, Object primaryKey) {
// JPA call
evictEntityData( cls, (Serializable) primaryKey );
}
@Override
public void evict(Class cls) {
// JPA
evictEntityData( cls );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deprecations
@Override
public EntityDataAccess getEntityRegionAccess(NavigableRole rootEntityName) {
return entityAccessMap.get( rootEntityName );
}
@Override
public NaturalIdDataAccess getNaturalIdRegionAccess(NavigableRole rootEntityName) {
return naturalIdAccessMap.get( rootEntityName );
}
@Override
public CollectionDataAccess getCollectionRegionAccess(NavigableRole collectionRole) {
return collectionAccessMap.get( collectionRole );
}
@Override
public String[] getSecondLevelCacheRegionNames() {
return ArrayHelper.toStringArray( legacySecondLevelCacheNames );
}
@Override
public Set<NaturalIdDataAccess> getNaturalIdAccessesInRegion(String regionName) {
return legacyNaturalIdAccessesForRegion.get( regionName );
}
}

View File

@ -6,19 +6,21 @@
*/
package org.hibernate.cache.internal;
import java.util.Properties;
import java.util.Map;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.NoCacheRegionFactoryAvailableException;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.cache.spi.DomainDataRegion;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Factory used if no caching enabled in config...
@ -38,7 +40,7 @@ public class NoCachingRegionFactory implements RegionFactory {
}
@Override
public void start(SessionFactoryOptions settings, Properties properties) throws CacheException {
public void start(SessionFactoryOptions settings, Map configValues) throws CacheException {
}
@Override
@ -61,32 +63,25 @@ public class NoCachingRegionFactory implements RegionFactory {
}
@Override
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
public CacheTransactionSynchronization createTransactionContext(SharedSessionContractImplementor session) {
return new NoCachingTransactionSynchronizationImpl( this );
}
@Override
public DomainDataRegion buildDomainDataRegion(
DomainDataRegionConfig regionConfig, DomainDataRegionBuildingContext buildingContext) {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
public QueryResultsRegion buildQueryResultsRegion(
String regionName, SessionFactoryImplementor sessionFactory) {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public CollectionRegion buildCollectionRegion(
String regionName,
Properties properties,
CacheDataDescription metadata) throws CacheException {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
public TimestampsRegion buildTimestampsRegion(
String regionName, SessionFactoryImplementor sessionFactory) {
throw new NoCacheRegionFactoryAvailableException();
}
}

View File

@ -0,0 +1,19 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import org.hibernate.cache.spi.AbstractCacheTransactionSynchronization;
import org.hibernate.cache.spi.RegionFactory;
/**
* @author Steve Ebersole
*/
public class NoCachingTransactionSynchronizationImpl extends AbstractCacheTransactionSynchronization {
public NoCachingTransactionSynchronizationImpl(RegionFactory regionFactory) {
super( regionFactory );
}
}

View File

@ -1,86 +1,52 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.persistence.EntityNotFoundException;
import org.hibernate.HibernateException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.QueryCache;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.cache.spi.QueryResultRegionAccess;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.UpdateTimestampsCache;
import org.hibernate.engine.spi.CacheImplementor;
import org.hibernate.cache.spi.QuerySpacesHelper;
import org.hibernate.cache.spi.TimestampsRegionAccess;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper;
/**
* The standard implementation of the Hibernate QueryCache interface. This
* implementation is very good at recognizing stale query results and
* and re-running queries when it detects this condition, re-caching the new
* results.
* The standard implementation of the Hibernate QueryCache interface. Works
* hind-in-hand with {@link TimestampsRegionAccess} to help in recognizing
* stale query results.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class StandardQueryCache implements QueryCache {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( StandardQueryCache.class );
public class QueryResultRegionAccessImpl implements QueryResultRegionAccess {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QueryResultRegionAccessImpl.class );
private static final boolean DEBUGGING = LOG.isDebugEnabled();
private static final boolean TRACING = LOG.isTraceEnabled();
private final QueryResultsRegion cacheRegion;
private final UpdateTimestampsCache updateTimestampsCache;
private final TimestampsRegionAccess timestampsCache;
/**
* Constructs a StandardQueryCache instance
*
* @param settings The SessionFactory settings.
* @param props Any properties
* @param updateTimestampsCache The update-timestamps cache to use.
* @param regionName The base query cache region name
*/
public StandardQueryCache(
final SessionFactoryOptions settings,
final Properties props,
final UpdateTimestampsCache updateTimestampsCache,
final String regionName) {
String regionNameToUse = regionName;
if ( regionNameToUse == null ) {
regionNameToUse = StandardQueryCache.class.getName();
}
final String prefix = settings.getCacheRegionPrefix();
if ( prefix != null ) {
regionNameToUse = prefix + '.' + regionNameToUse;
}
LOG.startingQueryCache( regionNameToUse );
this.cacheRegion = settings.getServiceRegistry().getService( RegionFactory.class ).buildQueryResultsRegion(
regionNameToUse,
props
);
this.updateTimestampsCache = updateTimestampsCache;
}
public StandardQueryCache(QueryResultsRegion cacheRegion, CacheImplementor cacheManager) {
LOG.startingQueryCache( cacheRegion.getName() );
QueryResultRegionAccessImpl(
QueryResultsRegion cacheRegion,
TimestampsRegionAccess timestampsCache) {
this.cacheRegion = cacheRegion;
this.updateTimestampsCache = cacheManager.getUpdateTimestampsCache();
this.timestampsCache = timestampsCache;
}
@Override
@ -88,56 +54,46 @@ public class StandardQueryCache implements QueryCache {
return cacheRegion;
}
@Override
public void destroy() {
try {
cacheRegion.destroy();
}
catch ( Exception e ) {
LOG.unableToDestroyQueryCache( cacheRegion.getName(), e.getMessage() );
}
}
@Override
public void clear() throws CacheException {
cacheRegion.evictAll();
}
@Override
@SuppressWarnings({ "unchecked" })
public boolean put(
final QueryKey key,
final List results,
final Type[] returnTypes,
final List result,
final boolean isNaturalKeyLookup,
final SharedSessionContractImplementor session) throws HibernateException {
if ( isNaturalKeyLookup && result.isEmpty() ) {
return false;
}
if ( DEBUGGING ) {
LOG.debugf( "Caching query results in region: %s; timestamp=%s", cacheRegion.getName(), session.getTimestamp() );
LOG.debugf( "Caching query results in region: %s; timestamp=%s", cacheRegion.getName(), session.getTransactionStartTimestamp() );
}
final List cacheable = new ArrayList( result.size() + 1 );
if ( TRACING ) {
logCachedResultDetails( key, null, returnTypes, cacheable );
}
cacheable.add( session.getTimestamp() );
final List resultsCopy = CollectionHelper.arrayList( results.size() );
final boolean isSingleResult = returnTypes.length == 1;
for ( Object aResult : result ) {
final Serializable cacheItem = isSingleResult
? returnTypes[0].disassemble( aResult, session, null )
: TypeHelper.disassemble( (Object[]) aResult, returnTypes, null, session, null );
cacheable.add( cacheItem );
for ( Object aResult : results ) {
final Serializable resultRowForCache;
if ( isSingleResult ) {
resultRowForCache = returnTypes[0].disassemble( aResult, session, null );
}
else {
resultRowForCache = TypeHelper.disassemble( (Object[]) aResult, returnTypes, null, session, null );
}
resultsCopy.add( resultRowForCache );
if ( TRACING ) {
logCachedResultRowDetails( returnTypes, aResult );
}
}
if ( TRACING ) {
logCachedResultDetails( key, null, returnTypes, resultsCopy );
}
final CacheItem cacheItem = new CacheItem(
session.getTransactionStartTimestamp(),
resultsCopy
);
try {
session.getEventListenerManager().cachePutStart();
cacheRegion.put( session, key, cacheable );
cacheRegion.getAccess().addToCache( key, cacheItem );
}
finally {
session.getEventListenerManager().cachePutEnd();
@ -146,123 +102,6 @@ public class StandardQueryCache implements QueryCache {
return true;
}
@Override
@SuppressWarnings({ "unchecked" })
public List get(
final QueryKey key,
final Type[] returnTypes,
final boolean isNaturalKeyLookup,
final Set<Serializable> spaces,
final SharedSessionContractImplementor session) throws HibernateException {
if ( DEBUGGING ) {
LOG.debugf( "Checking cached query results in region: %s", cacheRegion.getName() );
}
final List cacheable = getCachedResults( key, session );
if ( TRACING ) {
logCachedResultDetails( key, spaces, returnTypes, cacheable );
}
if ( cacheable == null ) {
if ( DEBUGGING ) {
LOG.debug( "Query results were not found in cache" );
}
return null;
}
final Long timestamp = (Long) cacheable.get( 0 );
if ( !isNaturalKeyLookup && !isUpToDate( spaces, timestamp, session ) ) {
if ( DEBUGGING ) {
LOG.debug( "Cached query results were not up-to-date" );
}
return null;
}
if ( DEBUGGING ) {
LOG.debug( "Returning cached query results" );
}
final boolean singleResult = returnTypes.length == 1;
for ( int i = 1; i < cacheable.size(); i++ ) {
if ( singleResult ) {
returnTypes[0].beforeAssemble( (Serializable) cacheable.get( i ), session );
}
else {
TypeHelper.beforeAssemble( (Serializable[]) cacheable.get( i ), returnTypes, session );
}
}
return assembleCachedResult(key, cacheable, isNaturalKeyLookup, singleResult, returnTypes, session);
}
private List assembleCachedResult(
final QueryKey key,
final List cacheable,
final boolean isNaturalKeyLookup,
boolean singleResult,
final Type[] returnTypes,
final SharedSessionContractImplementor session) throws HibernateException {
try {
final List result = new ArrayList( cacheable.size() - 1 );
if ( singleResult ) {
for ( int i = 1; i < cacheable.size(); i++ ) {
result.add( returnTypes[0].assemble( (Serializable) cacheable.get( i ), session, null ) );
}
}
else {
for ( int i = 1; i < cacheable.size(); i++ ) {
result.add(
TypeHelper.assemble( (Serializable[]) cacheable.get( i ), returnTypes, session, null )
);
if ( TRACING ) {
logCachedResultRowDetails( returnTypes, result.get( i - 1 ) );
}
}
}
return result;
}
catch ( RuntimeException ex ) {
if ( isNaturalKeyLookup ) {
// potentially perform special handling for natural-id look ups.
if ( UnresolvableObjectException.class.isInstance( ex )
|| EntityNotFoundException.class.isInstance( ex ) ) {
if ( DEBUGGING ) {
LOG.debug( "Unable to reassemble cached natural-id query result" );
}
cacheRegion.evict( key );
// EARLY EXIT !
return null;
}
}
throw ex;
}
}
private List getCachedResults(QueryKey key, SharedSessionContractImplementor session) {
List cacheable = null;
try {
session.getEventListenerManager().cacheGetStart();
cacheable = (List) cacheRegion.get( session, key );
}
finally {
session.getEventListenerManager().cacheGetEnd( cacheable != null );
}
return cacheable;
}
protected boolean isUpToDate(Set<Serializable> spaces, Long timestamp, SharedSessionContractImplementor session) {
if ( DEBUGGING ) {
LOG.debugf( "Checking query spaces are up-to-date: %s", spaces );
}
return updateTimestampsCache.isUpToDate( spaces, timestamp, session );
}
@Override
public String toString() {
return "StandardQueryCache(" + cacheRegion.getName() + ')';
}
private static void logCachedResultDetails(QueryKey key, Set querySpaces, Type[] returnTypes, List result) {
if ( !TRACING ) {
return;
@ -289,6 +128,102 @@ public class StandardQueryCache implements QueryCache {
}
}
@Override
public List get(
QueryKey key,
Set<Serializable> spaces,
final Type[] returnTypes,
SharedSessionContractImplementor session) {
return get(
key,
QuerySpacesHelper.INSTANCE.toStringArray( spaces ),
returnTypes,
session
);
}
@Override
@SuppressWarnings({ "unchecked" })
public List get(
final QueryKey key,
final String[] spaces,
final Type[] returnTypes,
final SharedSessionContractImplementor session) {
if ( DEBUGGING ) {
LOG.debugf( "Checking cached query results in region: %s", cacheRegion.getName() );
}
final CacheItem cacheItem = getCachedData( key, session );
if ( cacheItem == null ) {
if ( DEBUGGING ) {
LOG.debug( "Query results were not found in cache" );
}
return null;
}
if ( !timestampsCache.isUpToDate( spaces, cacheItem.timestamp, session ) ) {
if ( DEBUGGING ) {
LOG.debug( "Cached query results were not up-to-date" );
}
return null;
}
if ( DEBUGGING ) {
LOG.debug( "Returning cached query results" );
}
final boolean singleResult = returnTypes.length == 1;
for ( int i = 0; i < cacheItem.results.size(); i++ ) {
if ( singleResult ) {
returnTypes[0].beforeAssemble( (Serializable) cacheItem.results.get( i ), session );
}
else {
TypeHelper.beforeAssemble( (Serializable[]) cacheItem.results.get( i ), returnTypes, session );
}
}
return assembleCachedResult( key, cacheItem.results, singleResult, returnTypes, session );
}
private CacheItem getCachedData(QueryKey key, SharedSessionContractImplementor session) {
CacheItem cachedItem = null;
try {
session.getEventListenerManager().cacheGetStart();
cachedItem = (CacheItem) cacheRegion.getAccess().getFromCache( key );
}
finally {
session.getEventListenerManager().cacheGetEnd( cachedItem != null );
}
return cachedItem;
}
@SuppressWarnings("unchecked")
private List assembleCachedResult(
final QueryKey key,
final List cached,
boolean singleResult,
final Type[] returnTypes,
final SharedSessionContractImplementor session) throws HibernateException {
final List result = new ArrayList( cached.size() );
if ( singleResult ) {
for ( Object aCached : cached ) {
result.add( returnTypes[0].assemble( (Serializable) aCached, session, null ) );
}
}
else {
for ( int i = 0; i < cached.size(); i++ ) {
result.add(
TypeHelper.assemble( (Serializable[]) cached.get( i ), returnTypes, session, null )
);
if ( TRACING ) {
logCachedResultRowDetails( returnTypes, result.get( i ) );
}
}
}
return result;
}
private static void logCachedResultRowDetails(Type[] returnTypes, Object result) {
logCachedResultRowDetails(
returnTypes,
@ -345,4 +280,24 @@ public class StandardQueryCache implements QueryCache {
}
}
}
@Override
public String toString() {
return "QueryResultsCache(" + cacheRegion.getName() + ')';
}
@Override
public void clear() throws CacheException {
cacheRegion.getAccess().clearCache();
}
public static class CacheItem implements Serializable {
private final long timestamp;
private final List results;
CacheItem(long timestamp, List results) {
this.timestamp = timestamp;
this.results = results;
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.internal;
import org.hibernate.cache.spi.QueryCache;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.engine.spi.CacheImplementor;
/**
* Standard Hibernate implementation of the QueryCacheFactory interface. Returns instances of
* {@link StandardQueryCache}.
*/
public class StandardQueryCacheFactory implements QueryCacheFactory {
/**
* Singleton access
*/
public static final StandardQueryCacheFactory INSTANCE = new StandardQueryCacheFactory();
@Override
public QueryCache buildQueryCache(QueryResultsRegion region, CacheImplementor cacheManager) {
return new StandardQueryCache( region, cacheManager );
}
}

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.cache.spi.TimestampsRegionAccess;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.cache.spi.TimestampsRegion;
/**
* Standard Hibernate implementation of the QueryCacheFactory interface. Returns instances of
* {@link QueryResultRegionAccessImpl}.
*/
public class StandardTimestampsRegionAccessFactory implements TimestampsRegionAccessFactory {
/**
* Singleton access
*/
public static final StandardTimestampsRegionAccessFactory INSTANCE = new StandardTimestampsRegionAccessFactory();
@Override
public TimestampsRegionAccess buildTimestampsRegionAccess(
CacheImplementor cacheManager,
TimestampsRegion timestampsRegion) {
return new TimestampsRegionAccessEnabledImpl( timestampsRegion );
}
}

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import org.hibernate.cache.spi.TimestampsRegionAccess;
import org.hibernate.cache.spi.TimestampsRegion;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.jboss.logging.Logger;
/**
* TimestampsRegionAccess implementation for cases where query results caching
* (or second level caching overall) is disabled.
*
* @author Steve Ebersole
*/
public class TimestampsRegionAccessDisabledImpl implements TimestampsRegionAccess {
private static final Logger log = Logger.getLogger( TimestampsRegionAccessDisabledImpl.class );
@Override
public TimestampsRegion getRegion() {
return null;
}
@Override
public void preInvalidate(String[] spaces, SharedSessionContractImplementor session) {
log.trace( "TimestampsRegionAccess#preInvalidate - disabled" );
}
@Override
public void invalidate(String[] spaces, SharedSessionContractImplementor session) {
log.trace( "TimestampsRegionAccess#invalidate - disabled" );
}
@Override
public boolean isUpToDate(
String[] spaces,
Long timestamp,
SharedSessionContractImplementor session) {
log.trace( "TimestampsRegionAccess#isUpToDate - disabled" );
return false;
}
}

View File

@ -0,0 +1,146 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.internal;
import java.io.Serializable;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegionAccess;
import org.hibernate.cache.spi.TimestampsRegion;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.jboss.logging.Logger;
/**
* Standard implementation of QuerySpaceStalenessStrategy
*
* @author Steve Ebersole
*/
public class TimestampsRegionAccessEnabledImpl implements TimestampsRegionAccess {
private static final Logger log = Logger.getLogger( TimestampsRegionAccessEnabledImpl.class );
private static final boolean DEBUG_ENABLED = log.isDebugEnabled();
private final TimestampsRegion timestampsRegion;
public TimestampsRegionAccessEnabledImpl(TimestampsRegion timestampsRegion) {
this.timestampsRegion = timestampsRegion;
}
@Override
public TimestampsRegion getRegion() {
return timestampsRegion;
}
@Override
public void preInvalidate(
String[] spaces,
SharedSessionContractImplementor session) {
final SessionFactoryImplementor factory = session.getFactory();
final RegionFactory regionFactory = factory.getCache().getRegionFactory();
final boolean stats = factory.getStatistics().isStatisticsEnabled();
final Long ts = regionFactory.nextTimestamp() + regionFactory.getTimeout();
for ( Serializable space : spaces ) {
if ( DEBUG_ENABLED ) {
log.debugf( "Pre-invalidating space [%s], timestamp: %s", space, ts );
}
try {
session.getEventListenerManager().cachePutStart();
//put() has nowait semantics, is this really appropriate?
//note that it needs to be async replication, never local or sync
timestampsRegion.getAccess().addToCache( space, ts );
}
finally {
session.getEventListenerManager().cachePutEnd();
}
if ( stats ) {
factory.getStatistics().updateTimestampsCachePut();
}
}
}
@Override
public void invalidate(
String[] spaces,
SharedSessionContractImplementor session) {
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
final Long ts = session.getFactory().getCache().getRegionFactory().nextTimestamp();
for (Serializable space : spaces) {
if ( DEBUG_ENABLED ) {
log.debugf( "Invalidating space [%s], timestamp: %s", space, ts );
}
try {
session.getEventListenerManager().cachePutStart();
timestampsRegion.getAccess().addToCache( space, ts );
}
finally {
session.getEventListenerManager().cachePutEnd();
if ( stats ) {
session.getFactory().getStatistics().updateTimestampsCachePut();
}
}
}
}
@Override
public boolean isUpToDate(
String[] spaces,
Long timestamp,
SharedSessionContractImplementor session) {
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
for ( Serializable space : spaces ) {
final Long lastUpdate = getLastUpdateTimestampForSpace( space, session );
if ( lastUpdate == null ) {
// the last update timestamp for the given space was evicted from the
// cache or there have been no writes to it since startup
if ( stats ) {
session.getFactory().getStatistics().updateTimestampsCacheMiss();
}
}
else {
if ( DEBUG_ENABLED ) {
log.debugf(
"[%s] last update timestamp: %s",
space,
lastUpdate + ", result set timestamp: " + timestamp
);
}
if ( stats ) {
session.getFactory().getStatistics().updateTimestampsCacheHit();
}
if ( lastUpdate >= timestamp ) {
return false;
}
}
}
return true;
}
private Long getLastUpdateTimestampForSpace(Serializable space, SharedSessionContractImplementor session) {
Long ts = null;
try {
session.getEventListenerManager().cacheGetStart();
ts = (Long) timestampsRegion.getAccess().getFromCache( space );
}
finally {
session.getEventListenerManager().cacheGetEnd( ts != null );
}
return ts;
}
}

View File

@ -0,0 +1,60 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
/**
* @author Steve Ebersole
*/
public abstract class AbstractCacheTransactionSynchronization implements CacheTransactionSynchronization {
private long lastTransactionCompletionTimestamp;
private final RegionFactory regionFactory;
public AbstractCacheTransactionSynchronization(RegionFactory regionFactory) {
// prime the timestamp for any non-transactional access - until (if) we
// later join a new txn
this.lastTransactionCompletionTimestamp = regionFactory.nextTimestamp();
this.regionFactory = regionFactory;
}
@Override
public long getCurrentTransactionStartTimestamp() {
return lastTransactionCompletionTimestamp;
}
@Override
public final void transactionJoined() {
// reset the timestamp
this.lastTransactionCompletionTimestamp = regionFactory.nextTimestamp();
processTransactionJoin();
}
private void processTransactionJoin() {
// by default, nothing to do.
}
@Override
public final void transactionCompleting() {
processTransactionCompleting();
}
private void processTransactionCompleting() {
// by default, nothing to do.
}
@Override
public void transactionCompleted(boolean successful) {
// reset the timestamp for any non-transactional access after this
// point - until (if) we later join a new txn
// this.lastTransactionCompletionTimestamp = regionFactory.nextTimestamp();
processTransactionCompleted( successful );
}
private void processTransactionCompleted(boolean successful) {
// by default, nothing to do.
}
}

View File

@ -0,0 +1,210 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig;
import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.cfg.spi.EntityDataCachingConfig;
import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* @author Steve Ebersole
*/
public abstract class AbstractDomainDataRegion implements DomainDataRegion {
private final String name;
private final SessionFactoryImplementor sessionFactory;
private final RegionFactory regionFactory;
private final Map<NavigableRole,EntityDataAccess> entityDataAccessMap;
private final Map<NavigableRole,NaturalIdDataAccess> naturalIdDataAccessMap;
private final Map<NavigableRole,CollectionDataAccess> collectionDataAccessMap;
public AbstractDomainDataRegion(
DomainDataRegionConfig regionConfig,
RegionFactory regionFactory,
DomainDataRegionBuildingContext buildingContext) {
this.name = regionConfig.getRegionName();
this.sessionFactory = buildingContext.getSessionFactory();
this.regionFactory = regionFactory;
this.entityDataAccessMap = generateEntityDataAccessMap( regionConfig );
this.naturalIdDataAccessMap = generateNaturalIdDataAccessMap( regionConfig );
this.collectionDataAccessMap = generateCollectionDataAccessMap( regionConfig );
}
@Override
public String getName() {
return name;
}
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public RegionFactory getRegionFactory() {
return regionFactory;
}
@Override
public EntityDataAccess getEntityDataAccess(NavigableRole rootEntityRole) {
final EntityDataAccess access = entityDataAccessMap.get( rootEntityRole );
if ( access == null ) {
// todo (6.0) : is it an error here if the entity is not configured for caching (no map hit)?
}
return access;
}
@Override
public NaturalIdDataAccess getNaturalIdDataAccess(NavigableRole rootEntityRole) {
final NaturalIdDataAccess access = naturalIdDataAccessMap.get( rootEntityRole );
if ( access == null ) {
// todo (6.0) : is it an error here if the entity is not configured for caching (no map hit)?
}
return access;
}
@Override
public CollectionDataAccess getCollectionDataAccess(NavigableRole collectionRole) {
final CollectionDataAccess access = collectionDataAccessMap.get( collectionRole );
if ( access == null ) {
// todo (6.0) : is it an error here if the entity is not configured for caching (no map hit)?
}
return access;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// creation
protected abstract EntityDataAccess generateEntityAccess(EntityDataCachingConfig entityAccessConfig);
protected abstract CollectionDataAccess generateCollectionAccess(CollectionDataCachingConfig cachingConfig);
protected abstract NaturalIdDataAccess generateNaturalIdAccess(NaturalIdDataCachingConfig naturalIdAccessConfig);
private Map<NavigableRole, EntityDataAccess> generateEntityDataAccessMap(
DomainDataRegionConfig regionConfig) {
if ( regionConfig.getEntityCaching().isEmpty() ) {
return Collections.emptyMap();
}
final Map<NavigableRole, EntityDataAccess> accessMap = new ConcurrentHashMap<>();
for ( EntityDataCachingConfig entityAccessConfig : regionConfig.getEntityCaching() ) {
accessMap.computeIfAbsent(
entityAccessConfig.getNavigableRole(),
hierarchy -> generateEntityAccess( entityAccessConfig )
);
}
return Collections.unmodifiableMap( accessMap );
}
private Map<NavigableRole, NaturalIdDataAccess> generateNaturalIdDataAccessMap(DomainDataRegionConfig regionConfig) {
if ( regionConfig.getNaturalIdCaching().isEmpty() ) {
return Collections.emptyMap();
}
final Map<NavigableRole, NaturalIdDataAccess> accessMap = new ConcurrentHashMap<>();
for ( NaturalIdDataCachingConfig naturalIdAccessConfig : regionConfig.getNaturalIdCaching() ) {
accessMap.computeIfAbsent(
naturalIdAccessConfig.getNavigableRole(),
hierarchy -> generateNaturalIdAccess( naturalIdAccessConfig )
);
}
return Collections.unmodifiableMap( accessMap );
}
private Map<NavigableRole, CollectionDataAccess> generateCollectionDataAccessMap(
DomainDataRegionConfig regionConfig) {
if ( regionConfig.getCollectionCaching().isEmpty() ) {
return Collections.emptyMap();
}
final Map<NavigableRole, CollectionDataAccess> accessMap = new ConcurrentHashMap<>();
for ( CollectionDataCachingConfig cachingConfig : regionConfig.getCollectionCaching() ) {
accessMap.computeIfAbsent(
cachingConfig.getNavigableRole(),
hierarchy -> generateCollectionAccess( cachingConfig )
);
}
return Collections.unmodifiableMap( accessMap );
}
@Override
public void clear() {
for ( EntityDataAccess cacheAccess : entityDataAccessMap.values() ) {
cacheAccess.evictAll();
}
for ( NaturalIdDataAccess cacheAccess : naturalIdDataAccessMap.values() ) {
cacheAccess.evictAll();
}
for ( CollectionDataAccess cacheAccess : collectionDataAccessMap.values() ) {
cacheAccess.evictAll();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// destruction
/**
* Optional interface caching implementors can implement in their
* CachedDomainDataAccess impls to automatically have them destroyed
* when this region is destroyed
*/
public interface Destructible {
void destroy();
}
protected void releaseDataAccess(EntityDataAccess cacheAccess) {
if ( Destructible.class.isInstance( cacheAccess ) ) {
( (Destructible) cacheAccess ).destroy();
}
}
protected void releaseDataAccess(NaturalIdDataAccess cacheAccess) {
if ( Destructible.class.isInstance( cacheAccess ) ) {
( (Destructible) cacheAccess ).destroy();
}
}
protected void releaseDataAccess(CollectionDataAccess cacheAccess) {
if ( Destructible.class.isInstance( cacheAccess ) ) {
( (Destructible) cacheAccess ).destroy();
}
}
@Override
public void destroy() throws CacheException {
for ( EntityDataAccess cacheAccess : entityDataAccessMap.values() ) {
releaseDataAccess( cacheAccess );
}
for ( NaturalIdDataAccess cacheAccess : naturalIdDataAccessMap.values() ) {
releaseDataAccess( cacheAccess );
}
for ( CollectionDataAccess cacheAccess : collectionDataAccessMap.values() ) {
releaseDataAccess( cacheAccess );
}
}
}

View File

@ -1,49 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import java.util.Comparator;
import org.hibernate.type.Type;
/**
* Describes attributes regarding the type of data to be cached.
*
* @author Steve Ebersole
*/
public interface CacheDataDescription {
/**
* Is the data marked as being mutable?
*
* @return {@code true} if the data is mutable; {@code false} otherwise.
*/
public boolean isMutable();
/**
* Is the data to be cached considered versioned?
*
* If {@code true}, it is illegal for {@link #getVersionComparator} to return {@code null}
* or an instance of {@link org.hibernate.type.descriptor.java.IncomparableComparator}.
*
* @return {@code true} if the data is versioned; {@code false} otherwise.
*/
public boolean isVersioned();
/**
* Get the comparator used to compare two different version values. May return {@code null} <b>if</b>
* {@link #isVersioned()} returns false.
*
* @return The comparator for versions, or {@code null}
*/
public Comparator getVersionComparator();
/**
* @return Type of the key that will be used as the key in the cache, or {@code null} if the natural comparison
* ({@link Object#hashCode()} and {@link Object#equals(Object)} methods should be used.
*/
Type getKeyType();
}

View File

@ -0,0 +1,258 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.io.Serializable;
import java.util.Locale;
import java.util.Set;
import org.hibernate.Cache;
import org.hibernate.HibernateException;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.Service;
/**
* SPI contract for Hibernate's second-level cache engine
*
* @since 4.1
*
* @author Strong Liu
* @author Steve Ebersole
*/
@SuppressWarnings("unused")
public interface CacheImplementor extends Service, Cache, Serializable {
@Override
SessionFactoryImplementor getSessionFactory();
/**
* The underlying RegionFactory in use.
*
* @apiNote CacheImplementor acts partially as a wrapper for details
* of interacting with the configured RegionFactory. Care should
* be taken when accessing the RegionFactory directly.
*/
RegionFactory getRegionFactory();
/**
* An initialization phase allowing the caching provider to prime itself
* from the passed configs
*
* @since 5.3
*/
void prime(Set<DomainDataRegionConfig> cacheRegionConfigs);
/**
* Get a cache Region by name
*
* @apiNote It is only valid to call this method after {@link #prime} has
* been performed
*
* @since 5.3
*/
Region getRegion(String regionName);
/**
* The unqualified name of all regions. Intended for use with {@link #getRegion}
*
* @since 5.3
*/
Set<String> getCacheRegionNames();
/**
* Find the cache data access strategy for Hibernate's timestamps cache.
* Will return {@code null} if Hibernate is not configured for query result caching
*
* @since 5.3
*/
TimestampsRegionAccess getTimestampsRegionAccess();
/**
* Access to the "default" region used to store query results when caching
* was requested but no region was explicitly named. Will return {@code null}
* if Hibernate is not configured for query result caching
*/
QueryResultRegionAccess getDefaultQueryResultsRegionAccess();
/**
* Get query cache by <tt>region name</tt> or create a new one if none exist.
*
* If the region name is null, then default query cache region will be returned.
*
* Will return {@code null} if Hibernate is not configured for query result caching
*/
QueryResultRegionAccess getQueryResultsRegionAccess(String regionName);
/**
* Get the named QueryResultRegionAccess but not creating one if it
* does not already exist. This is intended for use by statistics.
*
* Will return {@code null} if Hibernate is not configured for query result
* caching or if no such region (yet) exists
*
* @since 5.3
*/
QueryResultRegionAccess getQueryResultsRegionAccessStrictly(String regionName);
/**
* Clean up the default query cache
*/
default void evictQueries() throws HibernateException {
QueryResultRegionAccess cache = getDefaultQueryResultsRegionAccess();
if ( cache != null ) {
cache.clear();
}
}
/**
* Close this "cache", releasing all underlying resources.
*/
void close();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deprecations (5.3)
/**
* Get the *qualified* names of all regions caching entity and collection data.
*
* @return All cache region names
*
* @deprecated (since 5.3) Use {@link CacheImplementor#getCacheRegionNames()} instead
*/
@Deprecated
String[] getSecondLevelCacheRegionNames();
/**
* Find the cache data access strategy for an entity. Will
* return {@code null} when the entity is not configured for caching.
*
* @param rootEntityName The NavigableRole representation of the root entity
*
* @apiNote It is only valid to call this method after {@link #prime} has
* been performed
*
* @deprecated Use {@link EntityPersister#getCacheAccessStrategy()} instead
*/
@Deprecated
EntityDataAccess getEntityRegionAccess(NavigableRole rootEntityName);
/**
* Find the cache data access strategy for the given entity's natural-id cache.
* Will return {@code null} when the entity does not define a natural-id, or its
* natural-id is not configured for caching.
*
* @param rootEntityName The NavigableRole representation of the root entity
*
* @apiNote It is only valid to call this method after {@link #prime} has
* been performed
*
* @deprecated Use {@link EntityPersister#getNaturalIdCacheAccessStrategy()} ()} instead
*/
@Deprecated
NaturalIdDataAccess getNaturalIdRegionAccess(NavigableRole rootEntityName);
/**
* Find the cache data access strategy for the given collection. Will
* return {@code null} when the collection is not configured for caching.
*
* @apiNote It is only valid to call this method after {@link #prime} has
* been performed
*
* @deprecated Use {@link EntityPersister#getNaturalIdCacheAccessStrategy()} ()} instead
*/
@Deprecated
CollectionDataAccess getCollectionRegionAccess(NavigableRole collectionRole);
/**
* Get {@code UpdateTimestampsCache} instance managed by the {@code SessionFactory}.
*
* @deprecated Use {@link #getTimestampsRegionAccess} instead
*/
@Deprecated
default UpdateTimestampsCache getUpdateTimestampsCache() {
return getTimestampsRegionAccess();
}
/**
* Get the default {@code QueryCache}.
*
* @deprecated Use {@link #getDefaultQueryResultsRegionAccess} instead.
*/
@Deprecated
default QueryCache getQueryCache() {
return getDefaultQueryResultsRegionAccess();
}
/**
* Get the default {@code QueryCache}.
*
* @deprecated Use {@link #getDefaultQueryResultsRegionAccess} instead.
*/
@Deprecated
default QueryCache getDefaultQueryCache() {
return getDefaultQueryResultsRegionAccess();
}
/**
* @deprecated Use {@link #getQueryResultsRegionAccess(String)} instead, but using unqualified name
*/
@Deprecated
default QueryCache getQueryCache(String regionName) throws HibernateException {
return getQueryResultsRegionAccess( unqualifyRegionName( regionName ) );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Some new (default) support methods for the above deprecations
// - themselves deprecated
/**
* @deprecated (since 5.3) No replacement - added just to continue some backwards compatibility
* in supporting the newly deprecated methods expecting a qualified (prefix +) region name
*/
@Deprecated
default String unqualifyRegionName(String name) {
if ( getSessionFactory().getSessionFactoryOptions().getCacheRegionPrefix() == null ) {
return name;
}
if ( !name.startsWith( getSessionFactory().getSessionFactoryOptions().getCacheRegionPrefix() ) ) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Legacy methods for accessing cache information expect a qualified (prefix) region name - " +
"but passed name [%s] was not qualified by the configured prefix [%s]",
name,
getSessionFactory().getSessionFactoryOptions().getCacheRegionPrefix()
)
);
}
return name.substring( getSessionFactory().getSessionFactoryOptions().getCacheRegionPrefix().length() + 1 );
}
/**
* @deprecated No replacement - added just for support of the newly deprecated methods expecting a qualified region name
*/
@Deprecated
default Region getRegionByLegacyName(String legacyName) {
return getRegion( unqualifyRegionName( legacyName ) );
}
/**
* @deprecated No replacement - added just for support of the newly deprecated methods expecting a qualified region name
*/
@Deprecated
Set<NaturalIdDataAccess> getNaturalIdAccessesInRegion(String legacyQualifiedRegionName);
}

View File

@ -0,0 +1,102 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
/**
* Defines a context object that a {@link RegionFactory} is asked to create
* ({@link RegionFactory#createTransactionContext}}) when a Hibernate Session
* is created. It's lifecycle is that of the Session. It receives
* "transactional event callbacks" around joining and completing resource
* transactions.
*
* This allows the cache impl to book-keep data related to current transaction,
* such as and process it in unique ways. E.g. this allows an impl to perform
* batch updates if Hibernate is configured to use JDBC-only transactions,
* and therefore information cannot be retrieved from the JTA transaction
* assigned to current thread.
*
* While transactional semantics might be fully implemented by the cache
* provider, Hibernate may require different transactional semantics: In order
* to prevent inconsistent reads, 2LC should not expose entities that are
* modified in any concurrently executing transactions, and force DB load
* instead. Native transactional implementation may provide looser semantics
* and 2LC implementation has to adapt to these.
*
* @implNote Even though a JTA transaction may involve more than one Session
* the CacheTransactionContext is specific to each Session since the distinction
* is generally unimportant. However, a provider is free to attempt to scope
* these CacheTransactionContext instances in such a way that they may be
* associated with more than one Session at a time. This SPI is designed
* to not require this of the caching impl, but it certainly allows the
* provider to do it
*
* @author Steve Ebersole
* @author Radim Vansa
*/
public interface CacheTransactionSynchronization {
/**
* What is the start time of this context object?
*
* @apiNote If not currently joined to a transaction, the timestamp from
* the last transaction is safe to use. If not ever/yet joined to a
* transaction, a timestamp at the time the Session/CacheTransactionSynchronization
* were created should be returned.
*
* @implSpec This "timestamp" need not be related to timestamp in the Java
* Date/millisecond sense. It just needs to be an incrementing value.
*/
long getCurrentTransactionStartTimestamp();
/**
* Callback that owning Session has become joined to a resource transaction.
*
* @apiNote Implementors can consider this the effective start of a
* transaction.
*/
void transactionJoined();
/**
* Callback that the underling resource transaction to which the owning
* Session was joined is in the beginning stages of completing. Note that
* this is only called for successful "begin completion" of the underlying
* resource transaction (not rolling-back, marked-for-rollback, etc)
*/
void transactionCompleting();
/**
* Callback that the underling resource transaction to which the owning
* Session was joined is in the "completed" stage. This method is called
* regardless of success or failure of the transaction - the outcome is
* passed as a boolean.
*
* @param successful Was the resource transaction successful?
*/
void transactionCompleted(boolean successful);
/**
* Currently not used. Here for future expansion
*
* @implNote Currently not used. JTA defines no standard means to
* be notified when a transaction is suspended nor resumed. Such
* a feature is proposed.
*/
@SuppressWarnings("unused")
default void transactionSuspended() {
// nothing to do since it is currently not used/supported
}
/**
* Currently not used. Here for future expansion
*
* @implNote Currently not used. JTA defines no standard means to
* be notified when a transaction is suspended nor resumed
*/
@SuppressWarnings("unused")
default void transactionResumed() {
// nothing to do since it is currently not used/supported
}
}

View File

@ -1,35 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
/**
* Defines the contract for a cache region which will specifically be used to
* store collection data.
* <p/>
* Impl note: Hibernate always deals with changes to collections which
* (potentially) has its data in the L2 cache by removing that collection
* data; in other words it never tries to update the cached state, thereby
* allowing it to avoid a bunch of concurrency problems.
*
* @author Steve Ebersole
*/
public interface CollectionRegion extends TransactionalDataRegion {
/**
* Build an access strategy for the requested access type.
*
* @param accessType The type of access strategy to build; never null.
* @return The appropriate strategy contract for accessing this region
* for the requested type of access.
* @throws org.hibernate.cache.CacheException Usually indicates mis-configuration.
*/
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException;
}

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
/**
* Specialized Region whose data is accessed directly - not requiring
* key wrapping, e.g.
*
* @author Steve Ebersole
*/
public interface DirectAccessRegion extends Region {
interface DataAccess {
Object getFromCache(Object key);
void addToCache(Object key, Object value);
void removeFromCache(Object key);
void clearCache();
}
DataAccess getAccess();
// Object get(Object key, SharedSessionContractImplementor session);
// void put(Object key, Object value, SharedSessionContractImplementor session);
//
// /**
// * Forcibly evict an item from the cache immediately without regard for transaction
// * isolation. This behavior is exactly Hibernate legacy behavior, but it is also required
// * by JPA - so we cannot remove it.
// *
// * @param key The key of the item to remove
// */
// void evict(Object key);
//
// /**
// * Forcibly evict all items from the cache immediately without regard for transaction
// * isolation. This behavior is exactly Hibernate legacy behavior, but it is also required
// * by JPA - so we cannot remove it.
// */
// void evictAll();
}

View File

@ -0,0 +1,52 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.metamodel.model.domain.NavigableRole;
/**
* A Region for cacheable domain data - entity, collection, natural-id
*
* @author Steve Ebersole
*/
public interface DomainDataRegion extends Region {
/**
* Build a EntityRegionAccess instance representing access to entity data
* stored in this cache region using the given AccessType.
*
* @param rootEntityRole The root entity name for the hierarchy whose data
* we want to access
*
* @throws org.hibernate.cache.CacheException If the provider cannot provide the requested access
*/
EntityDataAccess getEntityDataAccess(NavigableRole rootEntityRole);
/**
* Build a NaturalIdRegionAccess instance representing access to natural-id
* data stored in this cache region using the given AccessType.
*
* @param rootEntityRole The NavigableRole of the root entity whose
* natural-id data we want to access
*
* @throws org.hibernate.cache.CacheException If the provider cannot provide the requested access
*/
NaturalIdDataAccess getNaturalIdDataAccess(NavigableRole rootEntityRole);
/**
* Build a CollectionRegionAccess instance representing access to collection
* data stored in this cache region using the given AccessType.
*
* @param collectionRole The NavigableRole of the collection whose data
* we want to access
*
* @throws org.hibernate.cache.CacheException If the provider cannot provide the requested access
*/
CollectionDataAccess getCollectionDataAccess(NavigableRole collectionRole);
}

View File

@ -1,30 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
/**
* Defines the contract for a cache region which will specifically be used to
* store entity data.
*
* @author Steve Ebersole
*/
public interface EntityRegion extends TransactionalDataRegion {
/**
* Build an access strategy for the requested access type.
*
* @param accessType The type of access strategy to build; never null.
* @return The appropriate strategy contract for accessing this region
* for the requested type of access.
* @throws org.hibernate.cache.CacheException Usually indicates mis-configuration.
*/
EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException;
}

View File

@ -0,0 +1,20 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
/**
* Optional Region contract defining support for extra statistic information
*
* @author Steve Ebersole
*/
public interface ExtendedStatisticsSupport {
long getElementCountInMemory();
long getElementCountOnDisk();
long getSizeInMemory();
}

View File

@ -1,58 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Contract for general-purpose cache regions.
*
* @author Steve Ebersole
*/
public interface GeneralDataRegion extends Region {
/**
* Get an item from the cache.
*
* @param session
* @param key The key of the item to be retrieved.
*
* @return the cached object or <tt>null</tt>
*
* @throws org.hibernate.cache.CacheException Indicates a problem accessing the item or region.
*/
Object get(SharedSessionContractImplementor session, Object key) throws CacheException;
/**
* Put an item into the cache.
*
* @param session
* @param key The key under which to cache the item.
* @param value The item to cache.
*
* @throws CacheException Indicates a problem accessing the region.
*/
void put(SharedSessionContractImplementor session, Object key, Object value) throws CacheException;
/**
* Evict an item from the cache immediately (without regard for transaction
* isolation).
*
* @param key The key of the item to remove
* @throws CacheException Indicates a problem accessing the item or region.
*/
void evict(Object key) throws CacheException;
/**
* Evict all contents of this particular cache region (without regard for transaction
* isolation).
*
* @throws CacheException Indicates problem accessing the region.
*/
void evictAll() throws CacheException;
}

View File

@ -1,31 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
/**
* Defines the contract for a cache region which will specifically be used to
* store naturalId data.
*
* @author Eric Dalquist
* @author Steve Ebersole
*/
public interface NaturalIdRegion extends TransactionalDataRegion {
/**
* Build an access strategy for the requested access type.
*
* @param accessType The type of access strategy to build; never null.
* @return The appropriate strategy contract for accessing this region
* for the requested type of access.
* @throws org.hibernate.cache.CacheException Usually indicates mis-configuration.
*/
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException;
}

View File

@ -1,38 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import java.util.Comparator;
/**
* Contract for sources of optimistically lockable data sent to the second level
* cache.
* <p/>
* Note currently {@link org.hibernate.persister.entity.EntityPersister}s are
* the only viable source.
*
* @author Steve Ebersole
*/
public interface OptimisticCacheSource {
/**
* Is the data to be cached considered versioned?
* <p/>
* If true, it is illegal for {@link #getVersionComparator} to return
* null.
*
* @return True if the data is versioned; false otherwise.
*/
public boolean isVersioned();
/**
* Get the comparator used to compare two different version values.
* <p/>
* May return null <b>if</b> {@link #isVersioned()} returns false.
* @return Comparator used to compare two different version values.
*/
public Comparator getVersionComparator();
}

View File

@ -1,8 +1,8 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
@ -10,26 +10,25 @@ import java.io.Serializable;
import java.util.List;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.Type;
/**
* Defines the contract for caches capable of storing query results. These
* caches should only concern themselves with storing the matching result ids.
* The transactional semantics are necessarily less strict than the semantics
* of an item cache.
*
* @author Gavin King
* @author Steve Ebersole
*
* @deprecated Use {@link QueryResultRegionAccess} instead -
* {@link CacheImplementor#getQueryResultsRegionAccess} rather than
* {@link CacheImplementor#getQueryCache}
*/
@Deprecated
public interface QueryCache {
/**
* Clear items from the query cache.
*
* @throws CacheException Indicates a problem delegating to the underlying cache.
*/
void clear() throws CacheException;
void clear();
/**
* Put a result into the query cache.
@ -41,15 +40,13 @@ public interface QueryCache {
* @param session The originating session
*
* @return Whether the put actually happened.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
boolean put(
QueryKey key,
Type[] returnTypes,
List result,
boolean isNaturalKeyLookup,
SharedSessionContractImplementor session) throws HibernateException;
SharedSessionContractImplementor session);
/**
* Get results from the cache.
@ -61,15 +58,13 @@ public interface QueryCache {
* @param session The originating session
*
* @return The cached results; may be null.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
List get(
QueryKey key,
Type[] returnTypes,
boolean isNaturalKeyLookup,
Set<Serializable> spaces,
SharedSessionContractImplementor session) throws HibernateException;
SharedSessionContractImplementor session);
/**
* Destroy the cache.

View File

@ -1,27 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import org.hibernate.engine.spi.CacheImplementor;
/**
* Defines a factory for query cache instances. These factories are responsible for
* creating individual QueryCache instances.
*
* @author Steve Ebersole
*/
public interface QueryCacheFactory {
/**
* Builds a named query cache.
*
* @param region The cache region
* @param cacheManager The CacheImplementor reference.
*
* @return The cache.
*/
QueryCache buildQueryCache(QueryResultsRegion region, CacheImplementor cacheManager);
}

View File

@ -0,0 +1,121 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.Type;
/**
* Defines the responsibility for managing query result data caching
* in regards to a specific region.
*
* @author Gavin King
* @author Steve Ebersole
*/
public interface QueryResultRegionAccess extends QueryCache {
/**
* The underlying cache region being used.
*/
@Override
QueryResultsRegion getRegion();
/**
* Clear items from the query cache.
*
* @throws CacheException Indicates a problem delegating to the underlying cache.
*/
@Override
default void clear() throws CacheException {
getRegion().getAccess().clearCache();
}
/**
* Put a result into the query cache.
*
* @param key The cache key
* @param result The results to cache
* @param session The originating session
*
* @return Whether the put actually happened.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
boolean put(
QueryKey key,
List result,
Type[] returnTypes,
SharedSessionContractImplementor session) throws HibernateException;
/**
* Get results from the cache.
*
* @param key The cache key
* @param spaces The query spaces (used in invalidation plus validation checks)
* @param session The originating session
*
* @return The cached results; may be null.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
List get(
QueryKey key,
Set<Serializable> spaces,
Type[] returnTypes,
SharedSessionContractImplementor session) throws HibernateException;
/**
* Get results from the cache.
*
* @param key The cache key
* @param spaces The query spaces (used in invalidation plus validation checks)
* @param session The originating session
*
* @return The cached results; may be null.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
List get(
QueryKey key,
String[] spaces,
Type[] returnTypes,
SharedSessionContractImplementor session) throws HibernateException;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deprecations
@Override
default boolean put(
QueryKey key,
Type[] returnTypes,
List result,
boolean isNaturalKeyLookup,
SharedSessionContractImplementor session) {
return put( key, result, returnTypes, session );
}
@Override
default List get(
QueryKey key,
Type[] returnTypes,
boolean isNaturalKeyLookup,
Set<Serializable> spaces,
SharedSessionContractImplementor session) {
return get( key, spaces, returnTypes, session );
}
@Override
default void destroy() {
// nothing to do.. the region itself gets destroyed
}
}

View File

@ -1,8 +1,8 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
@ -12,5 +12,9 @@ package org.hibernate.cache.spi;
*
* @author Steve Ebersole
*/
public interface QueryResultsRegion extends GeneralDataRegion {
public interface QueryResultsRegion extends DirectAccessRegion {
@Override
default void clear() {
getAccess().clearCache();
}
}

View File

@ -0,0 +1,41 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @author Steve Ebersole
*/
public class QuerySpacesHelper {
/**
* Singleton access
*/
public static final QuerySpacesHelper INSTANCE = new QuerySpacesHelper();
private QuerySpacesHelper() {
}
public String[] toStringArray(Set spacesSet) {
return (String[]) spacesSet.toArray( new String[0] );
}
public Set<String> toStringSet(String[] spacesArray) {
final HashSet<String> set = new HashSet<>();
Collections.addAll( set, spacesArray );
return set;
}
public Set<Serializable> toSerializableSet(String[] spacesArray) {
final HashSet<Serializable> set = new HashSet<>();
Collections.addAll( set, spacesArray );
return set;
}
}

View File

@ -1,13 +1,11 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.util.Map;
import org.hibernate.cache.CacheException;
/**
@ -24,6 +22,13 @@ public interface Region {
*/
String getName();
RegionFactory getRegionFactory();
/**
* Clear all data cached in the region
*/
void clear();
/**
* The "end state" contract of the region's lifecycle. Called
* during {@link org.hibernate.SessionFactory#close()} to give
@ -32,68 +37,4 @@ public interface Region {
* @throws org.hibernate.cache.CacheException Indicates problem shutting down
*/
void destroy() throws CacheException;
/**
* Determine whether this region contains data for the given key.
* <p/>
* The semantic here is whether the cache contains data visible for the
* current call context. This should be viewed as a "best effort", meaning
* blocking should be avoid if possible.
*
* @param key The cache key
*
* @return True if the underlying cache contains corresponding data; false
* otherwise.
*/
boolean contains(Object key);
/**
* The number of bytes is this cache region currently consuming in memory.
*
* @return The number of bytes consumed by this region; -1 if unknown or
* unsupported.
*/
long getSizeInMemory();
/**
* The count of entries currently contained in the regions in-memory store.
*
* @return The count of entries in memory; -1 if unknown or unsupported.
*/
long getElementCountInMemory();
/**
* The count of entries currently contained in the regions disk store.
*
* @return The count of entries on disk; -1 if unknown or unsupported.
*/
long getElementCountOnDisk();
/**
* Get the contents of this region as a map.
* <p/>
* Implementors which do not support this notion
* should simply return an empty map.
*
* @return The content map.
*/
Map toMap();
/**
* Get the next timestamp according to the underlying cache implementor.
*
* @todo Document the usages of this method so providers know exactly what is expected.
*
* @return The next timestamp
*/
long nextTimestamp();
/**
* Get a timeout value.
*
* @todo Again, document the usages of this method so providers know exactly what is expected.
*
* @return The time out value
*/
int getTimeout();
}

View File

@ -1,18 +1,22 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.util.Map;
import java.util.Properties;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext;
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.service.Service;
import org.hibernate.service.spi.Stoppable;
/**
* Contract for building second level cache regions.
@ -22,32 +26,14 @@ import org.hibernate.service.Service;
* <li>MyRegionFactoryImpl()</li>
* </ul>
* Use the first when we need to read config properties prior to
* {@link #start(SessionFactoryOptions, Properties)} being called.
* {@link #start} being called.
*
* @author Steve Ebersole
*/
public interface RegionFactory extends Service {
public interface RegionFactory extends Service, Stoppable {
/**
* Lifecycle callback to perform any necessary initialization of the
* underlying cache implementation(s). Called exactly once during the
* construction of a {@link org.hibernate.internal.SessionFactoryImpl}.
*
* @param settings The settings in effect.
* @param properties The defined cfg properties
*
* @throws org.hibernate.cache.CacheException Indicates problems starting the L2 cache impl;
* considered as a sign to stop {@link org.hibernate.SessionFactory}
* building.
*
* @deprecated (since 5.2) use the form accepting map instead.
*/
@Deprecated
void start(SessionFactoryOptions settings, Properties properties) throws CacheException;
/**
* Lifecycle callback to perform any necessary initialization of the
* underlying cache implementation(s). Called exactly once during the
* underlying cache provider. Called exactly once during the
* construction of a {@link org.hibernate.internal.SessionFactoryImpl}.
*
* @param settings The settings in effect.
@ -57,18 +43,7 @@ public interface RegionFactory extends Service {
* considered as a sign to stop {@link org.hibernate.SessionFactory}
* building.
*/
default void start(SessionFactoryOptions settings, Map<String, Object> configValues) throws CacheException {
final Properties properties = new Properties();
properties.putAll( configValues );
start( settings, properties );
}
/**
* Lifecycle callback to perform any necessary cleanup of the underlying
* cache implementation(s). Called exactly once during
* {@link org.hibernate.SessionFactory#close}.
*/
void stop();
void start(SessionFactoryOptions settings, Map configValues) throws CacheException;
/**
* By default should we perform "minimal puts" when using this second
@ -80,185 +55,43 @@ public interface RegionFactory extends Service {
boolean isMinimalPutsEnabledByDefault();
/**
* Get the default access type for {@link EntityRegion entity} and
* {@link CollectionRegion collection} regions.
*
* @return This factory's default access type.
* Get the default access type for any "user model" data
*/
AccessType getDefaultAccessType();
CacheTransactionSynchronization createTransactionContext(SharedSessionContractImplementor session);
/**
* Generate a timestamp.
* <p/>
* This is generally used for cache content locking/unlocking purposes
* depending upon the access-strategy being used.
* Generate a timestamp. This value is generally used for purpose of
* locking/unlocking cache content depending upon the access-strategy being
* used. The intended consumer of this method is the Session to manage
* its {@link SharedSessionContractImplementor#getTransactionStartTimestamp} value.
*
* @return The generated timestamp.
* It is also expected that this be the value used for this's RegionFactory's
* CacheTransactionContext
*
* @apiNote This "timestamp" need not be related to timestamp in the Java Date/millisecond
* sense. It just needs to be an incrementing value
*/
long nextTimestamp();
/**
* Build a cache region specialized for storing entity data.
*
* @param regionName The name of the region.
* @param properties Configuration properties.
* @param metadata Information regarding the type of data to be cached
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*
* @deprecated (since 5.2) use the form taking Map instead
*/
@Deprecated
EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException;
/**
* Build a cache region specialized for storing entity data.
*
* @param regionName The name of the region.
* @param configValues Available config values.
* @param metadata Information regarding the type of data to be cached
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*/
default EntityRegion buildEntityRegion(String regionName, Map<String,Object> configValues, CacheDataDescription metadata)
throws CacheException {
final Properties properties = new Properties();
properties.putAll( configValues );
return buildEntityRegion( regionName, properties, metadata );
default long getTimeout() {
// most existing providers defined this as 60 seconds.
return 60000;
}
/**
* Build a cache region specialized for storing NaturalId to Primary Key mappings.
* Create a named Region for holding domain model data
*
* @param regionName The name of the region.
* @param properties Configuration properties.
* @param metadata Information regarding the type of data to be cached
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*
* @deprecated (since 5.2) use the form accepting a Map instead
* @param regionConfig The user requested caching configuration for this Region
* @param buildingContext Access to delegates useful in building the Region
*/
@Deprecated
NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException;
DomainDataRegion buildDomainDataRegion(
DomainDataRegionConfig regionConfig,
DomainDataRegionBuildingContext buildingContext);
/**
* Build a cache region specialized for storing NaturalId to Primary Key mappings.
*
* @param regionName The name of the region.
* @param configValues Available config values.
* @param metadata Information regarding the type of data to be cached
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*/
default NaturalIdRegion buildNaturalIdRegion(String regionName, Map<String,Object> configValues, CacheDataDescription metadata)
throws CacheException {
final Properties properties = new Properties();
properties.putAll( configValues );
return buildNaturalIdRegion( regionName, properties, metadata );
}
/**
* Build a cache region specialized for storing collection data.
*
* @param regionName The name of the region.
* @param properties Configuration properties.
* @param metadata Information regarding the type of data to be cached
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*/
CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException;
/**
* Build a cache region specialized for storing collection data.
*
* @param regionName The name of the region.
* @param configValues Available config values.
* @param metadata Information regarding the type of data to be cached
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*/
default CollectionRegion buildCollectionRegion(String regionName, Map<String,Object> configValues, CacheDataDescription metadata)
throws CacheException {
final Properties properties = new Properties();
properties.putAll( configValues );
return buildCollectionRegion( regionName, properties, metadata );
}
/**
* Build a cache region specialized for storing query results.
*
* @param regionName The name of the region.
* @param properties Configuration properties.
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*
* @deprecated (since 5.2) use the form taking Map instead
*/
@Deprecated
QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException;
/**
* Build a cache region specialized for storing query results.
*
* @param qualifyRegionName The qualified name of the region.
* @param configValues Available config values.
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*/
default QueryResultsRegion buildQueryResultsRegion(String qualifyRegionName, Map<String,Object> configValues) {
final Properties properties = new Properties();
properties.putAll( configValues );
return buildQueryResultsRegion( qualifyRegionName, properties );
}
/**
* Build a cache region specialized for storing update-timestamps data.
*
* @param regionName The name of the region.
* @param properties Configuration properties.
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*
* @deprecated (since 5.2) use the form taking Map
*/
@Deprecated
TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException;
/**
* Build a cache region specialized for storing update-timestamps data.
*
* @param regionName The name of the region.
* @param configValues The available config values.
*
* @return The built region
*
* @throws CacheException Indicates problems building the region.
*/
default TimestampsRegion buildTimestampsRegion(String regionName, Map<String,Object> configValues) throws CacheException {
final Properties properties = new Properties();
properties.putAll( configValues );
return buildTimestampsRegion( regionName, properties );
}
QueryResultsRegion buildQueryResultsRegion(String regionName, SessionFactoryImplementor sessionFactory);
TimestampsRegion buildTimestampsRegion(String regionName, SessionFactoryImplementor sessionFactory);
}

View File

@ -0,0 +1,32 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import org.jboss.logging.BasicLogger;
import org.jboss.logging.Logger;
import org.jboss.logging.annotations.MessageLogger;
import org.jboss.logging.annotations.ValidIdRange;
/**
* @author Steve Ebersole
*/
@MessageLogger( projectCode = "HHH" )
@ValidIdRange( min = 90001001, max = 90002000 )
public interface SecondLevelCacheLogger extends BasicLogger {
SecondLevelCacheLogger INSTANCE = Logger.getMessageLogger(
SecondLevelCacheLogger.class,
"org.hibernate.orm.cache"
);
enum RegionAccessType {
ENTITY,
NATURAL_ID,
COLLECTION,
QUERY_RESULTS,
TIMESTAMPS
}
}

View File

@ -1,16 +1,17 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
/**
* Defines the contract for a cache region which will specifically be used to
* store entity "update timestamps".
*
* @author Steve Ebersole
*/
public interface TimestampsRegion extends GeneralDataRegion {
public interface TimestampsRegion extends DirectAccessRegion {
@Override
default void clear() {
getAccess().clearCache();
}
}

View File

@ -0,0 +1,105 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
import java.io.Serializable;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Wrapper for a {@link TimestampsRegion} adding handling of stale results
*
* @author Steve Ebersole
*/
public interface TimestampsRegionAccess extends UpdateTimestampsCache {
TimestampsRegion getRegion();
/**
* Perform pre-invalidation of the passed spaces (table names)
* using the passed region for storing update-timestamps
*/
void preInvalidate(
String[] spaces,
SharedSessionContractImplementor session);
/**
* Perform invalidation of the passed spaces (table names)
* using the passed region for storing update-timestamps
*/
void invalidate(
String[] spaces,
SharedSessionContractImplementor session);
/**
* Perform an up-to-date check for the given set of query spaces as
* part of verifying the validity of cached query results.
*
* @param spaces The spaces to check
* @param timestamp The timestamp from the transaction when the query results were cached.
* @param session The session whether this check originated.
*
* @return Whether all those spaces are up-to-date
*/
boolean isUpToDate(
String[] spaces,
Long timestamp,
SharedSessionContractImplementor session);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deprecations
@Override
default void preInvalidate(Serializable[] spaces, SharedSessionContractImplementor session) {
final String[] spaceStrings = new String[ spaces.length ];
// todo - does this copy work?
System.arraycopy( spaces, 0, spaceStrings, 0, spaces.length );
preInvalidate( spaceStrings, session );
}
@Override
default void invalidate(Serializable[] spaces, SharedSessionContractImplementor session) {
final String[] spaceStrings = new String[ spaces.length ];
// todo - does this copy work?
System.arraycopy( spaces, 0, spaceStrings, 0, spaces.length );
invalidate( spaceStrings, session );
}
@Override
default boolean isUpToDate(
Set<Serializable> spaces,
Long timestamp,
SharedSessionContractImplementor session) {
final String[] spaceArray = new String[ spaces.size() ];
spaces.forEach(
new Consumer<Serializable>() {
int position = 0;
@Override
public void accept(Serializable serializable) {
spaceArray[position++] = (String) serializable;
}
}
);
return isUpToDate( spaceArray, timestamp, session );
}
@Override
default void clear() throws CacheException {
getRegion().getAccess().clearCache();
}
@Override
default void destroy() {
// nothing to do - the region itself is destroyed
}
}

View File

@ -0,0 +1,17 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
/**
* Responsible for building the TimestampsRegionAccessFactory to use for
* managing query results in regards to staleness
*
* @author Steve Ebersole
*/
public interface TimestampsRegionAccessFactory {
TimestampsRegionAccess buildTimestampsRegionAccess(CacheImplementor cacheManager, TimestampsRegion timestampsRegion);
}

View File

@ -1,15 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
/**
* Marker interface for identifying {@link org.hibernate.Cache} implementations which are aware of JTA transactions
*
* @author Steve Ebersole
*/
public interface TransactionAwareCache {
}

View File

@ -1,43 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
/**
* Defines contract for regions which hold transactionally-managed data.
* <p/>
* The data is not transactionally managed within the region; merely it is
* transactionally-managed in relation to its association with a particular
* {@link org.hibernate.Session}.
*
* @author Steve Ebersole
*/
public interface TransactionalDataRegion extends Region {
/**
* Is the underlying cache implementation aware of (and "participating in")
* ongoing JTA transactions?
* <p/>
* Regions which report that they are transaction-aware are considered
* "synchronous", in that we assume we can immediately (i.e. synchronously)
* write the changes to the cache and that the cache will properly manage
* application of the written changes within the bounds of ongoing JTA
* transactions. Conversely, regions reporting false are considered
* "asynchronous", where it is assumed that changes must be manually
* delayed by Hibernate until we are certain that the current transaction
* is successful (i.e. maintaining READ_COMMITTED isolation).
*
* @return True if transaction aware; false otherwise.
*/
public boolean isTransactionAware();
/**
* Get the description of the type of data to be stored here, which would have been given to the RegionFactory
* when creating this region
*
* @return The data descriptor.
*/
public CacheDataDescription getCacheDataDescription();
}

View File

@ -1,8 +1,8 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi;
@ -10,11 +10,7 @@ import java.io.Serializable;
import java.util.Set;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.jboss.logging.Logger;
/**
* Tracks the timestamps of the most recent updates to particular tables. It is
@ -25,102 +21,38 @@ import org.jboss.logging.Logger;
*
* @author Gavin King
* @author Mikheil Kapanadze
*
* @deprecated Use {@link TimestampsRegionAccess} instead
*/
public class UpdateTimestampsCache {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, UpdateTimestampsCache.class.getName() );
private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
@SuppressWarnings("unused")
@Deprecated
public interface UpdateTimestampsCache {
/**
* The region name of the update-timestamps cache.
*/
public static final String REGION_NAME = UpdateTimestampsCache.class.getName();
private final SessionFactoryImplementor factory;
private final TimestampsRegion region;
/**
* Constructs an UpdateTimestampsCache.
* Get the underlying cache region where data is stored..
*
* @param sessionFactory The SessionFactory
* @param region The underlying second level cache region to use.
* @return The underlying region.
*/
public UpdateTimestampsCache(SessionFactoryImplementor sessionFactory, TimestampsRegion region) {
LOG.startingUpdateTimestampsCache( region.getName() );
this.factory = sessionFactory;
this.region = region;
}
TimestampsRegion getRegion();
/**
* Perform pre-invalidation.
*
*
* @param spaces The spaces to pre-invalidate
*
* @param session
* @throws CacheException Indicated problem delegating to underlying region.
*/
public void preInvalidate(Serializable[] spaces, SharedSessionContractImplementor session) throws CacheException {
final boolean stats = factory != null && factory.getStatistics().isStatisticsEnabled();
final Long ts = region.nextTimestamp() + region.getTimeout();
for ( Serializable space : spaces ) {
if ( DEBUG_ENABLED ) {
LOG.debugf( "Pre-invalidating space [%s], timestamp: %s", space, ts );
}
try {
session.getEventListenerManager().cachePutStart();
//put() has nowait semantics, is this really appropriate?
//note that it needs to be async replication, never local or sync
region.put( session, space, ts );
}
finally {
session.getEventListenerManager().cachePutEnd();
}
if ( stats ) {
factory.getStatistics().updateTimestampsCachePut();
}
}
}
void preInvalidate(Serializable[] spaces, SharedSessionContractImplementor session) throws CacheException;
/**
* Perform invalidation.
*
*
* @param spaces The spaces to invalidate.
*
* @param session
*
* @throws CacheException Indicated problem delegating to underlying region.
*/
public void invalidate(Serializable[] spaces, SharedSessionContractImplementor session) throws CacheException {
final boolean stats = factory != null && factory.getStatistics().isStatisticsEnabled();
final Long ts = region.nextTimestamp();
for (Serializable space : spaces) {
if ( DEBUG_ENABLED ) {
LOG.debugf( "Invalidating space [%s], timestamp: %s", space, ts );
}
try {
session.getEventListenerManager().cachePutStart();
//put() has nowait semantics, is this really appropriate?
//note that it needs to be async replication, never local or sync
region.put( session, space, ts );
}
finally {
session.getEventListenerManager().cachePutEnd();
}
if ( stats ) {
factory.getStatistics().updateTimestampsCachePut();
}
}
}
void invalidate(Serializable[] spaces, SharedSessionContractImplementor session) throws CacheException;
/**
* Perform an up-to-date check for the given set of query spaces.
@ -129,91 +61,21 @@ public class UpdateTimestampsCache {
* @param spaces The spaces to check
* @param timestamp The timestamp against which to check.
*
* @param session
* @return Whether all those spaces are up-to-date
*
* @throws CacheException Indicated problem delegating to underlying region.
*/
public boolean isUpToDate(Set<Serializable> spaces, Long timestamp, SharedSessionContractImplementor session) throws CacheException {
final boolean stats = factory != null && factory.getStatistics().isStatisticsEnabled();
for ( Serializable space : spaces ) {
final Long lastUpdate = getLastUpdateTimestampForSpace( space, session );
if ( lastUpdate == null ) {
if ( stats ) {
factory.getStatistics().updateTimestampsCacheMiss();
}
//the last update timestamp was lost from the cache
//(or there were no updates since startup!)
//updateTimestamps.put( space, new Long( updateTimestamps.nextTimestamp() ) );
//result = false; // safer
}
else {
if ( DEBUG_ENABLED ) {
LOG.debugf(
"[%s] last update timestamp: %s",
space,
lastUpdate + ", result set timestamp: " + timestamp
);
}
if ( stats ) {
factory.getStatistics().updateTimestampsCacheHit();
}
if ( lastUpdate >= timestamp ) {
return false;
}
}
}
return true;
}
private Long getLastUpdateTimestampForSpace(Serializable space, SharedSessionContractImplementor session) {
Long ts = null;
try {
session.getEventListenerManager().cacheGetStart();
ts = (Long) region.get( session, space );
}
finally {
session.getEventListenerManager().cacheGetEnd( ts != null );
}
return ts;
}
boolean isUpToDate(Set<Serializable> spaces, Long timestamp, SharedSessionContractImplementor session) throws CacheException;
/**
* Clear the update-timestamps data.
*
* @throws CacheException Indicates problem delegating call to underlying region.
*/
public void clear() throws CacheException {
region.evictAll();
}
void clear() throws CacheException;
/**
* Destroys the cache.
*
* @throws CacheException Indicates problem delegating call to underlying region.
*/
public void destroy() {
try {
region.destroy();
}
catch (Exception e) {
LOG.unableToDestroyUpdateTimestampsCache( region.getName(), e.getMessage() );
}
}
/**
* Get the underlying cache region where data is stored..
*
* @return The underlying region.
*/
public TimestampsRegion getRegion() {
return region;
}
@Override
public String toString() {
return "UpdateTimestampsCache";
}
void destroy();
}

View File

@ -0,0 +1,189 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi.access;
import java.io.Serializable;
import javax.persistence.Cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.DomainDataRegion;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Base contract for accessing the underlying cached data for a particular
* Navigable of the user's domain model in a transactionally ACID manner.
*
* @author Steve Ebersole
* @author Gail Badner
*/
public interface CachedDomainDataAccess {
DomainDataRegion getRegion();
/**
* Determine whether this region contains data for the given key.
* <p/>
* The semantic here is whether the cache contains data visible for the
* current call context. This should be viewed as a "best effort", meaning
* blocking should be avoid if possible.
*
* @param key The cache key
*
* @return True if the underlying cache contains corresponding data; false
* otherwise.
*/
boolean contains(Object key);
/**
* Attempt to retrieve an object from the cache. Mainly used in attempting
* to resolve entities/collections from the second level cache.
*
* @param session Current session.
* @param key The key of the item to be retrieved.
*
* @return the cached data or {@code null}
*
* @throws CacheException Propagated from underlying cache provider
*/
Object get(SharedSessionContractImplementor session, Object key);
/**
* Attempt to cache an object, afterQuery loading from the database.
*
* @param session Current session.
* @param key The item key
* @param value The item
* @param version the item version number
*
* @return {@code true} if the object was successfully cached
*
* @throws CacheException Propagated from underlying cache provider
*/
boolean putFromLoad(
SharedSessionContractImplementor session,
Object key,
Object value,
Object version);
/**
* Attempt to cache an object, afterQuery loading from the database, explicitly
* specifying the minimalPut behavior.
*
* @param session Current session.
* @param key The item key
* @param value The item
* @param version the item version number
* @param minimalPutOverride Explicit minimalPut flag
*
* @return {@code true} if the object was successfully cached
*
* @throws CacheException Propagated from underlying cache provider
*/
boolean putFromLoad(
SharedSessionContractImplementor session,
Object key,
Object value,
Object version,
boolean minimalPutOverride);
/**
* We are going to attempt to update/delete the keyed object. This
* method is used by "asynchronous" concurrency strategies.
* <p/>
* The returned object must be passed back to {@link #unlockItem}, to release the
* lock. Concurrency strategies which do not support client-visible
* locks may silently return null.
*
* @param session Current session.
* @param key The key of the item to lock
* @param version The item's current version value
*
* @return A representation of our lock on the item; or {@code null}.
*
* @throws CacheException Propagated from underlying cache provider
*/
SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version);
/**
* Lock the entire region
*
* @return A representation of our lock on the item; or {@code null}.
*
* @throws CacheException Propagated from underlying cache provider
*/
SoftLock lockRegion();
/**
* Called when we have finished the attempted update/delete (which may or
* may not have been successful), after transaction completion. This method
* is used by "asynchronous" concurrency strategies.
*
* @param session Current session.
* @param key The item key
* @param lock The lock previously obtained from {@link #lockItem}
*
* @throws CacheException Propagated from underlying cache provider
*/
void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock);
/**
* Called after we have finished the attempted invalidation of the entire
* region
*
* @param lock The lock previously obtained from {@link #lockRegion}
*
* @throws CacheException Propagated from underlying cache provider
*/
void unlockRegion(SoftLock lock);
/**
* Called afterQuery an item has become stale (beforeQuery the transaction completes).
* This method is used by "synchronous" concurrency strategies.
*
* @param session Current session.
* @param key The key of the item to remove
*
* @throws CacheException Propagated from underlying cache provider
*/
void remove(SharedSessionContractImplementor session, Object key);
/**
* Called to evict data from the entire region
*
* @throws CacheException Propagated from underlying cache provider
*/
void removeAll();
/**
* Forcibly evict an item from the cache immediately without regard for transaction
* isolation and/or locking. This behavior is exactly Hibernate legacy behavior, but
* it is also required by JPA - so we cannot remove it.
* <p/>
* Used from JPA's {@link javax.persistence.Cache#evict(Class, Object)}, as well as the
* Hibernate extension {@link org.hibernate.Cache#evictEntityData(Class, Serializable)}
* and {@link org.hibernate.Cache#evictEntityData(String, Serializable)}
*
* @param key The key of the item to remove
*
* @throws CacheException Propagated from underlying cache provider
*/
void evict(Object key);
/**
* Forcibly evict all items from the cache immediately without regard for transaction
* isolation. This behavior is exactly Hibernate legacy behavior, but it is also required
* by JPA - so we cannot remove it.
* <p/>
* Used from our JPA impl of {@link Cache#evictAll()} as well as the Hibernate
* extensions {@link org.hibernate.Cache#evictEntityData(Class)},
* {@link org.hibernate.Cache#evictEntityData(String)} and
* {@link org.hibernate.Cache#evictEntityData()}
*
* @throws CacheException Propagated from underlying cache provider
*/
void evictAll();
}

View File

@ -1,12 +1,11 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi.access;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.collection.CollectionPersister;
@ -17,38 +16,37 @@ import org.hibernate.persister.collection.CollectionPersister;
* {@link #lockItem} -> {@link #remove} -> {@link #unlockItem}
* <p/>
* There is another usage pattern that is used to invalidate entries
* after performing "bulk" HQL/SQL operations:
* afterQuery performing "bulk" HQL/SQL operations:
* {@link #lockRegion} -> {@link #removeAll} -> {@link #unlockRegion}
*
* @author Gavin King
* @author Steve Ebersole
*/
public interface CollectionRegionAccessStrategy extends RegionAccessStrategy {
public interface CollectionDataAccess extends CachedDomainDataAccess {
/**
* To create instances of CollectionCacheKey for this region, Hibernate will invoke this method
* exclusively so that generated implementations can generate optimised keys.
* @param id the primary identifier of the Collection
* @param persister the persister for the type for which a key is being generated
* @param collectionDescriptor the descriptor of the collection for which a key is being generated
* @param factory a reference to the current SessionFactory
* @param tenantIdentifier the tenant id, or null if multi-tenancy is not being used.
*
* @return a key which can be used to identify this collection on this same region
*/
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier);
Object generateCacheKey(
Object id,
CollectionPersister collectionDescriptor,
SessionFactoryImplementor factory,
String tenantIdentifier);
/**
* Performs reverse operation to {@link #generateCacheKey(Object, CollectionPersister, SessionFactoryImplementor, String)}
* Performs reverse operation to {@link #generateCacheKey}
*
* @param cacheKey key previously returned from {@link #generateCacheKey(Object, CollectionPersister, SessionFactoryImplementor, String)}
* @return original key passed to {@link #generateCacheKey(Object, CollectionPersister, SessionFactoryImplementor, String)}
* @param cacheKey key previously returned from {@link #generateCacheKey}
*
* @return original key passed to {@link #generateCacheKey}
*/
public Object getCacheKeyId(Object cacheKey);
Object getCacheKeyId(Object cacheKey);
/**
* Get the wrapped collection cache region
*
* @return The underlying region
*/
public CollectionRegion getRegion();
}

View File

@ -1,13 +1,12 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi.access;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
@ -18,7 +17,7 @@ import org.hibernate.persister.entity.EntityPersister;
* <li><b>INSERTS</b> : {@link #insert} -> {@link #afterInsert}</li>
* <li><b>UPDATES</b> : {@link #lockItem} -> {@link #update} -> {@link #afterUpdate}</li>
* <li><b>DELETES</b> : {@link #lockItem} -> {@link #remove} -> {@link #unlockItem}</li>
* <li><b>LOADS</b> : {@link @putFromLoad}</li>
* <li><b>LOADS</b> : {@link #putFromLoad}</li>
* </ul>
* <p/>
* There is another usage pattern that is used to invalidate entries
@ -28,40 +27,34 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Gavin King
* @author Steve Ebersole
*/
public interface EntityRegionAccessStrategy extends RegionAccessStrategy {
public interface EntityDataAccess extends CachedDomainDataAccess {
/**
* To create instances of keys for this region, Hibernate will invoke this method
* exclusively so that generated implementations can generate optimised keys.
* @param id the primary identifier of the entity
* @param persister the persister for the type for which a key is being generated
* @param rootEntityDescriptor Hierarchy for which a key is being generated
* @param factory a reference to the current SessionFactory
* @param tenantIdentifier the tenant id, or null if multi-tenancy is not being used.
* @return a key which can be used to identify this entity on this same region
*
* todo (6.0) : the access for an entity knows the entity hierarchy and the factory. why pass them in?
*/
Object generateCacheKey(
Object id,
EntityPersister persister,
EntityPersister rootEntityDescriptor,
SessionFactoryImplementor factory,
String tenantIdentifier);
/**
* Performs reverse operation to {@link #generateCacheKey(Object, EntityPersister, SessionFactoryImplementor, String)}
* Performs reverse operation to {@link #generateCacheKey}
*
* @param cacheKey key previously returned from {@link #generateCacheKey(Object, EntityPersister, SessionFactoryImplementor, String)}
* @return original id passed to {@link #generateCacheKey(Object, EntityPersister, SessionFactoryImplementor, String)}
* @param cacheKey key previously returned from {@link #generateCacheKey}
* @return original id passed to {@link #generateCacheKey}
*/
Object getCacheKeyId(Object cacheKey);
/**
* Get the wrapped entity cache region
*
* @return The underlying region
*/
EntityRegion getRegion();
/**
* Called after an item has been inserted (before the transaction completes),
* Called afterQuery an item has been inserted (beforeQuery the transaction completes),
* instead of calling evict().
* This method is used by "synchronous" concurrency strategies.
*
@ -70,12 +63,12 @@ public interface EntityRegionAccessStrategy extends RegionAccessStrategy {
* @param value The item
* @param version The item's version value
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
* @throws CacheException Propagated from underlying cache provider
*/
boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException;
boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version);
/**
* Called after an item has been inserted (after the transaction completes),
* Called afterQuery an item has been inserted (afterQuery the transaction completes),
* instead of calling release().
* This method is used by "asynchronous" concurrency strategies.
*
@ -84,12 +77,12 @@ public interface EntityRegionAccessStrategy extends RegionAccessStrategy {
* @param value The item
* @param version The item's version value
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
* @throws CacheException Propagated from underlying cache provider
*/
boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException;
boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version);
/**
* Called after an item has been updated (before the transaction completes),
* Called afterQuery an item has been updated (beforeQuery the transaction completes),
* instead of calling evict(). This method is used by "synchronous" concurrency
* strategies.
*
@ -100,12 +93,17 @@ public interface EntityRegionAccessStrategy extends RegionAccessStrategy {
* @param currentVersion The item's current version value
* @param previousVersion The item's previous version value
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
* @throws CacheException Propagated from underlying cache provider
*/
boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException;
boolean update(
SharedSessionContractImplementor session,
Object key,
Object value,
Object currentVersion,
Object previousVersion);
/**
* Called after an item has been updated (after the transaction completes),
* Called afterQuery an item has been updated (afterQuery the transaction completes),
* instead of calling release(). This method is used by "asynchronous"
* concurrency strategies.
*
@ -116,7 +114,7 @@ public interface EntityRegionAccessStrategy extends RegionAccessStrategy {
* @param previousVersion The item's previous version value
* @param lock The lock previously obtained from {@link #lockItem}
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
* @throws CacheException Propagated from underlying cache provider
*/
boolean afterUpdate(
SharedSessionContractImplementor session,
@ -124,5 +122,5 @@ public interface EntityRegionAccessStrategy extends RegionAccessStrategy {
Object value,
Object currentVersion,
Object previousVersion,
SoftLock lock) throws CacheException;
SoftLock lock);
}

View File

@ -1,13 +1,12 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi.access;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
@ -23,90 +22,90 @@ import org.hibernate.persister.entity.EntityPersister;
* old entry as well as
* <p/>
* There is another usage pattern that is used to invalidate entries
* after performing "bulk" HQL/SQL operations:
* afterQuery performing "bulk" HQL/SQL operations:
* {@link #lockRegion} -> {@link #removeAll} -> {@link #unlockRegion}
* <p/>
* IMPORTANT : NaturalIds are not versioned so {@code null} will always be passed to the version parameter to:<ul>
* <li>{@link RegionAccessStrategy#putFromLoad(SharedSessionContractImplementor, Object, Object, long, Object)}</li>
* <li>{@link RegionAccessStrategy#putFromLoad(SharedSessionContractImplementor, Object, Object, long, Object, boolean)}</li>
* <li>{@link RegionAccessStrategy#lockItem(SharedSessionContractImplementor, Object, Object)}</li>
* <li>{@link CachedDomainDataAccess#putFromLoad(SharedSessionContractImplementor, Object, Object, Object)}</li>
* <li>{@link CachedDomainDataAccess#putFromLoad(SharedSessionContractImplementor, Object, Object, Object, boolean)}</li>
* <li>{@link CachedDomainDataAccess#lockItem(SharedSessionContractImplementor, Object, Object)}</li>
* </ul>
*
* @author Gavin King
* @author Steve Ebersole
* @author Eric Dalquist
*/
public interface NaturalIdRegionAccessStrategy extends RegionAccessStrategy {
public interface NaturalIdDataAccess extends CachedDomainDataAccess {
/**
* To create instances of NaturalIdCacheKey for this region, Hibernate will invoke this method
* exclusively so that generated implementations can generate optimised keys.
* @param naturalIdValues the sequence of values which unequivocally identifies a cached element on this region
* @param persister the persister of the element being cached
* @param session
* @param rootEntityDescriptor the persister of the element being cached
*
* @return a key which can be used to identify this an element unequivocally on this same region
*/
Object generateCacheKey(
Object[] naturalIdValues,
EntityPersister persister,
EntityPersister rootEntityDescriptor,
SharedSessionContractImplementor session);
/**
* Performs reverse operation to {@link #generateCacheKey(Object[], EntityPersister, SharedSessionContractImplementor)}, returning
* Performs reverse operation to {@link #generateCacheKey}, returning
* the original naturalIdValues.
* @param cacheKey key returned from {@link #generateCacheKey(Object[], EntityPersister, SharedSessionContractImplementor)}
* @param cacheKey key returned from {@link #generateCacheKey}
*
* @return the sequence of values which unequivocally identifies a cached element on this region
*/
Object[] getNaturalIdValues(Object cacheKey);
/**
* Get the wrapped naturalId cache region
*
* @return The underlying region
*/
NaturalIdRegion getRegion();
/**
* Called after an item has been inserted (before the transaction completes),
* Called afterQuery an item has been inserted (beforeQuery the transaction completes),
* instead of calling evict().
* This method is used by "synchronous" concurrency strategies.
*
* @param session Current session
* @param key The item key
* @param value The item
*
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
*
* @throws CacheException Propagated from underlying cache provider
*/
boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException;
boolean insert(SharedSessionContractImplementor session, Object key, Object value);
/**
* Called after an item has been inserted (after the transaction completes),
* Called afterQuery an item has been inserted (afterQuery the transaction completes),
* instead of calling release().
* This method is used by "asynchronous" concurrency strategies.
*
* @param session Current session
* @param key The item key
* @param value The item
*
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
*
* @throws CacheException Propagated from underlying cache provider
*/
boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException;
boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value);
/**
* Called after an item has been updated (before the transaction completes),
* Called afterQuery an item has been updated (beforeQuery the transaction completes),
* instead of calling evict(). This method is used by "synchronous" concurrency
* strategies.
*
* @param session Current session
* @param key The item key
* @param value The item
*
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region}
*
* @throws CacheException Propagated from underlying cache provider
*/
boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException;
boolean update(SharedSessionContractImplementor session, Object key, Object value);
/**
* Called after an item has been updated (after the transaction completes),
* Called afterQuery an item has been updated (afterQuery the transaction completes),
* instead of calling release(). This method is used by "asynchronous"
* concurrency strategies.
*
@ -114,8 +113,10 @@ public interface NaturalIdRegionAccessStrategy extends RegionAccessStrategy {
* @param key The item key
* @param value The item
* @param lock The lock previously obtained from {@link #lockItem}
*
* @return Were the contents of the cache actual changed by this operation?
* @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*
* @throws CacheException Propagated from underlying cache provider
*/
boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException;
boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock);
}

View File

@ -1,149 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi.access;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Base access strategy for all regions.
*
* @author Gail Badner
*/
public interface RegionAccessStrategy {
/**
* Attempt to retrieve an object from the cache. Mainly used in attempting
* to resolve entities/collections from the second level cache.
*
* @param session Current session.
* @param key The key of the item to be retrieved.
* @param txTimestamp a timestamp prior to the transaction start time
* @return the cached object or <tt>null</tt>
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException;
/**
* Attempt to cache an object, after loading from the database.
*
* @param session Current session.
* @param key The item key
* @param value The item
* @param txTimestamp a timestamp prior to the transaction start time
* @param version the item version number
* @return <tt>true</tt> if the object was successfully cached
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
boolean putFromLoad(
SharedSessionContractImplementor session,
Object key,
Object value,
long txTimestamp,
Object version) throws CacheException;
/**
* Attempt to cache an object, after loading from the database, explicitly
* specifying the minimalPut behavior.
*
* @param session Current session.
* @param key The item key
* @param value The item
* @param txTimestamp a timestamp prior to the transaction start time
* @param version the item version number
* @param minimalPutOverride Explicit minimalPut flag
* @return <tt>true</tt> if the object was successfully cached
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
boolean putFromLoad(
SharedSessionContractImplementor session,
Object key,
Object value,
long txTimestamp,
Object version,
boolean minimalPutOverride) throws CacheException;
/**
* We are going to attempt to update/delete the keyed object. This
* method is used by "asynchronous" concurrency strategies.
* <p/>
* The returned object must be passed back to {@link #unlockItem}, to release the
* lock. Concurrency strategies which do not support client-visible
* locks may silently return null.
*
* @param session Current session.
* @param key The key of the item to lock
* @param version The item's current version value
* @return A representation of our lock on the item; or null.
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException;
/**
* Lock the entire region
*
* @return A representation of our lock on the item; or null.
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
SoftLock lockRegion() throws CacheException;
/**
* Called when we have finished the attempted update/delete (which may or
* may not have been successful), after transaction completion. This method
* is used by "asynchronous" concurrency strategies.
*
* @param session Current session.
* @param key The item key
* @param lock The lock previously obtained from {@link #lockItem}
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException;
/**
* Called after we have finished the attempted invalidation of the entire
* region
*
* @param lock The lock previously obtained from {@link #lockRegion}
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
void unlockRegion(SoftLock lock) throws CacheException;
/**
* Called after an item has become stale (before the transaction completes).
* This method is used by "synchronous" concurrency strategies.
*
* @param session
* @param key The key of the item to remove
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
void remove(SharedSessionContractImplementor session, Object key) throws CacheException;
/**
* Called to evict data from the entire region
*
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
void removeAll() throws CacheException;
/**
* Forcibly evict an item from the cache immediately without regard for transaction
* isolation.
*
* @param key The key of the item to remove
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
void evict(Object key) throws CacheException;
/**
* Forcibly evict all items from the cache immediately without regard for transaction
* isolation.
*
* @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
*/
void evictAll() throws CacheException;
}

View File

@ -1,13 +1,13 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi.access;
/**
* Marker object for use by synchronous concurrency strategies
* Memento object for use by synchronous concurrency strategies
*
* @author Steve Ebersole
*/

View File

@ -1,8 +1,8 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.cache.spi.access;
@ -10,6 +10,8 @@ import org.hibernate.HibernateException;
/**
* Indicates that an unknown AccessType external name was encountered
* or that an AccessType was requested that the underlying cache provider
* does not support.
*
* @author Steve Ebersole
*

View File

@ -8,13 +8,13 @@
<html>
<body>
<p>
Defines contracts for transactional and concurrent access to cached
{@link org.hibernate.cache.spi.access.EntityRegionAccessStrategy entity} and
{@link org.hibernate.cache.spi.access.CollectionRegionAccessStrategy collection} data. Transactions pass in a
Defines contracts for transactional and concurrent access to cached
{@link org.hibernate.cache.spi.access.EntityDataAccess entity} and
{@link org.hibernate.cache.spi.access.CollectionDataAccess collection} data. Transactions pass in a
timestamp indicating transaction start time which is then used to protect against concurrent access (exactly how
that occurs is based on the actual access-strategy impl used). Two different implementation patterns are provided
for:
<ul>
<ul>
<li>
A transaction-aware cache implementation might be wrapped by a <i>synchronous</i> access strategy,
where updates to the cache are written to the cache inside the transaction.

View File

@ -13,6 +13,7 @@ import javax.persistence.GeneratedValue;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.registry.classloading.internal.TcclLookupPrecedence;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jpa.JpaCompliance;
import org.hibernate.query.internal.ParameterMetadataImpl;
@ -1054,7 +1055,7 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
String USE_QUERY_CACHE = "hibernate.cache.use_query_cache";
/**
* The {@link org.hibernate.cache.spi.QueryCacheFactory} implementation class.
* The {@link TimestampsRegionAccessFactory} implementation class.
*/
String QUERY_CACHE_FACTORY = "hibernate.cache.query_cache_factory";

View File

@ -16,8 +16,8 @@ import org.hibernate.boot.Metadata;
import org.hibernate.boot.SchemaAutoTooling;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegionAccessFactory;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.hql.spi.QueryTranslatorFactory;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
@ -93,7 +93,7 @@ public final class Settings {
LOG.debugf( "Second-level cache: %s", enabledDisabled( sessionFactoryOptions.isSecondLevelCacheEnabled() ) );
LOG.debugf( "Second-level query cache: %s", enabledDisabled( sessionFactoryOptions.isQueryCacheEnabled() ) );
LOG.debugf( "Second-level query cache factory: %s", sessionFactoryOptions.getQueryCacheFactory() );
LOG.debugf( "Second-level query cache factory: %s", sessionFactoryOptions.getTimestampsRegionAccessFactory() );
LOG.debugf( "Second-level cache region prefix: %s", sessionFactoryOptions.getCacheRegionPrefix() );
LOG.debugf( "Optimize second-level cache for minimal puts: %s", enabledDisabled( sessionFactoryOptions.isMinimalPutsEnabled() ) );
LOG.debugf( "Structured second-level cache entries: %s", enabledDisabled( sessionFactoryOptions.isStructuredCacheEntriesEnabled() ) );
@ -227,8 +227,8 @@ public final class Settings {
return sessionFactoryOptions.isQueryCacheEnabled();
}
public QueryCacheFactory getQueryCacheFactory() {
return sessionFactoryOptions.getQueryCacheFactory();
public TimestampsRegionAccessFactory getTimestampsRegionAccessFactory() {
return sessionFactoryOptions.getTimestampsRegionAccessFactory();
}
public String getCacheRegionPrefix() {

View File

@ -8,7 +8,7 @@ package org.hibernate.engine.internal;
import java.io.Serializable;
import org.hibernate.cache.spi.access.RegionAccessStrategy;
import org.hibernate.cache.spi.access.CachedDomainDataAccess;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -24,12 +24,12 @@ public final class CacheHelper {
public static Serializable fromSharedCache(
SharedSessionContractImplementor session,
Object cacheKey,
RegionAccessStrategy cacheAccessStrategy) {
CachedDomainDataAccess cacheAccess) {
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
Serializable cachedValue = null;
eventListenerManager.cacheGetStart();
try {
cachedValue = (Serializable) cacheAccessStrategy.get( session, cacheKey, session.getTimestamp() );
cachedValue = (Serializable) cacheAccess.get( session, cacheKey );
}
finally {
eventListenerManager.cacheGetEnd( cachedValue != null );

View File

@ -15,7 +15,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.AssertionFailure;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -107,7 +107,7 @@ public class NaturalIdXrefDelegate {
}
if ( persister.hasNaturalIdCache() ) {
final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister
.getNaturalIdCacheAccessStrategy();
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session() );
naturalIdCacheAccessStrategy.evict( naturalIdCacheKey );
@ -238,7 +238,7 @@ public class NaturalIdXrefDelegate {
}
// Try resolution from second-level cache
final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session() );
pk = CacheHelper.fromSharedCache( session(), naturalIdCacheKey, naturalIdCacheAccessStrategy );
@ -247,9 +247,7 @@ public class NaturalIdXrefDelegate {
final SessionFactoryImplementor factory = session().getFactory();
if ( pk != null ) {
if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCacheHit(
naturalIdCacheAccessStrategy.getRegion().getName()
);
factory.getStatistics().naturalIdCacheHit( persister.getRootEntityName() );
}
if ( LOG.isTraceEnabled() ) {
@ -274,7 +272,7 @@ public class NaturalIdXrefDelegate {
entityNaturalIdResolutionCache.naturalIdToPkMap.put( cachedNaturalId, pk );
}
else if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCacheMiss( naturalIdCacheAccessStrategy.getRegion().getName() );
factory.getStatistics().naturalIdCacheMiss( persister.getRootEntityName() );
}
return pk;

View File

@ -32,7 +32,7 @@ import org.hibernate.PersistentObjectException;
import org.hibernate.TransientObjectException;
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.loading.internal.LoadContexts;
@ -1783,7 +1783,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
Object[] naturalIdValues,
Object[] previousNaturalIdValues,
CachedNaturalIdValueSource source) {
final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session );
final SessionFactoryImplementor factory = session.getFactory();
@ -1798,12 +1798,11 @@ public class StatefulPersistenceContext implements PersistenceContext {
session,
naturalIdCacheKey,
id,
session.getTimestamp(),
null
);
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().naturalIdCachePut( naturalIdCacheAccessStrategy.getRegion().getName() );
factory.getStatistics().naturalIdCachePut( persister.getRootEntityName() );
}
break;
@ -1811,7 +1810,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
case INSERT: {
final boolean put = naturalIdCacheAccessStrategy.insert( session, naturalIdCacheKey, id );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().naturalIdCachePut( naturalIdCacheAccessStrategy.getRegion().getName() );
factory.getStatistics().naturalIdCachePut( persister.getRootEntityName() );
}
( (EventSource) session ).getActionQueue().registerProcess(
@ -1822,7 +1821,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
final boolean put = naturalIdCacheAccessStrategy.afterInsert( session, naturalIdCacheKey, id );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().naturalIdCachePut( naturalIdCacheAccessStrategy.getRegion().getName() );
factory.getStatistics().naturalIdCachePut( persister.getRootEntityName() );
}
}
else {
@ -1846,7 +1845,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
final SoftLock lock = naturalIdCacheAccessStrategy.lockItem( session, naturalIdCacheKey, null );
final boolean put = naturalIdCacheAccessStrategy.update( session, naturalIdCacheKey, id );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().naturalIdCachePut( naturalIdCacheAccessStrategy.getRegion().getName() );
factory.getStatistics().naturalIdCachePut( persister.getRootEntityName() );
}
( (EventSource) session ).getActionQueue().registerProcess(
@ -1863,7 +1862,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
);
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().naturalIdCachePut( naturalIdCacheAccessStrategy.getRegion().getName() );
factory.getStatistics().naturalIdCachePut( persister.getRootEntityName() );
}
}
else {
@ -1917,7 +1916,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
// 2) should prefer session-cached values if any (requires interaction from removeLocalNaturalIdCrossReference
persister = locateProperPersister( persister );
final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session );
naturalIdCacheAccessStrategy.evict( naturalIdCacheKey );

View File

@ -13,7 +13,7 @@ import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
@ -200,7 +200,7 @@ public final class TwoPhaseLoad {
final Object version = Versioning.getVersion( hydratedState, persister );
final CacheEntry entry = persister.buildCacheEntry( entity, hydratedState, version, session );
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object cacheKey = cache.generateCacheKey( id, persister, factory, session.getTenantIdentifier() );
// explicit handling of caching for rows just inserted and then somehow forced to be read
@ -226,7 +226,6 @@ public final class TwoPhaseLoad {
session,
cacheKey,
persister.getCacheEntryStructure().structure( entry ),
session.getTimestamp(),
version,
useMinimalPuts( session, entityEntry )
);

View File

@ -17,7 +17,7 @@ import java.util.Set;
import org.hibernate.CacheMode;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.entry.CollectionCacheEntry;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
@ -330,8 +330,8 @@ public class CollectionLoadContext {
}
final CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
final CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final Object cacheKey = cache.generateCacheKey(
final CollectionDataAccess cacheAccess = persister.getCacheAccessStrategy();
final Object cacheKey = cacheAccess.generateCacheKey(
lce.getKey(),
persister,
session.getFactory(),
@ -353,11 +353,10 @@ public class CollectionLoadContext {
if (isPutFromLoad) {
try {
session.getEventListenerManager().cachePutStart();
final boolean put = cache.putFromLoad(
final boolean put = cacheAccess.putFromLoad(
session,
cacheKey,
persister.getCacheEntryStructure().structure( entry ),
session.getTimestamp(),
version,
factory.getSessionFactoryOptions().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
);

View File

@ -397,7 +397,7 @@ public class ActionQueue {
beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
}
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
invalidateSpaces( executable.getPropertySpaces() );
invalidateSpaces( convertTimestampSpaces( executable.getPropertySpaces() ) );
}
if( executable.getAfterTransactionCompletionProcess() != null ) {
if( afterTransactionProcesses == null ) {
@ -407,6 +407,10 @@ public class ActionQueue {
}
}
private static String[] convertTimestampSpaces(Serializable[] spaces) {
return (String[]) spaces;
}
/**
* Are there unresolved entity insert actions that depend on non-nullable associations with a transient entity?
*
@ -620,8 +624,8 @@ public class ActionQueue {
// Strictly speaking, only a subset of the list may have been processed if a RuntimeException occurs.
// We still invalidate all spaces. I don't see this as a big deal - after all, RuntimeExceptions are
// unexpected.
Set<Serializable> propertySpaces = list.getQuerySpaces();
invalidateSpaces( propertySpaces.toArray( new Serializable[propertySpaces.size()] ) );
Set propertySpaces = list.getQuerySpaces();
invalidateSpaces( convertTimestampSpaces( propertySpaces ) );
}
}
@ -629,6 +633,10 @@ public class ActionQueue {
session.getJdbcCoordinator().executeBatch();
}
private static String[] convertTimestampSpaces(Set spaces) {
return (String[]) spaces.toArray( new String[ spaces.size() ] );
}
/**
* @param executable The action to execute
*/
@ -646,7 +654,7 @@ public class ActionQueue {
*
* @param spaces The spaces to invalidate
*/
private void invalidateSpaces(Serializable... spaces) {
private void invalidateSpaces(String... spaces) {
if ( spaces != null && spaces.length > 0 ) {
for ( Serializable s : spaces ) {
if( afterTransactionProcesses == null ) {
@ -655,7 +663,7 @@ public class ActionQueue {
afterTransactionProcesses.addSpaceToInvalidate( (String) s );
}
// Performance win: If we are processing an ExecutableList, this will only be called once
session.getFactory().getUpdateTimestampsCache().preInvalidate( spaces, session );
session.getFactory().getCache().getTimestampsRegionAccess().preInvalidate( spaces, session );
}
}
@ -984,7 +992,7 @@ public class ActionQueue {
}
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
session.getFactory().getUpdateTimestampsCache().invalidate(
session.getFactory().getCache().getTimestampsRegionAccess().invalidate(
querySpacesToInvalidate.toArray( new String[querySpacesToInvalidate.size()] ),
session
);

View File

@ -14,8 +14,8 @@ import java.util.Map;
import java.util.Map.Entry;
import org.hibernate.EntityMode;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.CacheHelper;
import org.hibernate.internal.CoreLogging;
@ -216,7 +216,7 @@ public class BatchFetchQueue {
private boolean isCached(EntityKey entityKey, EntityPersister persister) {
final SharedSessionContractImplementor session = context.getSession();
if ( context.getSession().getCacheMode().isGetEnabled() && persister.canReadFromCache() ) {
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object key = cache.generateCacheKey(
entityKey.getIdentifier(),
persister,
@ -332,7 +332,7 @@ public class BatchFetchQueue {
private boolean isCached(Serializable collectionKey, CollectionPersister persister) {
SharedSessionContractImplementor session = context.getSession();
if ( session.getCacheMode().isGetEnabled() && persister.hasCache() ) {
CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy();
CollectionDataAccess cache = persister.getCacheAccessStrategy();
Object cacheKey = cache.generateCacheKey(
collectionKey,
persister,

View File

@ -1,128 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.engine.spi;
import java.io.Serializable;
import org.hibernate.Cache;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.QueryCache;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.UpdateTimestampsCache;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.service.Service;
/**
* Define internal contact of <tt>Cache API</tt>
*
* @author Strong Liu
*/
public interface CacheImplementor extends Service, Cache, Serializable {
/**
* Close all cache regions.
*/
void close();
/**
* Get query cache by <tt>region name</tt> or create a new one if none exist.
* <p/>
* If the region name is null, then default query cache region will be returned.
*
* @param regionName Query cache region name.
* @return The {@code QueryCache} associated with the region name, or default query cache if the region name is <tt>null</tt>.
* @throws HibernateException {@code HibernateException} maybe thrown when the creation of new QueryCache instance.
*/
QueryCache getQueryCache(String regionName) throws HibernateException;
/**
* Get the default {@code QueryCache}.
*
* @deprecated Use {@link #getDefaultQueryCache} instead.
*/
@Deprecated
default QueryCache getQueryCache() {
return getDefaultQueryCache();
}
/**
* Get the default {@code QueryCache}.
*/
QueryCache getDefaultQueryCache();
/**
* Get {@code UpdateTimestampsCache} instance managed by the {@code SessionFactory}.
*/
UpdateTimestampsCache getUpdateTimestampsCache();
/**
* Clean up the default {@code QueryCache}.
*
* @throws HibernateException
*/
void evictQueries() throws HibernateException;
/**
* The underlying RegionFactory in use.
*
* @return The {@code RegionFactory}
*/
RegionFactory getRegionFactory();
/**
* Applies any defined prefix, handling all {@code null} checks.
*
* @param regionName The region name to qualify
*
* @return The qualified name
*/
String qualifyRegionName(String regionName);
/**
* Get the names of <tt>all</tt> cache regions, including entity, collection, natural-id and query caches.
*
* @return All cache region names
*/
String[] getSecondLevelCacheRegionNames();
/**
* Find the "access strategy" for the named entity cache region.
*
* @param regionName The name of the region
*
* @return That region's "access strategy"
*/
EntityRegionAccessStrategy getEntityRegionAccess(String regionName);
/**
* Find the "access strategy" for the named collection cache region.
*
* @param regionName The name of the region
*
* @return That region's "access strategy"
*/
CollectionRegionAccessStrategy getCollectionRegionAccess(String regionName);
/**
* Find the "access strategy" for the named natrual-id cache region.
*
* @param regionName The name of the region
*
* @return That region's "access strategy"
*/
NaturalIdRegionAccessStrategy getNaturalIdCacheRegionAccessStrategy(String regionName);
EntityRegionAccessStrategy determineEntityRegionAccessStrategy(PersistentClass model);
NaturalIdRegionAccessStrategy determineNaturalIdRegionAccessStrategy(PersistentClass model);
CollectionRegionAccessStrategy determineCollectionRegionAccessStrategy(Collection model);
}

View File

@ -7,7 +7,9 @@
package org.hibernate.engine.spi;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.internal.CacheImpl;
import org.hibernate.cache.internal.DisabledCaching;
import org.hibernate.cache.internal.EnabledCaching;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceInitiator;
@ -25,7 +27,9 @@ public class CacheInitiator implements SessionFactoryServiceInitiator<CacheImple
SessionFactoryImplementor sessionFactory,
SessionFactoryOptions sessionFactoryOptions,
ServiceRegistryImplementor registry) {
return new CacheImpl( sessionFactory );
return sessionFactoryOptions.isSecondLevelCacheEnabled()
? new EnabledCaching( sessionFactory )
: new DisabledCaching( sessionFactory );
}
@Override

View File

@ -48,6 +48,7 @@ import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.Transaction;
import org.hibernate.TypeHelper;
import org.hibernate.UnknownProfileException;
import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
@ -334,6 +335,11 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
delegate.markForRollbackOnly();
}
@Override
public long getTransactionStartTimestamp() {
return delegate.getTransactionStartTimestamp();
}
@Override
public FlushModeType getFlushMode() {
return delegate.getFlushMode();
@ -474,6 +480,16 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
return delegate.getTransaction();
}
@Override
public void startTransactionBoundary() {
delegate.startTransactionBoundary();
}
@Override
public CacheTransactionSynchronization getCacheTransactionSynchronization() {
return delegate.getCacheTransactionSynchronization();
}
@Override
public void afterTransactionBegin() {
delegate.afterTransactionBegin();

View File

@ -31,10 +31,7 @@ import org.hibernate.StatelessSession;
import org.hibernate.StatelessSessionBuilder;
import org.hibernate.TypeHelper;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.QueryCache;
import org.hibernate.cache.spi.Region;
import org.hibernate.cache.spi.UpdateTimestampsCache;
import org.hibernate.cache.spi.access.RegionAccessStrategy;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.cfg.Settings;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
@ -272,24 +269,9 @@ public class SessionFactoryDelegatingImpl implements SessionFactoryImplementor,
return delegate.findEntityGraphByName( name );
}
@Override
public QueryCache getQueryCache() {
return delegate.getQueryCache();
}
@Override
public QueryCache getQueryCache(String regionName) throws HibernateException {
return delegate.getQueryCache( regionName );
}
@Override
public UpdateTimestampsCache getUpdateTimestampsCache() {
return delegate.getUpdateTimestampsCache();
}
@Override
public StatisticsImplementor getStatisticsImplementor() {
return delegate.getStatisticsImplementor();
return delegate.getStatistics();
}
@Override
@ -322,31 +304,6 @@ public class SessionFactoryDelegatingImpl implements SessionFactoryImplementor,
return delegate.getIdentifierGenerator( rootEntityName );
}
@Override
public Region getSecondLevelCacheRegion(String regionName) {
return delegate.getSecondLevelCacheRegion( regionName );
}
@Override
public RegionAccessStrategy getSecondLevelCacheRegionAccessStrategy(String regionName) {
return delegate.getSecondLevelCacheRegionAccessStrategy(regionName);
}
@Override
public Region getNaturalIdCacheRegion(String regionName) {
return delegate.getNaturalIdCacheRegion( regionName );
}
@Override
public RegionAccessStrategy getNaturalIdCacheRegionAccessStrategy(String regionName) {
return delegate.getNaturalIdCacheRegionAccessStrategy(regionName);
}
@Override
public Map getAllSecondLevelCacheRegions() {
return delegate.getAllSecondLevelCacheRegions();
}
@Override
public SQLExceptionConverter getSQLExceptionConverter() {
return delegate.getSQLExceptionConverter();

View File

@ -21,13 +21,7 @@ import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.QueryCache;
import org.hibernate.cache.spi.Region;
import org.hibernate.cache.spi.UpdateTimestampsCache;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.RegionAccessStrategy;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.cfg.Settings;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
@ -217,7 +211,7 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory, Quer
/**
* @deprecated Just use {@link #getStatistics} (with covariant return here as {@link StatisticsImplementor}).
* @deprecated (since 5.2) Just use {@link #getStatistics} (with covariant return here as {@link StatisticsImplementor}).
*/
@Deprecated
default StatisticsImplementor getStatisticsImplementor() {
@ -420,138 +414,4 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory, Quer
EntityGraph findEntityGraphByName(String name);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Move to CacheImplementor calls
/**
* Get a named second-level cache region
*
* @param regionName The name of the region to retrieve.
*
* @return The name of the region
*
* @deprecated (since 5.2) Use this factory's {@link #getCache()} reference
* to access Region via {@link CacheImplementor#determineEntityRegionAccessStrategy} or
* {@link CacheImplementor#determineCollectionRegionAccessStrategy} instead.
*/
@Deprecated
default Region getSecondLevelCacheRegion(String regionName) {
final EntityRegionAccessStrategy entityRegionAccess = getCache().getEntityRegionAccess( regionName );
if ( entityRegionAccess != null ) {
return entityRegionAccess.getRegion();
}
final CollectionRegionAccessStrategy collectionRegionAccess = getCache().getCollectionRegionAccess( regionName );
if ( collectionRegionAccess != null ) {
return collectionRegionAccess.getRegion();
}
return null;
}
/**
* Find the "access strategy" for the named cache region.
*
* @param regionName The name of the region
*
* @return That region's "access strategy"
*
*
* @deprecated (since 5.2) Use this factory's {@link #getCache()} reference
* to access {@link CacheImplementor#determineEntityRegionAccessStrategy} or
* {@link CacheImplementor#determineCollectionRegionAccessStrategy} instead.
*/
@Deprecated
default RegionAccessStrategy getSecondLevelCacheRegionAccessStrategy(String regionName) {
final EntityRegionAccessStrategy entityRegionAccess = getCache().getEntityRegionAccess( regionName );
if ( entityRegionAccess != null ) {
return entityRegionAccess;
}
final CollectionRegionAccessStrategy collectionRegionAccess = getCache().getCollectionRegionAccess( regionName );
if ( collectionRegionAccess != null ) {
return collectionRegionAccess;
}
return null;
}
/**
* Get a named natural-id cache region
*
* @param regionName The name of the region to retrieve.
*
* @return The region
*
* @deprecated (since 5.2) Use this factory's {@link #getCache()} ->
* {@link CacheImplementor#getNaturalIdCacheRegionAccessStrategy(String)} ->
* {@link NaturalIdRegionAccessStrategy#getRegion()} instead.
*/
@Deprecated
default Region getNaturalIdCacheRegion(String regionName) {
return getCache().getNaturalIdCacheRegionAccessStrategy( regionName ).getRegion();
}
/**
* Find the "access strategy" for the named naturalId cache region.
*
* @param regionName The region name
*
* @return That region's "access strategy"
*
* @deprecated (since 5.2) Use this factory's {@link #getCache()} ->
* {@link CacheImplementor#getNaturalIdCacheRegionAccessStrategy(String)} instead.
*/
@Deprecated
default RegionAccessStrategy getNaturalIdCacheRegionAccessStrategy(String regionName) {
return getCache().getNaturalIdCacheRegionAccessStrategy( regionName );
}
/**
* Get a map of all the second level cache regions currently maintained in
* this session factory. The map is structured with the region name as the
* key and the {@link Region} instances as the values.
*
* @return The map of regions
*
* @deprecated (since 5.2) with no direct replacement; use this factory's {@link #getCache()} reference
* to access cache objects as needed.
*/
@Deprecated
Map getAllSecondLevelCacheRegions();
/**
* Get the default query cache.
*
* @deprecated Use {@link CacheImplementor#getDefaultQueryCache()} instead
*/
@Deprecated
default QueryCache getQueryCache() {
return getCache().getDefaultQueryCache();
}
/**
* Get a particular named query cache, or the default cache
*
* @param regionName the name of the cache region, or null for the default query cache
*
* @return the existing cache, or a newly created cache if none by that region name
*
* @deprecated Use {@link CacheImplementor#getQueryCache(String)} instead
*/
@Deprecated
default QueryCache getQueryCache(String regionName) {
return getCache().getQueryCache( regionName );
}
/**
* Get the cache of table update timestamps
*
* @deprecated Use {@link CacheImplementor#getUpdateTimestampsCache()} instead
*/
@Deprecated
default UpdateTimestampsCache getUpdateTimestampsCache() {
return getCache().getUpdateTimestampsCache();
}
}

View File

@ -21,6 +21,7 @@ import org.hibernate.Interceptor;
import org.hibernate.ScrollMode;
import org.hibernate.SharedSessionContract;
import org.hibernate.Transaction;
import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.cfg.Environment;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.jdbc.LobCreationContext;
@ -151,9 +152,27 @@ public interface SharedSessionContractImplementor
void markForRollbackOnly();
/**
* System time before the start of the transaction
* A "timestamp" at or before the start of the current transaction.
*
* @apiNote This "timestamp" need not be related to timestamp in the Java Date/millisecond
* sense. It just needs to be an incrementing value. See
* {@link CacheTransactionSynchronization#getCurrentTransactionStartTimestamp()}
*/
long getTimestamp();
long getTransactionStartTimestamp();
/**
* @deprecated (since 6.0) Use
*/
@Deprecated
default long getTimestamp() {
return getTransactionStartTimestamp();
}
/**
* The current CacheTransactionContext associated with the Session. This may
* return {@code null} when the Session is not currently part of a transaction.
*/
CacheTransactionSynchronization getCacheTransactionSynchronization();
/**
* Does this <tt>Session</tt> have an active Hibernate transaction

View File

@ -9,7 +9,7 @@ package org.hibernate.event.internal;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.ObjectDeletedException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.Status;
@ -66,7 +66,7 @@ public abstract class AbstractLockUpgradeEventListener extends AbstractReassocia
Object ck = null;
try {
if ( cachingEnabled ) {
EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
EntityDataAccess cache = persister.getCacheAccessStrategy();
ck = cache.generateCacheKey( entry.getId(), persister, source.getFactory(), source.getTenantIdentifier() );
lock = cache.lockItem( source, ck, entry.getVersion() );
}

View File

@ -669,7 +669,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
if ( snapshot == null ) {
//do we even really need this? the update will fail anyway....
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor()
session.getFactory().getStatistics()
.optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), id );

View File

@ -9,7 +9,7 @@ package org.hibernate.event.internal;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.entry.CollectionCacheEntry;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.CacheHelper;
@ -78,7 +78,7 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
}
if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
source.getFactory().getStatisticsImplementor().fetchCollection(
source.getFactory().getStatistics().fetchCollection(
ce.getLoadedPersister().getRole()
);
}
@ -116,17 +116,17 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
}
final SessionFactoryImplementor factory = source.getFactory();
final CollectionRegionAccessStrategy cacheAccessStrategy = persister.getCacheAccessStrategy();
final CollectionDataAccess cacheAccessStrategy = persister.getCacheAccessStrategy();
final Object ck = cacheAccessStrategy.generateCacheKey( id, persister, factory, source.getTenantIdentifier() );
final Object ce = CacheHelper.fromSharedCache( source, ck, persister.getCacheAccessStrategy() );
if ( factory.getStatistics().isStatisticsEnabled() ) {
if ( ce == null ) {
factory.getStatisticsImplementor()
factory.getStatistics()
.secondLevelCacheMiss( cacheAccessStrategy.getRegion().getName() );
}
else {
factory.getStatisticsImplementor()
factory.getStatistics()
.secondLevelCacheHit( cacheAccessStrategy.getRegion().getName() );
}
}

View File

@ -14,7 +14,7 @@ import org.hibernate.NonUniqueObjectException;
import org.hibernate.PersistentObjectException;
import org.hibernate.TypeMismatchException;
import org.hibernate.WrongClassException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl;
@ -384,7 +384,7 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
final SessionImplementor source) {
SoftLock lock = null;
final Object ck;
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
if ( persister.canWriteToCache() ) {
ck = cache.generateCacheKey(
event.getEntityId(),
@ -640,7 +640,7 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
final LoadEvent event,
final EntityPersister persister,
SessionImplementor source ) {
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
event.getEntityId(),
persister,
@ -651,12 +651,12 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
final Object ce = CacheHelper.fromSharedCache( source, ck, persister.getCacheAccessStrategy() );
if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
if ( ce == null ) {
source.getFactory().getStatisticsImplementor().secondLevelCacheMiss(
source.getFactory().getStatistics().secondLevelCacheMiss(
cache.getRegion().getName()
);
}
else {
source.getFactory().getStatisticsImplementor().secondLevelCacheHit(
source.getFactory().getStatistics().secondLevelCacheHit(
cache.getRegion().getName()
);
}

View File

@ -316,8 +316,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
}
else if ( isVersionChanged( entity, source, persister, target ) ) {
if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
source.getFactory().getStatisticsImplementor()
.optimisticFailure( entityName );
source.getFactory().getStatistics().optimisticFailure( entityName );
}
throw new StaleObjectStateException( entityName, id );
}

View File

@ -14,8 +14,8 @@ import org.hibernate.HibernateException;
import org.hibernate.PersistentObjectException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.engine.internal.Cascade;
import org.hibernate.engine.internal.CascadePoint;
@ -152,7 +152,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
// multiple actions queued during the same flush
previousVersion = persister.getVersion( object );
}
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
id,
persister,
@ -160,13 +160,8 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
source.getTenantIdentifier()
);
final SoftLock lock = cache.lockItem( source, ck, previousVersion );
source.getActionQueue().registerProcess( new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) {
cache.unlockItem( session, ck, lock );
}
} );
cache.remove( source, ck );
source.getActionQueue().registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) );
}
evictCachedCollections( persister, id, source );
@ -201,7 +196,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
if ( type.isCollectionType() ) {
CollectionPersister collectionPersister = source.getFactory().getMetamodel().collectionPersister( ( (CollectionType) type ).getRole() );
if ( collectionPersister.hasCache() ) {
final CollectionRegionAccessStrategy cache = collectionPersister.getCacheAccessStrategy();
final CollectionDataAccess cache = collectionPersister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
id,
collectionPersister,
@ -209,13 +204,8 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
source.getTenantIdentifier()
);
final SoftLock lock = cache.lockItem( source, ck, null );
source.getActionQueue().registerProcess( new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) {
cache.unlockItem( session, ck, lock );
}
} );
cache.remove( source, ck );
source.getActionQueue().registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) );
}
}
else if ( type.isComponentType() ) {

View File

@ -10,7 +10,7 @@ import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.ResolveNaturalIdEvent;
import org.hibernate.event.spi.ResolveNaturalIdEventListener;
@ -120,13 +120,12 @@ public class DefaultResolveNaturalIdEventListener
);
if ( stats ) {
final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = event.getEntityPersister().getNaturalIdCacheAccessStrategy();
final String regionName = naturalIdCacheAccessStrategy == null ? null : naturalIdCacheAccessStrategy.getRegion().getName();
final long endTime = System.nanoTime();
final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS );
factory.getStatisticsImplementor().naturalIdQueryExecuted(
regionName,
milliseconds );
factory.getStatistics().naturalIdQueryExecuted(
event.getEntityPersister().getRootEntityName(),
milliseconds
);
}
//PK can be null if the entity doesn't exist

Some files were not shown because too many files have changed in this diff Show More