@@ -232,7 +232,6 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
232
232
233
233
#region Persisters
234
234
235
- Dictionary < string , ICacheConcurrencyStrategy > caches = new Dictionary < string , ICacheConcurrencyStrategy > ( ) ;
236
235
entityPersisters = new Dictionary < string , IEntityPersister > ( ) ;
237
236
implementorToEntityName = new Dictionary < System . Type , string > ( ) ;
238
237
@@ -241,22 +240,15 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
241
240
foreach ( PersistentClass model in cfg . ClassMappings )
242
241
{
243
242
model . PrepareTemporaryTables ( mapping , settings . Dialect ) ;
244
- string cacheRegion = model . RootClazz . CacheRegionName ;
245
- ICacheConcurrencyStrategy cache ;
246
- if ( ! caches . TryGetValue ( cacheRegion , out cache ) )
247
- {
248
- cache =
249
- CacheFactory . CreateCache ( model . CacheConcurrencyStrategy , cacheRegion , model . IsMutable , settings , properties ) ;
250
- if ( cache != null )
251
- {
252
- caches . Add ( cacheRegion , cache ) ;
253
- if ( ! allCacheRegions . TryAdd ( cache . RegionName , cache . Cache ) )
254
- {
255
- throw new HibernateException ( "An item with the same key has already been added to allCacheRegions." ) ;
256
- }
257
- }
258
- }
259
- IEntityPersister cp = PersisterFactory . CreateClassPersister ( model , cache , this , mapping ) ;
243
+ var cacheRegion = model . RootClazz . CacheRegionName ;
244
+ var strategy = model . CacheConcurrencyStrategy ;
245
+ var cache = CacheFactory . CreateCache (
246
+ strategy ,
247
+ cacheRegion ,
248
+ model . IsMutable ,
249
+ settings ,
250
+ GetOrBuild ) ;
251
+ var cp = PersisterFactory . CreateClassPersister ( model , cache , this , mapping ) ;
260
252
entityPersisters [ model . EntityName ] = cp ;
261
253
classMeta [ model . EntityName ] = cp . ClassMetadata ;
262
254
@@ -271,14 +263,14 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
271
263
collectionPersisters = new Dictionary < string , ICollectionPersister > ( ) ;
272
264
foreach ( Mapping . Collection model in cfg . CollectionMappings )
273
265
{
274
- ICacheConcurrencyStrategy cache =
275
- CacheFactory . CreateCache ( model . CacheConcurrencyStrategy , model . CacheRegionName , model . Owner . IsMutable , settings ,
276
- properties ) ;
277
- if ( cache != null )
278
- {
279
- allCacheRegions [ cache . RegionName ] = cache . Cache ;
280
- }
281
- ICollectionPersister persister = PersisterFactory . CreateCollectionPersister ( model , cache , this ) ;
266
+ var cacheRegion = model . CacheRegionName ;
267
+ var cache = CacheFactory . CreateCache (
268
+ model . CacheConcurrencyStrategy ,
269
+ cacheRegion ,
270
+ model . Owner . IsMutable ,
271
+ settings ,
272
+ GetOrBuild ) ;
273
+ var persister = PersisterFactory . CreateCollectionPersister ( model , cache , this ) ;
282
274
collectionPersisters [ model . Role ] = persister ;
283
275
IType indexType = persister . IndexType ;
284
276
if ( indexType != null && indexType . IsAssociationType && ! indexType . IsAnyType )
@@ -379,8 +371,15 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
379
371
380
372
if ( settings . IsQueryCacheEnabled )
381
373
{
382
- updateTimestampsCache = new UpdateTimestampsCache ( settings , properties ) ;
383
- queryCache = settings . QueryCacheFactory . GetQueryCache ( null , updateTimestampsCache , settings , properties ) ;
374
+ var updateTimestampsCacheName = typeof ( StandardQueryCache ) . Name ;
375
+ updateTimestampsCache = new UpdateTimestampsCache ( GetOrBuild ( updateTimestampsCacheName ) ) ;
376
+ var queryCacheName = typeof ( StandardQueryCache ) . FullName ;
377
+ queryCache = settings . QueryCacheFactory . GetQueryCache (
378
+ queryCacheName ,
379
+ updateTimestampsCache ,
380
+ settings ,
381
+ properties ,
382
+ GetOrBuild ( queryCacheName ) ) ;
384
383
queryCaches = new ConcurrentDictionary < string , Lazy < IQueryCache > > ( ) ;
385
384
}
386
385
else
@@ -1007,6 +1006,25 @@ public ICache GetSecondLevelCacheRegion(string regionName)
1007
1006
return result ;
1008
1007
}
1009
1008
1009
+ /// <summary>
1010
+ /// Get an existing <see cref="ICache"/> or build a new one if not already existing.
1011
+ /// </summary>
1012
+ /// <param name="cacheRegion">The (unprefixed) cache region of the cache to get or build.</param>
1013
+ /// <returns>A cache.</returns>
1014
+ private ICache GetOrBuild ( string cacheRegion )
1015
+ {
1016
+ // If run concurrently for the same region, this may built many caches for the same region.
1017
+ // Currently only GetQueryCache may be run concurrently, and its implementation prevents
1018
+ // concurrent creation call for the same region, so this will not happen.
1019
+ // Otherwise the dictionary will have to be changed for using a lazy, see
1020
+ // https://stackoverflow.com/a/31637510/1178314
1021
+ var prefix = settings . CacheRegionPrefix ;
1022
+ if ( ! string . IsNullOrEmpty ( prefix ) )
1023
+ cacheRegion = prefix + '.' + cacheRegion ;
1024
+ return allCacheRegions . GetOrAdd ( cacheRegion ,
1025
+ cr => settings . CacheProvider . BuildCache ( cr , properties ) ) ;
1026
+ }
1027
+
1010
1028
/// <summary> Statistics SPI</summary>
1011
1029
public IStatisticsImplementor StatisticsImplementor
1012
1030
{
@@ -1035,12 +1053,12 @@ public IQueryCache GetQueryCache(string cacheRegion)
1035
1053
return queryCaches . GetOrAdd (
1036
1054
cacheRegion ,
1037
1055
cr => new Lazy < IQueryCache > (
1038
- ( ) =>
1039
- {
1040
- var currentQueryCache = settings . QueryCacheFactory . GetQueryCache ( cr , updateTimestampsCache , settings , properties ) ;
1041
- allCacheRegions [ currentQueryCache . RegionName ] = currentQueryCache . Cache ;
1042
- return currentQueryCache ;
1043
- } ) ) . Value ;
1056
+ ( ) => settings . QueryCacheFactory . GetQueryCache (
1057
+ cr ,
1058
+ updateTimestampsCache ,
1059
+ settings ,
1060
+ properties ,
1061
+ GetOrBuild ( cr ) ) ) ) . Value ;
1044
1062
}
1045
1063
1046
1064
public void EvictQueries ( )
0 commit comments