Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.internal.CacheImpl Maven / Gradle / Ivy
/*
* 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 .
*/
package org.hibernate.internal;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.persistence.PersistenceException;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
import org.hibernate.cache.internal.StandardQueryCache;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.QueryCache;
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.UpdateTimestampsCache;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.engine.spi.CacheImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
/**
* @author Steve Ebersole
* @author Strong Liu
*/
public class CacheImpl implements CacheImplementor {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( CacheImpl.class );
private final SessionFactoryImplementor sessionFactory;
private final SessionFactoryOptions settings;
private final transient RegionFactory regionFactory;
private final String cacheRegionPrefix;
private final transient ConcurrentHashMap allRegionsMap = new ConcurrentHashMap<>();
private final transient ConcurrentHashMap entityRegionAccessStrategyMap = new ConcurrentHashMap<>();
private final transient ConcurrentHashMap collectionRegionAccessStrategyMap = new ConcurrentHashMap<>();
private final transient ConcurrentHashMap naturalIdRegionAccessStrategyMap = new ConcurrentHashMap<>();
private final transient UpdateTimestampsCache updateTimestampsCache;
private final transient QueryCache defaultQueryCache;
private final transient ConcurrentMap queryCaches;
public CacheImpl(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
this.settings = sessionFactory.getSessionFactoryOptions();
this.regionFactory = settings.getServiceRegistry().getService( RegionFactory.class );
this.regionFactory.start( settings, sessionFactory.getProperties() );
this.cacheRegionPrefix = StringHelper.isEmpty( sessionFactory.getSessionFactoryOptions().getCacheRegionPrefix() )
? ""
: sessionFactory.getSessionFactoryOptions().getCacheRegionPrefix() + ".";
if ( settings.isQueryCacheEnabled() ) {
final TimestampsRegion timestampsRegion = regionFactory.buildTimestampsRegion(
qualifyRegionName( UpdateTimestampsCache.REGION_NAME ),
sessionFactory.getProperties()
);
updateTimestampsCache = new UpdateTimestampsCache( sessionFactory, timestampsRegion );
final QueryResultsRegion queryResultsRegion = regionFactory.buildQueryResultsRegion(
StandardQueryCache.class.getName(),
sessionFactory.getProperties()
);
defaultQueryCache = settings.getQueryCacheFactory().buildQueryCache( queryResultsRegion, this );
queryCaches = new ConcurrentHashMap<>();
}
else {
updateTimestampsCache = null;
defaultQueryCache = null;
queryCaches = null;
}
}
@Override
public SessionFactory getSessionFactory() {
return sessionFactory;
}
@Override
public RegionFactory getRegionFactory() {
return regionFactory;
}
@Override
public String qualifyRegionName(String regionName) {
return StringHelper.isEmpty( regionName )
? null
: cacheRegionPrefix + regionName;
}
@Override
public boolean containsEntity(Class entityClass, Serializable identifier) {
return containsEntity( entityClass.getName(), identifier );
}
@Override
public boolean containsEntity(String entityName, Serializable identifier) {
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
if ( p.hasCache() ) {
EntityRegionAccessStrategy cache = p.getCacheAccessStrategy();
Object key = cache.generateCacheKey( identifier, p, sessionFactory, null ); // have to assume non tenancy
return cache.getRegion().contains( key );
}
else {
return false;
}
}
@Override
public void evictEntity(Class entityClass, Serializable identifier) {
evictEntity( entityClass.getName(), identifier );
}
@Override
public void evictEntity(String entityName, Serializable identifier) {
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
if ( p.hasCache() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Evicting second-level cache: %s",
MessageHelper.infoString( p, identifier, sessionFactory )
);
}
EntityRegionAccessStrategy cache = p.getCacheAccessStrategy();
Object key = cache.generateCacheKey( identifier, p, sessionFactory, null ); // have to assume non tenancy
cache.evict( key );
}
}
@Override
public void evictEntityRegion(Class entityClass) {
evictEntityRegion( entityClass.getName() );
}
@Override
public void evictEntityRegion(String entityName) {
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
if ( p.hasCache() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting second-level cache: %s", p.getEntityName() );
}
p.getCacheAccessStrategy().evictAll();
}
}
@Override
public void evictEntityRegions() {
sessionFactory.getMetamodel().entityPersisters().keySet().forEach( this::evictEntityRegion );
}
@Override
public void evictNaturalIdRegion(Class entityClass) {
evictNaturalIdRegion( entityClass.getName() );
}
@Override
public void evictNaturalIdRegion(String entityName) {
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
if ( p.hasNaturalIdCache() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting natural-id cache: %s", p.getEntityName() );
}
p.getNaturalIdCacheAccessStrategy().evictAll();
}
}
@Override
public void evictNaturalIdRegions() {
sessionFactory.getMetamodel().entityPersisters().keySet().forEach( this::evictNaturalIdRegion );
}
@Override
public boolean containsCollection(String role, Serializable ownerIdentifier) {
CollectionPersister p = sessionFactory.getMetamodel().collectionPersister( role );
if ( p.hasCache() ) {
CollectionRegionAccessStrategy cache = p.getCacheAccessStrategy();
Object key = cache.generateCacheKey( ownerIdentifier, p, sessionFactory, null ); // have to assume non tenancy
return cache.getRegion().contains( key );
}
else {
return false;
}
}
@Override
public void evictCollection(String role, Serializable ownerIdentifier) {
CollectionPersister p = sessionFactory.getMetamodel().collectionPersister( role );
if ( p.hasCache() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Evicting second-level cache: %s",
MessageHelper.collectionInfoString( p, ownerIdentifier, sessionFactory )
);
}
CollectionRegionAccessStrategy cache = p.getCacheAccessStrategy();
Object key = cache.generateCacheKey( ownerIdentifier, p, sessionFactory, null ); // have to assume non tenancy
cache.evict( key );
}
}
@Override
public void evictCollectionRegion(String role) {
CollectionPersister p = sessionFactory.getMetamodel().collectionPersister( role );
if ( p.hasCache() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting second-level cache: %s", p.getRole() );
}
p.getCacheAccessStrategy().evictAll();
}
}
@Override
public void evictCollectionRegions() {
sessionFactory.getMetamodel().collectionPersisters().keySet().forEach( this::evictCollectionRegion );
}
@Override
public boolean containsQuery(String regionName) {
return sessionFactory.getSessionFactoryOptions().isQueryCacheEnabled()
&& queryCaches.containsKey( regionName );
}
@Override
public void evictDefaultQueryRegion() {
if ( sessionFactory.getSessionFactoryOptions().isQueryCacheEnabled() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debug( "Evicting default query region cache." );
}
getDefaultQueryCache().clear();
}
}
@Override
public void evictQueryRegion(String regionName) {
if ( regionName == null ) {
throw new NullPointerException(
"Region-name cannot be null (use Cache#evictDefaultQueryRegion to evict the default query cache)"
);
}
if ( sessionFactory.getSessionFactoryOptions().isQueryCacheEnabled() ) {
QueryCache namedQueryCache = queryCaches.get( regionName );
// TODO : cleanup entries in queryCaches + allCacheRegions ?
if ( namedQueryCache != null ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Evicting query cache, region: %s", regionName );
}
namedQueryCache.clear();
}
}
}
@Override
public void evictQueryRegions() {
evictDefaultQueryRegion();
if ( CollectionHelper.isEmpty( queryCaches ) ) {
return;
}
if ( LOG.isDebugEnabled() ) {
LOG.debug( "Evicting cache of all query regions." );
}
queryCaches.values().forEach( QueryCache::clear );
}
@Override
public void close() {
for ( EntityRegionAccessStrategy access : entityRegionAccessStrategyMap.values() ) {
access.getRegion().destroy();
}
for ( CollectionRegionAccessStrategy access : collectionRegionAccessStrategyMap.values() ) {
access.getRegion().destroy();
}
if ( settings.isQueryCacheEnabled() ) {
defaultQueryCache.destroy();
for ( QueryCache cache : queryCaches.values() ) {
cache.destroy();
}
updateTimestampsCache.destroy();
}
regionFactory.stop();
}
@Override
public QueryCache getDefaultQueryCache() {
return defaultQueryCache;
}
@Override
public QueryCache getQueryCache(String regionName) throws HibernateException {
if ( !settings.isQueryCacheEnabled() ) {
return null;
}
if ( regionName == null ) {
return getDefaultQueryCache();
}
QueryCache queryCache = queryCaches.get( regionName );
if ( queryCache == null ) {
synchronized (queryCaches) {
queryCache = queryCaches.get( regionName );
if ( queryCache == null ) {
final QueryResultsRegion region = regionFactory.buildQueryResultsRegion(
qualifyRegionName( regionName ),
sessionFactory.getProperties()
);
queryCache = settings.getQueryCacheFactory().buildQueryCache( region, this );
queryCaches.put( regionName, queryCache );
}
}
}
return queryCache;
}
@Override
public UpdateTimestampsCache getUpdateTimestampsCache() {
return updateTimestampsCache;
}
@Override
public void evictQueries() throws HibernateException {
if ( settings.isQueryCacheEnabled() ) {
defaultQueryCache.clear();
}
}
@Override
public String[] getSecondLevelCacheRegionNames() {
final Set names = new HashSet<>();
names.addAll( entityRegionAccessStrategyMap.keySet() );
names.addAll( collectionRegionAccessStrategyMap.keySet() );
names.addAll( naturalIdRegionAccessStrategyMap.keySet() );
if ( settings.isQueryCacheEnabled() ) {
names.add( updateTimestampsCache.getRegion().getName() );
names.addAll( queryCaches.keySet() );
}
return ArrayHelper.toStringArray( names );
}
@Override
public EntityRegionAccessStrategy getEntityRegionAccess(String regionName) {
return entityRegionAccessStrategyMap.get( regionName );
}
@Override
public CollectionRegionAccessStrategy getCollectionRegionAccess(String regionName) {
return collectionRegionAccessStrategyMap.get( regionName );
}
@Override
public NaturalIdRegionAccessStrategy getNaturalIdCacheRegionAccessStrategy(String regionName) {
return naturalIdRegionAccessStrategyMap.get( regionName );
}
@Override
public void evictAllRegions() {
evictCollectionRegions();
evictDefaultQueryRegion();
evictEntityRegions();
evictQueryRegions();
evictNaturalIdRegions();
}
@Override
public boolean contains(Class cls, Object primaryKey) {
return containsEntity( cls, (Serializable) primaryKey );
}
@Override
public void evict(Class cls, Object primaryKey) {
evictEntity( cls, (Serializable) primaryKey );
}
@Override
public void evict(Class cls) {
evictEntityRegion( cls );
}
@Override
public void evictAll() {
// Evict only the "JPA cache", which is purely defined as the entity regions.
evictEntityRegions();
// TODO : if we want to allow an optional clearing of all cache data, the additional calls would be:
// evictCollectionRegions();
// evictQueryRegions();
}
@Override
@SuppressWarnings("unchecked")
public T unwrap(Class 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 EntityRegionAccessStrategy determineEntityRegionAccessStrategy(PersistentClass model) {
final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();
EntityRegionAccessStrategy accessStrategy = entityRegionAccessStrategyMap.get( cacheRegionName );
if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
if ( accessType != null ) {
LOG.tracef( "Building shared cache region for entity data [%s]", model.getEntityName() );
EntityRegion entityRegion = regionFactory.buildEntityRegion(
cacheRegionName,
sessionFactory.getProperties(),
CacheDataDescriptionImpl.decode( model )
);
accessStrategy = entityRegion.buildAccessStrategy( accessType );
entityRegionAccessStrategyMap.put( cacheRegionName, accessStrategy );
}
}
return accessStrategy;
}
@Override
public NaturalIdRegionAccessStrategy determineNaturalIdRegionAccessStrategy(PersistentClass model) {
NaturalIdRegionAccessStrategy naturalIdAccessStrategy = null;
if ( model.hasNaturalId() && model.getNaturalIdCacheRegionName() != null ) {
final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName();
naturalIdAccessStrategy = naturalIdRegionAccessStrategyMap.get( naturalIdCacheRegionName );
if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
final CacheDataDescriptionImpl cacheDataDescription = CacheDataDescriptionImpl.decode( model );
NaturalIdRegion naturalIdRegion = null;
try {
naturalIdRegion = regionFactory.buildNaturalIdRegion(
naturalIdCacheRegionName,
sessionFactory.getProperties(),
cacheDataDescription
);
}
catch ( UnsupportedOperationException e ) {
LOG.warnf(
"Shared cache region factory [%s] does not support natural id caching; " +
"shared NaturalId caching will be disabled for not be enabled for %s",
regionFactory.getClass().getName(),
model.getEntityName()
);
}
if (naturalIdRegion != null) {
naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( regionFactory.getDefaultAccessType() );
naturalIdRegionAccessStrategyMap.put( naturalIdCacheRegionName, naturalIdAccessStrategy );
}
}
}
return naturalIdAccessStrategy;
}
@Override
public CollectionRegionAccessStrategy determineCollectionRegionAccessStrategy(Collection model) {
final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
CollectionRegionAccessStrategy accessStrategy = collectionRegionAccessStrategyMap.get( cacheRegionName );
if ( accessStrategy == null && settings.isSecondLevelCacheEnabled()) {
final AccessType accessType = AccessType.fromExternalName(model.getCacheConcurrencyStrategy());
if (accessType != null) {
LOG.tracev("Building shared cache region for collection data [{0}]", model.getRole());
CollectionRegion collectionRegion = regionFactory.buildCollectionRegion(
cacheRegionName,
sessionFactory.getProperties(),
CacheDataDescriptionImpl.decode( model)
);
accessStrategy = collectionRegion.buildAccessStrategy( accessType );
collectionRegionAccessStrategyMap.put( cacheRegionName, accessStrategy );
}
}
return accessStrategy;
}
}