From f432ecea687ce606144c8fca1f4fc7f1937e1c2a Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 13 Mar 2018 17:54:24 -0500 Subject: [PATCH] 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 --- .../caching/SecondLevelCacheTest.java | 7 +- .../persister/CollectionPersister.java | 1 - .../userguide/persister/EntityPersister.java | 2 - .../src/main/java/org/hibernate/Cache.java | 273 ++++- .../internal/BulkOperationCleanupAction.java | 29 +- .../action/internal/CollectionAction.java | 8 +- .../action/internal/EntityDeleteAction.java | 6 +- .../internal/EntityIdentityInsertAction.java | 2 +- .../action/internal/EntityInsertAction.java | 10 +- .../action/internal/EntityUpdateAction.java | 8 +- .../hibernate/boot/SessionFactoryBuilder.java | 4 +- .../InFlightMetadataCollectorImpl.java | 37 +- .../hibernate/boot/internal/MetadataImpl.java | 4 + .../internal/SessionFactoryBuilderImpl.java | 6 +- .../SessionFactoryOptionsBuilder.java | 20 +- .../boot/spi/AbstractDelegatingMetadata.java | 1 + ...stractDelegatingSessionFactoryBuilder.java | 6 +- ...stractDelegatingSessionFactoryOptions.java | 6 +- .../boot/spi/MetadataImplementor.java | 2 + .../boot/spi/SessionFactoryOptions.java | 12 +- .../AbstractDomainDataCachingConfig.java | 26 + .../CollectionDataCachingConfigImpl.java | 56 + .../internal/DomainDataRegionConfigImpl.java | 163 +++ .../internal/EntityDataCachingConfigImpl.java | 71 ++ .../NaturalIdDataCachingConfigImpl.java | 64 ++ .../org/hibernate/cache/cfg/package-info.java | 11 + .../cfg/spi/CollectionDataCachingConfig.java | 22 + .../cfg/spi/DomainDataCachingConfig.java | 38 + .../spi/DomainDataRegionBuildingContext.java | 35 + .../cache/cfg/spi/DomainDataRegionConfig.java | 33 + .../cfg/spi/EntityDataCachingConfig.java | 47 + .../cfg/spi/NaturalIdDataCachingConfig.java | 16 + .../internal/CacheDataDescriptionImpl.java | 106 -- .../internal/CollectionCacheInvalidator.java | 2 + .../cache/internal/DisabledCaching.java | 230 ++++ .../cache/internal/EnabledCaching.java | 599 ++++++++++ .../internal/NoCachingRegionFactory.java | 43 +- ...CachingTransactionSynchronizationImpl.java | 19 + ....java => QueryResultRegionAccessImpl.java} | 353 +++--- .../internal/StandardQueryCacheFactory.java | 28 - ...StandardTimestampsRegionAccessFactory.java | 30 + .../TimestampsRegionAccessDisabledImpl.java | 47 + .../TimestampsRegionAccessEnabledImpl.java | 146 +++ ...stractCacheTransactionSynchronization.java | 60 + .../cache/spi/AbstractDomainDataRegion.java | 210 ++++ .../cache/spi/CacheDataDescription.java | 49 - .../hibernate/cache/spi/CacheImplementor.java | 258 +++++ .../spi/CacheTransactionSynchronization.java | 102 ++ .../hibernate/cache/spi/CollectionRegion.java | 35 - .../cache/spi/DirectAccessRegion.java | 42 + .../hibernate/cache/spi/DomainDataRegion.java | 52 + .../org/hibernate/cache/spi/EntityRegion.java | 30 - .../cache/spi/ExtendedStatisticsSupport.java | 20 + .../cache/spi/GeneralDataRegion.java | 58 - .../hibernate/cache/spi/NaturalIdRegion.java | 31 - .../cache/spi/OptimisticCacheSource.java | 38 - .../org/hibernate/cache/spi/QueryCache.java | 27 +- .../cache/spi/QueryCacheFactory.java | 27 - .../cache/spi/QueryResultRegionAccess.java | 121 ++ .../cache/spi/QueryResultsRegion.java | 10 +- .../cache/spi/QuerySpacesHelper.java | 41 + .../java/org/hibernate/cache/spi/Region.java | 77 +- .../hibernate/cache/spi/RegionFactory.java | 235 +--- .../cache/spi/SecondLevelCacheLogger.java | 32 + .../hibernate/cache/spi/TimestampsRegion.java | 13 +- .../cache/spi/TimestampsRegionAccess.java | 105 ++ .../spi/TimestampsRegionAccessFactory.java | 17 + .../cache/spi/TransactionAwareCache.java | 15 - .../cache/spi/TransactionalDataRegion.java | 43 - .../cache/spi/UpdateTimestampsCache.java | 170 +-- .../spi/access/CachedDomainDataAccess.java | 189 +++ ...trategy.java => CollectionDataAccess.java} | 34 +- ...essStrategy.java => EntityDataAccess.java} | 58 +- ...Strategy.java => NaturalIdDataAccess.java} | 65 +- .../spi/access/RegionAccessStrategy.java | 149 --- .../hibernate/cache/spi/access/SoftLock.java | 6 +- .../access/UnknownAccessTypeException.java | 6 +- .../hibernate/cache/spi/access/package.html | 8 +- .../org/hibernate/cfg/AvailableSettings.java | 3 +- .../main/java/org/hibernate/cfg/Settings.java | 8 +- .../engine/internal/CacheHelper.java | 6 +- .../internal/NaturalIdXrefDelegate.java | 12 +- .../internal/StatefulPersistenceContext.java | 17 +- .../engine/internal/TwoPhaseLoad.java | 5 +- .../internal/CollectionLoadContext.java | 9 +- .../org/hibernate/engine/spi/ActionQueue.java | 20 +- .../hibernate/engine/spi/BatchFetchQueue.java | 8 +- .../engine/spi/CacheImplementor.java | 128 --- .../hibernate/engine/spi/CacheInitiator.java | 8 +- .../engine/spi/SessionDelegatorBaseImpl.java | 16 + .../spi/SessionFactoryDelegatingImpl.java | 47 +- .../engine/spi/SessionFactoryImplementor.java | 144 +-- .../spi/SharedSessionContractImplementor.java | 23 +- .../AbstractLockUpgradeEventListener.java | 4 +- .../DefaultFlushEntityEventListener.java | 2 +- ...aultInitializeCollectionEventListener.java | 10 +- .../internal/DefaultLoadEventListener.java | 10 +- .../internal/DefaultMergeEventListener.java | 3 +- .../internal/DefaultRefreshEventListener.java | 22 +- .../DefaultResolveNaturalIdEventListener.java | 11 +- .../AbstractSharedSessionContract.java | 54 +- .../org/hibernate/internal/CacheImpl.java | 519 --------- .../ConnectionObserverStatsBridge.java | 4 +- .../internal/SessionFactoryImpl.java | 7 +- .../org/hibernate/internal/SessionImpl.java | 8 + .../internal/StatelessSessionImpl.java | 16 +- .../internal/log/DeprecationLogger.java | 2 +- .../java/org/hibernate/loader/Loader.java | 19 +- .../hibernate/loader/custom/CustomLoader.java | 4 +- .../metamodel/internal/MetamodelImpl.java | 76 +- .../metamodel/model/domain/NavigableRole.java | 104 ++ .../AbstractCollectionPersister.java | 30 +- .../collection/BasicCollectionPersister.java | 4 +- .../collection/CollectionPersister.java | 10 +- .../collection/OneToManyPersister.java | 4 +- .../entity/AbstractEntityPersister.java | 37 +- .../persister/entity/EntityPersister.java | 17 +- .../entity/JoinedSubclassEntityPersister.java | 8 +- .../entity/SingleTableEntityPersister.java | 8 +- .../entity/UnionSubclassEntityPersister.java | 8 +- .../internal/PersisterFactoryImpl.java | 24 +- .../persister/spi/PersisterFactory.java | 16 +- .../resource/jdbc/spi/JdbcSessionOwner.java | 8 + ...sourceLocalTransactionCoordinatorImpl.java | 9 +- .../JtaTransactionCoordinatorImpl.java | 3 + .../spi/TransactionCoordinatorOwner.java | 10 + .../hibernate/stat/CacheRegionStatistics.java | 66 ++ .../stat/CacheableDataStatistics.java | 36 + .../hibernate/stat/CollectionStatistics.java | 24 +- .../org/hibernate/stat/EntityStatistics.java | 32 +- .../stat/NaturalIdCacheStatistics.java | 52 +- .../hibernate/stat/NaturalIdStatistics.java | 51 + .../org/hibernate/stat/QueryStatistics.java | 13 +- .../stat/SecondLevelCacheStatistics.java | 29 +- .../org/hibernate/stat/SessionStatistics.java | 8 +- .../java/org/hibernate/stat/Statistics.java | 130 ++- .../AbstractCacheableDataStatistics.java | 82 ++ .../internal/CacheRegionStatisticsImpl.java | 97 ++ .../internal/CollectionStatisticsImpl.java | 91 ++ .../ConcurrentCollectionStatisticsImpl.java | 80 -- .../ConcurrentEntityStatisticsImpl.java | 91 -- ...currentSecondLevelCacheStatisticsImpl.java | 111 -- ...eprecatedNaturalIdCacheStatisticsImpl.java | 257 +++++ .../stat/internal/EntityStatisticsImpl.java | 100 ++ ...Impl.java => NaturalIdStatisticsImpl.java} | 118 +- ...ticsImpl.java => QueryStatisticsImpl.java} | 47 +- ...tatisticsImpl.java => StatisticsImpl.java} | 1009 +++++++++-------- .../stat/internal/StatisticsInitiator.java | 2 +- .../stat/spi/StatisticsImplementor.java | 17 +- .../PersisterClassProviderTest.java | 19 +- .../ConcurrentQueryStatisticsTest.java | 3 +- .../internal/ConcurrentStatisticsTest.java | 18 +- .../persister/CollectionPersister.java | 4 +- .../persister/EntityPersister.java | 8 +- .../lazyCache/InitFromCacheTest.java | 64 +- .../cache/CollectionCacheEvictionTest.java | 8 +- .../test/cache/InsertedDataTest.java | 38 +- .../QualifiedRegionNameHandlingTest.java | 51 + .../test/cache/SharedRegionTest.java | 7 - .../GoofyPersisterClassProvider.java | 30 +- ...StructuredCachingOfConvertedValueTest.java | 47 +- ...structuredCachingOfConvertedValueTest.java | 45 +- .../test/filter/DynamicFilterTest.java | 11 +- .../test/legacy/CustomPersister.java | 19 +- ...edMutableNaturalIdStrictReadWriteTest.java | 19 +- .../cache/CacheLazyLoadNoTransTest.java | 10 +- .../test/querycache/QueryCacheTest.java | 126 +- ...ransactionCoordinatorOwnerTestingImpl.java | 4 + .../src/test/resources/log4j.properties | 3 + .../ehcache/AbstractEhcacheRegionFactory.java | 4 - .../nonstop/NonstopAccessStrategyFactory.java | 3 - ...opAwareCollectionRegionAccessStrategy.java | 3 - ...onstopAwareEntityRegionAccessStrategy.java | 3 - ...topAwareNaturalIdRegionAccessStrategy.java | 3 - .../regions/EhcacheCollectionRegion.java | 3 - .../internal/regions/EhcacheEntityRegion.java | 3 - .../regions/EhcacheGeneralDataRegion.java | 1 - .../regions/EhcacheNaturalIdRegion.java | 3 - .../EhcacheTransactionalDataRegion.java | 2 - .../AbstractEhcacheAccessStrategy.java | 2 - ...bstractReadWriteEhcacheAccessStrategy.java | 4 +- .../EhcacheAccessStrategyFactory.java | 3 - .../EhcacheAccessStrategyFactoryImpl.java | 3 - ...EhcacheCollectionRegionAccessStrategy.java | 3 - ...riteEhcacheEntityRegionAccessStrategy.java | 3 - ...eEhcacheNaturalIdRegionAccessStrategy.java | 3 - ...EhcacheCollectionRegionAccessStrategy.java | 3 - ...OnlyEhcacheEntityRegionAccessStrategy.java | 3 - ...yEhcacheNaturalIdRegionAccessStrategy.java | 3 - ...EhcacheCollectionRegionAccessStrategy.java | 2 - ...riteEhcacheEntityRegionAccessStrategy.java | 3 - ...eEhcacheNaturalIdRegionAccessStrategy.java | 3 - ...EhcacheCollectionRegionAccessStrategy.java | 3 - ...onalEhcacheEntityRegionAccessStrategy.java | 3 - ...lEhcacheNaturalIdRegionAccessStrategy.java | 2 - .../management/impl/CacheRegionStats.java | 4 +- .../management/impl/HibernateStatsImpl.java | 2 +- .../test/cache/HibernateCacheTest.java | 13 +- .../test/cache/ehcache/EhCacheTest.java | 12 +- .../ehcache/functional/InsertedDataTest.java | 16 +- .../cache/jcache/JCacheCollectionRegion.java | 3 - .../cache/jcache/JCacheEntityRegion.java | 3 - .../cache/jcache/JCacheGeneralDataRegion.java | 1 - .../cache/jcache/JCacheNaturalIdRegion.java | 3 - .../cache/jcache/JCacheRegionFactory.java | 4 - .../jcache/JCacheTransactionalDataRegion.java | 2 - ...AbstractReadWriteRegionAccessStrategy.java | 3 +- .../access/JCacheRegionAccessStrategy.java | 2 - ...nStrictCollectionRegionAccessStrategy.java | 1 - .../NonStrictEntityRegionAccessStrategy.java | 2 - ...onStrictNaturalIdRegionAccessStrategy.java | 2 - ...eadOnlyCollectionRegionAccessStrategy.java | 1 - .../ReadOnlyEntityRegionAccessStrategy.java | 2 - ...ReadOnlyNaturalIdRegionAccessStrategy.java | 2 - ...adWriteCollectionRegionAccessStrategy.java | 4 +- .../ReadWriteEntityRegionAccessStrategy.java | 2 - ...eadWriteNaturalIdRegionAccessStrategy.java | 2 - .../test/cache/HibernateCacheTest.java | 13 +- .../jcache/functional/InsertedDataTest.java | 16 +- .../cache/AbstractCachedDomainDataAccess.java | 149 +++ .../cache/AbstractDirectAccessRegion.java | 62 + .../cache/AbstractReadWriteAccess.java | 422 +++++++ .../AbstractReadWriteAccessStrategy.java | 368 ------ .../testing/cache/AbstractRegion.java | 30 + .../cache/BaseCollectionDataAccess.java | 55 + .../BaseCollectionRegionAccessStrategy.java | 50 - .../testing/cache/BaseEntityDataAccess.java | 68 ++ .../cache/BaseEntityRegionAccessStrategy.java | 74 -- .../testing/cache/BaseGeneralDataRegion.java | 63 - .../cache/BaseNaturalIdDataAccess.java | 83 ++ .../BaseNaturalIdRegionAccessStrategy.java | 70 -- .../hibernate/testing/cache/BaseRegion.java | 83 -- .../cache/BaseRegionAccessStrategy.java | 118 -- .../cache/BaseTransactionalDataRegion.java | 33 - .../CacheTransactionSynchronizationImpl.java | 23 + .../testing/cache/CachingRegionFactory.java | 70 +- .../CollectionNonStrictReadWriteAccess.java | 27 + .../cache/CollectionReadOnlyAccess.java | 20 + .../cache/CollectionReadWriteAccess.java | 80 ++ .../testing/cache/CollectionRegionImpl.java | 64 -- .../cache/CollectionTransactionAccess.java | 20 + .../testing/cache/DomainDataRegionImpl.java | 125 ++ .../cache/EntityNonStrictReadWriteAccess.java | 72 ++ .../testing/cache/EntityReadOnlyAccess.java | 64 ++ .../testing/cache/EntityReadWriteAccess.java | 135 +++ .../testing/cache/EntityRegionImpl.java | 62 - .../cache/EntityTransactionalAccess.java | 61 + ...=> NaturalIdNonStrictReadWriteAccess.java} | 30 +- .../cache/NaturalIdReadOnlyAccess.java | 30 + .../cache/NaturalIdReadWriteAccess.java | 107 ++ .../testing/cache/NaturalIdRegionImpl.java | 60 - .../cache/NaturalIdTransactionalAccess.java | 20 + ...adWriteCollectionRegionAccessStrategy.java | 30 - ...ctReadWriteEntityRegionAccessStrategy.java | 66 -- .../testing/cache/QueryResultsRegionImpl.java | 28 + ...eadOnlyCollectionRegionAccessStrategy.java | 16 - .../ReadOnlyEntityRegionAccessStrategy.java | 70 -- ...ReadOnlyNaturalIdRegionAccessStrategy.java | 25 - ...adWriteCollectionRegionAccessStrategy.java | 58 - .../ReadWriteEntityRegionAccessStrategy.java | 120 -- ...eadWriteNaturalIdRegionAccessStrategy.java | 117 -- .../testing/cache/SoftLockingSupport.java | 18 + .../testing/cache/TimestampsRegionImpl.java | 28 + ...ctionalCollectionRegionAccessStrategy.java | 25 - ...ansactionalEntityRegionAccessStrategy.java | 42 - ...actionalNaturalIdRegionAccessStrategy.java | 25 - migration-guide.adoc | 36 + 267 files changed, 7878 insertions(+), 5477 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/AbstractDomainDataCachingConfig.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/CollectionDataCachingConfigImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/DomainDataRegionConfigImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/EntityDataCachingConfigImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/NaturalIdDataCachingConfigImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/package-info.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/CollectionDataCachingConfig.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataCachingConfig.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionBuildingContext.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionConfig.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/EntityDataCachingConfig.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/NaturalIdDataCachingConfig.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/DisabledCaching.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingTransactionSynchronizationImpl.java rename hibernate-core/src/main/java/org/hibernate/cache/internal/{StandardQueryCache.java => QueryResultRegionAccessImpl.java} (50%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCacheFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/StandardTimestampsRegionAccessFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessDisabledImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessEnabledImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractCacheTransactionSynchronization.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractDomainDataRegion.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/CacheDataDescription.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/CacheImplementor.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/CacheTransactionSynchronization.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/CollectionRegion.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/DirectAccessRegion.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/DomainDataRegion.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/EntityRegion.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/ExtendedStatisticsSupport.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/GeneralDataRegion.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/OptimisticCacheSource.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCacheFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultRegionAccess.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/QuerySpacesHelper.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/SecondLevelCacheLogger.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccess.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccessFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionAwareCache.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionalDataRegion.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/access/CachedDomainDataAccess.java rename hibernate-core/src/main/java/org/hibernate/cache/spi/access/{CollectionRegionAccessStrategy.java => CollectionDataAccess.java} (57%) rename hibernate-core/src/main/java/org/hibernate/cache/spi/access/{EntityRegionAccessStrategy.java => EntityDataAccess.java} (66%) rename hibernate-core/src/main/java/org/hibernate/cache/spi/access/{NaturalIdRegionAccessStrategy.java => NaturalIdDataAccess.java} (63%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/engine/spi/CacheImplementor.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/internal/CacheImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/NavigableRole.java create mode 100755 hibernate-core/src/main/java/org/hibernate/stat/CacheRegionStatistics.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/CacheableDataStatistics.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/NaturalIdStatistics.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/AbstractCacheableDataStatistics.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/CacheRegionStatisticsImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/CollectionStatisticsImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentCollectionStatisticsImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentEntityStatisticsImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentSecondLevelCacheStatisticsImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/DeprecatedNaturalIdCacheStatisticsImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/stat/internal/EntityStatisticsImpl.java rename hibernate-core/src/main/java/org/hibernate/stat/internal/{ConcurrentNaturalIdCacheStatisticsImpl.java => NaturalIdStatisticsImpl.java} (52%) rename hibernate-core/src/main/java/org/hibernate/stat/internal/{ConcurrentQueryStatisticsImpl.java => QueryStatisticsImpl.java} (89%) rename hibernate-core/src/main/java/org/hibernate/stat/internal/{ConcurrentStatisticsImpl.java => StatisticsImpl.java} (65%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cache/QualifiedRegionNameHandlingTest.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractCachedDomainDataAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractDirectAccessRegion.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractRegion.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionDataAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityDataAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseGeneralDataRegion.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdDataAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseTransactionalDataRegion.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/CacheTransactionSynchronizationImpl.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionNonStrictReadWriteAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadOnlyAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadWriteAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionRegionImpl.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionTransactionAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/DomainDataRegionImpl.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityNonStrictReadWriteAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadOnlyAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadWriteAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityRegionImpl.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityTransactionalAccess.java rename hibernate-testing/src/main/java/org/hibernate/testing/cache/{NonstrictReadWriteNaturalIdRegionAccessStrategy.java => NaturalIdNonStrictReadWriteAccess.java} (53%) create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadOnlyAccess.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadWriteAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdTransactionalAccess.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteCollectionRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteEntityRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/QueryResultsRegionImpl.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyCollectionRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyEntityRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteCollectionRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteEntityRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/SoftLockingSupport.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/TimestampsRegionImpl.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalCollectionRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalEntityRegionAccessStrategy.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java diff --git a/documentation/src/test/java/org/hibernate/userguide/caching/SecondLevelCacheTest.java b/documentation/src/test/java/org/hibernate/userguide/caching/SecondLevelCacheTest.java index 981455a02d..20ec3f0896 100644 --- a/documentation/src/test/java/org/hibernate/userguide/caching/SecondLevelCacheTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/caching/SecondLevelCacheTest.java @@ -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 ); diff --git a/documentation/src/test/java/org/hibernate/userguide/persister/CollectionPersister.java b/documentation/src/test/java/org/hibernate/userguide/persister/CollectionPersister.java index 79b64b7cd3..550bf93d76 100644 --- a/documentation/src/test/java/org/hibernate/userguide/persister/CollectionPersister.java +++ b/documentation/src/test/java/org/hibernate/userguide/persister/CollectionPersister.java @@ -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; diff --git a/documentation/src/test/java/org/hibernate/userguide/persister/EntityPersister.java b/documentation/src/test/java/org/hibernate/userguide/persister/EntityPersister.java index 0beef27486..09509c05d0 100644 --- a/documentation/src/test/java/org/hibernate/userguide/persister/EntityPersister.java +++ b/documentation/src/test/java/org/hibernate/userguide/persister/EntityPersister.java @@ -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; diff --git a/hibernate-core/src/main/java/org/hibernate/Cache.java b/hibernate-core/src/main/java/org/hibernate/Cache.java index b4b33cf9de..f6346e11cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/Cache.java +++ b/hibernate-core/src/main/java/org/hibernate/Cache.java @@ -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". *

@@ -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(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java index b0c296fb32..9ce75bb989 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java @@ -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 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(); diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java index 083f5d76b1..e8462168b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java @@ -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, diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index 66450e12d7..666d551c0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -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, diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java index 63760711f1..9763cc8ba4 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java @@ -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(); diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index 1aa7d11b4f..c9f6782236 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -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 { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index f8d5483be2..717ab7872c 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -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 { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java index 236e7d21fd..86b12653ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java @@ -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. diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index a8b544262b..d4f4dde7c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -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 fetchProfileMap = new HashMap(); private final Map idGeneratorDefinitionMap = new HashMap(); + private final Map regionConfigBuilders = new ConcurrentHashMap<>(); + private Map 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() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java index e6eb2510b6..44b9ce7673 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java @@ -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 sqlResultSetMappingMap; private final Map namedEntityGraphMap; private final Map sqlFunctionMap; + private final java.util.Collection cacheRegionConfigBuilders; private final Database database; public MetadataImpl( @@ -98,6 +100,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable { Map sqlResultSetMappingMap, Map namedEntityGraphMap, Map sqlFunctionMap, + java.util.Collection 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; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java index 8345e12ad0..d91548e4ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java @@ -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; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index a18dfb55d7..619185ff35 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -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) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadata.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadata.java index cfe3d1e0d9..bb9c4c168f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadata.java @@ -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; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java index a5e49def13..cf8aba5ec7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java @@ -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 entityConfigs; + private final List naturalIdConfigs; + private final List collectionConfigs; + + private DomainDataRegionConfigImpl( + String regionName, + List entityConfigs, + List naturalIdConfigs, + List collectionConfigs) { + this.regionName = regionName; + this.entityConfigs = entityConfigs; + this.naturalIdConfigs = naturalIdConfigs; + this.collectionConfigs = collectionConfigs; + } + + @Override + public String getRegionName() { + return regionName; + } + + @Override + public List getEntityCaching() { + return entityConfigs; + } + + @Override + public List getNaturalIdCaching() { + return naturalIdConfigs; + } + + @Override + public List getCollectionCaching() { + return collectionConfigs; + } + + public static class Builder { + private final String regionName; + + private Map entityConfigsByRootName; + private List naturalIdConfigs; + private List 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) () -> ( (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 List finalize(Map configs) { + return configs == null + ? Collections.emptyList() + : Collections.unmodifiableList( new ArrayList( configs.values() ) ); + } + + private List finalize(List configs) { + return configs == null + ? Collections.emptyList() + : Collections.unmodifiableList( configs ); + } + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/EntityDataCachingConfigImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/EntityDataCachingConfigImpl.java new file mode 100644 index 0000000000..a4f9c02f46 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/EntityDataCachingConfigImpl.java @@ -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 versionComparatorAccess; + private final boolean isEntityMutable; + + private final Set cachedTypes = new HashSet<>(); + + public EntityDataCachingConfigImpl( + NavigableRole rootEntityName, + Supplier versionComparatorAccess, + boolean isEntityMutable, + AccessType accessType) { + super( accessType ); + this.navigableRole = rootEntityName; + this.versionComparatorAccess = versionComparatorAccess; + this.isEntityMutable = isEntityMutable; + } + + @Override + public Supplier 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 getCachedTypes() { + return cachedTypes; + } + + public void addCachedType(NavigableRole typeRole) { + cachedTypes.add( typeRole ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/NaturalIdDataCachingConfigImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/NaturalIdDataCachingConfigImpl.java new file mode 100644 index 0000000000..7ed683e3ab --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/internal/NaturalIdDataCachingConfigImpl.java @@ -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; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/package-info.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/package-info.java new file mode 100644 index 0000000000..e8df17b908 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/package-info.java @@ -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; diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/CollectionDataCachingConfig.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/CollectionDataCachingConfig.java new file mode 100644 index 0000000000..f690fa8722 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/CollectionDataCachingConfig.java @@ -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(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataCachingConfig.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataCachingConfig.java new file mode 100644 index 0000000000..5056a7b54d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataCachingConfig.java @@ -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(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionBuildingContext.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionBuildingContext.java new file mode 100644 index 0000000000..cd6e078ce6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionBuildingContext.java @@ -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(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionConfig.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionConfig.java new file mode 100644 index 0000000000..48ddfa0419 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/DomainDataRegionConfig.java @@ -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 getEntityCaching(); + + /** + * Retrieve the list of all natural-id data to be stored in this region + */ + List getNaturalIdCaching(); + + /** + * Retrieve the list of all collection data to be stored in this region + */ + List getCollectionCaching(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/EntityDataCachingConfig.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/EntityDataCachingConfig.java new file mode 100644 index 0000000000..5d7347f133 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/EntityDataCachingConfig.java @@ -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 getVersionComparatorAccess(); + + /** + * The list of specific subclasses of the root that are actually + * written to cache. + */ + Set getCachedTypes(); + + // todo (5.3) : what else is needed here? +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/NaturalIdDataCachingConfig.java b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/NaturalIdDataCachingConfig.java new file mode 100644 index 0000000000..d25c63b47c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/cfg/spi/NaturalIdDataCachingConfig.java @@ -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 { +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java deleted file mode 100644 index 3e3f123155..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/CacheDataDescriptionImpl.java +++ /dev/null @@ -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 . - */ -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() - ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java index f24ed358ca..b22ab86d84 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java @@ -194,5 +194,7 @@ public class CollectionCacheInvalidator beforeExecutions(); return getAfterTransactionCompletionProcess(); } + + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/DisabledCaching.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/DisabledCaching.java new file mode 100644 index 0000000000..93442b3a89 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/DisabledCaching.java @@ -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 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 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 unwrap(Class cls) { + return (T) this; + } + + @Override + public Set getNaturalIdAccessesInRegion(String regionName) { + return Collections.emptySet(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java new file mode 100644 index 0000000000..d5be434e34 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java @@ -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 regionsByName = new ConcurrentHashMap<>(); + + private final Map entityAccessMap = new ConcurrentHashMap<>(); + private final Map naturalIdAccessMap = new ConcurrentHashMap<>(); + private final Map collectionAccessMap = new ConcurrentHashMap<>(); + + private final TimestampsRegionAccess timestampsRegionAccess; + + private final QueryResultRegionAccess defaultQueryResultsRegionAccess; + private final Map namedQueryResultsRegionAccess = new ConcurrentHashMap<>(); + + + private final Set legacySecondLevelCacheNames = new LinkedHashSet<>(); + private final Map> 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 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 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 getCacheRegionNames() { + return regionsByName.keySet(); + } + + @Override + public void evictRegion(String regionName) { + getRegion( regionName ).clear(); + } + + @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 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 getNaturalIdAccessesInRegion(String regionName) { + return legacyNaturalIdAccessesForRegion.get( regionName ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java index 0fadf4b98e..65155a7ef4 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingRegionFactory.java @@ -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(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingTransactionSynchronizationImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingTransactionSynchronizationImpl.java new file mode 100644 index 0000000000..b6914f3a48 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/NoCachingTransactionSynchronizationImpl.java @@ -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 ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCache.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultRegionAccessImpl.java similarity index 50% rename from hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCache.java rename to hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultRegionAccessImpl.java index f0b7010f5f..d927e77185 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCache.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultRegionAccessImpl.java @@ -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 . + * 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 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 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 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; + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCacheFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCacheFactory.java deleted file mode 100644 index f0d0b4d0f2..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardQueryCacheFactory.java +++ /dev/null @@ -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 . - */ -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 ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardTimestampsRegionAccessFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardTimestampsRegionAccessFactory.java new file mode 100644 index 0000000000..103c3bc56c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/StandardTimestampsRegionAccessFactory.java @@ -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 ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessDisabledImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessDisabledImpl.java new file mode 100644 index 0000000000..55f573bbe8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessDisabledImpl.java @@ -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; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessEnabledImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessEnabledImpl.java new file mode 100644 index 0000000000..1ce3d90904 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsRegionAccessEnabledImpl.java @@ -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; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractCacheTransactionSynchronization.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractCacheTransactionSynchronization.java new file mode 100644 index 0000000000..b686893bcd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractCacheTransactionSynchronization.java @@ -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. + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractDomainDataRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractDomainDataRegion.java new file mode 100644 index 0000000000..6c59c1ad27 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/AbstractDomainDataRegion.java @@ -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 entityDataAccessMap; + private final Map naturalIdDataAccessMap; + private final Map 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 generateEntityDataAccessMap( + DomainDataRegionConfig regionConfig) { + if ( regionConfig.getEntityCaching().isEmpty() ) { + return Collections.emptyMap(); + } + + final Map accessMap = new ConcurrentHashMap<>(); + for ( EntityDataCachingConfig entityAccessConfig : regionConfig.getEntityCaching() ) { + accessMap.computeIfAbsent( + entityAccessConfig.getNavigableRole(), + hierarchy -> generateEntityAccess( entityAccessConfig ) + ); + } + + return Collections.unmodifiableMap( accessMap ); + } + + private Map generateNaturalIdDataAccessMap(DomainDataRegionConfig regionConfig) { + if ( regionConfig.getNaturalIdCaching().isEmpty() ) { + return Collections.emptyMap(); + } + + final Map accessMap = new ConcurrentHashMap<>(); + for ( NaturalIdDataCachingConfig naturalIdAccessConfig : regionConfig.getNaturalIdCaching() ) { + accessMap.computeIfAbsent( + naturalIdAccessConfig.getNavigableRole(), + hierarchy -> generateNaturalIdAccess( naturalIdAccessConfig ) + ); + } + + return Collections.unmodifiableMap( accessMap ); + } + + private Map generateCollectionDataAccessMap( + DomainDataRegionConfig regionConfig) { + if ( regionConfig.getCollectionCaching().isEmpty() ) { + return Collections.emptyMap(); + } + + final Map 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 ); + } + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheDataDescription.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheDataDescription.java deleted file mode 100644 index 850075284c..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheDataDescription.java +++ /dev/null @@ -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 . - */ -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} if - * {@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(); -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheImplementor.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheImplementor.java new file mode 100644 index 0000000000..2e01e1bc57 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheImplementor.java @@ -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 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 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 region name 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 getNaturalIdAccessesInRegion(String legacyQualifiedRegionName); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheTransactionSynchronization.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheTransactionSynchronization.java new file mode 100644 index 0000000000..415abdc70c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/CacheTransactionSynchronization.java @@ -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 + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/CollectionRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/CollectionRegion.java deleted file mode 100644 index 7f77c636d2..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/CollectionRegion.java +++ /dev/null @@ -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 . - */ -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. - *

- * 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; -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/DirectAccessRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/DirectAccessRegion.java new file mode 100644 index 0000000000..07f3c039cf --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/DirectAccessRegion.java @@ -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(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/DomainDataRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/DomainDataRegion.java new file mode 100644 index 0000000000..a9230ef7cf --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/DomainDataRegion.java @@ -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); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/EntityRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/EntityRegion.java deleted file mode 100644 index ecd3139beb..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/EntityRegion.java +++ /dev/null @@ -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 . - */ -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; -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/ExtendedStatisticsSupport.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/ExtendedStatisticsSupport.java new file mode 100644 index 0000000000..3577e18387 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/ExtendedStatisticsSupport.java @@ -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(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/GeneralDataRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/GeneralDataRegion.java deleted file mode 100644 index 6abcadf4a3..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/GeneralDataRegion.java +++ /dev/null @@ -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 . - */ -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 null - * - * @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; -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java deleted file mode 100644 index b6c571dcee..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/NaturalIdRegion.java +++ /dev/null @@ -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 . - */ -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; -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/OptimisticCacheSource.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/OptimisticCacheSource.java deleted file mode 100644 index 20f67f4f1d..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/OptimisticCacheSource.java +++ /dev/null @@ -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 . - */ -package org.hibernate.cache.spi; - -import java.util.Comparator; - -/** - * Contract for sources of optimistically lockable data sent to the second level - * cache. - *

- * 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? - *

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

- * May return null if {@link #isVersioned()} returns false. - * @return Comparator used to compare two different version values. - */ - public Comparator getVersionComparator(); -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCache.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCache.java index 0ba1b8c0b1..ac71b5bc06 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCache.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCache.java @@ -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 . + * 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 spaces, - SharedSessionContractImplementor session) throws HibernateException; + SharedSessionContractImplementor session); /** * Destroy the cache. diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCacheFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCacheFactory.java deleted file mode 100644 index b6c55ebf48..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryCacheFactory.java +++ /dev/null @@ -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 . - */ -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); -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultRegionAccess.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultRegionAccess.java new file mode 100644 index 0000000000..bfd6b22aa2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultRegionAccess.java @@ -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 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 spaces, + SharedSessionContractImplementor session) { + return get( key, spaces, returnTypes, session ); + } + + @Override + default void destroy() { + // nothing to do.. the region itself gets destroyed + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultsRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultsRegion.java index def8aaf739..35b6a71189 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultsRegion.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/QueryResultsRegion.java @@ -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 . + * 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(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/QuerySpacesHelper.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/QuerySpacesHelper.java new file mode 100644 index 0000000000..0eeb66cd4d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/QuerySpacesHelper.java @@ -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 toStringSet(String[] spacesArray) { + final HashSet set = new HashSet<>(); + Collections.addAll( set, spacesArray ); + return set; + } + + public Set toSerializableSet(String[] spacesArray) { + final HashSet set = new HashSet<>(); + Collections.addAll( set, spacesArray ); + return set; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/Region.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/Region.java index ec7493d991..1d2b4a5237 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/Region.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/Region.java @@ -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 . + * 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. - *

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

- * 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(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/RegionFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/RegionFactory.java index f9a68f4015..19585aa786 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/RegionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/RegionFactory.java @@ -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 . + * 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; *

  • MyRegionFactoryImpl()
  • * * 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 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. - *

    - * 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 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 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 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 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 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); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/SecondLevelCacheLogger.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/SecondLevelCacheLogger.java new file mode 100644 index 0000000000..2c30cfc309 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/SecondLevelCacheLogger.java @@ -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 + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegion.java index 88fa3a7454..a7c86c5a8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegion.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegion.java @@ -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 . + * 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(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccess.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccess.java new file mode 100644 index 0000000000..1ea7beec60 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccess.java @@ -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 spaces, + Long timestamp, + SharedSessionContractImplementor session) { + final String[] spaceArray = new String[ spaces.size() ]; + + spaces.forEach( + new Consumer() { + 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 + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccessFactory.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccessFactory.java new file mode 100644 index 0000000000..73d0de31c2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/TimestampsRegionAccessFactory.java @@ -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); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionAwareCache.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionAwareCache.java deleted file mode 100644 index 08fab8e0ff..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionAwareCache.java +++ /dev/null @@ -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 . - */ -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 { -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionalDataRegion.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionalDataRegion.java deleted file mode 100644 index 8151759c97..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/TransactionalDataRegion.java +++ /dev/null @@ -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 . - */ -package org.hibernate.cache.spi; - -/** - * Defines contract for regions which hold transactionally-managed data. - *

    - * 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? - *

    - * 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(); -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/UpdateTimestampsCache.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/UpdateTimestampsCache.java index 0c79b20abe..9e98e20fe3 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/UpdateTimestampsCache.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/UpdateTimestampsCache.java @@ -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 . + * 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 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 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(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CachedDomainDataAccess.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CachedDomainDataAccess.java new file mode 100644 index 0000000000..a7fee4220e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CachedDomainDataAccess.java @@ -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. + *

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

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

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

    + * 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(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionDataAccess.java similarity index 57% rename from hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java rename to hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionDataAccess.java index 621dc3c992..6b1383959e 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionRegionAccessStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/CollectionDataAccess.java @@ -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 . + * 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} *

    * 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(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityDataAccess.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java rename to hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityDataAccess.java index 9e01e4f4d0..fac7eff553 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityRegionAccessStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/EntityDataAccess.java @@ -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 . + * 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; *

  • INSERTS : {@link #insert} -> {@link #afterInsert}
  • *
  • UPDATES : {@link #lockItem} -> {@link #update} -> {@link #afterUpdate}
  • *
  • DELETES : {@link #lockItem} -> {@link #remove} -> {@link #unlockItem}
  • - *
  • LOADS : {@link @putFromLoad}
  • + *
  • LOADS : {@link #putFromLoad}
  • * *

    * 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); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdDataAccess.java similarity index 63% rename from hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java rename to hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdDataAccess.java index a899753fcd..11922e4413 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdRegionAccessStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/NaturalIdDataAccess.java @@ -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 . + * 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 *

    * 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} *

    * IMPORTANT : NaturalIds are not versioned so {@code null} will always be passed to the version parameter to:

    * * @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); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java deleted file mode 100644 index 96582b419a..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/RegionAccessStrategy.java +++ /dev/null @@ -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 . - */ -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 null - * @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 true 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 true 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. - *

    - * 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; -} diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/SoftLock.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/SoftLock.java index 6d39b15981..b37b7d32d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/SoftLock.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/SoftLock.java @@ -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 . + * 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 */ diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/UnknownAccessTypeException.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/UnknownAccessTypeException.java index e9f5df6795..1989d231e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/UnknownAccessTypeException.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/UnknownAccessTypeException.java @@ -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 . + * 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 * diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/package.html b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/package.html index f42d33a317..a84889bdb5 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/package.html +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/package.html @@ -8,13 +8,13 @@

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

      +
      • A transaction-aware cache implementation might be wrapped by a synchronous access strategy, where updates to the cache are written to the cache inside the transaction. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 68de591a75..d3327dc734 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -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"; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java index bf258ed132..5dbf67fd4d 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -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() { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java index 02784ffe32..39a7218b0a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java @@ -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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdXrefDelegate.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdXrefDelegate.java index 373048e2e7..eb315374cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdXrefDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdXrefDelegate.java @@ -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; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index 0fdd163b33..5018819df6 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java index 37dc266be6..28a53dafc8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java @@ -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 ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/CollectionLoadContext.java b/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/CollectionLoadContext.java index dcf6ee605a..1fa888960a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/CollectionLoadContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/CollectionLoadContext.java @@ -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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java index df89ea701c..1e64457d30 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java @@ -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 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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java index 98f96ebdea..1cd7d0ac5d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java @@ -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, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheImplementor.java deleted file mode 100644 index 47eaa450c2..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheImplementor.java +++ /dev/null @@ -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 . - */ -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 Cache API - * - * @author Strong Liu - */ -public interface CacheImplementor extends Service, Cache, Serializable { - - /** - * Close all cache regions. - */ - void close(); - - /** - * Get query cache by region name or create a new one if none exist. - *

        - * 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 null. - * @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 all 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); -} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java index 814ae3b4b2..66bdc04c70 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java @@ -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 - * {@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(); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java index 7903fcbc3e..dfcfb655b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java @@ -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 Session have an active Hibernate transaction diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractLockUpgradeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractLockUpgradeEventListener.java index d6c01c05c0..fcffbcd4cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractLockUpgradeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractLockUpgradeEventListener.java @@ -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() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java index d28de244bf..493411c3df 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java @@ -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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java index 2118ecd20b..9d30d460f2 100755 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java @@ -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() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java index 34c2906e73..e84e856060 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java @@ -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() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index 71ee951c2b..7f587cb585 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -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 ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java index 7bf4ca71be..73085caeb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java @@ -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() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java index c5e2e8b7ea..10da167ae1 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java @@ -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 diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index ed4d5c953c..dabea74d62 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -31,6 +31,7 @@ import org.hibernate.SessionException; import org.hibernate.Transaction; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.cache.spi.CacheTransactionSynchronization; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.engine.ResultSetMappingDefinition; @@ -108,6 +109,14 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont private final String tenantIdentifier; private final UUID sessionIdentifier; + private transient JdbcConnectionAccess jdbcConnectionAccess; + private transient JdbcSessionContext jdbcSessionContext; + private transient JdbcCoordinator jdbcCoordinator; + + private transient TransactionImplementor currentHibernateTransaction; + private transient TransactionCoordinator transactionCoordinator; + private transient CacheTransactionSynchronization cacheTransactionSync; + private final boolean isTransactionCoordinatorShared; private final Interceptor interceptor; @@ -124,13 +133,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont // transient & non-final for Serialization purposes - ugh private transient SessionEventListenerManagerImpl sessionEventsManager = new SessionEventListenerManagerImpl(); private transient EntityNameResolver entityNameResolver; - private transient JdbcConnectionAccess jdbcConnectionAccess; - private transient JdbcSessionContext jdbcSessionContext; - private transient JdbcCoordinator jdbcCoordinator; - private transient TransactionImplementor currentHibernateTransaction; - private transient TransactionCoordinator transactionCoordinator; private transient Boolean useStreamForLobBinding; - private transient long timestamp; private Integer jdbcBatchSize; @@ -139,7 +142,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreationOptions options) { this.factory = factory; this.sessionIdentifier = StandardRandomStrategy.INSTANCE.generateUUID( null ); - this.timestamp = factory.getCache().getRegionFactory().nextTimestamp(); + + this.cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this ); this.flushMode = options.getInitialSessionFlushMode(); @@ -273,11 +277,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont return tenantIdentifier; } - @Override - public long getTimestamp() { - return timestamp; - } - @Override public boolean isOpen() { return !isClosed(); @@ -407,6 +406,31 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont return this.currentHibernateTransaction; } + @Override + public void startTransactionBoundary() { + this.getCacheTransactionSynchronization().transactionJoined(); + } + + @Override + public void beforeTransactionCompletion() { + getCacheTransactionSynchronization().transactionCompleting(); + } + + @Override + public void afterTransactionCompletion(boolean successful, boolean delayed) { + getCacheTransactionSynchronization().transactionCompleted( successful ); + } + + @Override + public CacheTransactionSynchronization getCacheTransactionSynchronization() { + return cacheTransactionSync; + } + + @Override + public long getTransactionStartTimestamp() { + return getCacheTransactionSynchronization().getCurrentTransactionStartTimestamp(); + } + @Override public Transaction beginTransaction() { checkOpen(); @@ -414,8 +438,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont Transaction result = getTransaction(); result.begin(); - this.timestamp = factory.getCache().getRegionFactory().nextTimestamp(); - return result; } @@ -1085,7 +1107,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont jdbcSessionContext = new JdbcSessionContextImpl( this, (StatementInspector) ois.readObject() ); jdbcCoordinator = JdbcCoordinatorImpl.deserialize( ois, this ); - this.transactionCoordinator = factory.getServiceRegistry() + cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this ); + + transactionCoordinator = factory.getServiceRegistry() .getService( TransactionCoordinatorBuilder.class ) .buildTransactionCoordinator( jdbcCoordinator, this ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CacheImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/CacheImpl.java deleted file mode 100644 index c0af7cdc05..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/internal/CacheImpl.java +++ /dev/null @@ -1,519 +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 . - */ -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.mapping.RootClass; -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.canReadFromCache() ) { - 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.canWriteToCache() ) { - 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.canWriteToCache() ) { - 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() ); - } - - // todo (5.3) : normalize caching to the "first subclass" in the hierarchy whose subclasses all define caching - // 5.3 adds support for "subclass only" caching, so we need a different paradigm for - // code such as this that assumes root-only caching - - @Override - public EntityRegionAccessStrategy determineEntityRegionAccessStrategy(PersistentClass model) { - if ( ! settings.isSecondLevelCacheEnabled() ) { - return null; - } - - // cache settings are defined on root entity - final RootClass rootEntity = model.getRootClass(); - - final String cacheRegionName = cacheRegionPrefix + rootEntity.getCacheRegionName(); - EntityRegionAccessStrategy accessStrategy = entityRegionAccessStrategyMap.get( cacheRegionName ); - if ( accessStrategy == null ) { - final AccessType accessType = AccessType.fromExternalName( rootEntity.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; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/ConnectionObserverStatsBridge.java b/hibernate-core/src/main/java/org/hibernate/internal/ConnectionObserverStatsBridge.java index 9f91b9c549..3873444cf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/ConnectionObserverStatsBridge.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/ConnectionObserverStatsBridge.java @@ -25,7 +25,7 @@ public class ConnectionObserverStatsBridge implements ConnectionObserver, Serial @Override public void physicalConnectionObtained(Connection connection) { if ( sessionFactory.getStatistics().isStatisticsEnabled() ) { - sessionFactory.getStatisticsImplementor().connect(); + sessionFactory.getStatistics().connect(); } } @@ -40,7 +40,7 @@ public class ConnectionObserverStatsBridge implements ConnectionObserver, Serial @Override public void statementPrepared() { if ( sessionFactory.getStatistics().isStatisticsEnabled() ) { - sessionFactory.getStatisticsImplementor().prepareStatement(); + sessionFactory.getStatistics().prepareStatement(); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 34a8f7965d..796787ae8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -53,6 +53,7 @@ import org.hibernate.boot.cfgxml.spi.LoadedConfig; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.cache.spi.CacheImplementor; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.cfg.Settings; @@ -73,7 +74,6 @@ import org.hibernate.engine.profile.Fetch; import org.hibernate.engine.profile.FetchProfile; import org.hibernate.engine.query.spi.QueryPlanCache; import org.hibernate.engine.query.spi.ReturnMetadata; -import org.hibernate.engine.spi.CacheImplementor; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedQueryDefinitionBuilder; @@ -646,11 +646,6 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor { return getMetamodel().findEntityGraphByName( name ); } - @Override - public Map getAllSecondLevelCacheRegions() { - return null; - } - @Override public SessionFactoryOptions getSessionFactoryOptions() { return sessionFactoryOptions; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 53974c1a40..c02dd2c4db 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -2455,6 +2455,8 @@ public final class SessionImpl managedClose(); } } + + super.afterTransactionCompletion( successful, delayed ); } private static class LobHelperImpl implements LobHelper { @@ -3195,6 +3197,12 @@ public final class SessionImpl } } + @Override + public void startTransactionBoundary() { + checkOpenOrWaitingForAutoClose(); + super.startTransactionBoundary(); + } + @Override public void afterTransactionBegin() { checkOpenOrWaitingForAutoClose(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 5cd4462f24..375ed7a2c9 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -24,7 +24,7 @@ import org.hibernate.ScrollMode; import org.hibernate.SessionException; import org.hibernate.StatelessSession; import org.hibernate.UnresolvableObjectException; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.internal.StatefulPersistenceContext; import org.hibernate.engine.internal.Versioning; @@ -223,10 +223,18 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen // } if ( persister.canWriteToCache() ) { - final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy(); - final Object ck = cache.generateCacheKey( id, persister, getFactory(), getTenantIdentifier() ); - cache.evict( ck ); + final EntityDataAccess cacheAccess = persister.getCacheAccessStrategy(); + if ( cacheAccess != null ) { + final Object ck = cacheAccess.generateCacheKey( + id, + persister, + getFactory(), + getTenantIdentifier() + ); + cacheAccess.evict( ck ); + } } + String previousFetchProfile = this.getLoadQueryInfluencers().getInternalFetchProfile(); Object result = null; try { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 3bdecb0776..77dd1de4e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -24,7 +24,7 @@ import static org.jboss.logging.Logger.Level.WARN; @MessageLogger( projectCode = "HHH" ) @ValidIdRange( min = 90000001, max = 90001000 ) public interface DeprecationLogger extends BasicLogger { - public static final DeprecationLogger DEPRECATION_LOGGER = Logger.getMessageLogger( + DeprecationLogger DEPRECATION_LOGGER = Logger.getMessageLogger( DeprecationLogger.class, "org.hibernate.orm.deprecation" ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 87dc56a199..4cadd43b7a 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -32,9 +32,9 @@ import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.hibernate.WrongClassException; import org.hibernate.cache.spi.FilterKey; -import org.hibernate.cache.spi.QueryCache; import org.hibernate.cache.spi.QueryKey; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; +import org.hibernate.cache.spi.QueryResultRegionAccess; +import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl; import org.hibernate.collection.spi.PersistentCollection; @@ -67,7 +67,6 @@ import org.hibernate.internal.ScrollableResultsImpl; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.loader.spi.AfterLoadAction; -import org.hibernate.param.ParameterBinder; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Loadable; @@ -1640,7 +1639,7 @@ public abstract class Loader { // see if the entity defines reference caching, and if so use the cached reference (if one). if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) { - final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy(); + final EntityDataAccess cache = persister.getCacheAccessStrategy(); final Object ck = cache.generateCacheKey( key.getIdentifier(), persister, @@ -2513,7 +2512,7 @@ public abstract class Loader { final Set querySpaces, final Type[] resultTypes) { - QueryCache queryCache = factory.getCache().getQueryCache( queryParameters.getCacheRegion() ); + QueryResultRegionAccess queryCache = factory.getCache().getQueryResultsRegionAccess( queryParameters.getCacheRegion() ); QueryKey key = generateQueryKey( session, queryParameters ); @@ -2590,7 +2589,7 @@ public abstract class Loader { final QueryParameters queryParameters, final Set querySpaces, final Type[] resultTypes, - final QueryCache queryCache, + final QueryResultRegionAccess queryCache, final QueryKey key) { List result = null; @@ -2618,9 +2617,8 @@ public abstract class Loader { try { result = queryCache.get( key, - key.getResultTransformer().getCachedResultTypes( resultTypes ), - isImmutableNaturalKeyLookup, querySpaces, + key.getResultTransformer().getCachedResultTypes( resultTypes ), session ); } @@ -2649,15 +2647,14 @@ public abstract class Loader { final SharedSessionContractImplementor session, final QueryParameters queryParameters, final Type[] resultTypes, - final QueryCache queryCache, + final QueryResultRegionAccess queryCache, final QueryKey key, final List result) { if ( session.getCacheMode().isPutEnabled() ) { boolean put = queryCache.put( key, - key.getResultTransformer().getCachedResultTypes( resultTypes ), result, - queryParameters.isNaturalKeyLookup(), + key.getResultTransformer().getCachedResultTypes( resultTypes ), session ); if ( put && factory.getStatistics().isStatisticsEnabled() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java index 72e0230d23..d6f05c7924 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java @@ -20,8 +20,8 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.QueryException; import org.hibernate.Session; -import org.hibernate.cache.spi.QueryCache; import org.hibernate.cache.spi.QueryKey; +import org.hibernate.cache.spi.QueryResultRegionAccess; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -542,7 +542,7 @@ public class CustomLoader extends Loader { final SharedSessionContractImplementor session, final QueryParameters queryParameters, final Type[] resultTypes, - final QueryCache queryCache, + final QueryResultRegionAccess queryCache, final QueryKey key, final List result) { super.putResultInQueryCache( session, queryParameters, this.resultTypes, queryCache, key, result ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java index c857939708..7bc7fa619d 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java @@ -8,6 +8,7 @@ package org.hibernate.metamodel.internal; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -32,9 +33,12 @@ import org.hibernate.UnknownEntityTypeException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataImplementor; -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.cfg.internal.DomainDataRegionConfigImpl; +import org.hibernate.cache.cfg.spi.DomainDataRegionConfig; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.CollectionDataAccess; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.spi.EntityGraphImplementor; @@ -50,6 +54,8 @@ import org.hibernate.jpa.graph.internal.SubgraphImpl; import org.hibernate.mapping.Collection; import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.RootClass; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; @@ -102,6 +108,8 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable { public void initialize(MetadataImplementor mappingMetadata, JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting) { this.imports.putAll( mappingMetadata.getImports() ); + primeSecondLevelCacheRegions( mappingMetadata ); + final PersisterCreationContext persisterCreationContext = new PersisterCreationContext() { @Override public SessionFactoryImplementor getSessionFactory() { @@ -117,13 +125,9 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable { final PersisterFactory persisterFactory = sessionFactory.getServiceRegistry().getService( PersisterFactory.class ); for ( final PersistentClass model : mappingMetadata.getEntityBindings() ) { - final EntityRegionAccessStrategy accessStrategy = sessionFactory.getCache().determineEntityRegionAccessStrategy( - model - ); - - final NaturalIdRegionAccessStrategy naturalIdAccessStrategy = sessionFactory.getCache().determineNaturalIdRegionAccessStrategy( - model - ); + final NavigableRole rootEntityRole = new NavigableRole( model.getRootClass().getEntityName() ); + final EntityDataAccess accessStrategy = sessionFactory.getCache().getEntityRegionAccess( rootEntityRole ); + final NaturalIdDataAccess naturalIdAccessStrategy = sessionFactory.getCache().getNaturalIdRegionAccess( rootEntityRole ); final EntityPersister cp = persisterFactory.createEntityPersister( model, @@ -164,9 +168,10 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable { } for ( final Collection model : mappingMetadata.getCollectionBindings() ) { - final CollectionRegionAccessStrategy accessStrategy = sessionFactory.getCache().determineCollectionRegionAccessStrategy( - model - ); + final NavigableRole navigableRole = new NavigableRole( model.getRole() ); + + final CollectionDataAccess accessStrategy = sessionFactory.getCache().getCollectionRegionAccess( + navigableRole ); final CollectionPersister persister = persisterFactory.createCollectionPersister( model, @@ -229,6 +234,51 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable { } + private void primeSecondLevelCacheRegions(MetadataImplementor mappingMetadata) { + final Map regionConfigBuilders = new ConcurrentHashMap<>(); + + // todo : ultimately this code can be made more efficient when we have a better intrinsic understanding of the hierarchy as a whole + + for ( PersistentClass bootEntityDescriptor : mappingMetadata.getEntityBindings() ) { + final AccessType accessType = AccessType.fromExternalName( bootEntityDescriptor.getCacheConcurrencyStrategy() ); + + if ( accessType != null ) { + if ( bootEntityDescriptor.isCached() ) { + regionConfigBuilders.computeIfAbsent( bootEntityDescriptor.getRootClass().getCacheRegionName(), DomainDataRegionConfigImpl.Builder::new ) + .addEntityConfig( bootEntityDescriptor, accessType ); + } + + if ( RootClass.class.isInstance( bootEntityDescriptor ) + && bootEntityDescriptor.hasNaturalId() + && bootEntityDescriptor.getNaturalIdCacheRegionName() != null ) { + regionConfigBuilders.computeIfAbsent( bootEntityDescriptor.getNaturalIdCacheRegionName(), DomainDataRegionConfigImpl.Builder::new ) + .addNaturalIdConfig( (RootClass) bootEntityDescriptor, accessType ); + } + } + } + + for ( Collection collection : mappingMetadata.getCollectionBindings() ) { + final AccessType accessType = AccessType.fromExternalName( collection.getCacheConcurrencyStrategy() ); + if ( accessType != null ) { + regionConfigBuilders.computeIfAbsent( collection.getCacheConcurrencyStrategy(), DomainDataRegionConfigImpl.Builder::new ) + .addCollectionConfig( collection, accessType ); + } + } + + final Set regionConfigs; + if ( regionConfigBuilders.isEmpty() ) { + regionConfigs = Collections.emptySet(); + } + else { + regionConfigs = new HashSet<>(); + for ( DomainDataRegionConfigImpl.Builder builder : regionConfigBuilders.values() ) { + regionConfigs.add( builder.build() ); + } + } + + getSessionFactory().getCache().prime( regionConfigs ); + } + @SuppressWarnings("unchecked") private void applyNamedEntityGraphs(java.util.Collection namedEntityGraphs) { for ( NamedEntityGraphDefinition definition : namedEntityGraphs ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/NavigableRole.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/NavigableRole.java new file mode 100644 index 0000000000..f9b766411a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/NavigableRole.java @@ -0,0 +1,104 @@ +/* + * 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.metamodel.model.domain; + +import java.io.Serializable; +import java.util.Objects; + +import org.hibernate.internal.util.StringHelper; + +/** + * A representation of the static "Navigable" path relative to some "root entity". + * + * @author Steve Ebersole + */ +public class NavigableRole implements Serializable { + public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper"; + + private final NavigableRole parent; + private final String navigableName; + private final String fullPath; + + public NavigableRole(NavigableRole parent, String navigableName) { + this.parent = parent; + this.navigableName = navigableName; + + // the _identifierMapper is a "hidden" property on entities with composite keys. + // concatenating it will prevent the path from correctly being used to look up + // various things such as criteria paths and fetch profile association paths + if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) { + this.fullPath = parent != null ? parent.getFullPath() : ""; + } + else { + final String prefix; + if ( parent != null ) { + final String resolvedParent = parent.getFullPath(); + if ( StringHelper.isEmpty( resolvedParent ) ) { + prefix = ""; + } + else { + prefix = resolvedParent + '.'; + } + } + else { + prefix = ""; + } + + this.fullPath = prefix + navigableName; + } + } + + public NavigableRole(String navigableName) { + this( null, navigableName ); + } + + public NavigableRole() { + this( "" ); + } + + public NavigableRole append(String property) { + return new NavigableRole( this, property ); + } + + public NavigableRole getParent() { + return parent; + } + + public String getNavigableName() { + return navigableName; + } + + public String getFullPath() { + return fullPath; + } + + public boolean isRoot() { + return parent == null && StringHelper.isEmpty( navigableName ); + } + + @Override + public String toString() { + return getClass().getSimpleName() + '[' + fullPath + ']'; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + NavigableRole that = (NavigableRole) o; + return Objects.equals( getFullPath(), that.getFullPath() ); + } + + @Override + public int hashCode() { + return Objects.hash( getFullPath() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index ed0e77ebbd..adbff2b77f 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -24,7 +24,7 @@ import org.hibernate.QueryException; import org.hibernate.TransientObjectException; import org.hibernate.boot.model.relational.Database; import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.entry.CacheEntryStructure; import org.hibernate.cache.spi.entry.StructuredCollectionCacheEntry; import org.hibernate.cache.spi.entry.StructuredMapCacheEntry; @@ -60,6 +60,7 @@ import org.hibernate.mapping.List; import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Table; import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.PropertyMapping; @@ -111,7 +112,7 @@ public abstract class AbstractCollectionPersister // TODO: encapsulate the protected instance variables! - private final String role; + private final NavigableRole navigableRole; // SQL statements private final String sqlDeleteString; @@ -198,7 +199,7 @@ public abstract class AbstractCollectionPersister private final IdentifierGenerator identifierGenerator; private final PropertyMapping elementPropertyMapping; private final EntityPersister elementPersister; - private final CollectionRegionAccessStrategy cacheAccessStrategy; + private final CollectionDataAccess cacheAccessStrategy; private final CollectionType collectionType; private CollectionInitializer initializer; @@ -230,7 +231,7 @@ public abstract class AbstractCollectionPersister public AbstractCollectionPersister( Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws MappingException, CacheException { final Database database = creationContext.getMetadata().getDatabase(); @@ -250,7 +251,7 @@ public abstract class AbstractCollectionPersister dialect = factory.getDialect(); sqlExceptionHelper = factory.getSQLExceptionHelper(); collectionType = collectionBinding.getCollectionType(); - role = collectionBinding.getRole(); + navigableRole = new NavigableRole( collectionBinding.getRole() ); entityName = collectionBinding.getOwnerEntityName(); ownerPersister = factory.getEntityPersister( entityName ); queryLoaderName = collectionBinding.getLoaderName(); @@ -744,7 +745,12 @@ public abstract class AbstractCollectionPersister throws MappingException; @Override - public CollectionRegionAccessStrategy getCacheAccessStrategy() { + public NavigableRole getNavigableRole() { + return navigableRole; + } + + @Override + public CollectionDataAccess getCacheAccessStrategy() { return cacheAccessStrategy; } @@ -846,7 +852,7 @@ public abstract class AbstractCollectionPersister throws HibernateException, SQLException { Object index = getIndexType().nullSafeGet( rs, aliases, session, null ); if ( index == null ) { - throw new HibernateException( "null index column for collection: " + role ); + throw new HibernateException( "null index column for collection: " + navigableRole.getFullPath() ); } index = decrementIndexByBase( index ); return index; @@ -864,7 +870,7 @@ public abstract class AbstractCollectionPersister throws HibernateException, SQLException { Object id = getIdentifierType().nullSafeGet( rs, alias, session, null ); if ( id == null ) { - throw new HibernateException( "null identifier column for collection: " + role ); + throw new HibernateException( "null identifier column for collection: " + navigableRole.getFullPath() ); } return id; } @@ -891,7 +897,7 @@ public abstract class AbstractCollectionPersister throws HibernateException, SQLException { if ( key == null ) { - throw new NullPointerException( "null key for collection: " + role ); // an assertion + throw new NullPointerException( "null key for collection: " + navigableRole.getFullPath() ); // an assertion } getKeyType().nullSafeSet( st, key, i, session ); return i + keyColumnAliases.length; @@ -1603,7 +1609,7 @@ public abstract class AbstractCollectionPersister @Override public String getRole() { - return role; + return navigableRole.getFullPath(); } public String getOwnerEntityName() { @@ -1724,7 +1730,7 @@ public abstract class AbstractCollectionPersister if ( !isInverse && collection.isRowUpdatePossible() ) { - LOG.debugf( "Updating rows of collection: %s#%s", role, id ); + LOG.debugf( "Updating rows of collection: %s#%s", navigableRole.getFullPath(), id ); // update all the modified entries int count = doUpdateRows( id, collection, session ); @@ -1846,7 +1852,7 @@ public abstract class AbstractCollectionPersister @Override public String toString() { - return StringHelper.unqualify( getClass().getName() ) + '(' + role + ')'; + return StringHelper.unqualify( getClass().getName() ) + '(' + navigableRole.getFullPath() + ')'; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java index 38adcd32d4..d271051a69 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java @@ -17,7 +17,7 @@ import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; import org.hibernate.engine.spi.LoadQueryInfluencers; @@ -54,7 +54,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { public BasicCollectionPersister( Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws MappingException, CacheException { super( collectionBinding, cacheAccessStrategy, creationContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java index 7cb382873e..6e21f10ced 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java @@ -13,13 +13,14 @@ import java.util.Map; import org.hibernate.HibernateException; import org.hibernate.MappingException; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.entry.CacheEntryStructure; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGenerator; import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.walking.spi.CollectionDefinition; import org.hibernate.type.CollectionType; @@ -47,7 +48,7 @@ import org.hibernate.type.Type; * by the persister *

      • *
      • - * {@link CollectionRegionAccessStrategy} - the second level caching strategy for this collection + * {@link CollectionDataAccess} - the second level caching strategy for this collection *
      • *
      • * {@link org.hibernate.persister.spi.PersisterCreationContext} - access to additional @@ -72,7 +73,10 @@ public interface CollectionPersister extends CollectionDefinition { /** * Get the cache */ - CollectionRegionAccessStrategy getCacheAccessStrategy(); + CollectionDataAccess getCacheAccessStrategy(); + + NavigableRole getNavigableRole(); + /** * Get the cache structure */ diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java index 4afd3436b4..3c4cec89d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java @@ -15,7 +15,7 @@ import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; import org.hibernate.engine.spi.LoadQueryInfluencers; @@ -64,7 +64,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { public OneToManyPersister( Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws MappingException, CacheException { super( collectionBinding, cacheAccessStrategy, creationContext ); cascadeDeleteEnabled = collectionBinding.getKey().isCascadeDeleteEnabled() diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 2d92e4de24..b21a9fbe1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -38,8 +38,8 @@ import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeDescriptor; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.cache.spi.entry.CacheEntryStructure; import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl; @@ -101,6 +101,7 @@ import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.persister.walking.internal.EntityIdentifierDefinitionHelper; @@ -148,13 +149,15 @@ public abstract class AbstractEntityPersister public static final String ENTITY_CLASS = "class"; + private final NavigableRole navigableRole; + // moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private final SessionFactoryImplementor factory; private final boolean canReadFromCache; private final boolean canWriteToCache; private final boolean invalidateCache; - private final EntityRegionAccessStrategy cacheAccessStrategy; - private final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy; + private final EntityDataAccess cacheAccessStrategy; + private final NaturalIdDataAccess naturalIdRegionAccessStrategy; private final boolean isLazyPropertiesCacheable; private final CacheEntryHelper cacheEntryHelper; private final EntityMetamodel entityMetamodel; @@ -511,13 +514,15 @@ public abstract class AbstractEntityPersister @SuppressWarnings("UnnecessaryBoxing") public AbstractEntityPersister( final PersistentClass persistentClass, - final EntityRegionAccessStrategy cacheAccessStrategy, - final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy, + final EntityDataAccess cacheAccessStrategy, + final NaturalIdDataAccess naturalIdRegionAccessStrategy, final PersisterCreationContext creationContext) throws HibernateException { // moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ this.factory = creationContext.getSessionFactory(); + this.navigableRole = new NavigableRole( persistentClass.getEntityName() ); + if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) { this.canWriteToCache = persistentClass.isCached(); this.canReadFromCache = determineCanReadFromCache( persistentClass ); @@ -1064,9 +1069,9 @@ public abstract class AbstractEntityPersister } if ( session.getCacheMode().isGetEnabled() && canReadFromCache() && isLazyPropertiesCacheable() ) { - final EntityRegionAccessStrategy cache = getCacheAccessStrategy(); - final Object cacheKey = cache.generateCacheKey(id, this, session.getFactory(), session.getTenantIdentifier() ); - final Object ce = CacheHelper.fromSharedCache( session, cacheKey, cache ); + final EntityDataAccess cacheAccess = getCacheAccessStrategy(); + final Object cacheKey = cacheAccess.generateCacheKey(id, this, session.getFactory(), session.getTenantIdentifier() ); + final Object ce = CacheHelper.fromSharedCache( session, cacheKey, cacheAccess ); if ( ce != null ) { final CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure( ce, factory ); final Object initializedValue = initializeLazyPropertiesFromCache( fieldName, entity, session, entry, cacheEntry ); @@ -1264,6 +1269,11 @@ public abstract class AbstractEntityPersister || getFactory().getSessionFactoryOptions().isJdbcBatchVersionedData(); } + @Override + public NavigableRole getNavigableRole() { + return navigableRole; + } + public Serializable[] getQuerySpaces() { return getPropertySpaces(); } @@ -2471,8 +2481,7 @@ public abstract class AbstractEntityPersister catch (StaleStateException e) { if ( !isNullableTable( tableNumber ) ) { if ( getFactory().getStatistics().isStatisticsEnabled() ) { - getFactory().getStatisticsImplementor() - .optimisticFailure( getEntityName() ); + getFactory().getStatistics().optimisticFailure( getEntityName() ); } throw new StaleObjectStateException( getEntityName(), id ); } @@ -4404,7 +4413,7 @@ public abstract class AbstractEntityPersister return canWriteToCache; } - public EntityRegionAccessStrategy getCacheAccessStrategy() { + public EntityDataAccess getCacheAccessStrategy() { return cacheAccessStrategy; } @@ -4422,7 +4431,7 @@ public abstract class AbstractEntityPersister return naturalIdRegionAccessStrategy != null; } - public NaturalIdRegionAccessStrategy getNaturalIdCacheAccessStrategy() { + public NaturalIdDataAccess getNaturalIdCacheAccessStrategy() { return naturalIdRegionAccessStrategy; } @@ -4575,7 +4584,7 @@ public abstract class AbstractEntityPersister // check to see if it is in the second-level cache if ( session.getCacheMode().isGetEnabled() && canReadFromCache() ) { - final EntityRegionAccessStrategy cache = getCacheAccessStrategy(); + final EntityDataAccess cache = getCacheAccessStrategy(); final Object ck = cache.generateCacheKey( id, this, session.getFactory(), session.getTenantIdentifier() ); final Object ce = CacheHelper.fromSharedCache( session, ck, getCacheAccessStrategy() ); if ( ce != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index 5ef01a5489..eb47a19382 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -16,9 +16,8 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; -import org.hibernate.cache.spi.OptimisticCacheSource; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.cache.spi.entry.CacheEntryStructure; import org.hibernate.engine.spi.CascadeStyle; @@ -29,6 +28,7 @@ import org.hibernate.engine.spi.ValueInclusion; import org.hibernate.id.IdentifierGenerator; import org.hibernate.internal.FilterAliasGenerator; import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityTuplizer; @@ -48,10 +48,10 @@ import org.hibernate.type.VersionType; * to be handled by the persister *
      • *
      • - * {@link EntityRegionAccessStrategy} - the second level caching strategy for this entity + * {@link org.hibernate.cache.spi.access.EntityDataAccess} - the second level caching strategy for this entity *
      • *
      • - * {@link NaturalIdRegionAccessStrategy} - the second level caching strategy for the natural-id + * {@link org.hibernate.cache.spi.access.NaturalIdDataAccess} - the second level caching strategy for the natural-id * defined for this entity, if one *
      • *
      • @@ -66,7 +66,7 @@ import org.hibernate.type.VersionType; * @see org.hibernate.persister.spi.PersisterFactory * @see org.hibernate.persister.spi.PersisterClassResolver */ -public interface EntityPersister extends OptimisticCacheSource, EntityDefinition { +public interface EntityPersister extends EntityDefinition { /** * The property name of the "special" identifier property in HQL @@ -97,6 +97,7 @@ public interface EntityPersister extends OptimisticCacheSource, EntityDefinition */ SessionFactoryImplementor getFactory(); + NavigableRole getNavigableRole(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // stuff that is persister-centric and/or EntityInfo-centric ~~~~~~~~~~~~~~ @@ -517,7 +518,7 @@ public interface EntityPersister extends OptimisticCacheSource, EntityDefinition /** * Get the cache (optional operation) */ - EntityRegionAccessStrategy getCacheAccessStrategy(); + EntityDataAccess getCacheAccessStrategy(); /** * Get the cache structure */ @@ -533,7 +534,7 @@ public interface EntityPersister extends OptimisticCacheSource, EntityDefinition /** * Get the NaturalId cache (optional operation) */ - NaturalIdRegionAccessStrategy getNaturalIdCacheAccessStrategy(); + NaturalIdDataAccess getNaturalIdCacheAccessStrategy(); /** * Get the user-visible metadata for the class (optional operation) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index c8b9e626ff..b3f6c3eb54 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -11,8 +11,8 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.QueryException; import org.hibernate.boot.model.relational.Database; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; @@ -128,8 +128,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { public JoinedSubclassEntityPersister( final PersistentClass persistentClass, - final EntityRegionAccessStrategy cacheAccessStrategy, - final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy, + final EntityDataAccess cacheAccessStrategy, + final NaturalIdDataAccess naturalIdRegionAccessStrategy, final PersisterCreationContext creationContext) throws HibernateException { super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, creationContext ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index b602947c5d..1afbb6b852 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -18,8 +18,8 @@ import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -117,8 +117,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { public SingleTableEntityPersister( final PersistentClass persistentClass, - final EntityRegionAccessStrategy cacheAccessStrategy, - final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy, + final EntityDataAccess cacheAccessStrategy, + final NaturalIdDataAccess naturalIdRegionAccessStrategy, final PersisterCreationContext creationContext) throws HibernateException { super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, creationContext ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index 47c6912af2..04f72dad9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -20,8 +20,8 @@ import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cfg.Settings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -70,8 +70,8 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister { public UnionSubclassEntityPersister( final PersistentClass persistentClass, - final EntityRegionAccessStrategy cacheAccessStrategy, - final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy, + final EntityDataAccess cacheAccessStrategy, + final NaturalIdDataAccess naturalIdRegionAccessStrategy, final PersisterCreationContext creationContext) throws HibernateException { super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, creationContext ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java index 6ea4fa634d..acf9cbb334 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java @@ -11,9 +11,9 @@ import java.lang.reflect.InvocationTargetException; import org.hibernate.HibernateException; import org.hibernate.MappingException; -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.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.persister.collection.CollectionPersister; @@ -39,8 +39,8 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi */ public static final Class[] ENTITY_PERSISTER_CONSTRUCTOR_ARGS = new Class[] { PersistentClass.class, - EntityRegionAccessStrategy.class, - NaturalIdRegionAccessStrategy.class, + EntityDataAccess.class, + NaturalIdDataAccess.class, PersisterCreationContext.class }; @@ -49,7 +49,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi */ public static final Class[] COLLECTION_PERSISTER_CONSTRUCTOR_ARGS = new Class[] { Collection.class, - CollectionRegionAccessStrategy.class, + CollectionDataAccess.class, PersisterCreationContext.class }; @@ -64,8 +64,8 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi @SuppressWarnings( {"unchecked"}) public EntityPersister createEntityPersister( PersistentClass entityBinding, - EntityRegionAccessStrategy entityCacheAccessStrategy, - NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy, + EntityDataAccess entityCacheAccessStrategy, + NaturalIdDataAccess naturalIdCacheAccessStrategy, PersisterCreationContext creationContext) throws HibernateException { // If the metadata for the entity specified an explicit persister class, use it... Class persisterClass = entityBinding.getEntityPersisterClass(); @@ -87,8 +87,8 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi private EntityPersister createEntityPersister( Class persisterClass, PersistentClass entityBinding, - EntityRegionAccessStrategy entityCacheAccessStrategy, - NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy, + EntityDataAccess entityCacheAccessStrategy, + NaturalIdDataAccess naturalIdCacheAccessStrategy, PersisterCreationContext creationContext) { try { final Constructor constructor = persisterClass.getConstructor( ENTITY_PERSISTER_CONSTRUCTOR_ARGS ); @@ -128,7 +128,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi @SuppressWarnings( {"unchecked"}) public CollectionPersister createCollectionPersister( Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws HibernateException { // If the metadata for the collection specified an explicit persister class, use it Class persisterClass = collectionBinding.getCollectionPersisterClass(); @@ -144,7 +144,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi private CollectionPersister createCollectionPersister( Class persisterClass, Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) { try { Constructor constructor = persisterClass.getConstructor( COLLECTION_PERSISTER_CONSTRUCTOR_ARGS ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java b/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java index c30db259b0..d4d044c7b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/spi/PersisterFactory.java @@ -7,9 +7,9 @@ package org.hibernate.persister.spi; import org.hibernate.HibernateException; -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.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.persister.collection.CollectionPersister; @@ -34,10 +34,10 @@ public interface PersisterFactory extends Service { * * @throws HibernateException Indicates a problem building the persister. */ - public EntityPersister createEntityPersister( + EntityPersister createEntityPersister( PersistentClass entityBinding, - EntityRegionAccessStrategy entityCacheAccessStrategy, - NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy, + EntityDataAccess entityCacheAccessStrategy, + NaturalIdDataAccess naturalIdCacheAccessStrategy, PersisterCreationContext creationContext) throws HibernateException; /** @@ -51,9 +51,9 @@ public interface PersisterFactory extends Service { * * @throws HibernateException Indicates a problem building the persister. */ - public CollectionPersister createCollectionPersister( + CollectionPersister createCollectionPersister( Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws HibernateException; } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcSessionOwner.java b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcSessionOwner.java index 274d674507..abdf030247 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcSessionOwner.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcSessionOwner.java @@ -32,6 +32,14 @@ public interface JdbcSessionOwner { */ TransactionCoordinator getTransactionCoordinator(); + /** + * Callback indicating recognition of entering into a transactional + * context whether that is explicitly via the Hibernate + * {@link org.hibernate.Transaction} API or via registration + * of Hibernate's JTA Synchronization impl with a JTA Transaction + */ + void startTransactionBoundary(); + /** * A after-begin callback from the coordinator to its owner. */ diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcResourceLocalTransactionCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcResourceLocalTransactionCoordinatorImpl.java index 41719a8ecb..94e26850f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcResourceLocalTransactionCoordinatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jdbc/internal/JdbcResourceLocalTransactionCoordinatorImpl.java @@ -11,7 +11,6 @@ import java.util.List; import javax.persistence.RollbackException; import javax.transaction.Status; -import org.hibernate.TransactionException; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.transaction.spi.IsolationDelegate; import org.hibernate.engine.transaction.spi.TransactionObserver; @@ -158,7 +157,15 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC if(this.timeOut > 0) { transactionCoordinatorOwner.setTransactionTimeOut( this.timeOut ); } + + + // report entering into a "transactional context" + transactionCoordinatorOwner.startTransactionBoundary(); + + // trigger the Transaction-API-only after-begin callback transactionCoordinatorOwner.afterTransactionBegin(); + + // notify all registered observers for ( TransactionObserver observer : observers() ) { observer.afterBegin(); } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java index d6d034f379..9d0e886d46 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java @@ -172,6 +172,9 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy getSynchronizationCallbackCoordinator().synchronizationRegistered(); synchronizationRegistered = true; log.debug( "Hibernate RegisteredSynchronization successfully registered with JTA platform" ); + + // report entering into a "transactional context" + getTransactionCoordinatorOwner().startTransactionBoundary(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/spi/TransactionCoordinatorOwner.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/spi/TransactionCoordinatorOwner.java index 2be9699ee1..fbde477e74 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/spi/TransactionCoordinatorOwner.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/spi/TransactionCoordinatorOwner.java @@ -28,6 +28,16 @@ public interface TransactionCoordinatorOwner { */ boolean isActive(); + /** + * Callback indicating recognition of entering into a transactional + * context whether that is explicitly via the Hibernate + * {@link org.hibernate.Transaction} API or via registration + * of Hibernate's JTA Synchronization impl with a JTA Transaction + */ + default void startTransactionBoundary() { + getJdbcSessionOwner().startTransactionBoundary(); + } + /** * A after-begin callback from the coordinator to its owner. */ diff --git a/hibernate-core/src/main/java/org/hibernate/stat/CacheRegionStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/CacheRegionStatistics.java new file mode 100755 index 0000000000..8a5453e888 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/CacheRegionStatistics.java @@ -0,0 +1,66 @@ +/* + * 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.stat; + +import java.io.Serializable; + +/** + * Second level cache statistics of a specific region + * + * @author Gavin King + */ +public interface CacheRegionStatistics extends Serializable { + long NO_EXTENDED_STAT_SUPPORT_RETURN = Long.MIN_VALUE;; + + /** + * The number of cache puts into the region since the last Statistics + * clearing + */ + long getPutCount(); + + /** + * The number of successful cache look-ups against the region since the + * last Statistics clearing + */ + long getHitCount(); + + /** + * The number of unsuccessful cache look-ups against the region since the + * last Statistics clearing + */ + long getMissCount(); + + /** + * The number of elements currently in memory within the cache provider. + * + * This is an optional value contingent upon the underlying provider defining + * {@link org.hibernate.cache.spi.ExtendedStatisticsSupport}. If the provider + * does not support extended stats, {@link #NO_EXTENDED_STAT_SUPPORT_RETURN} + * is returned instead. + */ + long getElementCountInMemory(); + + /** + * The number of elements currently stored to disk within the cache provider. + * + * This is an optional value contingent upon the underlying provider defining + * {@link org.hibernate.cache.spi.ExtendedStatisticsSupport}. If the provider + * does not support extended stats, {@link #NO_EXTENDED_STAT_SUPPORT_RETURN} + * is returned instead. + */ + long getElementCountOnDisk(); + + /** + * The size that the in-memory elements take up within the cache provider. + * + * This is an optional value contingent upon the underlying provider defining + * {@link org.hibernate.cache.spi.ExtendedStatisticsSupport}. If the provider + * does not support extended stats, {@link #NO_EXTENDED_STAT_SUPPORT_RETURN} + * is returned instead. + */ + long getSizeInMemory(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/CacheableDataStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/CacheableDataStatistics.java new file mode 100644 index 0000000000..bd50406c4f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/CacheableDataStatistics.java @@ -0,0 +1,36 @@ +/* + * 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.stat; + +/** + * @author Steve Ebersole + */ +public interface CacheableDataStatistics { + /** + * The name of the region where this data is cached. + */ + String getCacheRegionName(); + + /** + * The number of times this data has been into its configured cache region + * since the last Statistics clearing + */ + long getCachePutCount(); + + /** + * The number of successful cache look-ups for this data from its + * configured cache region since the last Statistics clearing + */ + long getCacheHitCount(); + + + /** + * The number of unsuccessful cache look-ups for this data from its + * configured cache region since the last Statistics clearing + */ + long getCacheMissCount(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/CollectionStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/CollectionStatistics.java index 35395d33a2..d2a7b85fe7 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/CollectionStatistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/CollectionStatistics.java @@ -12,16 +12,36 @@ import java.io.Serializable; * Collection related statistics * * @author Gavin King + * @author Steve Ebersole */ -public interface CollectionStatistics extends Serializable { - +public interface CollectionStatistics extends CacheableDataStatistics, Serializable { + /** + * Number of times (since last Statistics clearing) this collection + * has been loaded + */ long getLoadCount(); + /** + * Number of times (since last Statistics clearing) this collection + * has been fetched + */ long getFetchCount(); + /** + * Number of times (since last Statistics clearing) this collection + * has been recreated (rows potentially deleted and then rows (re-)inserted) + */ long getRecreateCount(); + /** + * Number of times (since last Statistics clearing) this collection + * has been removed + */ long getRemoveCount(); + /** + * Number of times (since last Statistics clearing) this collection + * has been updated + */ long getUpdateCount(); } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/EntityStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/EntityStatistics.java index b881972446..ae8456ea23 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/EntityStatistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/EntityStatistics.java @@ -12,18 +12,42 @@ import java.io.Serializable; * Entity related statistics * * @author Gavin King + * @author Steve Ebersole */ -public interface EntityStatistics extends Serializable { +public interface EntityStatistics extends CacheableDataStatistics, Serializable { + /** + * Number of times (since last Statistics clearing) this entity + * has been deleted + */ long getDeleteCount(); + /** + * Number of times (since last Statistics clearing) this entity + * has been inserted + */ long getInsertCount(); - long getLoadCount(); - + /** + * Number of times (since last Statistics clearing) this entity + * has been updated + */ long getUpdateCount(); + /** + * Number of times (since last Statistics clearing) this entity + * has been loaded + */ + long getLoadCount(); + + /** + * Number of times (since last Statistics clearing) this entity + * has been fetched + */ long getFetchCount(); + /** + * Number of times (since last Statistics clearing) this entity + * has experienced an optimistic lock failure. + */ long getOptimisticFailureCount(); - } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java index 30509f88cd..55892bb35c 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdCacheStatistics.java @@ -1,41 +1,53 @@ /* * 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 . + * 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.stat; -import java.io.Serializable; -import java.util.Map; - /** - * NaturalId query statistics - *

        - * Note that for a cached natural id, the cache miss is equals to the db count + * @deprecated (since 5.3) Use {@link NaturalIdStatistics} - unfortunately the + * old statistics contracts exposed these by region name, rather than the name of + * the entity defining the natural-id * - * @author Eric Dalquist + * @author Steve Ebersole */ -public interface NaturalIdCacheStatistics extends Serializable { +@Deprecated +public interface NaturalIdCacheStatistics { + /** + * Number of times (since last Statistics clearing) the "natural id + * resolution" query has been executed + */ + long getExecutionCount(); + + /** + * The average amount of time it takes (since last Statistics clearing) for + * the execution of this "natural id resolution" query + */ + long getExecutionAvgTime(); + + /** + * The maximum amount of time it takes (since last Statistics clearing) for + * the execution of this "natural id resolution" query + */ + long getExecutionMaxTime(); + + /** + * The minimum amount of time it takes (since last Statistics clearing) for + * the execution of this "natural id resolution" query + */ + long getExecutionMinTime(); + long getHitCount(); long getMissCount(); long getPutCount(); - - long getExecutionCount(); - - long getExecutionAvgTime(); - - long getExecutionMaxTime(); - - long getExecutionMinTime(); long getElementCountInMemory(); long getElementCountOnDisk(); long getSizeInMemory(); - - Map getEntries(); } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdStatistics.java new file mode 100644 index 0000000000..40b11b5d3b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/NaturalIdStatistics.java @@ -0,0 +1,51 @@ +/* + * 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.stat; + +import java.io.Serializable; + +/** + * Statistics pertaining to the execution of the "natural id resolution" query. + * + * @apiNote The natural-id resolution data is allowed to be stored in the + * second level cache, and if so stored will have available caching stats as + * well available via {@link Statistics#getDomainDataRegionStatistics} using the + * configured region name + * + * todo (6.0) : consider a means to get the cache Region statistics for: + * 1) an entity by name + * 2) a collection by role + * 3) a natural-id by entity name + * + * @author Eric Dalquist + * @author Steve Ebersole + */ +public interface NaturalIdStatistics extends CacheableDataStatistics, Serializable { + /** + * Number of times (since last Statistics clearing) the "natural id + * resolution" query has been executed + */ + long getExecutionCount(); + + /** + * The average amount of time it takes (since last Statistics clearing) for + * the execution of this "natural id resolution" query + */ + long getExecutionAvgTime(); + + /** + * The maximum amount of time it takes (since last Statistics clearing) for + * the execution of this "natural id resolution" query + */ + long getExecutionMaxTime(); + + /** + * The minimum amount of time it takes (since last Statistics clearing) for + * the execution of this "natural id resolution" query + */ + long getExecutionMinTime(); +} \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/stat/QueryStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/QueryStatistics.java index 2380ac7900..78a37cc427 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/QueryStatistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/QueryStatistics.java @@ -14,16 +14,11 @@ import java.io.Serializable; * Note that for a cached query, the cache miss is equals to the db count * * @author Gavin King + * @author Steve Ebersole */ public interface QueryStatistics extends Serializable { long getExecutionCount(); - long getCacheHitCount(); - - long getCachePutCount(); - - long getCacheMissCount(); - long getExecutionRowCount(); long getExecutionAvgTime(); @@ -35,4 +30,10 @@ public interface QueryStatistics extends Serializable { long getExecutionTotalTime(); double getExecutionAvgTimeAsDouble(); + + long getCacheHitCount(); + + long getCachePutCount(); + + long getCacheMissCount(); } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java index 1854c0c092..cc9deb1914 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java @@ -1,32 +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 . + * 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.stat; -import java.io.Serializable; -import java.util.Map; - /** - * Second level cache statistics of a specific region + * Cache statistics pertaining to a specific data region * * @author Gavin King + * @author Steve Ebersole + * + * @deprecated Use {@link CacheRegionStatistics} instead */ -public interface SecondLevelCacheStatistics extends Serializable { - - long getHitCount(); - - long getMissCount(); - - long getPutCount(); - - long getElementCountInMemory(); - - long getElementCountOnDisk(); - - long getSizeInMemory(); - - Map getEntries(); +@Deprecated +public interface SecondLevelCacheStatistics extends CacheRegionStatistics { } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/SessionStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/SessionStatistics.java index 749758a53d..328c7467a4 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/SessionStatistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/SessionStatistics.java @@ -17,21 +17,21 @@ public interface SessionStatistics { /** * Get the number of entity instances associated with the session */ - public int getEntityCount(); + int getEntityCount(); /** * Get the number of collection instances associated with the session */ - public int getCollectionCount(); + int getCollectionCount(); /** * Get the set of all EntityKeys * @see org.hibernate.engine.spi.EntityKey */ - public Set getEntityKeys(); + Set getEntityKeys(); /** * Get the set of all CollectionKeys * @see org.hibernate.engine.spi.CollectionKey */ - public Set getCollectionKeys(); + Set getCollectionKeys(); } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java b/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java index cb38a63659..226dd590e8 100755 --- a/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/Statistics.java @@ -14,11 +14,27 @@ package org.hibernate.stat; * @author Emmanuel Bernard */ public interface Statistics { + + /** + * Are statistics enabled + */ + boolean isStatisticsEnabled(); + + /** + * Enable statistics logs (this is a dynamic parameter) + */ + void setStatisticsEnabled(boolean b); /** * reset all statistics */ void clear(); + /** + * log in info level the main statistics + */ + void logSummary(); + + /** * find entity statistics per name * @@ -36,32 +52,60 @@ public interface Statistics { CollectionStatistics getCollectionStatistics(String role); /** - * Second level cache statistics per region + * Natural id resolution query statistics for an entity type * - * @param regionName region name - * - * @return SecondLevelCacheStatistics or {@code null} if the second level cache is not enabled - * - * @throws IllegalArgumentException if the region name could not be resolved - */ - SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName); - - /** - * Natural id cache statistics per region - * - * @param regionName region name + * @param entityName The entity name that is the root of the hierarchy containing the + * natural id * @return NaturalIdCacheStatistics */ - NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName); + NaturalIdStatistics getNaturalIdStatistics(String entityName); - /** + /** * Query statistics from query string (HQL or SQL) - * + * * @param queryString query string * @return QueryStatistics */ QueryStatistics getQueryStatistics(String queryString); + /** + * Second level cache statistics per domain data (entity, collection, natural-id) region + * + * @param regionName The unqualified region name + * + * @return The stats for the named region, or {@code null} if the second level cache is + * not enabled + * + * @throws IllegalArgumentException if the region name could not be resolved + */ + CacheRegionStatistics getDomainDataRegionStatistics(String regionName); + + /** + * Second level cache statistics per query region + * + * @param regionName The unqualified region name + * + * @return Stats for the named region, or {@code null} if (1) query result caching is + * not enabled or (2) no query region exists with that name + */ + CacheRegionStatistics getQueryRegionStatistics(String regionName); + + /** + * Get statistics for either a domain-data or query-result region - this + * method checks both, preferring domain data region if one. Think of it + * as a cascading check to:

          + *
        1. {@link #getDomainDataRegionStatistics}
        2. + *
        3. {@link #getQueryRegionStatistics}
        4. + *
        + * Note that returning null is preferred here over throwing an exception when + * no region exists with that name. + * + * @param regionName The unqualified region name + * + * @return Stats for the named region, or {@code null} if no such region exists + */ + CacheRegionStatistics getCacheRegionStatistics(String regionName); + /** * Get global number of entity deletes * @return entity deletion count @@ -138,6 +182,8 @@ public interface Statistics { */ String getNaturalIdQueryExecutionMaxTimeRegion(); + String getNaturalIdQueryExecutionMaxTimeEntity(); + /** * Get the global number of cached naturalId lookups successfully retrieved from cache */ @@ -232,25 +278,14 @@ public interface Statistics { long getCollectionRecreateCount(); /** - * @return start time in ms (JVM standards {@link System#currentTimeMillis()}) + * The milliseconds (JVM standard {@link System#currentTimeMillis()}) from + * which all statistics accessed since the initial creation of this Statistics + * instance or the last {@link #clear()} + * + * @apiNote This time(stamp) is */ long getStartTime(); - /** - * log in info level the main statistics - */ - void logSummary(); - - /** - * Are statistics logged - */ - boolean isStatisticsEnabled(); - - /** - * Enable statistics logs (this is a dynamic parameter) - */ - void setStatisticsEnabled(boolean b); - /** * Get all executed query strings */ @@ -267,7 +302,9 @@ public interface Statistics { String[] getCollectionRoleNames(); /** - * Get all second-level cache region names + * Get all second-level cache region names. Note: for backwards + * compatibility this method returns just the names of regions + * storing domain data, not query result regions */ String[] getSecondLevelCacheRegionNames(); @@ -296,4 +333,31 @@ public interface Statistics { * that occurred */ long getOptimisticFailureCount(); + + + /** + * Second level cache statistics per region + * + * @param regionName qualified region name + * + * @return SecondLevelCacheStatistics or {@code null} if the second level cache is not enabled + * + * @throws IllegalArgumentException if the region name could not be resolved + * + * @deprecated (since 5.3) Use {@link #getDomainDataRegionStatistics} instead + */ + @Deprecated + SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName); + + /** + * Natural id cache statistics per region + * + * @param regionName region name + * @return NaturalIdCacheStatistics + * + * @deprecated (since 5.3) Use {@link #getNaturalIdStatistics} or + * {@link @getDomainDataRegionStatistics} instead depending on need + */ + @Deprecated + NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName); } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/AbstractCacheableDataStatistics.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/AbstractCacheableDataStatistics.java new file mode 100644 index 0000000000..3617fe6fce --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/AbstractCacheableDataStatistics.java @@ -0,0 +1,82 @@ +/* + * 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.stat.internal; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +import org.hibernate.cache.spi.Region; +import org.hibernate.stat.CacheableDataStatistics; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractCacheableDataStatistics implements CacheableDataStatistics { + private final String cacheRegionName; + + private final AtomicLong cacheHitCount = new AtomicLong(); + private final AtomicLong cacheMissCount = new AtomicLong(); + private final AtomicLong cachePutCount = new AtomicLong(); + + public AbstractCacheableDataStatistics(Supplier regionSupplier) { + final Region region = regionSupplier.get(); + this.cacheRegionName = region != null ? region.getName() : null; + } + + @Override + public String getCacheRegionName() { + return cacheRegionName; + } + + public long getCacheHitCount() { + return cacheHitCount.get(); + } + + public long getCachePutCount() { + return cachePutCount.get(); + } + + public long getCacheMissCount() { + return cacheMissCount.get(); + } + + void incrementCacheHitCount() { + if ( cacheRegionName == null ) { + throw new IllegalStateException( "Illegal attempt to increment cache hit count for non-cached data" ); + } + + cacheHitCount.getAndIncrement(); + } + + void incrementCacheMissCount() { + if ( cacheRegionName == null ) { + throw new IllegalStateException( "Illegal attempt to increment cache miss count for non-cached data" ); + } + + cacheMissCount.getAndIncrement(); + } + + void incrementCachePutCount() { + if ( cacheRegionName == null ) { + throw new IllegalStateException( "Illegal attempt to increment cache put count for non-cached data" ); + } + + cachePutCount.getAndIncrement(); + } + + protected void appendCacheStats(StringBuilder buf) { + if ( cacheRegionName == null ) { + return; + } + + buf.append( ",cacheRegion=" ).append( cacheRegionName ) + .append( ",cacheHitCount=" ).append( getCacheHitCount() ) + .append( ",cacheMissCount=" ).append( getCacheMissCount() ) + .append( ",cachePutCount=" ).append( getCachePutCount() ); + + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/CacheRegionStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/CacheRegionStatisticsImpl.java new file mode 100644 index 0000000000..58ba73439c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/CacheRegionStatisticsImpl.java @@ -0,0 +1,97 @@ +/* + * 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.stat.internal; + +import java.io.Serializable; +import java.util.concurrent.atomic.AtomicLong; + +import org.hibernate.cache.spi.ExtendedStatisticsSupport; +import org.hibernate.cache.spi.Region; +import org.hibernate.stat.CacheRegionStatistics; +import org.hibernate.stat.SecondLevelCacheStatistics; + +/** + * Second level cache statistics of a specific region + * + * @author Alex Snaps + */ +public class CacheRegionStatisticsImpl implements CacheRegionStatistics, SecondLevelCacheStatistics, Serializable { + private final transient Region region; + + private AtomicLong hitCount = new AtomicLong(); + private AtomicLong missCount = new AtomicLong(); + private AtomicLong putCount = new AtomicLong(); + + CacheRegionStatisticsImpl(Region region) { + this.region = region; + } + + @Override + public long getHitCount() { + return hitCount.get(); + } + + @Override + public long getMissCount() { + return missCount.get(); + } + + @Override + public long getPutCount() { + return putCount.get(); + } + + @Override + public long getElementCountInMemory() { + if ( region instanceof ExtendedStatisticsSupport ) { + return ( (ExtendedStatisticsSupport) region ).getElementCountInMemory(); + } + return NO_EXTENDED_STAT_SUPPORT_RETURN; + } + + @Override + public long getElementCountOnDisk() { + if ( region instanceof ExtendedStatisticsSupport ) { + return ( (ExtendedStatisticsSupport) region ).getElementCountOnDisk(); + } + return NO_EXTENDED_STAT_SUPPORT_RETURN; + } + + @Override + public long getSizeInMemory() { + if ( region instanceof ExtendedStatisticsSupport ) { + return ( (ExtendedStatisticsSupport) region ).getSizeInMemory(); + } + return NO_EXTENDED_STAT_SUPPORT_RETURN; + } + + void incrementHitCount() { + hitCount.getAndIncrement(); + } + + void incrementMissCount() { + missCount.getAndIncrement(); + } + + void incrementPutCount() { + putCount.getAndIncrement(); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder().append( "CacheRegionStatistics" ) + .append( "[region=").append( region.getName() ) + .append( ",hitCount=").append( this.hitCount ) + .append( ",missCount=").append( this.missCount ) + .append( ",putCount=").append( this.putCount ) + .append( ",elementCountInMemory=" ).append( this.getElementCountInMemory() ) + .append( ",elementCountOnDisk=" ).append( this.getElementCountOnDisk() ) + .append( ",sizeInMemory=" ).append( this.getSizeInMemory() ) + .append( ']' ); + return buf.toString(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/CollectionStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/CollectionStatisticsImpl.java new file mode 100644 index 0000000000..b3b24702e2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/CollectionStatisticsImpl.java @@ -0,0 +1,91 @@ +/* + * 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.stat.internal; + +import java.io.Serializable; +import java.util.concurrent.atomic.AtomicLong; + +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.stat.CollectionStatistics; + +/** + * Collection related statistics + * + * @author Alex Snaps + */ +public class CollectionStatisticsImpl extends AbstractCacheableDataStatistics implements CollectionStatistics, Serializable { + private final String collectionRole; + + private AtomicLong loadCount = new AtomicLong(); + private AtomicLong fetchCount = new AtomicLong(); + private AtomicLong updateCount = new AtomicLong(); + private AtomicLong removeCount = new AtomicLong(); + private AtomicLong recreateCount = new AtomicLong(); + + CollectionStatisticsImpl(CollectionPersister persister) { + super( + () -> persister.getCacheAccessStrategy() != null + ? persister.getCacheAccessStrategy().getRegion() + : null + ); + + this.collectionRole = persister.getRole(); + } + + public long getLoadCount() { + return loadCount.get(); + } + + public long getFetchCount() { + return fetchCount.get(); + } + + public long getRecreateCount() { + return recreateCount.get(); + } + + public long getRemoveCount() { + return removeCount.get(); + } + + public long getUpdateCount() { + return updateCount.get(); + } + + void incrementLoadCount() { + loadCount.getAndIncrement(); + } + + void incrementFetchCount() { + fetchCount.getAndIncrement(); + } + + void incrementUpdateCount() { + updateCount.getAndIncrement(); + } + + void incrementRecreateCount() { + recreateCount.getAndIncrement(); + } + + void incrementRemoveCount() { + removeCount.getAndIncrement(); + } + + public String toString() { + final StringBuilder buffer = new StringBuilder() + .append( "CollectionStatistics" ) + .append( "[collectionRole=" ).append( collectionRole ) + .append( ",loadCount=" ).append( this.loadCount ) + .append( ",fetchCount=" ).append( this.fetchCount ) + .append( ",recreateCount=" ).append( this.recreateCount ) + .append( ",removeCount=" ).append( this.removeCount ) + .append( ",updateCount=" ).append( this.updateCount ); + appendCacheStats( buffer ); + return buffer.append(']').toString(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentCollectionStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentCollectionStatisticsImpl.java deleted file mode 100644 index 59d099e1d4..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentCollectionStatisticsImpl.java +++ /dev/null @@ -1,80 +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 . - */ -package org.hibernate.stat.internal; - -import java.util.concurrent.atomic.AtomicLong; - -import org.hibernate.stat.CollectionStatistics; - -/** - * Collection related statistics - * - * @author Alex Snaps - */ -public class ConcurrentCollectionStatisticsImpl extends CategorizedStatistics implements CollectionStatistics { - ConcurrentCollectionStatisticsImpl(String role) { - super(role); - } - - private AtomicLong loadCount = new AtomicLong(); - private AtomicLong fetchCount = new AtomicLong(); - private AtomicLong updateCount = new AtomicLong(); - private AtomicLong removeCount = new AtomicLong(); - private AtomicLong recreateCount = new AtomicLong(); - - public long getLoadCount() { - return loadCount.get(); - } - - public long getFetchCount() { - return fetchCount.get(); - } - - public long getRecreateCount() { - return recreateCount.get(); - } - - public long getRemoveCount() { - return removeCount.get(); - } - - public long getUpdateCount() { - return updateCount.get(); - } - - public String toString() { - return new StringBuilder() - .append("CollectionStatistics") - .append("[loadCount=").append(this.loadCount) - .append(",fetchCount=").append(this.fetchCount) - .append(",recreateCount=").append(this.recreateCount) - .append(",removeCount=").append(this.removeCount) - .append(",updateCount=").append(this.updateCount) - .append(']') - .toString(); - } - - void incrementLoadCount() { - loadCount.getAndIncrement(); - } - - void incrementFetchCount() { - fetchCount.getAndIncrement(); - } - - void incrementUpdateCount() { - updateCount.getAndIncrement(); - } - - void incrementRecreateCount() { - recreateCount.getAndIncrement(); - } - - void incrementRemoveCount() { - removeCount.getAndIncrement(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentEntityStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentEntityStatisticsImpl.java deleted file mode 100644 index 00a289c835..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentEntityStatisticsImpl.java +++ /dev/null @@ -1,91 +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 . - */ -package org.hibernate.stat.internal; - -import java.util.concurrent.atomic.AtomicLong; - -import org.hibernate.stat.EntityStatistics; - -/** - * Entity related statistics - * - * @author Alex Snaps - */ -public class ConcurrentEntityStatisticsImpl extends CategorizedStatistics implements EntityStatistics { - - ConcurrentEntityStatisticsImpl(String name) { - super(name); - } - - private AtomicLong loadCount = new AtomicLong(); - private AtomicLong updateCount = new AtomicLong(); - private AtomicLong insertCount = new AtomicLong(); - private AtomicLong deleteCount = new AtomicLong(); - private AtomicLong fetchCount = new AtomicLong(); - private AtomicLong optimisticFailureCount = new AtomicLong(); - - public long getDeleteCount() { - return deleteCount.get(); - } - - public long getInsertCount() { - return insertCount.get(); - } - - public long getLoadCount() { - return loadCount.get(); - } - - public long getUpdateCount() { - return updateCount.get(); - } - - public long getFetchCount() { - return fetchCount.get(); - } - - public long getOptimisticFailureCount() { - return optimisticFailureCount.get(); - } - - public String toString() { - return new StringBuilder() - .append("EntityStatistics") - .append("[loadCount=").append(this.loadCount) - .append(",updateCount=").append(this.updateCount) - .append(",insertCount=").append(this.insertCount) - .append(",deleteCount=").append(this.deleteCount) - .append(",fetchCount=").append(this.fetchCount) - .append(",optimisticLockFailureCount=").append(this.optimisticFailureCount) - .append(']') - .toString(); - } - - void incrementLoadCount() { - loadCount.getAndIncrement(); - } - - void incrementFetchCount() { - fetchCount.getAndIncrement(); - } - - void incrementUpdateCount() { - updateCount.getAndIncrement(); - } - - void incrementInsertCount() { - insertCount.getAndIncrement(); - } - - void incrementDeleteCount() { - deleteCount.getAndIncrement(); - } - - void incrementOptimisticFailureCount() { - optimisticFailureCount.getAndIncrement(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentSecondLevelCacheStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentSecondLevelCacheStatisticsImpl.java deleted file mode 100644 index 3866fafb3b..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentSecondLevelCacheStatisticsImpl.java +++ /dev/null @@ -1,111 +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 . - */ -package org.hibernate.stat.internal; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -import org.hibernate.cache.spi.Region; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.stat.SecondLevelCacheStatistics; - -/** - * Second level cache statistics of a specific region - * - * @author Alex Snaps - */ -public class ConcurrentSecondLevelCacheStatisticsImpl extends CategorizedStatistics implements SecondLevelCacheStatistics { - private final transient Region region; - private final transient EntityRegionAccessStrategy entityRegionAccessStrategy; - private final transient CollectionRegionAccessStrategy collectionRegionAccessStrategy; - private AtomicLong hitCount = new AtomicLong(); - private AtomicLong missCount = new AtomicLong(); - private AtomicLong putCount = new AtomicLong(); - - ConcurrentSecondLevelCacheStatisticsImpl( - Region region, - EntityRegionAccessStrategy entityRegionAccessStrategy, - CollectionRegionAccessStrategy collectionRegionAccessStrategy) { - super( region.getName() ); - this.region = region; - this.entityRegionAccessStrategy = entityRegionAccessStrategy; - this.collectionRegionAccessStrategy = collectionRegionAccessStrategy; - } - - public long getHitCount() { - return hitCount.get(); - } - - public long getMissCount() { - return missCount.get(); - } - - public long getPutCount() { - return putCount.get(); - } - - public long getElementCountInMemory() { - return region.getElementCountInMemory(); - } - - public long getElementCountOnDisk() { - return region.getElementCountOnDisk(); - } - - public long getSizeInMemory() { - return region.getSizeInMemory(); - } - - public Map getEntries() { - Map map = new HashMap(); - for ( Object o : region.toMap().entrySet() ) { - Map.Entry me = (Map.Entry) o; - Object id; - if ( entityRegionAccessStrategy != null ) { - id = entityRegionAccessStrategy.getCacheKeyId( me.getKey() ); - } - else if ( collectionRegionAccessStrategy != null ) { - id = collectionRegionAccessStrategy.getCacheKeyId( me.getKey() ); - } - else { - id = me.getKey(); - } - map.put( id, me.getValue() ); - } - return map; - } - - public String toString() { - StringBuilder buf = new StringBuilder() - .append( "SecondLevelCacheStatistics" ) - .append( "[hitCount=").append( this.hitCount ) - .append( ",missCount=").append( this.missCount ) - .append( ",putCount=").append( this.putCount ); - //not sure if this would ever be null but wanted to be careful - if ( region != null ) { - buf.append( ",elementCountInMemory=" ).append( this.getElementCountInMemory() ) - .append( ",elementCountOnDisk=" ).append( this.getElementCountOnDisk() ) - .append( ",sizeInMemory=" ).append( this.getSizeInMemory() ); - } - buf.append( ']' ); - return buf.toString(); - } - - void incrementHitCount() { - hitCount.getAndIncrement(); - } - - void incrementMissCount() { - missCount.getAndIncrement(); - } - - void incrementPutCount() { - putCount.getAndIncrement(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/DeprecatedNaturalIdCacheStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/DeprecatedNaturalIdCacheStatisticsImpl.java new file mode 100644 index 0000000000..5614d44d17 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/DeprecatedNaturalIdCacheStatisticsImpl.java @@ -0,0 +1,257 @@ +/* + * 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.stat.internal; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.hibernate.cache.spi.DomainDataRegion; +import org.hibernate.cache.spi.ExtendedStatisticsSupport; +import org.hibernate.cache.spi.Region; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; +import org.hibernate.stat.NaturalIdCacheStatistics; +import org.hibernate.stat.NaturalIdStatistics; + +import static org.hibernate.stat.CacheRegionStatistics.NO_EXTENDED_STAT_SUPPORT_RETURN; + +/** + * @deprecated (since 5.3) {@link NaturalIdStatistics} is preferred over + * {@link NaturalIdCacheStatistics} + * + * @author Eric Dalquist + */ +@Deprecated +public class DeprecatedNaturalIdCacheStatisticsImpl implements NaturalIdCacheStatistics { + private final String regionName; + private final transient Set accessStrategies; + + private final AtomicLong executionCount = new AtomicLong(); + private final AtomicLong executionMaxTime = new AtomicLong(); + private final AtomicLong executionMinTime = new AtomicLong( Long.MAX_VALUE ); + private final AtomicLong totalExecutionTime = new AtomicLong(); + + private final AtomicLong cacheHitCount = new AtomicLong(); + private final AtomicLong cacheMissCount = new AtomicLong(); + private final AtomicLong cachePutCount = new AtomicLong(); + + private final Lock readLock; + private final Lock writeLock; + + { + final ReadWriteLock lock = new ReentrantReadWriteLock(); + this.readLock = lock.readLock(); + this.writeLock = lock.writeLock(); + } + + DeprecatedNaturalIdCacheStatisticsImpl(String regionName, Set accessStrategies) { + this.regionName = regionName; + this.accessStrategies = accessStrategies; + } + + /** + * queries executed to the DB + */ + @Override + public long getExecutionCount() { + return this.executionCount.get(); + } + + /** + * average time in ms taken by the excution of this query onto the DB + */ + @Override + public long getExecutionAvgTime() { + // We write lock here to be sure that we always calculate the average time + // with all updates from the executed applied: executionCount and totalExecutionTime + // both used in the calculation + this.writeLock.lock(); + try { + long avgExecutionTime = 0; + if ( this.executionCount.get() > 0 ) { + avgExecutionTime = this.totalExecutionTime.get() / this.executionCount.get(); + } + return avgExecutionTime; + } + finally { + this.writeLock.unlock(); + } + } + + /** + * max time in ms taken by the excution of this query onto the DB + */ + @Override + public long getExecutionMaxTime() { + return this.executionMaxTime.get(); + } + + /** + * min time in ms taken by the excution of this query onto the DB + */ + @Override + public long getExecutionMinTime() { + return this.executionMinTime.get(); + } + + @Override + public long getHitCount() { + return this.cacheHitCount.get(); + } + + @Override + public long getMissCount() { + return this.cacheMissCount.get(); + } + + @Override + public long getPutCount() { + return this.cachePutCount.get(); + } + + @Override + public long getElementCountInMemory() { + long count = 0; + HashSet processedRegions = null; + + for ( NaturalIdDataAccess accessStrategy : accessStrategies ) { + final DomainDataRegion region = accessStrategy.getRegion(); + if ( ExtendedStatisticsSupport.class.isInstance( region ) ) { + + } + + if ( region instanceof ExtendedStatisticsSupport ) { + if ( processedRegions == null ) { + processedRegions = new HashSet<>(); + } + if ( processedRegions.add( region ) ) { + count += ( (ExtendedStatisticsSupport) region ).getElementCountInMemory(); + } + } + + } + + if ( count == 0 ) { + return NO_EXTENDED_STAT_SUPPORT_RETURN; + } + + return count; + } + + @Override + public long getElementCountOnDisk() { + long count = 0; + HashSet processedRegions = null; + + for ( NaturalIdDataAccess accessStrategy : accessStrategies ) { + final DomainDataRegion region = accessStrategy.getRegion(); + if ( ExtendedStatisticsSupport.class.isInstance( region ) ) { + + } + + if ( region instanceof ExtendedStatisticsSupport ) { + if ( processedRegions == null ) { + processedRegions = new HashSet<>(); + } + if ( processedRegions.add( region ) ) { + count += ( (ExtendedStatisticsSupport) region ).getElementCountOnDisk(); + } + } + + } + + if ( count == 0 ) { + return NO_EXTENDED_STAT_SUPPORT_RETURN; + } + + return count; + } + + @Override + public long getSizeInMemory() { + long count = 0; + HashSet processedRegions = null; + + for ( NaturalIdDataAccess accessStrategy : accessStrategies ) { + final DomainDataRegion region = accessStrategy.getRegion(); + if ( ExtendedStatisticsSupport.class.isInstance( region ) ) { + + } + + if ( region instanceof ExtendedStatisticsSupport ) { + if ( processedRegions == null ) { + processedRegions = new HashSet<>(); + } + if ( processedRegions.add( region ) ) { + count += ( (ExtendedStatisticsSupport) region ).getElementCountOnDisk(); + } + } + + } + + if ( count == 0 ) { + return NO_EXTENDED_STAT_SUPPORT_RETURN; + } + + return count; + } + + void incrementHitCount() { + cacheHitCount.getAndIncrement(); + } + + void incrementMissCount() { + cacheMissCount.getAndIncrement(); + } + + void incrementPutCount() { + cachePutCount.getAndIncrement(); + } + + void queryExecuted(long time) { + // read lock is enough, concurrent updates are supported by the underlying type AtomicLong + // this only guards executed(long, long) to be called, when another thread is executing getExecutionAvgTime() + this.readLock.lock(); + try { + // Less chances for a context switch + //noinspection StatementWithEmptyBody + for ( long old = this.executionMinTime.get(); time < old && !this.executionMinTime.compareAndSet( old, time ); old = this.executionMinTime.get() ) { + } + //noinspection StatementWithEmptyBody + for ( long old = this.executionMaxTime.get(); time > old && !this.executionMaxTime.compareAndSet( old, time ); old = this.executionMaxTime.get() ) { + } + this.executionCount.getAndIncrement(); + this.totalExecutionTime.addAndGet( time ); + } + finally { + this.readLock.unlock(); + } + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder() + .append( "NaturalIdCacheStatistics(deprecated)" ) + .append( "[regionName=" ).append( regionName ) + .append( ",executionCount=" ).append( getExecutionCount() ) + .append( ",executionAvgTime=" ).append( getExecutionAvgTime() ) + .append( ",executionMinTime=" ).append( getExecutionMinTime() ) + .append( ",executionMaxTime=" ).append( getExecutionMaxTime() ); + + buf.append( ",hitCount=" ).append( getHitCount() ) + .append( ",missCount=" ).append( getMissCount() ) + .append( ",putCount=" ).append( getPutCount() ) + .append( ",elementCountInMemory=" ).append( this.getElementCountInMemory() ) + .append( ",elementCountOnDisk=" ).append( this.getElementCountOnDisk() ) + .append( ",sizeInMemory=" ).append( this.getSizeInMemory() ); + + return buf.append( ']' ).toString(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/EntityStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/EntityStatisticsImpl.java new file mode 100644 index 0000000000..7904ae04bb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/EntityStatisticsImpl.java @@ -0,0 +1,100 @@ +/* + * 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.stat.internal; + +import java.io.Serializable; +import java.util.concurrent.atomic.AtomicLong; + +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.stat.EntityStatistics; + +/** + * Entity related statistics + * + * @author Alex Snaps + */ +public class EntityStatisticsImpl extends AbstractCacheableDataStatistics implements EntityStatistics, Serializable { + private final String rootEntityName; + + private AtomicLong loadCount = new AtomicLong(); + private AtomicLong updateCount = new AtomicLong(); + private AtomicLong insertCount = new AtomicLong(); + private AtomicLong deleteCount = new AtomicLong(); + private AtomicLong fetchCount = new AtomicLong(); + private AtomicLong optimisticFailureCount = new AtomicLong(); + + EntityStatisticsImpl(EntityPersister rootEntityDescriptor) { + super( + () -> rootEntityDescriptor.getCacheAccessStrategy() != null + ? rootEntityDescriptor.getCacheAccessStrategy().getRegion() + : null + ); + this.rootEntityName = rootEntityDescriptor.getRootEntityName(); + } + + public long getDeleteCount() { + return deleteCount.get(); + } + + public long getInsertCount() { + return insertCount.get(); + } + + public long getLoadCount() { + return loadCount.get(); + } + + public long getUpdateCount() { + return updateCount.get(); + } + + public long getFetchCount() { + return fetchCount.get(); + } + + public long getOptimisticFailureCount() { + return optimisticFailureCount.get(); + } + + void incrementLoadCount() { + loadCount.getAndIncrement(); + } + + void incrementFetchCount() { + fetchCount.getAndIncrement(); + } + + void incrementUpdateCount() { + updateCount.getAndIncrement(); + } + + void incrementInsertCount() { + insertCount.getAndIncrement(); + } + + void incrementDeleteCount() { + deleteCount.getAndIncrement(); + } + + void incrementOptimisticFailureCount() { + optimisticFailureCount.getAndIncrement(); + } + + public String toString() { + final StringBuilder buffer = new StringBuilder() + .append( "EntityStatistics" ) + .append( "[rootEntityName=" ).append( rootEntityName ) + .append( ",loadCount=" ).append( this.loadCount ) + .append( ",updateCount=" ).append( this.updateCount ) + .append( ",insertCount=" ).append( this.insertCount ) + .append( ",deleteCount=" ).append( this.deleteCount ) + .append( ",fetchCount=" ).append( this.fetchCount ) + .append( ",optimisticLockFailureCount=" ).append( this.optimisticFailureCount ); + appendCacheStats( buffer ); + return buffer.append( ']' ).toString(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/NaturalIdStatisticsImpl.java similarity index 52% rename from hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java rename to hibernate-core/src/main/java/org/hibernate/stat/internal/NaturalIdStatisticsImpl.java index 7eedbe4676..faa48a40cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/NaturalIdStatisticsImpl.java @@ -6,29 +6,25 @@ */ package org.hibernate.stat.internal; -import java.util.HashMap; -import java.util.Map; +import java.io.Serializable; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.hibernate.cache.spi.Region; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; -import org.hibernate.stat.NaturalIdCacheStatistics; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.stat.NaturalIdStatistics; /** - * NaturalId cache statistics of a specific region + * NaturalId cache statistics of a specific entity * * @author Eric Dalquist */ -public class ConcurrentNaturalIdCacheStatisticsImpl extends CategorizedStatistics implements NaturalIdCacheStatistics { +public class NaturalIdStatisticsImpl extends AbstractCacheableDataStatistics implements NaturalIdStatistics, Serializable { private static final long serialVersionUID = 1L; - private final transient Region region; - private final transient NaturalIdRegionAccessStrategy accessStrategy; - private final AtomicLong hitCount = new AtomicLong(); - private final AtomicLong missCount = new AtomicLong(); - private final AtomicLong putCount = new AtomicLong(); + + private final String rootEntityName; + private final AtomicLong executionCount = new AtomicLong(); private final AtomicLong executionMaxTime = new AtomicLong(); private final AtomicLong executionMinTime = new AtomicLong( Long.MAX_VALUE ); @@ -43,25 +39,13 @@ public class ConcurrentNaturalIdCacheStatisticsImpl extends CategorizedStatistic this.writeLock = lock.writeLock(); } - ConcurrentNaturalIdCacheStatisticsImpl(Region region, NaturalIdRegionAccessStrategy accessStrategy) { - super( region.getName() ); - this.region = region; - this.accessStrategy = accessStrategy; - } - - @Override - public long getHitCount() { - return this.hitCount.get(); - } - - @Override - public long getMissCount() { - return this.missCount.get(); - } - - @Override - public long getPutCount() { - return this.putCount.get(); + NaturalIdStatisticsImpl(EntityPersister rootEntityDescriptor) { + super( + () -> rootEntityDescriptor.getCacheAccessStrategy() != null + ? rootEntityDescriptor.getCacheAccessStrategy().getRegion() + : null + ); + this.rootEntityName = rootEntityDescriptor.getRootEntityName(); } /** @@ -109,65 +93,6 @@ public class ConcurrentNaturalIdCacheStatisticsImpl extends CategorizedStatistic return this.executionMinTime.get(); } - @Override - public long getElementCountInMemory() { - return this.region.getElementCountInMemory(); - } - - @Override - public long getElementCountOnDisk() { - return this.region.getElementCountOnDisk(); - } - - @Override - public long getSizeInMemory() { - return this.region.getSizeInMemory(); - } - - @Override - @SuppressWarnings("unchecked") - public Map getEntries() { - final Map map = new HashMap(); - for ( Object o : this.region.toMap().entrySet() ) { - Map.Entry me = (Map.Entry) o; - map.put( accessStrategy.getNaturalIdValues(me.getKey()), me.getValue() ); - } - return map; - } - - @Override - public String toString() { - final StringBuilder buf = new StringBuilder() - .append( "NaturalIdCacheStatistics" ) - .append( "[hitCount=" ).append( this.hitCount ) - .append( ",missCount=" ).append( this.missCount ) - .append( ",putCount=" ).append( this.putCount ) - .append( ",executionCount=" ).append( this.executionCount ) - .append( ",executionAvgTime=" ).append( this.getExecutionAvgTime() ) - .append( ",executionMinTime=" ).append( this.executionMinTime ) - .append( ",executionMaxTime=" ).append( this.executionMaxTime ); - // not sure if this would ever be null but wanted to be careful - if ( this.region != null ) { - buf.append( ",elementCountInMemory=" ).append( this.getElementCountInMemory() ) - .append( ",elementCountOnDisk=" ).append( this.getElementCountOnDisk() ) - .append( ",sizeInMemory=" ).append( this.getSizeInMemory() ); - } - buf.append( ']' ); - return buf.toString(); - } - - void incrementHitCount() { - this.hitCount.getAndIncrement(); - } - - void incrementMissCount() { - this.missCount.getAndIncrement(); - } - - void incrementPutCount() { - this.putCount.getAndIncrement(); - } - void queryExecuted(long time) { // read lock is enough, concurrent updates are supported by the underlying type AtomicLong // this only guards executed(long, long) to be called, when another thread is executing getExecutionAvgTime() @@ -187,4 +112,17 @@ public class ConcurrentNaturalIdCacheStatisticsImpl extends CategorizedStatistic this.readLock.unlock(); } } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder() + .append( "NaturalIdCacheStatistics" ) + .append( "[rootEntityName=" ).append( rootEntityName ) + .append( ",executionCount=" ).append( this.executionCount ) + .append( ",executionAvgTime=" ).append( this.getExecutionAvgTime() ) + .append( ",executionMinTime=" ).append( this.executionMinTime ) + .append( ",executionMaxTime=" ).append( this.executionMaxTime ); + appendCacheStats( buf ); + return buf.append( ']' ).toString(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentQueryStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java similarity index 89% rename from hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentQueryStatisticsImpl.java rename to hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java index 4216a4be8a..851394937a 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentQueryStatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java @@ -13,6 +13,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import org.hibernate.stat.QueryStatistics; +import org.jboss.logging.Logger; + /** * Query statistics (HQL and SQL) *

        @@ -20,7 +22,11 @@ import org.hibernate.stat.QueryStatistics; * * @author Alex Snaps */ -public class ConcurrentQueryStatisticsImpl extends CategorizedStatistics implements QueryStatistics { +public class QueryStatisticsImpl implements QueryStatistics { + private static final Logger log = Logger.getLogger( QueryStatisticsImpl.class ); + + private final String query; + private final AtomicLong cacheHitCount = new AtomicLong(); private final AtomicLong cacheMissCount = new AtomicLong(); private final AtomicLong cachePutCount = new AtomicLong(); @@ -39,8 +45,8 @@ public class ConcurrentQueryStatisticsImpl extends CategorizedStatistics impleme writeLock = lock.writeLock(); } - ConcurrentQueryStatisticsImpl(String query) { - super(query); + QueryStatisticsImpl(String query) { + this.query = query; } /** @@ -134,6 +140,8 @@ public class ConcurrentQueryStatisticsImpl extends CategorizedStatistics impleme * @param time time taken */ void executed(long rows, long time) { + log.tracef( "QueryStatistics - query executed : %s", query ); + // read lock is enough, concurrent updates are supported by the underlying type AtomicLong // this only guards executed(long, long) to be called, when another thread is executing getExecutionAvgTime() readLock.lock(); @@ -150,9 +158,28 @@ public class ConcurrentQueryStatisticsImpl extends CategorizedStatistics impleme } } + void incrementCacheHitCount() { + log.tracef( "QueryStatistics - cache hit : %s", query ); + + cacheHitCount.getAndIncrement(); + } + + void incrementCacheMissCount() { + log.tracef( "QueryStatistics - cache miss : %s", query ); + + cacheMissCount.getAndIncrement(); + } + + void incrementCachePutCount() { + log.tracef( "QueryStatistics - cache put : %s", query ); + + cachePutCount.getAndIncrement(); + } + public String toString() { return "QueryStatistics" - + "[cacheHitCount=" + this.cacheHitCount + + "[query=" + query + + ",cacheHitCount=" + this.cacheHitCount + ",cacheMissCount=" + this.cacheMissCount + ",cachePutCount=" + this.cachePutCount + ",executionCount=" + this.executionCount @@ -162,16 +189,4 @@ public class ConcurrentQueryStatisticsImpl extends CategorizedStatistics impleme + ",executionMinTime=" + this.executionMinTime + ']'; } - - void incrementCacheHitCount() { - cacheHitCount.getAndIncrement(); - } - - void incrementCacheMissCount() { - cacheMissCount.getAndIncrement(); - } - - void incrementCachePutCount() { - cachePutCount.getAndIncrement(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java rename to hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 6ace93a64d..c48f6e3359 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -10,14 +10,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; -import org.hibernate.cache.spi.QueryCache; +import org.hibernate.cache.spi.QueryResultRegionAccess; import org.hibernate.cache.spi.Region; -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.SessionFactoryImplementor; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.service.Service; import org.hibernate.stat.spi.StatisticsImplementor; @@ -29,13 +27,14 @@ import static org.hibernate.internal.CoreLogging.messageLogger; * @author Alex Snaps */ @SuppressWarnings({ "unchecked" }) -public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service { - private static final CoreMessageLogger LOG = messageLogger( ConcurrentStatisticsImpl.class ); +public class StatisticsImpl implements StatisticsImplementor, Service { + private static final CoreMessageLogger LOG = messageLogger( StatisticsImpl.class ); private SessionFactoryImplementor sessionFactory; private volatile boolean isStatisticsEnabled; private volatile long startTime; + private AtomicLong sessionOpenCount = new AtomicLong(); private AtomicLong sessionCloseCount = new AtomicLong(); private AtomicLong flushCount = new AtomicLong(); @@ -65,7 +64,8 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service private AtomicLong naturalIdQueryExecutionCount = new AtomicLong(); private AtomicLong naturalIdQueryExecutionMaxTime = new AtomicLong(); private volatile String naturalIdQueryExecutionMaxTimeRegion; - + private volatile String naturalIdQueryExecutionMaxTimeEntity; + private AtomicLong queryExecutionCount = new AtomicLong(); private AtomicLong queryExecutionMaxTime = new AtomicLong(); private volatile String queryExecutionMaxTimeQueryString; @@ -82,18 +82,29 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service private AtomicLong optimisticFailureCount = new AtomicLong(); - private final ConcurrentMap entityStatistics = new ConcurrentHashMap(); - private final ConcurrentMap naturalIdCacheStatistics = new ConcurrentHashMap(); - private final ConcurrentMap collectionStatistics = new ConcurrentHashMap(); - private final ConcurrentMap secondLevelCacheStatistics = new ConcurrentHashMap<>(); - private final ConcurrentMap queryStatistics = new ConcurrentHashMap(); + private final ConcurrentMap entityStatsMap = new ConcurrentHashMap(); + private final ConcurrentMap naturalIdQueryStatsMap = new ConcurrentHashMap(); + private final ConcurrentMap collectionStatsMap = new ConcurrentHashMap(); + + /** + * Keyed by query string + */ + private final ConcurrentMap queryStatsMap = new ConcurrentHashMap(); + + /** + * Keyed by region name + */ + private final ConcurrentMap l2CacheStatsMap = new ConcurrentHashMap<>(); + + private final ConcurrentMap deprecatedNaturalIdStatsMap = new ConcurrentHashMap(); + @SuppressWarnings({ "UnusedDeclaration" }) - public ConcurrentStatisticsImpl() { + public StatisticsImpl() { clear(); } - public ConcurrentStatisticsImpl(SessionFactoryImplementor sessionFactory) { + public StatisticsImpl(SessionFactoryImplementor sessionFactory) { clear(); this.sessionFactory = sessionFactory; } @@ -112,6 +123,7 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service naturalIdQueryExecutionCount.set( 0 ); naturalIdQueryExecutionMaxTime.set( 0 ); naturalIdQueryExecutionMaxTimeRegion = null; + naturalIdQueryExecutionMaxTimeEntity = null; sessionCloseCount.set( 0 ); sessionOpenCount.set( 0 ); @@ -149,231 +161,317 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service optimisticFailureCount.set( 0 ); - secondLevelCacheStatistics.clear(); - entityStatistics.clear(); - collectionStatistics.clear(); - queryStatistics.clear(); - naturalIdCacheStatistics.clear(); + entityStatsMap.clear(); + collectionStatsMap.clear(); + naturalIdQueryStatsMap.clear(); + l2CacheStatsMap.clear(); + queryStatsMap.clear(); + deprecatedNaturalIdStatsMap.clear(); startTime = System.currentTimeMillis(); } - public void openSession() { - sessionOpenCount.getAndIncrement(); + @Override + public long getStartTime() { + return startTime; } - public void closeSession() { - sessionCloseCount.getAndIncrement(); + @Override + public boolean isStatisticsEnabled() { + return isStatisticsEnabled; } - public void flush() { - flushCount.getAndIncrement(); + @Override + public void setStatisticsEnabled(boolean b) { + isStatisticsEnabled = b; } - public void connect() { - connectCount.getAndIncrement(); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Entity stats + + @Override + public String[] getEntityNames() { + if ( sessionFactory == null ) { + return ArrayHelper.toStringArray( entityStatsMap.keySet() ); + } + else { + return sessionFactory.getMetamodel().getAllEntityNames(); + } } + @Override + public EntityStatisticsImpl getEntityStatistics(String entityName) { + if ( sessionFactory == null ) { + return null; + } + + return entityStatsMap.computeIfAbsent( + entityName, + s -> new EntityStatisticsImpl( sessionFactory.getMetamodel().entityPersister( entityName ) ) + ); + } + + @Override + public long getEntityLoadCount() { + return entityLoadCount.get(); + } + + @Override + public long getEntityFetchCount() { + return entityFetchCount.get(); + } + + @Override + public long getEntityDeleteCount() { + return entityDeleteCount.get(); + } + + @Override + public long getEntityInsertCount() { + return entityInsertCount.get(); + } + + @Override + public long getEntityUpdateCount() { + return entityUpdateCount.get(); + } + + @Override + public long getOptimisticFailureCount() { + return optimisticFailureCount.get(); + } + + @Override public void loadEntity(String entityName) { entityLoadCount.getAndIncrement(); getEntityStatistics( entityName ).incrementLoadCount(); } + @Override public void fetchEntity(String entityName) { entityFetchCount.getAndIncrement(); getEntityStatistics( entityName ).incrementFetchCount(); } - /** - * find entity statistics per name - * - * @param entityName entity name - * - * @return EntityStatistics object - */ - public ConcurrentEntityStatisticsImpl getEntityStatistics(String entityName) { - ConcurrentEntityStatisticsImpl es = entityStatistics.get( entityName ); - if ( es == null ) { - es = new ConcurrentEntityStatisticsImpl( entityName ); - ConcurrentEntityStatisticsImpl previous; - if ( ( previous = entityStatistics.putIfAbsent( entityName, es ) ) != null ) { - es = previous; - } - } - return es; - } - + @Override public void updateEntity(String entityName) { entityUpdateCount.getAndIncrement(); - ConcurrentEntityStatisticsImpl es = getEntityStatistics( entityName ); - es.incrementUpdateCount(); + getEntityStatistics( entityName ).incrementUpdateCount(); } + @Override public void insertEntity(String entityName) { entityInsertCount.getAndIncrement(); - ConcurrentEntityStatisticsImpl es = getEntityStatistics( entityName ); - es.incrementInsertCount(); + getEntityStatistics( entityName ).incrementInsertCount(); } + @Override public void deleteEntity(String entityName) { entityDeleteCount.getAndIncrement(); - ConcurrentEntityStatisticsImpl es = getEntityStatistics( entityName ); - es.incrementDeleteCount(); + getEntityStatistics( entityName ).incrementDeleteCount(); } - /** - * Get collection statistics per role - * - * @param role collection role - * - * @return CollectionStatistics - */ - public ConcurrentCollectionStatisticsImpl getCollectionStatistics(String role) { - ConcurrentCollectionStatisticsImpl cs = collectionStatistics.get( role ); - if ( cs == null ) { - cs = new ConcurrentCollectionStatisticsImpl( role ); - ConcurrentCollectionStatisticsImpl previous; - if ( ( previous = collectionStatistics.putIfAbsent( role, cs ) ) != null ) { - cs = previous; - } + @Override + public void optimisticFailure(String entityName) { + optimisticFailureCount.getAndIncrement(); + getEntityStatistics( entityName ).incrementOptimisticFailureCount(); + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Collection stats + + @Override + public String[] getCollectionRoleNames() { + if ( sessionFactory == null ) { + return ArrayHelper.toStringArray( collectionStatsMap.keySet() ); + } + else { + return sessionFactory.getMetamodel().getAllCollectionRoles(); } - return cs; } + @Override + public CollectionStatisticsImpl getCollectionStatistics(String role) { + if ( sessionFactory == null ) { + return null; + } + + return collectionStatsMap.computeIfAbsent( + role, + s -> new CollectionStatisticsImpl( sessionFactory.getMetamodel().collectionPersister( role ) ) + ); + } + + @Override + public long getCollectionLoadCount() { + return collectionLoadCount.get(); + } + + @Override + public long getCollectionFetchCount() { + return collectionFetchCount.get(); + } + + @Override + public long getCollectionUpdateCount() { + return collectionUpdateCount.get(); + } + + @Override + public long getCollectionRemoveCount() { + return collectionRemoveCount.get(); + } + + @Override + public long getCollectionRecreateCount() { + return collectionRecreateCount.get(); + } + + @Override public void loadCollection(String role) { collectionLoadCount.getAndIncrement(); getCollectionStatistics( role ).incrementLoadCount(); } + @Override public void fetchCollection(String role) { collectionFetchCount.getAndIncrement(); getCollectionStatistics( role ).incrementFetchCount(); } + @Override public void updateCollection(String role) { collectionUpdateCount.getAndIncrement(); getCollectionStatistics( role ).incrementUpdateCount(); } + @Override public void recreateCollection(String role) { collectionRecreateCount.getAndIncrement(); getCollectionStatistics( role ).incrementRecreateCount(); } + @Override public void removeCollection(String role) { collectionRemoveCount.getAndIncrement(); getCollectionStatistics( role ).incrementRemoveCount(); } - + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Natural-id stats @Override - public ConcurrentNaturalIdCacheStatisticsImpl getNaturalIdCacheStatistics(String regionName) { - ConcurrentNaturalIdCacheStatisticsImpl stat = naturalIdCacheStatistics.get( regionName ); - - if ( stat == null ) { - if ( sessionFactory == null ) { - return null; - } - - final NaturalIdRegionAccessStrategy accessStrategy = sessionFactory.getCache().getNaturalIdCacheRegionAccessStrategy( regionName ); - stat = new ConcurrentNaturalIdCacheStatisticsImpl( accessStrategy.getRegion(), accessStrategy ); - ConcurrentNaturalIdCacheStatisticsImpl previous; - if ( ( previous = naturalIdCacheStatistics.putIfAbsent( regionName, stat ) ) != null ) { - stat = previous; - } + public NaturalIdStatisticsImpl getNaturalIdStatistics(String rootEntityName) { + if ( sessionFactory == null ) { + return null; } - return stat; - } - - /** - * Second level cache statistics per region - * - * @param regionName region name - * - * @return SecondLevelCacheStatistics or null if the second level cache is not enabled - * - * @throws IllegalArgumentException if the region name could not be resolved - */ - public ConcurrentSecondLevelCacheStatisticsImpl getSecondLevelCacheStatistics(String regionName) { - ConcurrentSecondLevelCacheStatisticsImpl stat = secondLevelCacheStatistics.get( regionName ); - if ( stat == null ) { - if ( sessionFactory == null ) { - return null; - } - - final EntityRegionAccessStrategy entityRegionAccess = sessionFactory.getCache().getEntityRegionAccess( regionName ); - final CollectionRegionAccessStrategy collectionRegionAccess = sessionFactory.getCache().getCollectionRegionAccess( regionName ); - - if ( entityRegionAccess == null && collectionRegionAccess == null ) { - final QueryCache queryCache = sessionFactory.getCache().getQueryCache( regionName ); - if ( queryCache == null ) { - return null; + return naturalIdQueryStatsMap.computeIfAbsent( + rootEntityName, + s -> { + final EntityPersister entityDescriptor = sessionFactory.getMetamodel().entityPersister( rootEntityName ); + if ( !entityDescriptor.hasNaturalIdentifier() ) { + throw new IllegalArgumentException( "Given entity [" + rootEntityName + "] does not define natural-id" ); + } + return new NaturalIdStatisticsImpl( entityDescriptor ); } - final Region region = queryCache.getRegion(); - if ( region == null ) { - throw new IllegalArgumentException( "Could not resolve region name [" + regionName + "]" ); - } - stat = new ConcurrentSecondLevelCacheStatisticsImpl( region, null, null ); - } - else { - - final Region region = entityRegionAccess != null - ? entityRegionAccess.getRegion() - : collectionRegionAccess.getRegion(); - - stat = new ConcurrentSecondLevelCacheStatisticsImpl( - region, - entityRegionAccess, - collectionRegionAccess - ); - } - - ConcurrentSecondLevelCacheStatisticsImpl previous; - if ( ( previous = secondLevelCacheStatistics.putIfAbsent( regionName, stat ) ) != null ) { - stat = previous; - } - } - - return stat; + ); } - public void secondLevelCachePut(String regionName) { - secondLevelCachePutCount.getAndIncrement(); - getSecondLevelCacheStatistics( regionName ).incrementPutCount(); - } - - public void secondLevelCacheHit(String regionName) { - secondLevelCacheHitCount.getAndIncrement(); - getSecondLevelCacheStatistics( regionName ).incrementHitCount(); - } - - public void secondLevelCacheMiss(String regionName) { - secondLevelCacheMissCount.getAndIncrement(); - getSecondLevelCacheStatistics( regionName ).incrementMissCount(); - } - @Override - public void naturalIdCachePut(String regionName) { + public DeprecatedNaturalIdCacheStatisticsImpl getNaturalIdCacheStatistics(String regionName) { + return deprecatedNaturalIdStatsMap.computeIfAbsent( + sessionFactory.getCache().unqualifyRegionName( regionName ), + unqualifiedRegionName -> new DeprecatedNaturalIdCacheStatisticsImpl( + unqualifiedRegionName, + sessionFactory.getCache().getNaturalIdAccessesInRegion( unqualifiedRegionName ) + ) + ); + } + + @Override + public long getNaturalIdQueryExecutionCount() { + return naturalIdQueryExecutionCount.get(); + } + + @Override + public long getNaturalIdQueryExecutionMaxTime() { + return naturalIdQueryExecutionMaxTime.get(); + } + + @Override + public String getNaturalIdQueryExecutionMaxTimeRegion() { + return naturalIdQueryExecutionMaxTimeRegion; + } + + @Override + public String getNaturalIdQueryExecutionMaxTimeEntity() { + return naturalIdQueryExecutionMaxTimeEntity; + } + + @Override + public long getNaturalIdCacheHitCount() { + return naturalIdCacheHitCount.get(); + } + + @Override + public long getNaturalIdCacheMissCount() { + return naturalIdCacheMissCount.get(); + } + + @Override + public long getNaturalIdCachePutCount() { + return naturalIdCachePutCount.get(); + } + + @Override + public void naturalIdCachePut(String rootEntityName) { naturalIdCachePutCount.getAndIncrement(); - getNaturalIdCacheStatistics( regionName ).incrementPutCount(); + + final EntityPersister rootEntityPersister = sessionFactory.getMetamodel().entityPersister( rootEntityName ); + final String regionName = rootEntityPersister.getNaturalIdCacheAccessStrategy().getRegion().getName(); + + getDomainDataRegionStatistics( regionName ).incrementPutCount(); + + getNaturalIdCacheStatistics( qualify( regionName ) ).incrementPutCount(); } @Override - public void naturalIdCacheHit(String regionName) { + public void naturalIdCacheHit(String rootEntityName) { naturalIdCacheHitCount.getAndIncrement(); - getNaturalIdCacheStatistics( regionName ).incrementHitCount(); + + final EntityPersister rootEntityPersister = sessionFactory.getMetamodel().entityPersister( rootEntityName ); + final String regionName = rootEntityPersister.getNaturalIdCacheAccessStrategy().getRegion().getName(); + getDomainDataRegionStatistics( regionName ).incrementHitCount(); + + getNaturalIdCacheStatistics( qualify( regionName ) ).incrementHitCount(); } @Override - public void naturalIdCacheMiss(String regionName) { + public void naturalIdCacheMiss(String rootEntityName) { naturalIdCacheMissCount.getAndIncrement(); - getNaturalIdCacheStatistics( regionName ).incrementMissCount(); + + final EntityPersister rootEntityPersister = sessionFactory.getMetamodel().entityPersister( rootEntityName ); + final String regionName = rootEntityPersister.getNaturalIdCacheAccessStrategy().getRegion().getName(); + getDomainDataRegionStatistics( regionName ).incrementMissCount(); + + getNaturalIdCacheStatistics( qualify( regionName ) ).incrementMissCount(); } - + + protected String qualify(String regionName) { + return sessionFactory.getSessionFactoryOptions().getCacheRegionPrefix() == null + ? regionName + : sessionFactory.getSessionFactoryOptions().getCacheRegionPrefix() + '.' + regionName; + } + @Override - public void naturalIdQueryExecuted(String regionName, long time) { + public void naturalIdQueryExecuted(String rootEntityName, long time) { naturalIdQueryExecutionCount.getAndIncrement(); + boolean isLongestQuery; //noinspection StatementWithEmptyBody for ( long old = naturalIdQueryExecutionMaxTime.get(); @@ -381,66 +479,156 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service old = naturalIdQueryExecutionMaxTime.get() ) { // nothing to do here given the odd loop structure... } - if ( isLongestQuery && regionName != null ) { - naturalIdQueryExecutionMaxTimeRegion = regionName; + + if ( isLongestQuery ) { + naturalIdQueryExecutionMaxTimeEntity = rootEntityName; } - if ( regionName != null ) { - getNaturalIdCacheStatistics( regionName ).queryExecuted( time ); + + final EntityPersister rootEntityPersister = sessionFactory.getMetamodel().entityPersister( rootEntityName ); + + getNaturalIdStatistics( rootEntityName ).queryExecuted( time ); + + if ( rootEntityPersister.hasNaturalIdCache() ) { + final String naturalIdRegionName = rootEntityPersister.getNaturalIdCacheAccessStrategy() + .getRegion() + .getName(); + getNaturalIdCacheStatistics( qualify( naturalIdRegionName ) ).queryExecuted( time ); + + if ( isLongestQuery ) { + naturalIdQueryExecutionMaxTimeRegion = naturalIdRegionName; + } } } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Second-level cache region stats + @Override - public void queryExecuted(String hql, int rows, long time) { - LOG.hql(hql, time, (long) rows ); - queryExecutionCount.getAndIncrement(); - boolean isLongestQuery; - //noinspection StatementWithEmptyBody - for ( long old = queryExecutionMaxTime.get(); - ( isLongestQuery = time > old ) && ( !queryExecutionMaxTime.compareAndSet( old, time ) ); - old = queryExecutionMaxTime.get() ) { - // nothing to do here given the odd loop structure... - } - if ( isLongestQuery ) { - queryExecutionMaxTimeQueryString = hql; - } - if ( hql != null ) { - ConcurrentQueryStatisticsImpl qs = getQueryStatistics( hql ); - qs.executed( rows, time ); + public String[] getSecondLevelCacheRegionNames() { + if ( sessionFactory == null ) { + throw new IllegalStateException( "Statistics no longer associated with SessionFactory - cannot get (legacy) region names" ); } + + return sessionFactory.getCache().getSecondLevelCacheRegionNames(); } + @Override - public void queryCacheHit(String hql, String regionName) { - queryCacheHitCount.getAndIncrement(); - if ( hql != null ) { - ConcurrentQueryStatisticsImpl qs = getQueryStatistics( hql ); - qs.incrementCacheHitCount(); + public CacheRegionStatisticsImpl getDomainDataRegionStatistics(String regionName) { + if ( sessionFactory == null ) { + return null; } - ConcurrentSecondLevelCacheStatisticsImpl slcs = getSecondLevelCacheStatistics( - regionName + + return l2CacheStatsMap.computeIfAbsent( + regionName, + s -> { + final Region region = sessionFactory.getCache().getRegion( regionName ); + + if ( region == null ) { + throw new IllegalArgumentException( "Unknown cache region : " + regionName ); + } + + return new CacheRegionStatisticsImpl( region ); + } ); - slcs.incrementHitCount(); } + @Override - public void queryCacheMiss(String hql, String regionName) { - queryCacheMissCount.getAndIncrement(); - if ( hql != null ) { - ConcurrentQueryStatisticsImpl qs = getQueryStatistics( hql ); - qs.incrementCacheMissCount(); + public CacheRegionStatisticsImpl getQueryRegionStatistics(String regionName) { + final CacheRegionStatisticsImpl existing = l2CacheStatsMap.get( regionName ); + if ( existing != null ) { + return existing; } - ConcurrentSecondLevelCacheStatisticsImpl slcs = getSecondLevelCacheStatistics( - regionName + + if ( sessionFactory == null ) { + return null; + } + + final QueryResultRegionAccess regionAccess = sessionFactory.getCache() + .getQueryResultsRegionAccessStrictly( regionName ); + if ( regionAccess == null ) { + return null; + } + + return l2CacheStatsMap.computeIfAbsent( + regionName, + s -> new CacheRegionStatisticsImpl( regionAccess.getRegion() ) ); - slcs.incrementMissCount(); } + @Override - public void queryCachePut(String hql, String regionName) { - queryCachePutCount.getAndIncrement(); - if ( hql != null ) { - ConcurrentQueryStatisticsImpl qs = getQueryStatistics( hql ); - qs.incrementCachePutCount(); + public CacheRegionStatisticsImpl getCacheRegionStatistics(String regionName) { + final CacheRegionStatisticsImpl existing = l2CacheStatsMap.get( regionName ); + if ( existing != null ) { + return existing; } - ConcurrentSecondLevelCacheStatisticsImpl slcs = getSecondLevelCacheStatistics( regionName ); - slcs.incrementPutCount(); + + if ( sessionFactory == null ) { + return null; + } + + // first try domain data region + try { + return getDomainDataRegionStatistics( regionName ); + } + catch (IllegalArgumentException ignore) { + } + + // and fallback to query result region + return getQueryRegionStatistics( regionName ); + } + + @Override + public CacheRegionStatisticsImpl getSecondLevelCacheStatistics(String regionName) { + return getCacheRegionStatistics( sessionFactory.getCache().unqualifyRegionName( regionName ) ); + } + + @Override + public long getSecondLevelCacheHitCount() { + return secondLevelCacheHitCount.get(); + } + + @Override + public long getSecondLevelCacheMissCount() { + return secondLevelCacheMissCount.get(); + } + + @Override + public long getSecondLevelCachePutCount() { + return secondLevelCachePutCount.get(); + } + + @Override + public long getUpdateTimestampsCacheHitCount() { + return updateTimestampsCacheHitCount.get(); + } + + @Override + public long getUpdateTimestampsCacheMissCount() { + return updateTimestampsCacheMissCount.get(); + } + + @Override + public long getUpdateTimestampsCachePutCount() { + return updateTimestampsCachePutCount.get(); + } + + @Override + public void secondLevelCachePut(String regionName) { + secondLevelCachePutCount.getAndIncrement(); + getDomainDataRegionStatistics( regionName ).incrementPutCount(); + } + + @Override + public void secondLevelCacheHit(String regionName) { + secondLevelCacheHitCount.getAndIncrement(); + getDomainDataRegionStatistics( regionName ).incrementHitCount(); + } + + @Override + public void secondLevelCacheMiss(String regionName) { + secondLevelCacheMissCount.getAndIncrement(); + getDomainDataRegionStatistics( regionName ).incrementMissCount(); } @Override @@ -458,232 +646,207 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service updateTimestampsCachePutCount.getAndIncrement(); } - /** - * Query statistics from query string (HQL or SQL) - * - * @param queryString query string - * - * @return QueryStatistics - */ + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Query statistics + @Override - public ConcurrentQueryStatisticsImpl getQueryStatistics(String queryString) { - ConcurrentQueryStatisticsImpl qs = queryStatistics.get( queryString ); - if ( qs == null ) { - qs = new ConcurrentQueryStatisticsImpl( queryString ); - ConcurrentQueryStatisticsImpl previous; - if ( ( previous = queryStatistics.putIfAbsent( queryString, qs ) ) != null ) { - qs = previous; - } - } - return qs; + public String[] getQueries() { + return ArrayHelper.toStringArray( queryStatsMap.keySet() ); } - /** - * @return entity deletion count - */ @Override - public long getEntityDeleteCount() { - return entityDeleteCount.get(); + public QueryStatisticsImpl getQueryStatistics(String queryString) { + return queryStatsMap.computeIfAbsent( + queryString, + s -> new QueryStatisticsImpl( queryString ) + ); } - /** - * @return entity insertion count - */ - @Override - public long getEntityInsertCount() { - return entityInsertCount.get(); - } - - /** - * @return entity load (from DB) - */ - @Override - public long getEntityLoadCount() { - return entityLoadCount.get(); - } - - /** - * @return entity fetch (from DB) - */ - @Override - public long getEntityFetchCount() { - return entityFetchCount.get(); - } - - /** - * @return entity update - */ - @Override - public long getEntityUpdateCount() { - return entityUpdateCount.get(); - } @Override public long getQueryExecutionCount() { return queryExecutionCount.get(); } + @Override public long getQueryCacheHitCount() { return queryCacheHitCount.get(); } + @Override public long getQueryCacheMissCount() { return queryCacheMissCount.get(); } + @Override public long getQueryCachePutCount() { return queryCachePutCount.get(); } - @Override - public long getUpdateTimestampsCacheHitCount() { - return updateTimestampsCacheHitCount.get(); - } - @Override - public long getUpdateTimestampsCacheMissCount() { - return updateTimestampsCacheMissCount.get(); - } - @Override - public long getUpdateTimestampsCachePutCount() { - return updateTimestampsCachePutCount.get(); - } - /** - * @return flush - */ @Override - public long getFlushCount() { - return flushCount.get(); - } - - /** - * @return session connect - */ - @Override - public long getConnectCount() { - return connectCount.get(); - } - - /** - * @return second level cache hit - */ - @Override - public long getSecondLevelCacheHitCount() { - return secondLevelCacheHitCount.get(); - } - - /** - * @return second level cache miss - */ - @Override - public long getSecondLevelCacheMissCount() { - return secondLevelCacheMissCount.get(); - } - - /** - * @return second level cache put - */ - @Override - public long getSecondLevelCachePutCount() { - return secondLevelCachePutCount.get(); + public String getQueryExecutionMaxTimeQueryString() { + return queryExecutionMaxTimeQueryString; } @Override - public long getNaturalIdQueryExecutionCount() { - return naturalIdQueryExecutionCount.get(); + public long getQueryExecutionMaxTime() { + return queryExecutionMaxTime.get(); } @Override - public long getNaturalIdQueryExecutionMaxTime() { - return naturalIdQueryExecutionMaxTime.get(); - } - - @Override - public String getNaturalIdQueryExecutionMaxTimeRegion() { - return naturalIdQueryExecutionMaxTimeRegion; - } - - @Override - public long getNaturalIdCacheHitCount() { - return naturalIdCacheHitCount.get(); + public void queryExecuted(String hql, int rows, long time) { + LOG.hql(hql, time, (long) rows ); + queryExecutionCount.getAndIncrement(); + + boolean isLongestQuery; + //noinspection StatementWithEmptyBody + for ( long old = queryExecutionMaxTime.get(); + ( isLongestQuery = time > old ) && ( !queryExecutionMaxTime.compareAndSet( old, time ) ); + old = queryExecutionMaxTime.get() ) { + // nothing to do here given the odd loop structure... + } + + if ( isLongestQuery ) { + queryExecutionMaxTimeQueryString = hql; + } + + if ( hql != null ) { + getQueryStatistics( hql ).executed( rows, time ); + } } @Override - public long getNaturalIdCacheMissCount() { - return naturalIdCacheMissCount.get(); + public void queryCacheHit(String hql, String regionName) { + LOG.tracef( "Statistics#queryCacheHit( `%s`, `%s` )", hql, regionName ); + + queryCacheHitCount.getAndIncrement(); + + getQueryRegionStats( regionName ).incrementHitCount(); + + if ( hql != null ) { + getQueryStatistics( hql ).incrementCacheHitCount(); + } + } + + private CacheRegionStatisticsImpl getQueryRegionStats(String regionName) { + return l2CacheStatsMap.computeIfAbsent( + regionName, + s -> new CacheRegionStatisticsImpl( sessionFactory.getCache().getQueryResultsRegionAccess( regionName ).getRegion() ) + ); + } + + + @Override + public void queryCacheMiss(String hql, String regionName) { + LOG.tracef( "Statistics#queryCacheMiss( `%s`, `%s` )", hql, regionName ); + + queryCacheMissCount.getAndIncrement(); + + getQueryRegionStats( regionName ).incrementMissCount(); + + if ( hql != null ) { + getQueryStatistics( hql ).incrementCacheMissCount(); + } } @Override - public long getNaturalIdCachePutCount() { - return naturalIdCachePutCount.get(); + public void queryCachePut(String hql, String regionName) { + LOG.tracef( "Statistics#queryCachePut( `%s`, `%s` )", hql, regionName ); + + queryCachePutCount.getAndIncrement(); + + getQueryRegionStats( regionName ).incrementPutCount(); + + if ( hql != null ) { + getQueryStatistics( hql ).incrementCachePutCount(); + } } - /** - * @return session closing - */ - @Override - public long getSessionCloseCount() { - return sessionCloseCount.get(); - } - /** - * @return session opening - */ + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Session/misc stats + @Override public long getSessionOpenCount() { return sessionOpenCount.get(); } - /** - * @return collection loading (from DB) - */ @Override - public long getCollectionLoadCount() { - return collectionLoadCount.get(); + public long getSessionCloseCount() { + return sessionCloseCount.get(); } - /** - * @return collection fetching (from DB) - */ @Override - public long getCollectionFetchCount() { - return collectionFetchCount.get(); + public long getFlushCount() { + return flushCount.get(); } - /** - * @return collection update - */ @Override - public long getCollectionUpdateCount() { - return collectionUpdateCount.get(); + public long getConnectCount() { + return connectCount.get(); } - /** - * @return collection removal - * FIXME: even if isInverse="true"? - */ @Override - public long getCollectionRemoveCount() { - return collectionRemoveCount.get(); + public long getSuccessfulTransactionCount() { + return committedTransactionCount.get(); } - /** - * @return collection recreation - */ @Override - public long getCollectionRecreateCount() { - return collectionRecreateCount.get(); + public long getTransactionCount() { + return transactionCount.get(); } - /** - * @return start time in ms (JVM standards {@link System#currentTimeMillis()}) - */ @Override - public long getStartTime() { - return startTime; + public long getCloseStatementCount() { + return closeStatementCount.get(); } - /** - * log in info level the main statistics - */ + @Override + public long getPrepareStatementCount() { + return prepareStatementCount.get(); + } + + @Override + public void openSession() { + sessionOpenCount.getAndIncrement(); + } + + @Override + public void closeSession() { + sessionCloseCount.getAndIncrement(); + } + + @Override + public void flush() { + flushCount.getAndIncrement(); + } + + @Override + public void connect() { + connectCount.getAndIncrement(); + } + + @Override + public void prepareStatement() { + prepareStatementCount.getAndIncrement(); + } + + @Override + public void closeStatement() { + closeStatementCount.getAndIncrement(); + } + + @Override + public void endTransaction(boolean success) { + transactionCount.getAndIncrement(); + if ( success ) { + committedTransactionCount.getAndIncrement(); + } + } + + + @Override public void logSummary() { LOG.loggingStatistics(); @@ -725,118 +888,6 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service LOG.maxQueryTime( queryExecutionMaxTime.get() ); } - /** - * Are statistics logged - */ - @Override - public boolean isStatisticsEnabled() { - return isStatisticsEnabled; - } - - /** - * Enable statistics logs (this is a dynamic parameter) - */ - @Override - public void setStatisticsEnabled(boolean b) { - isStatisticsEnabled = b; - } - - /** - * @return Returns the max query execution time, - * for all queries - */ - @Override - public long getQueryExecutionMaxTime() { - return queryExecutionMaxTime.get(); - } - - /** - * Get all executed query strings - */ - @Override - public String[] getQueries() { - return ArrayHelper.toStringArray( queryStatistics.keySet() ); - } - - /** - * Get the names of all entities - */ - @Override - public String[] getEntityNames() { - if ( sessionFactory == null ) { - return ArrayHelper.toStringArray( entityStatistics.keySet() ); - } - else { - return sessionFactory.getMetamodel().getAllEntityNames(); - } - } - - /** - * Get the names of all collection roles - */ - @Override - public String[] getCollectionRoleNames() { - if ( sessionFactory == null ) { - return ArrayHelper.toStringArray( collectionStatistics.keySet() ); - } - else { - return sessionFactory.getMetamodel().getAllCollectionRoles(); - } - } - - /** - * Get all second-level cache region names - */ - @Override - public String[] getSecondLevelCacheRegionNames() { - if ( sessionFactory == null ) { - return ArrayHelper.toStringArray( secondLevelCacheStatistics.keySet() ); - } - else { - return sessionFactory.getCache().getSecondLevelCacheRegionNames(); - } - } - @Override - public void endTransaction(boolean success) { - transactionCount.getAndIncrement(); - if ( success ) { - committedTransactionCount.getAndIncrement(); - } - } - @Override - public long getSuccessfulTransactionCount() { - return committedTransactionCount.get(); - } - @Override - public long getTransactionCount() { - return transactionCount.get(); - } - @Override - public void closeStatement() { - closeStatementCount.getAndIncrement(); - } - @Override - public void prepareStatement() { - prepareStatementCount.getAndIncrement(); - } - @Override - public long getCloseStatementCount() { - return closeStatementCount.get(); - } - @Override - public long getPrepareStatementCount() { - return prepareStatementCount.get(); - } - @Override - public void optimisticFailure(String entityName) { - optimisticFailureCount.getAndIncrement(); - ( (ConcurrentEntityStatisticsImpl) getEntityStatistics( entityName ) ).incrementOptimisticFailureCount(); - } - @Override - public long getOptimisticFailureCount() { - return optimisticFailureCount.get(); - } - @Override public String toString() { return new StringBuilder() @@ -880,8 +931,4 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service .append( ']' ) .toString(); } - @Override - public String getQueryExecutionMaxTimeQueryString() { - return queryExecutionMaxTimeQueryString; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsInitiator.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsInitiator.java index ba96e129fe..1692cd712f 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsInitiator.java @@ -86,7 +86,7 @@ public class StatisticsInitiator implements SessionFactoryServiceInitiator { - Document d = (Document) s.createQuery( "from Document fetch all properties" ).uniqueResult(); - assertTrue( isPropertyInitialized( d, "text" ) ); - assertTrue( isPropertyInitialized( d, "summary" ) ); + doInHibernate( + this::sessionFactory, + s -> { + Document d = (Document) s.createQuery( "from Document fetch all properties" ).uniqueResult(); + assertTrue( isPropertyInitialized( d, "text" ) ); + assertTrue( isPropertyInitialized( d, "summary" ) ); - BaseRegion region = (BaseRegion) persister.getCacheAccessStrategy().getRegion(); - Object cacheKey = persister.getCacheAccessStrategy().generateCacheKey( d.id, persister, sessionFactory(), null ); - StandardCacheEntryImpl cacheEntry = (StandardCacheEntryImpl) region.getDataMap().get( cacheKey ); - assertNotNull( cacheEntry ); - } ); + final EntityDataAccess entityDataAccess = persister.getCacheAccessStrategy(); + final Object cacheKey = entityDataAccess.generateCacheKey( + d.id, + persister, + sessionFactory(), + null + ); + final Object cachedItem = entityDataAccess.get( (SharedSessionContractImplementor) s, cacheKey ); + assertNotNull( cachedItem ); + assertTyping( StandardCacheEntryImpl.class, cachedItem ); + } + ); sessionFactory().getStatistics().clear(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java index f6a003dc7f..be02ce32fd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java @@ -9,7 +9,7 @@ package org.hibernate.test.cache; import org.hibernate.ObjectNotFoundException; import org.hibernate.Session; import org.hibernate.cache.internal.CollectionCacheInvalidator; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionImplementor; @@ -92,9 +92,9 @@ public class CollectionCacheEvictionTest extends BaseCoreFunctionalTestCase { Session session = openSession(); SessionImplementor sessionImplementor = (SessionImplementor) session; - CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy(); + CollectionDataAccess cache = persister.getCacheAccessStrategy(); Object key = cache.generateCacheKey( 1, persister, sessionFactory(), session.getTenantIdentifier() ); - Object cachedValue = cache.get( sessionImplementor, key, sessionImplementor.getTimestamp() ); + Object cachedValue = cache.get( sessionImplementor, key ); assertNull( cachedValue ); Company company = session.get( Company.class, 1 ); @@ -105,7 +105,7 @@ public class CollectionCacheEvictionTest extends BaseCoreFunctionalTestCase { session = openSession(); sessionImplementor = (SessionImplementor) session; key = cache.generateCacheKey( 1, persister, sessionFactory(), session.getTenantIdentifier() ); - cachedValue = cache.get( sessionImplementor, key, sessionImplementor.getTimestamp() ); + cachedValue = cache.get( sessionImplementor, key ); assertNotNull( "Collection wasn't cached", cachedValue ); session.close(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/InsertedDataTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/InsertedDataTest.java index a596a106ee..73c34502dc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/InsertedDataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/InsertedDataTest.java @@ -6,18 +6,13 @@ */ package org.hibernate.test.cache; -import java.util.Map; - -import org.junit.Test; - import org.hibernate.Session; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; -import org.hibernate.persister.entity.Lockable; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -54,8 +49,7 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 1, cacheMap.size() ); + assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); s = openSession(); s.beginTransaction(); @@ -77,8 +71,7 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 0, cacheMap.size() ); + assertFalse( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); } @Test @@ -95,8 +88,8 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 1, cacheMap.size() ); + assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); + s = openSession(); s.beginTransaction(); @@ -119,8 +112,7 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 0, cacheMap.size() ); + assertFalse( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); s = openSession(); s.beginTransaction(); @@ -143,8 +135,7 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 1, cacheMap.size() ); + assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); s = openSession(); s.beginTransaction(); @@ -167,14 +158,13 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 1, cacheMap.size() ); - Object lock = cacheMap.values().iterator().next(); - assertEquals( "org.hibernate.testing.cache.AbstractReadWriteAccessStrategy$Lock", lock.getClass().getName() ); + assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); +// Object lock = cacheMap.values().iterator().next(); +// assertEquals( "org.hibernate.testing.cache.AbstractReadWriteAccessStrategy$Lock", lock.getClass().getName() ); s = openSession(); s.beginTransaction(); - item = (CacheableItem) s.get( CacheableItem.class, item.getId() ); + item = s.get( CacheableItem.class, item.getId() ); s.getTransaction().commit(); s.close(); @@ -195,8 +185,7 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 1, cacheMap.size() ); + assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); s = openSession(); s.beginTransaction(); @@ -220,8 +209,7 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); - assertEquals( 0, cacheMap.size() ); + assertFalse( sessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); s = openSession(); s.beginTransaction(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/QualifiedRegionNameHandlingTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/QualifiedRegionNameHandlingTest.java new file mode 100644 index 0000000000..b5130f3db2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/QualifiedRegionNameHandlingTest.java @@ -0,0 +1,51 @@ +/* + * 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.test.cache; + +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; + +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; + +/** + * @author Steve Ebersole + */ +public class QualifiedRegionNameHandlingTest extends BaseNonConfigCoreFunctionalTestCase { + private static final String PREFIX = "app1"; + + private static final String LOCAL_NAME = "a.b.c"; + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + + ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" ); + ssrb.applySetting( AvailableSettings.USE_QUERY_CACHE, "true" ); + ssrb.applySetting( AvailableSettings.CACHE_REGION_PREFIX, PREFIX ); + } + + @Test + public void testValidCall() { + MatcherAssert.assertThat( + sessionFactory().getCache().unqualifyRegionName( PREFIX + '.' + LOCAL_NAME ), + CoreMatchers.is( LOCAL_NAME ) + ); + } + + @Test + public void testUnqualifiedNameUsed() { + try { + sessionFactory().getCache().unqualifyRegionName( LOCAL_NAME ); + } + catch (IllegalArgumentException expected) { + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/SharedRegionTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/SharedRegionTest.java index e5b0938a20..ffcef3594e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/SharedRegionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/SharedRegionTest.java @@ -6,7 +6,6 @@ */ package org.hibernate.test.cache; -import java.util.Properties; import javax.persistence.Entity; import javax.persistence.Id; @@ -15,12 +14,6 @@ import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.SessionFactoryOptions; -import org.hibernate.cache.CacheException; -import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.internal.SimpleCacheKeysFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.EntityRegion; import org.hibernate.cfg.AvailableSettings; import org.hibernate.testing.cache.CachingRegionFactory; diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java index 03828bf933..d73eb34762 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java @@ -20,9 +20,9 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; -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.entry.CacheEntry; import org.hibernate.cache.spi.entry.CacheEntryStructure; import org.hibernate.cfg.NotYetImplementedException; @@ -39,6 +39,7 @@ import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.MultiLoadOptions; @@ -73,12 +74,17 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { public NoopEntityPersister( final PersistentClass persistentClass, - final EntityRegionAccessStrategy cacheAccessStrategy, - final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy, + final EntityDataAccess cacheAccessStrategy, + final NaturalIdDataAccess naturalIdRegionAccessStrategy, final PersisterCreationContext creationContext) { throw new GoofyException(NoopEntityPersister.class); } + @Override + public NavigableRole getNavigableRole() { + return null; + } + @Override public EntityMode getEntityMode() { return null; @@ -213,7 +219,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { return false; } - @Override public Comparator getVersionComparator() { return null; } @@ -400,7 +405,7 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { } @Override - public EntityRegionAccessStrategy getCacheAccessStrategy() { + public EntityDataAccess getCacheAccessStrategy() { return null; } @@ -410,7 +415,7 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { } @Override - public NaturalIdRegionAccessStrategy getNaturalIdCacheAccessStrategy() { + public NaturalIdDataAccess getNaturalIdCacheAccessStrategy() { return null; } @@ -629,11 +634,16 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { public NoopCollectionPersister( Collection collectionBinding, - CollectionRegionAccessStrategy cacheAccessStrategy, + CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) { throw new GoofyException(NoopCollectionPersister.class); } + @Override + public NavigableRole getNavigableRole() { + return null; + } + public void initialize(Serializable key, SharedSessionContractImplementor session) throws HibernateException { //To change body of implemented methods use File | Settings | File Templates. } @@ -642,7 +652,7 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { return false; //To change body of implemented methods use File | Settings | File Templates. } - public CollectionRegionAccessStrategy getCacheAccessStrategy() { + public CollectionDataAccess getCacheAccessStrategy() { return null; //To change body of implemented methods use File | Settings | File Templates. } diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicStructuredCachingOfConvertedValueTest.java b/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicStructuredCachingOfConvertedValueTest.java index 757831ad6c..8e02391ca9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicStructuredCachingOfConvertedValueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicStructuredCachingOfConvertedValueTest.java @@ -9,13 +9,14 @@ package org.hibernate.test.converter.caching; import java.util.Map; import org.hibernate.Session; +import org.hibernate.cache.spi.DomainDataRegion; +import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.cache.CachingRegionFactory; -import org.hibernate.testing.cache.EntityRegionImpl; -import org.hibernate.testing.cache.ReadWriteEntityRegionAccessStrategy; +import org.hibernate.testing.cache.EntityReadWriteAccess; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; @@ -33,7 +34,7 @@ public class BasicStructuredCachingOfConvertedValueTest extends BaseNonConfigCor @SuppressWarnings("unchecked") public void basicCacheStructureTest() { EntityPersister persister = sessionFactory().getMetamodel().entityPersisters().get( Address.class.getName() ); - EntityRegionImpl region = (EntityRegionImpl) persister.getCacheAccessStrategy().getRegion(); + DomainDataRegion region = persister.getCacheAccessStrategy().getRegion(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // test during store... @@ -46,10 +47,21 @@ public class BasicStructuredCachingOfConvertedValueTest extends BaseNonConfigCor session.close(); { - final Object cachedItem = region.getDataMap().values().iterator().next(); - final Map state = (Map) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue(); - // this is the point of the Jira.. that this "should be" the converted value - assertThat( state.get( "postalArea" ), instanceOf( PostalArea.class ) ); + inSession( + s -> { + final EntityDataAccess entityDataAccess = region.getEntityDataAccess( persister.getNavigableRole() ); + final Object cacheKey = entityDataAccess.generateCacheKey( + 1, + persister, + sessionFactory(), + null + ); + final Object cachedItem = entityDataAccess.get( s, cacheKey ); + final Map state = (Map) cachedItem; + // this is the point of the Jira.. that this "should be" the converted value + assertThat( state.get( "postalArea" ), instanceOf( PostalArea.class ) ); + } + ); } assertThat( PostalAreaConverter.toDatabaseCallCount, is(1) ); @@ -58,7 +70,7 @@ public class BasicStructuredCachingOfConvertedValueTest extends BaseNonConfigCor // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // test during load... PostalAreaConverter.clearCounts(); - region.evictAll(); + sessionFactory().getCache().evictAll(); session = openSession(); session.getTransaction().begin(); @@ -67,10 +79,21 @@ public class BasicStructuredCachingOfConvertedValueTest extends BaseNonConfigCor session.close(); { - final Object cachedItem = region.getDataMap().values().iterator().next(); - final Map state = (Map) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue(); - // this is the point of the Jira.. that this "should be" the converted value - assertThat( state.get( "postalArea" ), instanceOf( PostalArea.class ) ); + inSession( + s -> { + final EntityDataAccess entityDataAccess = region.getEntityDataAccess( persister.getNavigableRole() ); + final Object cacheKey = entityDataAccess.generateCacheKey( + 1, + persister, + sessionFactory(), + null + ); + final Object cachedItem = entityDataAccess.get( s, cacheKey ); + final Map state = (Map) cachedItem; + // this is the point of the Jira.. that this "should be" the converted value + assertThat( state.get( "postalArea" ), instanceOf( PostalArea.class ) ); + } + ); } assertThat( PostalAreaConverter.toDatabaseCallCount, is(0) ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicUnstructuredCachingOfConvertedValueTest.java b/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicUnstructuredCachingOfConvertedValueTest.java index 3a6b479357..752b4e7bf3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicUnstructuredCachingOfConvertedValueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/caching/BasicUnstructuredCachingOfConvertedValueTest.java @@ -9,14 +9,15 @@ package org.hibernate.test.converter.caching; import java.util.Map; import org.hibernate.Session; +import org.hibernate.cache.spi.DomainDataRegion; +import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.entry.StandardCacheEntryImpl; import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.cache.CachingRegionFactory; -import org.hibernate.testing.cache.EntityRegionImpl; -import org.hibernate.testing.cache.ReadWriteEntityRegionAccessStrategy; +import org.hibernate.testing.cache.EntityReadWriteAccess; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; @@ -36,7 +37,7 @@ public class BasicUnstructuredCachingOfConvertedValueTest extends BaseNonConfigC @SuppressWarnings("unchecked") public void basicCacheStructureTest() { EntityPersister persister = sessionFactory().getMetamodel().entityPersisters().get( Address.class.getName() ); - EntityRegionImpl region = (EntityRegionImpl) persister.getCacheAccessStrategy().getRegion(); + final DomainDataRegion region = persister.getCacheAccessStrategy().getRegion(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // test during store... @@ -49,9 +50,21 @@ public class BasicUnstructuredCachingOfConvertedValueTest extends BaseNonConfigC session.close(); { - final Object cachedItem = region.getDataMap().values().iterator().next(); - final StandardCacheEntryImpl state = (StandardCacheEntryImpl) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue(); - assertThat( state.getDisassembledState()[postalAreaAttributeIndex], instanceOf( PostalArea.class ) ); + inSession( + s -> { + final EntityDataAccess entityDataAccess = region.getEntityDataAccess( persister.getNavigableRole() ); + final Object cacheKey = entityDataAccess.generateCacheKey( + 1, + persister, + sessionFactory(), + null + ); + final Object cachedItem = entityDataAccess.get( s, cacheKey ); + final StandardCacheEntryImpl state = (StandardCacheEntryImpl) cachedItem; + // this is the point of the Jira.. that this "should be" the converted value + assertThat( state.getDisassembledState()[postalAreaAttributeIndex], instanceOf( PostalArea.class ) ); + } + ); } assertThat( PostalAreaConverter.toDatabaseCallCount, is(1) ); @@ -60,7 +73,7 @@ public class BasicUnstructuredCachingOfConvertedValueTest extends BaseNonConfigC // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // test during load... PostalAreaConverter.clearCounts(); - region.evictAll(); + sessionFactory().getCache().evictAll(); session = openSession(); session.getTransaction().begin(); @@ -69,9 +82,21 @@ public class BasicUnstructuredCachingOfConvertedValueTest extends BaseNonConfigC session.close(); { - final Object cachedItem = region.getDataMap().values().iterator().next(); - final StandardCacheEntryImpl state = (StandardCacheEntryImpl) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue(); - assertThat( state.getDisassembledState()[postalAreaAttributeIndex], instanceOf( PostalArea.class ) ); + inSession( + s -> { + final EntityDataAccess entityDataAccess = region.getEntityDataAccess( persister.getNavigableRole() ); + final Object cacheKey = entityDataAccess.generateCacheKey( + 1, + persister, + sessionFactory(), + null + ); + final Object cachedItem = entityDataAccess.get( s, cacheKey ); + final StandardCacheEntryImpl state = (StandardCacheEntryImpl) cachedItem; + // this is the point of the Jira.. that this "should be" the converted value + assertThat( state.getDisassembledState()[postalAreaAttributeIndex], instanceOf( PostalArea.class ) ); + } + ); } assertThat( PostalAreaConverter.toDatabaseCallCount, is(0) ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java b/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java index 7a2f6aa8dd..ed578f3c12 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java @@ -20,7 +20,7 @@ import org.hibernate.FetchMode; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.entry.CollectionCacheEntry; import org.hibernate.cfg.AvailableSettings; import org.hibernate.criterion.DetachedCriteria; @@ -33,14 +33,11 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.transform.DistinctRootEntityResultTransformer; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; -import org.jboss.logging.Logger; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; @@ -101,14 +98,14 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase { Hibernate.initialize( sp.getOrders() ); CollectionPersister persister = sessionFactory().getCollectionPersister( Salesperson.class.getName() + ".orders" ); assertTrue( "No cache for collection", persister.hasCache() ); - CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy(); + CollectionDataAccess cache = persister.getCacheAccessStrategy(); Object cacheKey = cache.generateCacheKey( testData.steveId, persister, sessionFactory(), session.getTenantIdentifier() ); - CollectionCacheEntry cachedData = ( CollectionCacheEntry ) cache.get( ( SessionImplementor ) session, cacheKey, ts ); + CollectionCacheEntry cachedData = ( CollectionCacheEntry ) cache.get( ( SessionImplementor ) session, cacheKey ); assertNotNull( "collection was not in cache", cachedData ); session.close(); @@ -127,7 +124,7 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase { sessionFactory(), session.getTenantIdentifier() ); - CollectionCacheEntry cachedData2 = ( CollectionCacheEntry ) persister.getCacheAccessStrategy().get( ( SessionImplementor ) session, cacheKey2, ts ); + CollectionCacheEntry cachedData2 = ( CollectionCacheEntry ) persister.getCacheAccessStrategy().get( ( SessionImplementor ) session, cacheKey2 ); assertNotNull( "collection no longer in cache!", cachedData2 ); assertSame( "Different cache values!", cachedData, cachedData2 ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java index 61fab110f1..e8f6fb040e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java @@ -19,8 +19,8 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.cache.spi.entry.CacheEntryStructure; import org.hibernate.cache.spi.entry.StandardCacheEntryImpl; @@ -43,6 +43,7 @@ import org.hibernate.internal.StaticFilterAliasGenerator; import org.hibernate.internal.util.compare.EqualsHelper; import org.hibernate.mapping.PersistentClass; import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.MultiLoadOptions; import org.hibernate.persister.spi.PersisterCreationContext; @@ -66,8 +67,8 @@ public class CustomPersister implements EntityPersister { @SuppressWarnings("UnusedParameters") public CustomPersister( PersistentClass model, - EntityRegionAccessStrategy cacheAccessStrategy, - NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy, + EntityDataAccess cacheAccessStrategy, + NaturalIdDataAccess naturalIdRegionAccessStrategy, PersisterCreationContext creationContext) { this.factory = creationContext.getSessionFactory(); this.entityMetamodel = new EntityMetamodel( model, this, factory ); @@ -85,6 +86,11 @@ public class CustomPersister implements EntityPersister { return factory; } + @Override + public NavigableRole getNavigableRole() { + return new NavigableRole( getEntityName() ); + } + @Override public EntityEntryFactory getEntityEntryFactory() { return MutableEntityEntryFactory.INSTANCE; @@ -472,7 +478,7 @@ public class CustomPersister implements EntityPersister { return false; } - public EntityRegionAccessStrategy getCacheAccessStrategy() { + public EntityDataAccess getCacheAccessStrategy() { return null; } @@ -480,7 +486,7 @@ public class CustomPersister implements EntityPersister { return false; } - public NaturalIdRegionAccessStrategy getNaturalIdCacheAccessStrategy() { + public NaturalIdDataAccess getNaturalIdCacheAccessStrategy() { return null; } @@ -679,7 +685,6 @@ public class CustomPersister implements EntityPersister { return null; } - @Override public Comparator getVersionComparator() { return null; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/naturalid/mutable/cached/CachedMutableNaturalIdStrictReadWriteTest.java b/hibernate-core/src/test/java/org/hibernate/test/naturalid/mutable/cached/CachedMutableNaturalIdStrictReadWriteTest.java index 0d7731a4cf..639f310cf3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/naturalid/mutable/cached/CachedMutableNaturalIdStrictReadWriteTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/naturalid/mutable/cached/CachedMutableNaturalIdStrictReadWriteTest.java @@ -6,20 +6,18 @@ */ package org.hibernate.test.naturalid.mutable.cached; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.io.Serializable; -import java.util.Map; - import org.hibernate.Session; import org.hibernate.cfg.Configuration; import org.hibernate.stat.NaturalIdCacheStatistics; + import org.hibernate.testing.TestForIssue; import org.hibernate.testing.cache.CachingRegionFactory; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + public class CachedMutableNaturalIdStrictReadWriteTest extends CachedMutableNaturalIdTest { @@ -45,12 +43,7 @@ public class CachedMutableNaturalIdStrictReadWriteTest extends "hibernate.test." + AllCached.class.getName() + "##NaturalId" ); - final Map entries = stats.getEntries(); - assertEquals( 1, entries.size() ); - final Serializable[] cacheKey = (Serializable[]) entries.keySet().iterator().next(); - assertEquals( 1, cacheKey.length ); - assertEquals( it.getName(), cacheKey[0] ); - assertNotNull( entries.get( cacheKey ) ); + assertEquals( 1, stats.getPutCount() ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/cache/CacheLazyLoadNoTransTest.java b/hibernate-core/src/test/java/org/hibernate/test/ondemandload/cache/CacheLazyLoadNoTransTest.java index 5adfea9228..404025a349 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/cache/CacheLazyLoadNoTransTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/ondemandload/cache/CacheLazyLoadNoTransTest.java @@ -25,7 +25,7 @@ import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionImplementor; @@ -136,13 +136,9 @@ public class CacheLazyLoadNoTransTest extends BaseNonConfigCoreFunctionalTestCas private boolean isCached(Serializable id, Class entityClass, String attr) { Session session = openSession(); CollectionPersister persister = sessionFactory().getCollectionPersister( entityClass.getName() + "." + attr ); - CollectionRegionAccessStrategy cache = persister.getCacheAccessStrategy(); + CollectionDataAccess cache = persister.getCacheAccessStrategy(); Object key = cache.generateCacheKey( id, persister, sessionFactory(), session.getTenantIdentifier() ); - Object cachedValue = cache.get( - ( (SessionImplementor) session ), - key, - ( (SessionImplementor) session ).getTimestamp() - ); + Object cachedValue = cache.get( ( (SessionImplementor) session ), key ); session.close(); return cachedValue != null; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java index 2db8468039..7855edda7a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java @@ -29,6 +29,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.criterion.Restrictions; import org.hibernate.stat.EntityStatistics; import org.hibernate.stat.QueryStatistics; +import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.transform.Transformers; import org.hibernate.type.Type; @@ -182,12 +183,16 @@ public class QueryCacheTest extends BaseNonConfigCoreFunctionalTestCase { @Test public void testQueryCacheInvalidation() throws Exception { - sessionFactory().getCache().evictQueryRegions(); - sessionFactory().getStatistics().clear(); + + final StatisticsImplementor statistics = sessionFactory().getStatistics(); + statistics.clear(); final String queryString = "from Item i where i.name='widget'"; + final QueryStatistics qs = statistics.getQueryStatistics( queryString ); + final EntityStatistics es = statistics.getEntityStatistics( Item.class.getName() ); + Session s = openSession(); Transaction t = s.beginTransaction(); s.createQuery( queryString ).setCacheable(true).list(); @@ -198,8 +203,27 @@ public class QueryCacheTest extends BaseNonConfigCoreFunctionalTestCase { t.commit(); s.close(); - QueryStatistics qs = s.getSessionFactory().getStatistics().getQueryStatistics( queryString ); - EntityStatistics es = s.getSessionFactory().getStatistics().getEntityStatistics( Item.class.getName() ); + // hit -> 0 + // miss -> 1 + // put -> 1 + + assertEquals( es.getInsertCount(), 1 ); + assertEquals( es.getUpdateCount(), 0 ); + + assertEquals( statistics.getQueryCacheHitCount(), 0 ); + assertEquals( qs.getCacheHitCount(), 0 ); + + assertEquals( statistics.getQueryCacheMissCount(), 1 ); + assertEquals( qs.getCacheMissCount(), 1); + + assertEquals( statistics.getQueryCachePutCount(), 1 ); + assertEquals( qs.getCachePutCount(), 1); + + assertEquals( statistics.getQueryExecutionCount(), 1 ); + assertEquals( qs.getExecutionCount(), 1 ); + + assertEquals( statistics.getEntityFetchCount(), 0 ); + Thread.sleep(200); @@ -210,8 +234,28 @@ public class QueryCacheTest extends BaseNonConfigCoreFunctionalTestCase { t.commit(); s.close(); + // hit -> 0 + // miss -> 2 + // put -> 2 + + assertEquals( es.getInsertCount(), 1 ); + assertEquals( es.getUpdateCount(), 0 ); + + assertEquals( statistics.getQueryCacheHitCount(), 0 ); assertEquals( qs.getCacheHitCount(), 0 ); + assertEquals( statistics.getQueryCacheMissCount(), 2 ); + assertEquals( qs.getCacheMissCount(), 2 ); + + assertEquals( statistics.getQueryCachePutCount(), 2 ); + assertEquals( qs.getCachePutCount(), 2 ); + + assertEquals( statistics.getQueryExecutionCount(), 2 ); + assertEquals( qs.getExecutionCount(), 2 ); + + assertEquals( statistics.getEntityFetchCount(), 0 ); + + s = openSession(); t = s.beginTransaction(); result = s.createQuery( queryString ).setCacheable(true).list(); @@ -219,22 +263,66 @@ public class QueryCacheTest extends BaseNonConfigCoreFunctionalTestCase { t.commit(); s.close(); + // hit -> 1 + // miss -> 2 + // put -> 2 + + assertEquals( es.getInsertCount(), 1 ); + assertEquals( es.getUpdateCount(), 0 ); + + assertEquals( statistics.getQueryCacheHitCount(), 1 ); + assertEquals( qs.getCacheHitCount(), 1); + + assertEquals( statistics.getQueryCacheMissCount(), 2 ); + assertEquals( qs.getCacheMissCount(), 2 ); + + assertEquals( statistics.getQueryCachePutCount(), 2 ); + assertEquals( qs.getCachePutCount(), 2 ); + + assertEquals( statistics.getQueryExecutionCount(), 2 ); + assertEquals( qs.getExecutionCount(), 2 ); + + assertEquals( statistics.getEntityFetchCount(), 0 ); + + assertEquals( qs.getCacheHitCount(), 1 ); - assertEquals( s.getSessionFactory().getStatistics().getEntityFetchCount(), 0 ); + assertEquals( statistics.getEntityFetchCount(), 0 ); s = openSession(); t = s.beginTransaction(); result = s.createQuery( queryString ).setCacheable(true).list(); assertEquals( result.size(), 1 ); - assertTrue( Hibernate.isInitialized( result.get(0) ) ); i = (Item) result.get(0); + assertTrue( Hibernate.isInitialized( i ) ); + assertTrue( s.contains( i ) ); i.setName("Widget"); + s.flush(); t.commit(); s.close(); + // hit -> 2 + // miss -> 2 + // put -> 2 + // + // + another invalidation + + assertEquals( es.getInsertCount(), 1 ); + assertEquals( es.getUpdateCount(), 1 ); + + assertEquals( statistics.getQueryCacheHitCount(), 2 ); assertEquals( qs.getCacheHitCount(), 2 ); + + assertEquals( statistics.getQueryCacheMissCount(), 2 ); assertEquals( qs.getCacheMissCount(), 2 ); - assertEquals( s.getSessionFactory().getStatistics().getEntityFetchCount(), 0 ); + + assertEquals( statistics.getQueryCachePutCount(), 2 ); + assertEquals( qs.getCachePutCount(), 2 ); + + assertEquals( statistics.getQueryExecutionCount(), 2 ); + assertEquals( qs.getExecutionCount(), 2 ); + + assertEquals( statistics.getEntityFetchCount(), 0 ); + Thread.sleep(200); @@ -247,6 +335,30 @@ public class QueryCacheTest extends BaseNonConfigCoreFunctionalTestCase { t.commit(); s.close(); + // hit -> 2 + // miss -> 3 + // put -> 3 + + + assertEquals( es.getInsertCount(), 1 ); + assertEquals( es.getUpdateCount(), 1 ); + + assertEquals( statistics.getQueryCacheHitCount(), 2 ); + assertEquals( qs.getCacheHitCount(), 2 ); + + assertEquals( statistics.getQueryCacheMissCount(), 3 ); + assertEquals( qs.getCacheMissCount(), 3 ); + + assertEquals( statistics.getQueryCachePutCount(), 3); + assertEquals( qs.getCachePutCount(), 3 ); + + assertEquals( statistics.getQueryExecutionCount(), 3); + assertEquals( qs.getExecutionCount(), 3 ); + + assertEquals( statistics.getEntityFetchCount(), 0 ); + assertEquals( es.getFetchCount(), 0 ); + + assertEquals( qs.getCacheHitCount(), 2 ); assertEquals( qs.getCacheMissCount(), 3 ); assertEquals( qs.getCachePutCount(), 3 ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jta/TransactionCoordinatorOwnerTestingImpl.java b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jta/TransactionCoordinatorOwnerTestingImpl.java index a3828f4961..d43d363173 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jta/TransactionCoordinatorOwnerTestingImpl.java +++ b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jta/TransactionCoordinatorOwnerTestingImpl.java @@ -61,6 +61,10 @@ public class TransactionCoordinatorOwnerTestingImpl implements TransactionCoordi return active; } + @Override + public void startTransactionBoundary() { + } + @Override public void afterTransactionBegin() { log.debug( "#afterTransactionBegin called" ); diff --git a/hibernate-core/src/test/resources/log4j.properties b/hibernate-core/src/test/resources/log4j.properties index 40feef756b..0ad1dc3ae8 100644 --- a/hibernate-core/src/test/resources/log4j.properties +++ b/hibernate-core/src/test/resources/log4j.properties @@ -59,3 +59,6 @@ log4j.logger.org.hibernate.engine.internal.Cascade=trace log4j.logger.org.hibernate.testing.junit4.TestClassMetadata=info, unclosedSessionFactoryFile log4j.logger.org.hibernate.boot.model.process.internal.ScanningCoordinator=debug + +log4j.logger.org.hibernate.cache trace +log4j.logger.org.hibernate.stat trace \ No newline at end of file diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AbstractEhcacheRegionFactory.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AbstractEhcacheRegionFactory.java index 5089edce1c..d86bef8906 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AbstractEhcacheRegionFactory.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/AbstractEhcacheRegionFactory.java @@ -25,10 +25,6 @@ import org.hibernate.cache.ehcache.internal.regions.EhcacheTimestampsRegion; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactoryImpl; import org.hibernate.cache.ehcache.management.impl.ProviderMBeanRegistrationHelper; -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.spi.QueryResultsRegion; import org.hibernate.cache.spi.RegionFactory; import org.hibernate.cache.spi.TimestampsRegion; diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAccessStrategyFactory.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAccessStrategyFactory.java index 64850057d2..21ba100a12 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAccessStrategyFactory.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAccessStrategyFactory.java @@ -11,9 +11,6 @@ import org.hibernate.cache.ehcache.internal.regions.EhcacheEntityRegion; import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; 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; /** * Implementation of {@link org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory} that takes care of Nonstop cache exceptions using diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareCollectionRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareCollectionRegionAccessStrategy.java index fcca99ad69..c1a88554a2 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareCollectionRegionAccessStrategy.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareCollectionRegionAccessStrategy.java @@ -10,9 +10,6 @@ import net.sf.ehcache.constructs.nonstop.NonStopCacheException; import org.hibernate.cache.CacheException; import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.CollectionRegion; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.collection.CollectionPersister; diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareEntityRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareEntityRegionAccessStrategy.java index 3cbd790d43..8c7e37f633 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareEntityRegionAccessStrategy.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareEntityRegionAccessStrategy.java @@ -10,9 +10,6 @@ import net.sf.ehcache.constructs.nonstop.NonStopCacheException; import org.hibernate.cache.CacheException; import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.entity.EntityPersister; diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java index df9081b9a5..928a900c6b 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/nonstop/NonstopAwareNaturalIdRegionAccessStrategy.java @@ -10,9 +10,6 @@ import net.sf.ehcache.constructs.nonstop.NonStopCacheException; import org.hibernate.cache.CacheException; import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.NaturalIdRegion; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.entity.EntityPersister; diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheCollectionRegion.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheCollectionRegion.java index d6ed550aba..bbb05cbbbe 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheCollectionRegion.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheCollectionRegion.java @@ -14,10 +14,7 @@ import net.sf.ehcache.Ehcache; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.CollectionRegion; import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; /** * A collection region specific wrapper around an Ehcache instance. diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheEntityRegion.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheEntityRegion.java index f59f536fdb..b1c798f884 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheEntityRegion.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheEntityRegion.java @@ -13,10 +13,7 @@ import net.sf.ehcache.Ehcache; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.EntityRegion; import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; /** * An entity region specific wrapper around an Ehcache instance. diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheGeneralDataRegion.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheGeneralDataRegion.java index c57d7bf829..7c93cc298a 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheGeneralDataRegion.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheGeneralDataRegion.java @@ -16,7 +16,6 @@ import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.EhCacheMessageLogger; import org.hibernate.cache.ehcache.internal.nonstop.HibernateNonstopCacheExceptionHandler; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; -import org.hibernate.cache.spi.GeneralDataRegion; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.jboss.logging.Logger; diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java index 4347c0cfc3..10c987b208 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheNaturalIdRegion.java @@ -14,10 +14,7 @@ import net.sf.ehcache.Ehcache; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.NaturalIdRegion; import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; /** * A collection region specific wrapper around an Ehcache instance. diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheTransactionalDataRegion.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheTransactionalDataRegion.java index d24f6b90ee..6a07948d59 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheTransactionalDataRegion.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/regions/EhcacheTransactionalDataRegion.java @@ -19,8 +19,6 @@ import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.internal.nonstop.HibernateNonstopCacheExceptionHandler; import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.TransactionalDataRegion; /** * An Ehcache specific TransactionalDataRegion. diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractEhcacheAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractEhcacheAccessStrategy.java index 0d2f303fb0..f4babf81a6 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractEhcacheAccessStrategy.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractEhcacheAccessStrategy.java @@ -9,8 +9,6 @@ package org.hibernate.cache.ehcache.internal.strategy; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.internal.regions.EhcacheTransactionalDataRegion; -import org.hibernate.cache.spi.access.RegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SharedSessionContractImplementor; /** diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractReadWriteEhcacheAccessStrategy.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractReadWriteEhcacheAccessStrategy.java index 1dc2dc40c0..96ba3e1ab3 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractReadWriteEhcacheAccessStrategy.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/ehcache/internal/strategy/AbstractReadWriteEhcacheAccessStrategy.java @@ -15,8 +15,6 @@ import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.CacheException; import org.hibernate.cache.ehcache.EhCacheMessageLogger; import org.hibernate.cache.ehcache.internal.regions.EhcacheTransactionalDataRegion; -import org.hibernate.cache.spi.access.RegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.jboss.logging.Logger; @@ -288,7 +286,7 @@ abstract class AbstractReadWriteEhcacheAccessStrategy - implements CollectionRegionAccessStrategy { + implements CollectionDataAccess { public ReadWriteCollectionRegionAccessStrategy(JCacheCollectionRegion jCacheCollectionRegion) { super( jCacheCollectionRegion ); diff --git a/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteEntityRegionAccessStrategy.java b/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteEntityRegionAccessStrategy.java index 75f8f271b0..48a3d310ed 100644 --- a/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteEntityRegionAccessStrategy.java +++ b/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteEntityRegionAccessStrategy.java @@ -9,8 +9,6 @@ package org.hibernate.cache.jcache.access; import org.hibernate.cache.CacheException; import org.hibernate.cache.internal.DefaultCacheKeysFactory; import org.hibernate.cache.jcache.JCacheEntityRegion; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.entity.EntityPersister; diff --git a/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteNaturalIdRegionAccessStrategy.java b/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteNaturalIdRegionAccessStrategy.java index 722cb49c2c..abdcf50f9f 100644 --- a/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteNaturalIdRegionAccessStrategy.java +++ b/hibernate-jcache/src/main/java/org/hibernate/cache/jcache/access/ReadWriteNaturalIdRegionAccessStrategy.java @@ -10,8 +10,6 @@ package org.hibernate.cache.jcache.access; import org.hibernate.cache.CacheException; import org.hibernate.cache.internal.DefaultCacheKeysFactory; import org.hibernate.cache.jcache.JCacheNaturalIdRegion; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.entity.EntityPersister; diff --git a/hibernate-jcache/src/test/java/org/hibernate/test/cache/HibernateCacheTest.java b/hibernate-jcache/src/test/java/org/hibernate/test/cache/HibernateCacheTest.java index 441ee20a78..22fe87a416 100644 --- a/hibernate-jcache/src/test/java/org/hibernate/test/cache/HibernateCacheTest.java +++ b/hibernate-jcache/src/test/java/org/hibernate/test/cache/HibernateCacheTest.java @@ -14,10 +14,9 @@ import java.util.Map; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.cfg.AvailableSettings; import org.hibernate.stat.QueryStatistics; -import org.hibernate.stat.SecondLevelCacheStatistics; +import org.hibernate.stat.CacheRegionStatistics; import org.hibernate.stat.Statistics; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; @@ -70,9 +69,9 @@ public class HibernateCacheTest extends BaseNonConfigCoreFunctionalTestCase { t.commit(); s.close(); - SecondLevelCacheStatistics slcs = sessionFactory() + CacheRegionStatistics slcs = sessionFactory() .getStatistics() - .getSecondLevelCacheStatistics( REGION_PREFIX + Item.class.getName() ); + .getDomainDataRegionStatistics( REGION_PREFIX + Item.class.getName() ); assertThat( slcs.getPutCount(), equalTo( 1L ) ); assertThat( slcs.getEntries().size(), equalTo( 1 ) ); @@ -115,7 +114,7 @@ public class HibernateCacheTest extends BaseNonConfigCoreFunctionalTestCase { sessionFactory().getCache().evictEntityRegion( Item.class.getName() ); Statistics stats = sessionFactory().getStatistics(); stats.clear(); - SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics( REGION_PREFIX + Item.class.getName() ); + CacheRegionStatistics statistics = stats.getDomainDataRegionStatistics( REGION_PREFIX + Item.class.getName() ); Map cacheEntries = statistics.getEntries(); assertThat( cacheEntries.size(), equalTo( 0 ) ); } @@ -165,8 +164,8 @@ public class HibernateCacheTest extends BaseNonConfigCoreFunctionalTestCase { } // check the version value in the cache... - SecondLevelCacheStatistics slcs = sessionFactory().getStatistics() - .getSecondLevelCacheStatistics( REGION_PREFIX + VersionedItem.class.getName() ); + CacheRegionStatistics slcs = sessionFactory().getStatistics() + .getDomainDataRegionStatistics( REGION_PREFIX + VersionedItem.class.getName() ); assertNotNull(slcs); final Map entries = slcs.getEntries(); Object entry = entries.get( item.getId() ); diff --git a/hibernate-jcache/src/test/java/org/hibernate/test/cache/jcache/functional/InsertedDataTest.java b/hibernate-jcache/src/test/java/org/hibernate/test/cache/jcache/functional/InsertedDataTest.java index 01be8b1134..080b0c75c9 100644 --- a/hibernate-jcache/src/test/java/org/hibernate/test/cache/jcache/functional/InsertedDataTest.java +++ b/hibernate-jcache/src/test/java/org/hibernate/test/cache/jcache/functional/InsertedDataTest.java @@ -64,7 +64,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 1, cacheMap.size() ); s = openSession(); @@ -87,7 +87,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 0, cacheMap.size() ); } @@ -105,7 +105,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 1, cacheMap.size() ); s = openSession(); @@ -129,7 +129,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 0, cacheMap.size() ); s = openSession(); @@ -153,7 +153,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 1, cacheMap.size() ); s = openSession(); @@ -177,7 +177,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 1, cacheMap.size() ); Object lock = cacheMap.values().iterator().next(); assertEquals( "org.hibernate.cache.jcache.access.AbstractReadWriteRegionAccessStrategy$Lock", lock.getClass().getName() ); @@ -205,7 +205,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().commit(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 1, cacheMap.size() ); s = openSession(); @@ -230,7 +230,7 @@ public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase { s.getTransaction().rollback(); s.close(); - Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries(); + Map cacheMap = sessionFactory().getStatistics().getDomainDataRegionStatistics( "item" ).getEntries(); assertEquals( 0, cacheMap.size() ); s = openSession(); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractCachedDomainDataAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractCachedDomainDataAccess.java new file mode 100644 index 0000000000..8bfb6b91cf --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractCachedDomainDataAccess.java @@ -0,0 +1,149 @@ +/* + * 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.testing.cache; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.hibernate.cache.spi.AbstractDomainDataRegion; +import org.hibernate.cache.spi.access.CachedDomainDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractCachedDomainDataAccess implements CachedDomainDataAccess, AbstractDomainDataRegion.Destructible { + private static final Logger log = Logger.getLogger( AbstractCachedDomainDataAccess.class ); + + private final DomainDataRegionImpl region; + + private Map data; + + protected AbstractCachedDomainDataAccess(DomainDataRegionImpl region) { + this.region = region; + } + + @Override + public DomainDataRegionImpl getRegion() { + return region; + } + + protected Object getFromCache(Object key) { + log.debugf( "Locating entry in cache data map [region=`%s`] : %s", key ); + if ( data == null ) { + return null; + } + return data.get( key ); + } + + @SuppressWarnings({"unchecked", "WeakerAccess"}) + protected void addToCache(Object key, Object value) { + log.debugf( "Adding entry to cache data map [region=`%s`] : %s -> %s", getRegion().getName(), key, value ); + getOrMakeData().put( key, value ); + } + + @SuppressWarnings({"unchecked", "WeakerAccess"}) + protected void removeFromCache(Object key) { + log.debugf( "Removing entry from cache data map [region=`%s`] : %s", key ); + if ( data != null ) { + data.remove( key ); + } + } + + @SuppressWarnings({"unchecked", "WeakerAccess"}) + protected void clearCache() { + log.debugf( "Clearing cache data map [region=`%s`]" ); + if ( data != null ) { + data.clear(); + } + } + + public Map getData() { + return data == null ? Collections.emptyMap() : Collections.unmodifiableMap( data ); + } + + private Map getOrMakeData() { + if ( data == null ) { + data = new ConcurrentHashMap(); + } + return data; + } + + @Override + public boolean contains(Object key) { + return data != null && data.containsKey( key ); + } + + @Override + public Object get(SharedSessionContractImplementor session, Object key) { + return getFromCache( key ); + } + + @Override + public boolean putFromLoad( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version) { + addToCache( key, value ); + return true; + } + + @Override + public boolean putFromLoad( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version, + boolean minimalPutOverride) { + return putFromLoad( session, key, value, version ); + } + + private static final SoftLock REGION_LOCK = new SoftLock() { + }; + + @Override + public SoftLock lockRegion() { + return REGION_LOCK; + } + + @Override + public void unlockRegion(SoftLock lock) { + evictAll(); + } + + @Override + public void remove(SharedSessionContractImplementor session, Object key) { + removeFromCache( key ); + } + + @Override + public void removeAll() { + clearCache(); + } + + @Override + public void evict(Object key) { + removeFromCache( key ); + } + + @Override + public void evictAll() { + clearCache(); + } + + @Override + public void destroy() { + if ( data != null ) { + data.clear(); + } + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractDirectAccessRegion.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractDirectAccessRegion.java new file mode 100644 index 0000000000..0dcb667672 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractDirectAccessRegion.java @@ -0,0 +1,62 @@ +/* + * 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.testing.cache; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.hibernate.cache.spi.DirectAccessRegion; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractDirectAccessRegion + extends AbstractRegion + implements DirectAccessRegion, DirectAccessRegion.DataAccess { + private Map dataMap; + + public AbstractDirectAccessRegion(String name) { + super( name ); + } + + @Override + public DataAccess getAccess() { + return this; + } + + @Override + public Object getFromCache(Object key) { + if ( dataMap == null ) { + return null; + } + return dataMap.get( key ); + } + + @Override + @SuppressWarnings("unchecked") + public void addToCache(Object key, Object value) { + if ( dataMap == null ) { + dataMap = new ConcurrentHashMap(); + } + + dataMap.put( key, value ); + } + + @Override + public void removeFromCache(Object key) { + if ( dataMap != null ) { + dataMap.remove( key ); + } + } + + @Override + public void clearCache() { + if ( dataMap != null ) { + dataMap.clear(); + } + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccess.java new file mode 100644 index 0000000000..f92fdba27d --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccess.java @@ -0,0 +1,422 @@ +/* + * 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.testing.cache; + +import java.io.Serializable; +import java.util.Comparator; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.hibernate.cache.spi.SecondLevelCacheLogger.RegionAccessType; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractReadWriteAccess extends AbstractCachedDomainDataAccess { + private static final Logger log = Logger.getLogger( AbstractReadWriteAccess.class ); + private static final boolean DEBUG_ENABLED = log.isDebugEnabled(); + + private final UUID uuid = UUID.randomUUID(); + private final AtomicLong nextLockId = new AtomicLong(); + private final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); + private final Lock readLock = reentrantReadWriteLock.readLock(); + private final Lock writeLock = reentrantReadWriteLock.writeLock(); + + protected AbstractReadWriteAccess(DomainDataRegionImpl region) { + super( region ); + } + + protected abstract Comparator getVersionComparator(); + + protected UUID uuid() { + return uuid; + } + + protected long nextLockId() { + return nextLockId.getAndIncrement(); + } + + protected Lock readLock() { + return readLock; + } + + protected Lock writeLock() { + return writeLock; + } + + /** + * Returns null if the item is not readable. Locked items are not readable, nor are items created + * afterQuery the start of this transaction. + */ + @Override + public Object get(SharedSessionContractImplementor session, Object key) { + log.debugf( "Getting cached data from region [`%s` (%s)] by key [%s]", getRegion().getName(), key ); + try { + readLock.lock(); + Lockable item = (Lockable) getFromCache( key ); + + if ( item == null ) { + log.debugf( "Cache miss : region = `%s`, key = `%s`", getRegion().getName(), key ); + return null; + } + + boolean readable = item.isReadable( session.getTransactionStartTimestamp() ); + if ( readable ) { + log.debugf( "Cache hit : region = `%s`, key = `%s`", getRegion().getName(), key ); + return item.getValue(); + } + else { + log.debugf( "Cache hit, but item is unreadable/invalid : region = `%s`, key = `%s`", getRegion().getName(), key ); + return null; + } + } + finally { + readLock.unlock(); + } + } + + @Override + public boolean putFromLoad( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version) { + try { + log.debugf( "Caching data from load [region=`%s` (%s)] : key[%s] -> value[%s]", getRegion().getName(), getAccessType(), key, value ); + writeLock.lock(); + Lockable item = (Lockable) getFromCache( key ); + + boolean writable = item == null || item.isWriteable( session.getTransactionStartTimestamp(), version, getVersionComparator() ); + if ( writable ) { + addToCache( key, new Item( value, version, session.getTransactionStartTimestamp() ) ); + return true; + } + else { + log.debugf( + "Cache put-from-load [region=`%s` (%s), key=`%s`, value=`%s`] failed due to being non-writable", + getAccessType(), + getRegion().getName(), + key, + value + ); + return false; + } + } + finally { + writeLock.unlock(); + } + } + + protected abstract RegionAccessType getAccessType(); + + @Override + public final boolean putFromLoad( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version, + boolean minimalPutOverride) { + return putFromLoad( session, key, value, version ); + } + + @Override + public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) { + try { + writeLock.lock(); + + long timeout = getRegion().getRegionFactory().nextTimestamp() + getRegion().getRegionFactory().getTimeout(); + log.debugf( "Locking cache item [region=`%s` (%s)] : `%s` (timeout=%s, version=%s)", getRegion().getName(), getAccessType(), key, timeout, version ); + + Lockable item = (Lockable) getFromCache( key ); + final SoftLockImpl lock = ( item == null ) + ? new SoftLockImpl( timeout, uuid, nextLockId(), version ) + : item.lock( timeout, uuid, nextLockId() ); + addToCache( key, lock ); + return lock; + } + finally { + writeLock.unlock(); + } + } + + @Override + public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) { + try { + log.debugf( "Unlocking cache item [region=`%s` (%s)] : %s", getRegion().getName(), getAccessType(), key ); + writeLock.lock(); + Lockable item = (Lockable) getFromCache( key ); + + if ( ( item != null ) && item.isUnlockable( lock ) ) { + decrementLock( session, key, (SoftLockImpl) item ); + } + else { + handleLockExpiry( session, key, item ); + } + } + finally { + writeLock.unlock(); + } + } + + @SuppressWarnings("WeakerAccess") + protected void decrementLock(SharedSessionContractImplementor session, Object key, SoftLockImpl lock) { + lock.unlock( getRegion().getRegionFactory().nextTimestamp() ); + addToCache( key, lock ); + } + + @SuppressWarnings("WeakerAccess") + protected void handleLockExpiry(SharedSessionContractImplementor session, Object key, Lockable lock) { + log.info( "Cached entry expired : " + key ); + + // create new lock that times out immediately + long ts = getRegion().getRegionFactory().nextTimestamp() + getRegion().getRegionFactory().getTimeout(); + SoftLockImpl newLock = new SoftLockImpl( ts, uuid, nextLockId.getAndIncrement(), null ); + //newLock.unlock( ts ); + newLock.unlock( ts - getRegion().getRegionFactory().getTimeout() ); + addToCache( key, newLock ); + } + + @Override + public void remove(SharedSessionContractImplementor session, Object key) { + if ( getFromCache( key ) instanceof SoftLock ) { + log.debugf( "Skipping #remove call in read-write access to maintain SoftLock : %s", key ); + // don'tm do anything... we want the SoftLock to remain in place + } + else { + super.remove( session, key ); + } + } + + /** + * Interface type implemented by all wrapper objects in the cache. + */ + public interface Lockable { + + /** + * Returns true if the enclosed value can be read by a transaction started at the given time. + */ + boolean isReadable(long txTimestamp); + + /** + * Returns true if the enclosed value can be replaced with one of the given version by a + * transaction started at the given time. + */ + boolean isWriteable(long txTimestamp, Object version, Comparator versionComparator); + + /** + * Returns the enclosed value. + */ + Object getValue(); + + /** + * Returns true if the given lock can be unlocked using the given SoftLock instance as a handle. + */ + boolean isUnlockable(SoftLock lock); + + /** + * Locks this entry, stamping it with the UUID and lockId given, with the lock timeout occuring at the specified + * time. The returned Lock object can be used to unlock the entry in the future. + */ + SoftLockImpl lock(long timeout, UUID uuid, long lockId); + } + + /** + * Wrapper type representing unlocked items. + */ + public final static class Item implements Serializable, Lockable { + private static final long serialVersionUID = 1L; + private final Object value; + private final Object version; + private final long timestamp; + + /** + * Creates an unlocked item wrapping the given value with a version and creation timestamp. + */ + Item(Object value, Object version, long timestamp) { + this.value = value; + this.version = version; + this.timestamp = timestamp; + } + + @Override + public boolean isReadable(long txTimestamp) { + if ( DEBUG_ENABLED ) { + log.debugf( + "Checking readability of read-write cache item [timestamp=`%s`, version=`%s`] : txTimestamp=`%s`", + (Object) timestamp, + version, + txTimestamp + ); + } + + return txTimestamp > timestamp; + } + + @Override + public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) { + if ( DEBUG_ENABLED ) { + log.debugf( + "Checking writeability of read-write cache item [timestamp=`%s`, version=`%s`] : txTimestamp=`%s`, newVersion=`%s`", + timestamp, + version, + txTimestamp, + newVersion + ); + } + + //noinspection unchecked + return version != null && versionComparator.compare( version, newVersion ) < 0; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public boolean isUnlockable(SoftLock lock) { + return false; + } + + @Override + public SoftLockImpl lock(long timeout, UUID uuid, long lockId) { + return new SoftLockImpl( timeout, uuid, lockId, version ); + } + } + + /** + * Wrapper type representing locked items. + */ + public static class SoftLockImpl implements Serializable, Lockable, SoftLock { + + private static final long serialVersionUID = 2L; + + private final UUID sourceUuid; + private final long lockId; + private final Object version; + + private long timeout; + private boolean concurrent; + private int multiplicity = 1; + private long unlockTimestamp; + + /** + * Creates a locked item with the given identifiers and object version. + */ + SoftLockImpl(long timeout, UUID sourceUuid, long lockId, Object version) { + this.timeout = timeout; + this.lockId = lockId; + this.version = version; + this.sourceUuid = sourceUuid; + } + + + @Override + public boolean isReadable(long txTimestamp) { + return false; + } + + @Override + public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) { + if ( DEBUG_ENABLED ) { + log.debugf( + "Checking writeability of read-write cache lock [timeout=`%s`, lockId=`%s`, version=`%s`, sourceUuid=%s, multiplicity=`%s`, unlockTimestamp=`%s`] : txTimestamp=`%s`, newVersion=`%s`", + timeout, + lockId, + version, + sourceUuid, + multiplicity, + unlockTimestamp, + txTimestamp, + newVersion + ); + } + + if ( txTimestamp > timeout ) { + // if timed-out - allow write + return true; + } + if ( multiplicity > 0 ) { + // if still locked - disallow write + return false; + } + + //noinspection unchecked + return version == null + ? txTimestamp > unlockTimestamp + : versionComparator.compare( version, newVersion ) < 0; + } + + @Override + public Object getValue() { + return null; + } + + @Override + public boolean isUnlockable(SoftLock lock) { + return equals( lock ); + } + + @Override + public boolean equals(Object o) { + if ( o == this ) { + return true; + } + else if ( o instanceof SoftLockImpl ) { + return ( lockId == ( (SoftLockImpl) o ).lockId ) && sourceUuid.equals( ( (SoftLockImpl) o ).sourceUuid ); + } + else { + return false; + } + } + + @Override + public int hashCode() { + int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 ); + int temp = (int) lockId; + for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) { + temp ^= ( lockId >>> ( i * Integer.SIZE ) ); + } + return hash + temp; + } + + /** + * Returns true if this Lock has been concurrently locked by more than one transaction. + */ + public boolean wasLockedConcurrently() { + return concurrent; + } + + @Override + public SoftLockImpl lock(long timeout, UUID uuid, long lockId) { + concurrent = true; + multiplicity++; + this.timeout = timeout; + return this; + } + + /** + * Unlocks this Lock, and timestamps the unlock event. + */ + public void unlock(long timestamp) { + if ( --multiplicity == 0 ) { + unlockTimestamp = timestamp; + } + } + + @Override + public String toString() { + return "Lock Source-UUID:" + sourceUuid + " Lock-ID:" + lockId; + } + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccessStrategy.java deleted file mode 100644 index 73273989e8..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractReadWriteAccessStrategy.java +++ /dev/null @@ -1,368 +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 . - */ -package org.hibernate.testing.cache; - -import java.io.Serializable; -import java.util.Comparator; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -import org.jboss.logging.Logger; - -/** - * @author Strong Liu - */ -public abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy { - private static final Logger LOG = Logger.getLogger( AbstractReadWriteAccessStrategy.class.getName() ); - - private final UUID uuid = UUID.randomUUID(); - private final AtomicLong nextLockId = new AtomicLong(); - private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); - protected java.util.concurrent.locks.Lock readLock = reentrantReadWriteLock.readLock(); - protected java.util.concurrent.locks.Lock writeLock = reentrantReadWriteLock.writeLock(); - - /** - * Returns null if the item is not readable. Locked items are not readable, nor are items created - * after the start of this transaction. - */ - @Override - public final Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException { - LOG.debugf( "getting key[%s] from region[%s]", key, getInternalRegion().getName() ); - try { - readLock.lock(); - Lockable item = (Lockable) getInternalRegion().get( session, key ); - - boolean readable = item != null && item.isReadable( txTimestamp ); - if ( readable ) { - LOG.debugf( "hit key[%s] in region[%s]", key, getInternalRegion().getName() ); - return item.getValue(); - } - else { - if ( item == null ) { - LOG.debugf( "miss key[%s] in region[%s]", key, getInternalRegion().getName() ); - } - else { - LOG.debugf( "hit key[%s] in region[%s], but it is unreadable", key, getInternalRegion().getName() ); - } - return null; - } - } - finally { - readLock.unlock(); - } - } - - abstract Comparator getVersionComparator(); - - /** - * Returns false and fails to put the value if there is an existing un-writeable item mapped to this - * key. - */ - @Override - public final boolean putFromLoad( - SharedSessionContractImplementor session, - Object key, - Object value, - long txTimestamp, - Object version, - boolean minimalPutOverride) - throws CacheException { - try { - LOG.debugf( "putting key[%s] -> value[%s] into region[%s]", key, value, getInternalRegion().getName() ); - writeLock.lock(); - Lockable item = (Lockable) getInternalRegion().get( session, key ); - boolean writeable = item == null || item.isWriteable( txTimestamp, version, getVersionComparator() ); - if ( writeable ) { - LOG.debugf( - "putting key[%s] -> value[%s] into region[%s] success", - key, - value, - getInternalRegion().getName() - ); - getInternalRegion().put( session, key, new Item( value, version, getInternalRegion().nextTimestamp() ) ); - return true; - } - else { - LOG.debugf( - "putting key[%s] -> value[%s] into region[%s] fail due to it is unwriteable", - key, - value, - getInternalRegion().getName() - ); - return false; - } - } - finally { - writeLock.unlock(); - } - } - - /** - * Soft-lock a cache item. - */ - @Override - public final SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException { - - try { - LOG.debugf( "locking key[%s] in region[%s]", key, getInternalRegion().getName() ); - writeLock.lock(); - Lockable item = (Lockable) getInternalRegion().get( session, key ); - long timeout = getInternalRegion().nextTimestamp() + getInternalRegion().getTimeout(); - final Lock lock = ( item == null ) ? new Lock( timeout, uuid, nextLockId(), version ) : item.lock( - timeout, - uuid, - nextLockId() - ); - getInternalRegion().put( session, key, lock ); - return lock; - } - finally { - writeLock.unlock(); - } - } - - /** - * Soft-unlock a cache item. - */ - @Override - public final void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - - try { - LOG.debugf( "unlocking key[%s] in region[%s]", key, getInternalRegion().getName() ); - writeLock.lock(); - Lockable item = (Lockable) getInternalRegion().get( session, key ); - - if ( ( item != null ) && item.isUnlockable( lock ) ) { - decrementLock(session, key, (Lock) item ); - } - else { - handleLockExpiry(session, key, item ); - } - } - finally { - writeLock.unlock(); - } - } - - private long nextLockId() { - return nextLockId.getAndIncrement(); - } - - /** - * Unlock and re-put the given key, lock combination. - */ - protected void decrementLock(SharedSessionContractImplementor session, Object key, Lock lock) { - lock.unlock( getInternalRegion().nextTimestamp() ); - getInternalRegion().put( session, key, lock ); - } - - /** - * Handle the timeout of a previous lock mapped to this key - */ - protected void handleLockExpiry(SharedSessionContractImplementor session, Object key, Lockable lock) { - LOG.info( "Cached entry expired : " + key ); - - long ts = getInternalRegion().nextTimestamp() + getInternalRegion().getTimeout(); - // create new lock that times out immediately - Lock newLock = new Lock( ts, uuid, nextLockId.getAndIncrement(), null ); - newLock.unlock( ts ); - getInternalRegion().put( session, key, newLock ); - } - - /** - * Interface type implemented by all wrapper objects in the cache. - */ - public interface Lockable { - - /** - * Returns true if the enclosed value can be read by a transaction started at the given time. - */ - boolean isReadable(long txTimestamp); - - /** - * Returns true if the enclosed value can be replaced with one of the given version by a - * transaction started at the given time. - */ - boolean isWriteable(long txTimestamp, Object version, Comparator versionComparator); - - /** - * Returns the enclosed value. - */ - Object getValue(); - - /** - * Returns true if the given lock can be unlocked using the given SoftLock instance as a handle. - */ - boolean isUnlockable(SoftLock lock); - - /** - * Locks this entry, stamping it with the UUID and lockId given, with the lock timeout occuring at the specified - * time. The returned Lock object can be used to unlock the entry in the future. - */ - Lock lock(long timeout, UUID uuid, long lockId); - } - - /** - * Wrapper type representing unlocked items. - */ - public final static class Item implements Serializable, Lockable { - - private static final long serialVersionUID = 1L; - private final Object value; - private final Object version; - private final long timestamp; - - /** - * Creates an unlocked item wrapping the given value with a version and creation timestamp. - */ - Item(Object value, Object version, long timestamp) { - this.value = value; - this.version = version; - this.timestamp = timestamp; - } - - @Override - public boolean isReadable(long txTimestamp) { - return txTimestamp > timestamp; - } - - @Override - public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) { - return version != null && versionComparator.compare( version, newVersion ) < 0; - } - - @Override - public Object getValue() { - return value; - } - - @Override - public boolean isUnlockable(SoftLock lock) { - return false; - } - - @Override - public Lock lock(long timeout, UUID uuid, long lockId) { - return new Lock( timeout, uuid, lockId, version ); - } - } - - /** - * Wrapper type representing locked items. - */ - public final static class Lock implements Serializable, Lockable, SoftLock { - - private static final long serialVersionUID = 2L; - - private final UUID sourceUuid; - private final long lockId; - private final Object version; - - private long timeout; - private boolean concurrent; - private int multiplicity = 1; - private long unlockTimestamp; - - /** - * Creates a locked item with the given identifiers and object version. - */ - Lock(long timeout, UUID sourceUuid, long lockId, Object version) { - this.timeout = timeout; - this.lockId = lockId; - this.version = version; - this.sourceUuid = sourceUuid; - } - - @Override - public boolean isReadable(long txTimestamp) { - return false; - } - - @Override - public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) { - if ( txTimestamp > timeout ) { - // if timedout then allow write - return true; - } - if ( multiplicity > 0 ) { - // if still locked then disallow write - return false; - } - return version == null ? txTimestamp > unlockTimestamp : versionComparator.compare( - version, - newVersion - ) < 0; - } - - @Override - public Object getValue() { - return null; - } - - @Override - public boolean isUnlockable(SoftLock lock) { - return equals( lock ); - } - - @Override - public boolean equals(Object o) { - if ( o == this ) { - return true; - } - else if ( o instanceof Lock ) { - return ( lockId == ( (Lock) o ).lockId ) && sourceUuid.equals( ( (Lock) o ).sourceUuid ); - } - else { - return false; - } - } - - @Override - public int hashCode() { - int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 ); - int temp = (int) lockId; - for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) { - temp ^= ( lockId >>> ( i * Integer.SIZE ) ); - } - return hash + temp; - } - - /** - * Returns true if this Lock has been concurrently locked by more than one transaction. - */ - public boolean wasLockedConcurrently() { - return concurrent; - } - - @Override - public Lock lock(long timeout, UUID uuid, long lockId) { - concurrent = true; - multiplicity++; - this.timeout = timeout; - return this; - } - - /** - * Unlocks this Lock, and timestamps the unlock event. - */ - public void unlock(long timestamp) { - if ( --multiplicity == 0 ) { - unlockTimestamp = timestamp; - } - } - - @Override - public String toString() { - return "Lock Source-UUID:" + sourceUuid + " Lock-ID:" + lockId; - } - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractRegion.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractRegion.java new file mode 100644 index 0000000000..b89658163d --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/AbstractRegion.java @@ -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.testing.cache; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.Region; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractRegion implements Region { + private final String name; + + public AbstractRegion(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public void destroy() throws CacheException { + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionDataAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionDataAccess.java new file mode 100644 index 0000000000..ccd5bbdd46 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionDataAccess.java @@ -0,0 +1,55 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.spi.access.CollectionDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * @author Steve Ebersole + */ +public abstract class BaseCollectionDataAccess + extends AbstractCachedDomainDataAccess + implements CollectionDataAccess { + + public BaseCollectionDataAccess(DomainDataRegionImpl region) { + super( region ); + } + + @Override + public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { + return getRegion().getEffectiveKeysFactory().createCollectionKey( id, persister, factory, tenantIdentifier ); + } + + @Override + public Object getCacheKeyId(Object cacheKey) { + return getRegion().getEffectiveKeysFactory().getCollectionId( cacheKey ); + } + + @Override + public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) { + return null; + } + + @Override + public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) { + + } + + @Override + public SoftLock lockRegion() { + return null; + } + + @Override + public void unlockRegion(SoftLock lock) { + clearCache(); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionRegionAccessStrategy.java deleted file mode 100644 index 2fc05ea3a5..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseCollectionRegionAccessStrategy.java +++ /dev/null @@ -1,50 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.spi.CollectionRegion; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.persister.collection.CollectionPersister; - -/** - * @author Strong Liu - */ -class BaseCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy { - - private final CollectionRegionImpl region; - - BaseCollectionRegionAccessStrategy(CollectionRegionImpl region) { - this.region = region; - } - - @Override - protected BaseGeneralDataRegion getInternalRegion() { - return region; - } - - @Override - protected boolean isDefaultMinimalPutOverride() { - return region.getSettings().isMinimalPutsEnabled(); - } - - @Override - public CollectionRegion getRegion() { - return region; - } - - @Override - public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { - return region.getRegionFactory().getCacheKeysFactory().createCollectionKey( id, persister, factory, tenantIdentifier ); - } - - @Override - public Object getCacheKeyId(Object cacheKey) { - return region.getRegionFactory().getCacheKeysFactory().getCollectionId( cacheKey ); - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityDataAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityDataAccess.java new file mode 100644 index 0000000000..b8efe08191 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityDataAccess.java @@ -0,0 +1,68 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.EntityPersister; + +/** + * @author Steve Ebersole + */ +public abstract class BaseEntityDataAccess + extends AbstractCachedDomainDataAccess + implements EntityDataAccess { + + public BaseEntityDataAccess(DomainDataRegionImpl region) { + super( region ); + } + + @Override + public Object generateCacheKey( + Object id, + EntityPersister rootEntityDescriptor, + SessionFactoryImplementor factory, + String tenantIdentifier) { + return getRegion().getEffectiveKeysFactory().createEntityKey( + id, + rootEntityDescriptor, + factory, + tenantIdentifier + ); + } + + @Override + public Object getCacheKeyId(Object cacheKey) { + return getRegion().getEffectiveKeysFactory().getEntityId( cacheKey ); + } + + @Override + public SoftLock lockRegion() { + return null; + } + + @Override + public void unlockRegion(SoftLock lock) { + clearCache(); + } + + public SoftLock lockItem( + SharedSessionContractImplementor session, + Object key, + Object version) { + return null; + } + + @Override + public void unlockItem( + SharedSessionContractImplementor session, + Object key, + SoftLock lock) { + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityRegionAccessStrategy.java deleted file mode 100644 index 470b5ecae7..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseEntityRegionAccessStrategy.java +++ /dev/null @@ -1,74 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.persister.entity.EntityPersister; - -/** - * @author Strong Liu - */ -class BaseEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy { - - private final EntityRegionImpl region; - - BaseEntityRegionAccessStrategy(EntityRegionImpl region) { - this.region = region; - } - - @Override - public EntityRegion getRegion() { - return region; - } - - @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - return putFromLoad( session, key, value, 0, version ); - } - - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - return true; - } - - @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException { - return false; - } - - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) - throws CacheException { - return false; - } - - @Override - protected BaseGeneralDataRegion getInternalRegion() { - return region; - } - - @Override - protected boolean isDefaultMinimalPutOverride() { - return region.getSettings().isMinimalPutsEnabled(); - } - - @Override - public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { - return region.getRegionFactory().getCacheKeysFactory().createEntityKey( id, persister, factory, tenantIdentifier ); - } - - @Override - public Object getCacheKeyId(Object cacheKey) { - return region.getRegionFactory().getCacheKeysFactory().getEntityId( cacheKey ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseGeneralDataRegion.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseGeneralDataRegion.java deleted file mode 100644 index c2624a34e4..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseGeneralDataRegion.java +++ /dev/null @@ -1,63 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.GeneralDataRegion; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -import org.jboss.logging.Logger; - -/** - * @author Strong Liu - */ -class BaseGeneralDataRegion extends BaseRegion implements GeneralDataRegion { - private static final Logger LOG = Logger.getLogger( BaseGeneralDataRegion.class.getName() ); - - BaseGeneralDataRegion(CachingRegionFactory cachingRegionFactory, String name) { - super( cachingRegionFactory, name ); - } - - @Override - public Object get(SharedSessionContractImplementor session, Object key) throws CacheException { - LOG.debugf( "Cache[%s] lookup : key[%s]", getName(), key ); - if ( key == null ) { - return null; - } - Object result = cache.get( key ); - if ( result != null ) { - LOG.debugf( "Cache[%s] hit: %s", getName(), key ); - } - return result; - } - - @Override - public void put(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - LOG.debugf( "Caching[%s] : [%s] -> [%s]", getName(), key, value ); - if ( key == null || value == null ) { - LOG.debug( "Key or Value is null" ); - return; - } - cache.put( key, value ); - } - - @Override - public void evict(Object key) throws CacheException { - LOG.debugf( "Evicting[%s]: %s", getName(), key ); - if ( key == null ) { - LOG.debug( "Key is null" ); - return; - } - cache.remove( key ); - } - - @Override - public void evictAll() throws CacheException { - LOG.debugf( "evict cache[%s]", getName() ); - cache.clear(); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdDataAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdDataAccess.java new file mode 100644 index 0000000000..5dd4b71fe5 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdDataAccess.java @@ -0,0 +1,83 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.spi.access.NaturalIdDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.EntityPersister; + +/** + * @author Steve Ebersole + */ +public abstract class BaseNaturalIdDataAccess extends AbstractCachedDomainDataAccess implements NaturalIdDataAccess { + public BaseNaturalIdDataAccess(DomainDataRegionImpl region) { + super( region ); + } + + @Override + public Object generateCacheKey( + Object[] naturalIdValues, + EntityPersister persister, + SharedSessionContractImplementor session) { + return getRegion().getEffectiveKeysFactory().createNaturalIdKey( naturalIdValues, persister, session ); + } + + @Override + public Object[] getNaturalIdValues(Object cacheKey) { + return getRegion().getEffectiveKeysFactory().getNaturalIdValues( cacheKey ); + } + + + + + @Override + public boolean insert(SharedSessionContractImplementor session, Object key, Object value) { + addToCache( key, value ); + return true; + } + + @Override + public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) { + return false; + } + + @Override + public boolean update(SharedSessionContractImplementor session, Object key, Object value) { + addToCache( key, value ); + return true; + } + + @Override + public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) { + return false; + } + + @Override + public SoftLock lockRegion() { + return null; + } + + @Override + public void unlockRegion(SoftLock lock) { + clearCache(); + } + + public SoftLock lockItem( + SharedSessionContractImplementor session, + Object key, + Object version) { + return null; + } + + @Override + public void unlockItem( + SharedSessionContractImplementor session, + Object key, + SoftLock lock) { + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java deleted file mode 100644 index d659a6b7da..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseNaturalIdRegionAccessStrategy.java +++ /dev/null @@ -1,70 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.NaturalIdRegion; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.persister.entity.EntityPersister; - -/** - * @author Eric Dalquist - */ -class BaseNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy { - private final NaturalIdRegionImpl region; - - @Override - protected BaseGeneralDataRegion getInternalRegion() { - return region; - } - - @Override - protected boolean isDefaultMinimalPutOverride() { - return region.getSettings().isMinimalPutsEnabled(); - } - - @Override - public NaturalIdRegion getRegion() { - return region; - } - - @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - return putFromLoad( session, key, value, 0, null ); - } - - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - return false; - } - - @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - return putFromLoad( session, key, value, 0, null ); - } - - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException { - return false; - } - - BaseNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { - this.region = region; - } - - @Override - public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) { - return region.getRegionFactory().getCacheKeysFactory().createNaturalIdKey( naturalIdValues, persister, session ); - } - - @Override - public Object[] getNaturalIdValues(Object cacheKey) { - return region.getRegionFactory().getCacheKeysFactory().getNaturalIdValues( cacheKey ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java deleted file mode 100644 index 7b7cf3f527..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java +++ /dev/null @@ -1,83 +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 . - */ -package org.hibernate.testing.cache; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.Region; - -/** - * @author Strong Liu - */ -public class BaseRegion implements Region { - private final CachingRegionFactory cachingRegionFactory; - private final String name; - protected final Map cache = new ConcurrentHashMap(); - - private static int timeout = Timestamper.ONE_MS * 60000; //60s - - BaseRegion(CachingRegionFactory cachingRegionFactory, String name) { - this.cachingRegionFactory = cachingRegionFactory; - this.name = name; - } - - public CachingRegionFactory getRegionFactory() { - return cachingRegionFactory; - } - - @Override - public String getName() { - return name; - } - - @Override - public boolean contains(Object key) { - return key != null ? cache.containsKey( key ) : false; - } - - @Override - public void destroy() throws CacheException { - cache.clear(); - } - - @Override - public long getSizeInMemory() { - return -1; - } - - @Override - public long getElementCountInMemory() { - return cache.size(); - } - - @Override - public long getElementCountOnDisk() { - return 0; - } - - @Override - public Map toMap() { - return Collections.unmodifiableMap( cache ); - } - - @Override - public long nextTimestamp() { - return Timestamper.next(); - } - - @Override - public int getTimeout() { - return timeout; - } - - public Map getDataMap() { - return cache; - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegionAccessStrategy.java deleted file mode 100644 index aea7c62bfe..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegionAccessStrategy.java +++ /dev/null @@ -1,118 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.RegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -import org.jboss.logging.Logger; - -/** - * @author Strong Liu - */ -public abstract class BaseRegionAccessStrategy implements RegionAccessStrategy { - - private static final Logger LOG = Logger.getLogger( BaseRegionAccessStrategy.class ); - - protected abstract BaseGeneralDataRegion getInternalRegion(); - - protected abstract boolean isDefaultMinimalPutOverride(); - - @Override - public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException { - return getInternalRegion().get( session, key ); - } - - @Override - public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException { - return putFromLoad(session, key, value, txTimestamp, version, isDefaultMinimalPutOverride() ); - } - - @Override - public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) - throws CacheException { - - if ( key == null || value == null ) { - return false; - } - if ( minimalPutOverride && getInternalRegion().contains( key ) ) { - LOG.debugf( "Item already cached: %s", key ); - return false; - } - LOG.debugf( "Caching: %s", key ); - getInternalRegion().put( session, key, value ); - return true; - - } - - /** - * Region locks are not supported. - * - * @return null - * - * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#lockRegion() - * @see org.hibernate.cache.spi.access.CollectionRegionAccessStrategy#lockRegion() - */ - @Override - public SoftLock lockRegion() throws CacheException { - return null; - } - - /** - * Region locks are not supported - perform a cache clear as a precaution. - * - * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#unlockRegion(org.hibernate.cache.spi.access.SoftLock) - * @see org.hibernate.cache.spi.access.CollectionRegionAccessStrategy#unlockRegion(org.hibernate.cache.spi.access.SoftLock) - */ - @Override - public void unlockRegion(SoftLock lock) throws CacheException { - evictAll(); - } - - @Override - public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException { - return null; - } - - @Override - public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - } - - - /** - * A no-op since this is an asynchronous cache access strategy. - * - * @see RegionAccessStrategy#remove(SharedSessionContractImplementor, Object) - */ - @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - } - - /** - * Called to evict data from the entire region - * - * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - * @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#removeAll() - * @see org.hibernate.cache.spi.access.CollectionRegionAccessStrategy#removeAll() - */ - @Override - public void removeAll() throws CacheException { - evictAll(); - } - - @Override - public void evict(Object key) throws CacheException { - getInternalRegion().evict( key ); - } - - @Override - public void evictAll() throws CacheException { - getInternalRegion().evictAll(); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseTransactionalDataRegion.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseTransactionalDataRegion.java deleted file mode 100644 index 4a84bdfa84..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseTransactionalDataRegion.java +++ /dev/null @@ -1,33 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.TransactionalDataRegion; - -/** - * @author Strong Liu - */ -class BaseTransactionalDataRegion extends BaseGeneralDataRegion implements TransactionalDataRegion { - private final CacheDataDescription metadata; - - BaseTransactionalDataRegion(CachingRegionFactory cachingRegionFactory, String name, CacheDataDescription metadata) { - super( cachingRegionFactory, name ); - this.metadata = metadata; - } - - @Override - public CacheDataDescription getCacheDataDescription() { - return metadata; - } - - @Override - public boolean isTransactionAware() { - return false; - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CacheTransactionSynchronizationImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CacheTransactionSynchronizationImpl.java new file mode 100644 index 0000000000..0d83f9f119 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CacheTransactionSynchronizationImpl.java @@ -0,0 +1,23 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.spi.AbstractCacheTransactionSynchronization; +import org.hibernate.cache.spi.RegionFactory; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +class CacheTransactionSynchronizationImpl extends AbstractCacheTransactionSynchronization { + private static final Logger log = Logger.getLogger( CacheTransactionSynchronizationImpl.class ); + + CacheTransactionSynchronizationImpl(RegionFactory regionFactory) { + super( regionFactory ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CachingRegionFactory.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CachingRegionFactory.java index fbd9bbb70f..df9a42d395 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CachingRegionFactory.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CachingRegionFactory.java @@ -1,30 +1,34 @@ /* * 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 . + * 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.testing.cache; +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.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.CacheDataDescription; import org.hibernate.cache.spi.CacheKeysFactory; -import org.hibernate.cache.spi.CollectionRegion; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.NaturalIdRegion; +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; import org.jboss.logging.Logger; /** * @author Strong Liu + * @author Steve Ebersole */ public class CachingRegionFactory implements RegionFactory { private static final Logger LOG = Logger.getLogger( CachingRegionFactory.class.getName() ); @@ -33,7 +37,6 @@ public class CachingRegionFactory implements RegionFactory { private final CacheKeysFactory cacheKeysFactory; - private SessionFactoryOptions settings; private Properties properties; public CachingRegionFactory() { @@ -49,7 +52,7 @@ public class CachingRegionFactory implements RegionFactory { } public CachingRegionFactory(CacheKeysFactory cacheKeysFactory, Properties properties) { - LOG.warn( "CachingRegionFactory should be only used for testing." ); + LOG.warn( "org.hibernate.testing.cache.CachingRegionFactory should be only used for testing." ); this.cacheKeysFactory = cacheKeysFactory; this.properties = properties; } @@ -59,9 +62,7 @@ public class CachingRegionFactory implements RegionFactory { } @Override - public void start(SessionFactoryOptions settings, Properties properties) throws CacheException { - this.settings = settings; - this.properties = properties; + public void start(SessionFactoryOptions settings, Map configValues) throws CacheException { } @Override @@ -83,48 +84,39 @@ public class CachingRegionFactory implements RegionFactory { @Override public long nextTimestamp() { +// return System.currentTimeMillis(); return Timestamper.next(); } @Override - public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) - throws CacheException { - return new EntityRegionImpl( this, regionName, metadata, settings ); + public long getTimeout() { + return Timestamper.ONE_MS * 60000; } @Override - public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata) - throws CacheException { - return new NaturalIdRegionImpl( this, regionName, metadata, settings ); + public CacheTransactionSynchronization createTransactionContext(SharedSessionContractImplementor session) { + return new CacheTransactionSynchronizationImpl( this ); } @Override - public CollectionRegion buildCollectionRegion( + public DomainDataRegion buildDomainDataRegion( + DomainDataRegionConfig regionConfig, + DomainDataRegionBuildingContext buildingContext) { + return new DomainDataRegionImpl( regionConfig, this, buildingContext ); + } + + @Override + public QueryResultsRegion buildQueryResultsRegion( String regionName, - Properties properties, - CacheDataDescription metadata) throws CacheException { - return new CollectionRegionImpl( this, regionName, metadata, settings ); + SessionFactoryImplementor sessionFactory) { + return new QueryResultsRegionImpl( regionName, sessionFactory ); } @Override - public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException { - return new QueryResultsRegionImpl( this, regionName ); + public TimestampsRegion buildTimestampsRegion( + String regionName, + SessionFactoryImplementor sessionFactory) { + return new TimestampsRegionImpl( regionName, sessionFactory ); } - @Override - public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException { - return new TimestampsRegionImpl( this, regionName ); - } - - private static class QueryResultsRegionImpl extends BaseGeneralDataRegion implements QueryResultsRegion { - QueryResultsRegionImpl(CachingRegionFactory cachingRegionFactory, String name) { - super( cachingRegionFactory, name ); - } - } - - private static class TimestampsRegionImpl extends BaseGeneralDataRegion implements TimestampsRegion { - TimestampsRegionImpl(CachingRegionFactory cachingRegionFactory, String name) { - super( cachingRegionFactory, name ); - } - } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionNonStrictReadWriteAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionNonStrictReadWriteAccess.java new file mode 100644 index 0000000000..9a6a08ff40 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionNonStrictReadWriteAccess.java @@ -0,0 +1,27 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +/** + * @author Steve Ebersole + */ +public class CollectionNonStrictReadWriteAccess extends BaseCollectionDataAccess { + public CollectionNonStrictReadWriteAccess( + DomainDataRegionImpl region, + CollectionDataCachingConfig config) { + super( region ); + } + + @Override + public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) { + removeFromCache( key ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadOnlyAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadOnlyAccess.java new file mode 100644 index 0000000000..f82cb51c22 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadOnlyAccess.java @@ -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.testing.cache; + +import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig; + +/** + * @author Steve Ebersole + */ +public class CollectionReadOnlyAccess extends BaseCollectionDataAccess { + public CollectionReadOnlyAccess( + DomainDataRegionImpl region, + CollectionDataCachingConfig config) { + super( region ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadWriteAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadWriteAccess.java new file mode 100644 index 0000000000..3efe9c57e5 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionReadWriteAccess.java @@ -0,0 +1,80 @@ +/* + * 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.testing.cache; + +import java.util.Comparator; + +import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig; +import org.hibernate.cache.spi.SecondLevelCacheLogger; +import org.hibernate.cache.spi.access.CollectionDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * @author Chris Cranford + */ +public class CollectionReadWriteAccess extends AbstractReadWriteAccess implements CollectionDataAccess { + private final NavigableRole collectionRole; + private final Comparator versionComparator; + + public CollectionReadWriteAccess( + DomainDataRegionImpl region, + CollectionDataCachingConfig config) { + super( region ); + this.collectionRole = config.getNavigableRole(); + this.versionComparator = config.getOwnerVersionComparator(); + } + + @Override + protected SecondLevelCacheLogger.RegionAccessType getAccessType() { + return SecondLevelCacheLogger.RegionAccessType.COLLECTION; + } + + @Override + public Object generateCacheKey( + Object id, + CollectionPersister collectionDescriptor, + SessionFactoryImplementor factory, + String tenantIdentifier) { + return getRegion().getEffectiveKeysFactory().createCollectionKey( id, collectionDescriptor, factory, tenantIdentifier ); + } + + @Override + public Object getCacheKeyId(Object cacheKey) { + return getRegion().getEffectiveKeysFactory().getCollectionId( cacheKey ); + } + + @Override + protected Comparator getVersionComparator() { + return versionComparator; + } + + @Override + public Object get(SharedSessionContractImplementor session, Object key) { + return super.get( session, key ); + } + + @Override + public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, Object version) { + return super.putFromLoad( session, key, value, version ); + } + + @Override + public SoftLock lockItem( + SharedSessionContractImplementor session, Object key, Object version) { + return super.lockItem( session, key, version ); + } + + @Override + public void unlockItem( + SharedSessionContractImplementor session, Object key, SoftLock lock) { + super.unlockItem( session, key, lock ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionRegionImpl.java deleted file mode 100644 index 8d087d2266..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionRegionImpl.java +++ /dev/null @@ -1,64 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.boot.spi.SessionFactoryOptions; -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.CollectionRegion; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; - -import org.jboss.logging.Logger; - -/** - * @author Strong Liu - */ -class CollectionRegionImpl extends BaseTransactionalDataRegion implements CollectionRegion { - private static final Logger LOG = Logger.getLogger( CollectionRegionImpl.class.getName() ); - - private final SessionFactoryOptions settings; - - CollectionRegionImpl( - CachingRegionFactory cachingRegionFactory, - String name, - CacheDataDescription metadata, - SessionFactoryOptions settings) { - super( cachingRegionFactory, name, metadata ); - this.settings = settings; - } - - public SessionFactoryOptions getSettings() { - return settings; - } - - @Override - public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { - switch ( accessType ) { - case READ_ONLY: { - if ( getCacheDataDescription().isMutable() ) { - LOG.warnf( "read-only cache configured for mutable collection [ %s ]", getName() ); - } - return new ReadOnlyCollectionRegionAccessStrategy( this ); - } - case READ_WRITE: { - return new ReadWriteCollectionRegionAccessStrategy( this ); - } - case NONSTRICT_READ_WRITE: { - return new NonstrictReadWriteCollectionRegionAccessStrategy( this ); - } - case TRANSACTIONAL: { - return new TransactionalCollectionRegionAccessStrategy( this ); -// throw new UnsupportedOperationException( "doesn't support this access strategy" ); - } - default: { - throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" ); - } - } - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionTransactionAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionTransactionAccess.java new file mode 100644 index 0000000000..fc01c3614e --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/CollectionTransactionAccess.java @@ -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.testing.cache; + +import org.hibernate.cache.cfg.spi.CollectionDataCachingConfig; + +/** + * @author Steve Ebersole + */ +public class CollectionTransactionAccess extends BaseCollectionDataAccess { + public CollectionTransactionAccess( + DomainDataRegionImpl region, + CollectionDataCachingConfig config) { + super( region ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/DomainDataRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/DomainDataRegionImpl.java new file mode 100644 index 0000000000..7812b30153 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/DomainDataRegionImpl.java @@ -0,0 +1,125 @@ +/* + * 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.testing.cache; + +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.AbstractDomainDataRegion; +import org.hibernate.cache.spi.CacheKeysFactory; +import org.hibernate.cache.spi.access.AccessType; +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; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.entity.EntityPersister; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +public class DomainDataRegionImpl extends AbstractDomainDataRegion { + private static final Logger log = Logger.getLogger( DomainDataRegionImpl.class ); + + private final CacheKeysFactory effectiveKeysFactory; + + public DomainDataRegionImpl( + DomainDataRegionConfig regionConfig, + CachingRegionFactory regionFactory, + DomainDataRegionBuildingContext buildingContext) { + super( regionConfig, regionFactory, buildingContext ); + + this.effectiveKeysFactory = buildingContext.getEnforcedCacheKeysFactory() != null + ? buildingContext.getEnforcedCacheKeysFactory() + : regionFactory.getCacheKeysFactory(); + } + + public CacheKeysFactory getEffectiveKeysFactory() { + return effectiveKeysFactory; + } + + @Override + public EntityDataAccess generateEntityAccess(EntityDataCachingConfig entityAccessConfig) { + final NavigableRole namedEntityRole = entityAccessConfig.getNavigableRole(); + final AccessType accessType = entityAccessConfig.getAccessType(); + + log.debugf( "Generating entity cache access [%s] : %s", accessType.getExternalName(), namedEntityRole ); + + switch ( accessType ) { + case READ_ONLY: { + return new EntityReadOnlyAccess( this, entityAccessConfig ); + } + case TRANSACTIONAL: { + return new EntityTransactionalAccess( this, entityAccessConfig ); + } + case READ_WRITE: { + return new EntityReadWriteAccess( this, entityAccessConfig ); + } + case NONSTRICT_READ_WRITE: { + return new EntityNonStrictReadWriteAccess( this, entityAccessConfig ); + } + default: { + throw new IllegalArgumentException( "Unrecognized cache AccessType - " + accessType ); + } + } + } + + @Override + public NaturalIdDataAccess generateNaturalIdAccess(NaturalIdDataCachingConfig naturalIdDataCachingConfig) { + final NavigableRole namedEntityRole = naturalIdDataCachingConfig.getNavigableRole(); + final AccessType accessType = naturalIdDataCachingConfig.getAccessType(); + + log.debugf( "Generating entity natural-id access [%s] : %s", accessType.getExternalName(), namedEntityRole ); + + switch ( accessType ) { + case READ_ONLY: { + return new NaturalIdReadOnlyAccess( this, naturalIdDataCachingConfig ); + } + case TRANSACTIONAL: { + return new NaturalIdTransactionalAccess( this, naturalIdDataCachingConfig ); + } + case READ_WRITE: { + return new NaturalIdReadWriteAccess( this, naturalIdDataCachingConfig ); + } + case NONSTRICT_READ_WRITE: { + return new NaturalIdNonStrictReadWriteAccess( this, naturalIdDataCachingConfig ); + } + default: { + throw new IllegalArgumentException( "Unrecognized cache AccessType - " + accessType ); + } + } + } + + @Override + public CollectionDataAccess generateCollectionAccess(CollectionDataCachingConfig config) { + final NavigableRole namedCollectionRole = config.getNavigableRole(); + + log.debugf( "Generating collection cache access : %s", namedCollectionRole ); + + switch ( config.getAccessType() ) { + case READ_ONLY: { + return new CollectionReadOnlyAccess( this, config ); + } + case TRANSACTIONAL: { + return new CollectionTransactionAccess( this, config ); + } + case READ_WRITE: { + return new CollectionReadWriteAccess( this, config ); + } + case NONSTRICT_READ_WRITE: { + return new CollectionNonStrictReadWriteAccess( this, config ); + } + default: { + throw new IllegalArgumentException( "Unrecognized cache AccessType - " + config.getAccessType() ); + } + } + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityNonStrictReadWriteAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityNonStrictReadWriteAccess.java new file mode 100644 index 0000000000..77ec8b85c1 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityNonStrictReadWriteAccess.java @@ -0,0 +1,72 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.cfg.spi.EntityDataCachingConfig; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +/** + * @author Steve Ebersole + */ +public class EntityNonStrictReadWriteAccess extends BaseEntityDataAccess { + public EntityNonStrictReadWriteAccess(DomainDataRegionImpl domainDataRegion, EntityDataCachingConfig entityAccessConfig) { + super( domainDataRegion ); + } + + + @Override + public boolean insert( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version) { + return false; + } + + @Override + public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) { + return false; + } + + @Override + public boolean update( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion) { + removeFromCache( key ); + return false; + } + + @Override + public boolean afterUpdate( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion, + SoftLock lock) { + unlockItem( session, key, lock ); + return false; + } + + /** + * Since this is a non-strict read/write strategy item locking is not used. + */ + @Override + public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { + removeFromCache( key ); + } + + @Override + public void remove(SharedSessionContractImplementor session, Object key) { + removeFromCache( key ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadOnlyAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadOnlyAccess.java new file mode 100644 index 0000000000..cafb709062 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadOnlyAccess.java @@ -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.testing.cache; + +import org.hibernate.cache.cfg.spi.EntityDataCachingConfig; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +public class EntityReadOnlyAccess extends BaseEntityDataAccess { + private static final Logger log = Logger.getLogger( EntityReadOnlyAccess.class ); + + public EntityReadOnlyAccess(DomainDataRegionImpl region, EntityDataCachingConfig congfig) { + super( region ); + } + + @Override + public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) { + // wait until tx complete - see `#afterInsert` + return false; + } + + @Override + public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) { + addToCache( key, value ); + return true; + } + + @Override + public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) { + evict( key ); + } + + @Override + public boolean update( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion) { + log.debugf( "Illegal attempt to update item cached as read-only [%s]", key ); + throw new UnsupportedOperationException( "Can't update readonly object" ); + } + + @Override + public boolean afterUpdate( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion, + SoftLock lock) { + log.debugf( "Illegal attempt to update item cached as read-only [%s]", key ); + throw new UnsupportedOperationException( "Can't write to a readonly object" ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadWriteAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadWriteAccess.java new file mode 100644 index 0000000000..6911ee7ee1 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityReadWriteAccess.java @@ -0,0 +1,135 @@ +/* + * 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.testing.cache; + +import java.util.Comparator; + +import org.hibernate.cache.cfg.spi.EntityDataCachingConfig; +import org.hibernate.cache.spi.SecondLevelCacheLogger; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.EntityPersister; + +/** + * @author Steve Ebersole + */ +public class EntityReadWriteAccess extends AbstractReadWriteAccess implements EntityDataAccess { + private final Comparator versionComparator; + + protected EntityReadWriteAccess(DomainDataRegionImpl region, EntityDataCachingConfig entityAccessConfig) { + super( region ); + this.versionComparator = entityAccessConfig.getVersionComparatorAccess() == null + ? null + : entityAccessConfig.getVersionComparatorAccess().get(); + } + + @Override + protected SecondLevelCacheLogger.RegionAccessType getAccessType() { + return SecondLevelCacheLogger.RegionAccessType.ENTITY; + } + + @Override + protected Comparator getVersionComparator() { + return versionComparator; + } + + @Override + public Object generateCacheKey( + Object id, + EntityPersister rootEntityDescriptor, + SessionFactoryImplementor factory, + String tenantIdentifier) { + return getRegion().getEffectiveKeysFactory().createEntityKey( id, rootEntityDescriptor, factory, tenantIdentifier ); + } + + @Override + public Object getCacheKeyId(Object cacheKey) { + return getRegion().getEffectiveKeysFactory().getEntityId( cacheKey ); + } + + @Override + public boolean insert( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version) { + return false; + } + + @Override + public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) { + try { + writeLock().lock(); + Lockable item = (Lockable) getFromCache( key ); + if ( item == null ) { + addToCache( key, new Item( value, version, getRegion().getRegionFactory().nextTimestamp() ) ); + return true; + } + else { + return false; + } + } + finally { + writeLock().unlock(); + } + } + + @Override + public boolean update( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion) { + return false; + } + + @Override + public boolean afterUpdate( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion, + SoftLock lock) { + try { + writeLock().lock(); + Lockable item = (Lockable) getFromCache( key ); + + if ( item != null && item.isUnlockable( lock ) ) { + SoftLockImpl lockItem = (SoftLockImpl) item; + if ( lockItem.wasLockedConcurrently() ) { + decrementLock( session, key, lockItem ); + return false; + } + else { + addToCache( key, new Item( value, currentVersion, getRegion().getRegionFactory().nextTimestamp() ) ); + return true; + } + } + else { + handleLockExpiry(session, key, item ); + return false; + } + } + finally { + writeLock().unlock(); + } + } + + @Override + public SoftLock lockRegion() { + return null; + } + + @Override + public void unlockRegion(SoftLock lock) { + + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityRegionImpl.java deleted file mode 100644 index 360b13278a..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityRegionImpl.java +++ /dev/null @@ -1,62 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.boot.spi.SessionFactoryOptions; -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; - -import org.jboss.logging.Logger; - -/** - * @author Strong Liu - */ -public class EntityRegionImpl extends BaseTransactionalDataRegion implements EntityRegion { - private static final Logger LOG = Logger.getLogger( EntityRegionImpl.class ); - - private final SessionFactoryOptions settings; - - protected EntityRegionImpl( - CachingRegionFactory cachingRegionFactory, - String name, - CacheDataDescription metadata, - SessionFactoryOptions settings) { - super( cachingRegionFactory, name, metadata ); - this.settings = settings; - - } - - public SessionFactoryOptions getSettings() { - return settings; - } - - @Override - public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { - switch ( accessType ) { - case READ_ONLY: - if ( getCacheDataDescription().isMutable() ) { - LOG.warnf( "read-only cache configured for mutable entity [ %s ]", getName() ); - } - return new ReadOnlyEntityRegionAccessStrategy( this ); - case READ_WRITE: - return new ReadWriteEntityRegionAccessStrategy( this ); - case NONSTRICT_READ_WRITE: - return new NonstrictReadWriteEntityRegionAccessStrategy( this ); - case TRANSACTIONAL: -// throw new UnsupportedOperationException( "doesn't support this access strategy" ); - return new TransactionalEntityRegionAccessStrategy( this ); - - default: - throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" ); - } - - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityTransactionalAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityTransactionalAccess.java new file mode 100644 index 0000000000..f3e11068d4 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/EntityTransactionalAccess.java @@ -0,0 +1,61 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.cfg.spi.EntityDataCachingConfig; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +/** + * @author Steve Ebersole + */ +public class EntityTransactionalAccess extends BaseEntityDataAccess { + public EntityTransactionalAccess(DomainDataRegionImpl region, EntityDataCachingConfig entityAccessConfig) { + super( region ); + } + + @Override + public boolean insert( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version) { + addToCache( key, value ); + return true; + } + + @Override + public boolean afterInsert( + SharedSessionContractImplementor session, + Object key, + Object value, + Object version) { + return false; + } + + @Override + public boolean update( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion) { + addToCache( key, value ); + return true; + } + + @Override + public boolean afterUpdate( + SharedSessionContractImplementor session, + Object key, + Object value, + Object currentVersion, + Object previousVersion, + SoftLock lock) { + return false; + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdNonStrictReadWriteAccess.java similarity index 53% rename from hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java rename to hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdNonStrictReadWriteAccess.java index e72ef68207..ef195fb13e 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteNaturalIdRegionAccessStrategy.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdNonStrictReadWriteAccess.java @@ -1,46 +1,48 @@ /* * 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 . + * 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.testing.cache; -import org.hibernate.cache.CacheException; +import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig; import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SharedSessionContractImplementor; /** - * @author Eric Dalquist + * @author Steve Ebersole */ -class NonstrictReadWriteNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy { - NonstrictReadWriteNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { +public class NaturalIdNonStrictReadWriteAccess extends BaseNaturalIdDataAccess { + public NaturalIdNonStrictReadWriteAccess( + DomainDataRegionImpl region, + NaturalIdDataCachingConfig naturalIdDataCachingConfig) { super( region ); } @Override - public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - evict( key ); + public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) { + removeFromCache( key ); } @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - evict( key ); + public void remove(SharedSessionContractImplementor session, Object key) { + removeFromCache( key ); } @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { + public boolean insert(SharedSessionContractImplementor session, Object key, Object value) { return false; } @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { + public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) { return false; } @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - remove( session, key ); + public boolean update(SharedSessionContractImplementor session, Object key, Object value) { + removeFromCache( key ); return false; } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadOnlyAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadOnlyAccess.java new file mode 100644 index 0000000000..a62cb42db4 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadOnlyAccess.java @@ -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.testing.cache; + +import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +/** + * @author Steve Ebersole + */ +public class NaturalIdReadOnlyAccess extends BaseNaturalIdDataAccess { + public NaturalIdReadOnlyAccess( + DomainDataRegionImpl region, + NaturalIdDataCachingConfig naturalIdDataCachingConfig) { + super( region ); + } + + @Override + public void unlockItem( + SharedSessionContractImplementor session, + Object key, + SoftLock lock) { + evict( key ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadWriteAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadWriteAccess.java new file mode 100644 index 0000000000..e5a4f56dd0 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdReadWriteAccess.java @@ -0,0 +1,107 @@ +/* + * 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.testing.cache; + +import java.util.Comparator; + +import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig; +import org.hibernate.cache.spi.SecondLevelCacheLogger; +import org.hibernate.cache.spi.access.NaturalIdDataAccess; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.EntityPersister; + +/** + * @author Steve Ebersole + */ +public class NaturalIdReadWriteAccess extends AbstractReadWriteAccess implements NaturalIdDataAccess { + + public NaturalIdReadWriteAccess( + DomainDataRegionImpl region, + NaturalIdDataCachingConfig naturalIdDataCachingConfig) { + super( region ); + } + + @Override + protected SecondLevelCacheLogger.RegionAccessType getAccessType() { + return SecondLevelCacheLogger.RegionAccessType.NATURAL_ID; + } + + @Override + protected Comparator getVersionComparator() { + // natural-id has no comparator + return null; + } + + @Override + public Object generateCacheKey( + Object[] naturalIdValues, + EntityPersister rootEntityDescriptor, + SharedSessionContractImplementor session) { + return getRegion().getEffectiveKeysFactory().createNaturalIdKey( naturalIdValues, rootEntityDescriptor, session ); + } + + @Override + public Object[] getNaturalIdValues(Object cacheKey) { + return getRegion().getEffectiveKeysFactory().getNaturalIdValues( cacheKey ); + } + + @Override + public boolean insert(SharedSessionContractImplementor session, Object key, Object value) { + return false; + } + + @Override + public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) { + try { + writeLock().lock(); + Lockable item = (Lockable) getFromCache( key ); + if ( item == null ) { + addToCache( key, new Item( value, null, getRegion().getRegionFactory().nextTimestamp() ) ); + return true; + } + else { + return false; + } + } + finally { + writeLock().unlock(); + } + } + + @Override + public boolean update(SharedSessionContractImplementor session, Object key, Object value) { + return false; + } + + @Override + public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) { + try { + writeLock().lock(); + Lockable item = (Lockable) getFromCache( key ); + + if ( item != null && item.isUnlockable( lock ) ) { + SoftLockImpl lockItem = (SoftLockImpl) item; + if ( lockItem.wasLockedConcurrently() ) { + decrementLock( session, key, lockItem ); + return false; + } + else { + addToCache( key, new Item( value, null, getRegion().getRegionFactory().nextTimestamp() ) ); + return true; + } + } + else { + handleLockExpiry( session, key, item ); + return false; + } + } + finally { + writeLock().unlock(); + } + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java deleted file mode 100644 index 7317b145d3..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdRegionImpl.java +++ /dev/null @@ -1,60 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.boot.spi.SessionFactoryOptions; -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.NaturalIdRegion; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; - -import org.jboss.logging.Logger; - -/** - * @author Eric Dalquist - */ -class NaturalIdRegionImpl extends BaseTransactionalDataRegion implements NaturalIdRegion { - private static final Logger LOG = Logger.getLogger( NaturalIdRegionImpl.class.getName() ); - - private final SessionFactoryOptions settings; - - NaturalIdRegionImpl( - CachingRegionFactory cachingRegionFactory, - String name, - CacheDataDescription metadata, - SessionFactoryOptions settings) { - super( cachingRegionFactory, name, metadata ); - this.settings = settings; - } - - public SessionFactoryOptions getSettings() { - return settings; - } - - @Override - public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { - switch ( accessType ) { - case READ_ONLY: - if ( getCacheDataDescription().isMutable() ) { - LOG.warnf( "read-only cache configured for mutable collection [ %s ]", getName() ); - } - return new ReadOnlyNaturalIdRegionAccessStrategy( this ); - case READ_WRITE: - return new ReadWriteNaturalIdRegionAccessStrategy( this ); - case NONSTRICT_READ_WRITE: - return new NonstrictReadWriteNaturalIdRegionAccessStrategy( this ); - case TRANSACTIONAL: - return new TransactionalNaturalIdRegionAccessStrategy( this ); -// throw new UnsupportedOperationException( "doesn't support this access strategy" ); - default: - throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" ); - } - } - - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdTransactionalAccess.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdTransactionalAccess.java new file mode 100644 index 0000000000..4c0722f949 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NaturalIdTransactionalAccess.java @@ -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.testing.cache; + +import org.hibernate.cache.cfg.spi.NaturalIdDataCachingConfig; + +/** + * @author Steve Ebersole + */ +public class NaturalIdTransactionalAccess extends BaseNaturalIdDataAccess { + public NaturalIdTransactionalAccess( + DomainDataRegionImpl region, + NaturalIdDataCachingConfig naturalIdDataCachingConfig) { + super( region ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteCollectionRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteCollectionRegionAccessStrategy.java deleted file mode 100644 index c68f955fa9..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteCollectionRegionAccessStrategy.java +++ /dev/null @@ -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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -/** - * @author Strong Liu - */ -class NonstrictReadWriteCollectionRegionAccessStrategy extends BaseCollectionRegionAccessStrategy { - NonstrictReadWriteCollectionRegionAccessStrategy(CollectionRegionImpl region) { - super( region ); - } - - @Override - public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - evict( key ); - } - - @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - evict( key ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteEntityRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteEntityRegionAccessStrategy.java deleted file mode 100644 index fecaa92204..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/NonstrictReadWriteEntityRegionAccessStrategy.java +++ /dev/null @@ -1,66 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -/** - * @author Strong Liu - */ -class NonstrictReadWriteEntityRegionAccessStrategy extends BaseEntityRegionAccessStrategy { - NonstrictReadWriteEntityRegionAccessStrategy(EntityRegionImpl region) { - super( region ); - } - - /** - * Since this is a non-strict read/write strategy item locking is not used. - */ - @Override - public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - evict( key ); - } - - /** - * Returns false since this is an asynchronous cache access strategy. - */ - @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - return false; - } - - /** - * Returns false since this is a non-strict read/write cache access strategy - */ - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - return false; - } - - /** - * Removes the entry since this is a non-strict read/write cache strategy. - */ - @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException { - evict( key ); - return false; - } - - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) - throws CacheException { - unlockItem( session, key, lock ); - return false; - } - - @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - evict( key ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/QueryResultsRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/QueryResultsRegionImpl.java new file mode 100644 index 0000000000..68d1780907 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/QueryResultsRegionImpl.java @@ -0,0 +1,28 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.spi.QueryResultsRegion; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.engine.spi.SessionFactoryImplementor; + +/** + * @author Steve Ebersole + */ +class QueryResultsRegionImpl extends AbstractDirectAccessRegion implements QueryResultsRegion { + private final SessionFactoryImplementor sessionFactory; + + QueryResultsRegionImpl(String name, SessionFactoryImplementor sessionFactory) { + super( name ); + this.sessionFactory = sessionFactory; + } + + @Override + public RegionFactory getRegionFactory() { + return sessionFactory.getCache().getRegionFactory(); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyCollectionRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyCollectionRegionAccessStrategy.java deleted file mode 100644 index 1e6e8c174a..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyCollectionRegionAccessStrategy.java +++ /dev/null @@ -1,16 +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 . - */ -package org.hibernate.testing.cache; - -/** - * @author Strong Liu - */ -class ReadOnlyCollectionRegionAccessStrategy extends BaseCollectionRegionAccessStrategy { - ReadOnlyCollectionRegionAccessStrategy(CollectionRegionImpl region) { - super( region ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyEntityRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyEntityRegionAccessStrategy.java deleted file mode 100644 index ce61fa0fd3..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyEntityRegionAccessStrategy.java +++ /dev/null @@ -1,70 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -import org.jboss.logging.Logger; - -/** - * @author Strong Liu - */ -class ReadOnlyEntityRegionAccessStrategy extends BaseEntityRegionAccessStrategy { - private static final Logger LOG = Logger.getLogger( ReadOnlyEntityRegionAccessStrategy.class ); - - - ReadOnlyEntityRegionAccessStrategy(EntityRegionImpl region) { - super( region ); - } - - /** - * This cache is asynchronous hence a no-op - */ - @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - return false; //wait until tx complete, see afterInsert(). - } - - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - getInternalRegion().put( session, key, value ); //save into cache since the tx is completed - return true; - } - - @Override - public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - evict( key ); - } - - /** - * Throws UnsupportedOperationException since this cache is read-only - * - * @throws UnsupportedOperationException always - */ - @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException { - LOG.info( "Illegal attempt to update item cached as read-only : " + key ); - throw new UnsupportedOperationException( "Can't write to a readonly object" ); - } - - /** - * Throws UnsupportedOperationException since this cache is read-only - * - * @throws UnsupportedOperationException always - */ - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) - throws CacheException { - LOG.info( "Illegal attempt to update item cached as read-only : " + key ); - throw new UnsupportedOperationException( "Can't write to a readonly object" ); - } - - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java deleted file mode 100644 index d0013957d3..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadOnlyNaturalIdRegionAccessStrategy.java +++ /dev/null @@ -1,25 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -/** - * @author Eric Dalquist - */ -class ReadOnlyNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy { - ReadOnlyNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { - super( region ); - } - - @Override - public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException { - evict( key ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteCollectionRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteCollectionRegionAccessStrategy.java deleted file mode 100644 index 833b040720..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteCollectionRegionAccessStrategy.java +++ /dev/null @@ -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 . - */ -package org.hibernate.testing.cache; - -import java.util.Comparator; - -import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.CollectionRegion; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.persister.collection.CollectionPersister; - -/** - * @author Strong Liu - */ -class ReadWriteCollectionRegionAccessStrategy extends AbstractReadWriteAccessStrategy - implements CollectionRegionAccessStrategy { - - private final CollectionRegionImpl region; - - ReadWriteCollectionRegionAccessStrategy(CollectionRegionImpl region) { - this.region = region; - } - - @Override - Comparator getVersionComparator() { - return region.getCacheDataDescription().getVersionComparator(); - } - - @Override - protected BaseGeneralDataRegion getInternalRegion() { - return region; - } - - @Override - protected boolean isDefaultMinimalPutOverride() { - return region.getSettings().isMinimalPutsEnabled(); - } - - @Override - public CollectionRegion getRegion() { - return region; - } - - @Override - public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { - return region.getRegionFactory().getCacheKeysFactory().createCollectionKey( id, persister, factory, tenantIdentifier ); - } - - @Override - public Object getCacheKeyId(Object cacheKey) { - return region.getRegionFactory().getCacheKeysFactory().getCollectionId( cacheKey ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteEntityRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteEntityRegionAccessStrategy.java deleted file mode 100644 index dba17638d7..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteEntityRegionAccessStrategy.java +++ /dev/null @@ -1,120 +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 . - */ -package org.hibernate.testing.cache; - -import java.util.Comparator; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.persister.entity.EntityPersister; - -/** - * @author Strong Liu - */ -public class ReadWriteEntityRegionAccessStrategy extends AbstractReadWriteAccessStrategy - implements EntityRegionAccessStrategy { - private final EntityRegionImpl region; - - ReadWriteEntityRegionAccessStrategy(EntityRegionImpl region) { - this.region = region; - } - - @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - return false; - } - - @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException { - return false; - } - - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException { - - try { - writeLock.lock(); - Lockable item = (Lockable) region.get( session, key ); - if ( item == null ) { - region.put( session, key, new Item( value, version, region.nextTimestamp() ) ); - return true; - } - else { - return false; - } - } - finally { - writeLock.unlock(); - } - } - - - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) - throws CacheException { - try { - writeLock.lock(); - Lockable item = (Lockable) region.get( session, key ); - - if ( item != null && item.isUnlockable( lock ) ) { - Lock lockItem = (Lock) item; - if ( lockItem.wasLockedConcurrently() ) { - decrementLock(session, key, lockItem ); - return false; - } - else { - region.put( session, key, new Item( value, currentVersion, region.nextTimestamp() ) ); - return true; - } - } - else { - handleLockExpiry(session, key, item ); - return false; - } - } - finally { - writeLock.unlock(); - } - } - - - @Override - protected BaseGeneralDataRegion getInternalRegion() { - return region; - } - - @Override - protected boolean isDefaultMinimalPutOverride() { - return region.getSettings().isMinimalPutsEnabled(); - } - - @Override - Comparator getVersionComparator() { - return region.getCacheDataDescription().getVersionComparator(); - } - - @Override - public EntityRegion getRegion() { - return region; - } - - @Override - public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { - return region.getRegionFactory().getCacheKeysFactory().createEntityKey( id, persister, factory, tenantIdentifier ); - } - - @Override - public Object getCacheKeyId(Object cacheKey) { - return region.getRegionFactory().getCacheKeysFactory().getEntityId( cacheKey ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java deleted file mode 100644 index 9500a2db4f..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/ReadWriteNaturalIdRegionAccessStrategy.java +++ /dev/null @@ -1,117 +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 . - */ -package org.hibernate.testing.cache; - -import java.util.Comparator; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.internal.DefaultCacheKeysFactory; -import org.hibernate.cache.spi.NaturalIdRegion; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.persister.entity.EntityPersister; - -/** - * @author Eric Dalquist - */ -class ReadWriteNaturalIdRegionAccessStrategy extends AbstractReadWriteAccessStrategy - implements NaturalIdRegionAccessStrategy { - - private final NaturalIdRegionImpl region; - - ReadWriteNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { - this.region = region; - } - - @Override - public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - return false; - } - - @Override - public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - return false; - } - - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException { - - try { - writeLock.lock(); - Lockable item = (Lockable) region.get( session, key ); - if ( item == null ) { - region.put( session, key, new Item( value, null, region.nextTimestamp() ) ); - return true; - } - else { - return false; - } - } - finally { - writeLock.unlock(); - } - } - - - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException { - try { - writeLock.lock(); - Lockable item = (Lockable) region.get( session, key ); - - if ( item != null && item.isUnlockable( lock ) ) { - Lock lockItem = (Lock) item; - if ( lockItem.wasLockedConcurrently() ) { - decrementLock( session, key, lockItem ); - return false; - } - else { - region.put( session, key, new Item( value, null, region.nextTimestamp() ) ); - return true; - } - } - else { - handleLockExpiry( session, key, item ); - return false; - } - } - finally { - writeLock.unlock(); - } - } - - @Override - Comparator getVersionComparator() { - return region.getCacheDataDescription().getVersionComparator(); - } - - @Override - protected BaseGeneralDataRegion getInternalRegion() { - return region; - } - - @Override - protected boolean isDefaultMinimalPutOverride() { - return region.getSettings().isMinimalPutsEnabled(); - } - - @Override - public NaturalIdRegion getRegion() { - return region; - } - - @Override - public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) { - return region.getRegionFactory().getCacheKeysFactory().createNaturalIdKey( naturalIdValues, persister, session ); - } - - @Override - public Object[] getNaturalIdValues(Object cacheKey) { - return region.getRegionFactory().getCacheKeysFactory().getNaturalIdValues( cacheKey ); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/SoftLockingSupport.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/SoftLockingSupport.java new file mode 100644 index 0000000000..90662fdfa3 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/SoftLockingSupport.java @@ -0,0 +1,18 @@ +/* + * 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.testing.cache; + +/** + * @author Steve Ebersole + */ +public class SoftLockingSupport { + private SoftLockingSupport() { + } + + + +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TimestampsRegionImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TimestampsRegionImpl.java new file mode 100644 index 0000000000..57ef213121 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TimestampsRegionImpl.java @@ -0,0 +1,28 @@ +/* + * 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.testing.cache; + +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.TimestampsRegion; +import org.hibernate.engine.spi.SessionFactoryImplementor; + +/** + * @author Steve Ebersole + */ +class TimestampsRegionImpl extends AbstractDirectAccessRegion implements TimestampsRegion { + private final SessionFactoryImplementor sessionFactory; + + TimestampsRegionImpl(String regionName, SessionFactoryImplementor sessionFactory) { + super( regionName ); + this.sessionFactory = sessionFactory; + } + + @Override + public RegionFactory getRegionFactory() { + return sessionFactory.getCache().getRegionFactory(); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalCollectionRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalCollectionRegionAccessStrategy.java deleted file mode 100644 index 3e77238c97..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalCollectionRegionAccessStrategy.java +++ /dev/null @@ -1,25 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -/** - * @author Strong Liu - */ -class TransactionalCollectionRegionAccessStrategy extends BaseCollectionRegionAccessStrategy { - TransactionalCollectionRegionAccessStrategy(CollectionRegionImpl region) { - super( region ); - } - - @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - evict( key ); - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalEntityRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalEntityRegionAccessStrategy.java deleted file mode 100644 index b99c30f9b4..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalEntityRegionAccessStrategy.java +++ /dev/null @@ -1,42 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -/** - * @author Strong Liu - */ -class TransactionalEntityRegionAccessStrategy extends BaseEntityRegionAccessStrategy { - TransactionalEntityRegionAccessStrategy(EntityRegionImpl region) { - super( region ); - } - - @Override - public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) { - return false; - } - - @Override - public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) { - return false; - } - - @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - evict( key ); - } - - @Override - public boolean update( - SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, - Object previousVersion) throws CacheException { - return insert(session, key, value, currentVersion); - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java deleted file mode 100644 index 8a94bedd17..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/TransactionalNaturalIdRegionAccessStrategy.java +++ /dev/null @@ -1,25 +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 . - */ -package org.hibernate.testing.cache; - -import org.hibernate.cache.CacheException; -import org.hibernate.engine.spi.SharedSessionContractImplementor; - -/** - * @author Eric Dalquist - */ -class TransactionalNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy { - TransactionalNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) { - super( region ); - } - - @Override - public void remove(SharedSessionContractImplementor session, Object key) throws CacheException { - evict( key ); - } - -} diff --git a/migration-guide.adoc b/migration-guide.adoc index cd81e81b22..24b4371de9 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -96,3 +96,39 @@ therefore, avoiding the need of updating any library dependency. ==== The relocation pom may be dropped in a future release. ==== + + +=== 5.3 -> 6.0 compatibility changes + +The original driving force behind these series of changes is an effort to be as proactive as possible +about designing compatibility between 5.3 and 6.0. + + +==== Second-level cache provider SPI changes + +As a fix for a potentially nasty bug in caching, we needed to redesign the Second-level cache provider +SPI. Details can be seen on the https://hibernate.atlassian.net/browse/HHH-11356[HHH-11356] Jira issue. +Originally slated for 6.0 - to avoid the SPI changes, it was decided to back-port it to 5.3 because the +bug became really important. + +One manifestation of this is the clarification that a single second-level cache region +may not be used to store both query-results and domain-data (entity, collection and natural-id). + +Care was taken to maintain backwards compatibility so that applications could continue unchanged, +although the older access methods have been deprecated as described above. + + +==== Statistics changes + +The change for HHH-11356 required changes in its consumers. One such consumer is the Hibernate +Statistics system.... + + +==== Cache regionName expectations in API and SPI calls + +prefixed v. un-prefixed + + +==== Type system changes + +Use of NavigableRole, back-ported from 6.0 \ No newline at end of file