Skip to content

Make Most of the Dictionaries in SessionFactoryImpl ReadOnly Improves #3657 #3658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
47 changes: 26 additions & 21 deletions src/NHibernate/Impl/SessionFactoryImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,23 +105,23 @@ public void HandleEntityNotFound(string entityName, string propertyName, object
new ConcurrentDictionary<string, CacheBase>();

[NonSerialized]
private readonly IDictionary<string, IClassMetadata> classMetadata;
private readonly IReadOnlyDictionary<string, IClassMetadata> classMetadata;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All theses changes look superfluous to me, because this will never be enough to get the build of a session factory threadsafe with concurrent uses of the factory being built. The only reasonable fix is to not end up using a factory that is concurrently being built.


[NonSerialized]
private readonly IDictionary<string, ICollectionMetadata> collectionMetadata;
private readonly IReadOnlyDictionary<string, ICollectionMetadata> collectionMetadata;
[NonSerialized]
private readonly Dictionary<string, ICollectionPersister> collectionPersisters;
private readonly IReadOnlyDictionary<string, ICollectionPersister> collectionPersisters;
[NonSerialized]
private readonly ILookup<string, ICollectionPersister> collectionPersistersSpaces;

[NonSerialized]
private readonly IDictionary<string, ISet<string>> collectionRolesByEntityParticipant;
private readonly IReadOnlyDictionary<string, ISet<string>> collectionRolesByEntityParticipant;
[NonSerialized]
private readonly ICurrentSessionContext currentSessionContext;
[NonSerialized]
private readonly IEntityNotFoundDelegate entityNotFoundDelegate;
[NonSerialized]
private readonly IDictionary<string, IEntityPersister> entityPersisters;
private readonly IReadOnlyDictionary<string, IEntityPersister> entityPersisters;
[NonSerialized]
private readonly ILookup<string, IEntityPersister> entityPersistersSpaces;

Expand All @@ -130,27 +130,27 @@ public void HandleEntityNotFound(string entityName, string propertyName, object
/// </summary>
/// <remarks>this is a shortcut.</remarks>
[NonSerialized]
private readonly IDictionary<System.Type, string> implementorToEntityName;
private readonly IReadOnlyDictionary<System.Type, string> implementorToEntityName;

[NonSerialized]
private readonly EventListeners eventListeners;

[NonSerialized]
private readonly Dictionary<string, FilterDefinition> filters;
[NonSerialized]
private readonly Dictionary<string, IIdentifierGenerator> identifierGenerators;
private readonly IReadOnlyDictionary<string, IIdentifierGenerator> identifierGenerators;

[NonSerialized]
private readonly Dictionary<string, string> imports;
private readonly IReadOnlyDictionary<string, string> imports;

[NonSerialized]
private readonly IInterceptor interceptor;
private readonly string name;
[NonSerialized]
private readonly Dictionary<string, NamedQueryDefinition> namedQueries;
private readonly IReadOnlyDictionary<string, NamedQueryDefinition> namedQueries;

[NonSerialized]
private readonly Dictionary<string, NamedSQLQueryDefinition> namedSqlQueries;
private readonly IReadOnlyDictionary<string, NamedSQLQueryDefinition> namedSqlQueries;

[NonSerialized]
private readonly IDictionary<string, string> properties;
Expand All @@ -168,7 +168,7 @@ public void HandleEntityNotFound(string entityName, string propertyName, object
[NonSerialized]
private readonly SQLFunctionRegistry sqlFunctionRegistry;
[NonSerialized]
private readonly Dictionary<string, ResultSetMappingDefinition> sqlResultSetMappings;
private readonly ReadOnlyDictionary<string, ResultSetMappingDefinition> sqlResultSetMappings;
[NonSerialized]
private readonly UpdateTimestampsCache updateTimestampsCache;
[NonSerialized]
Expand Down Expand Up @@ -265,8 +265,8 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
#region Persisters

var caches = new Dictionary<Tuple<string, string>, ICacheConcurrencyStrategy>();
entityPersisters = new Dictionary<string, IEntityPersister>();
implementorToEntityName = new Dictionary<System.Type, string>();
var tmpEntityPersisters = new Dictionary<string, IEntityPersister>();
var tmpImplementorToEntityName = new Dictionary<System.Type, string>();

Dictionary<string, IClassMetadata> classMeta = new Dictionary<string, IClassMetadata>();

Expand All @@ -280,23 +280,26 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
model.EntityName,
caches);
var cp = PersisterFactory.CreateClassPersister(model, cache, this, mapping);
entityPersisters[model.EntityName] = cp;
tmpEntityPersisters[model.EntityName] = cp;
classMeta[model.EntityName] = cp.ClassMetadata;

if (model.HasPocoRepresentation)
{
implementorToEntityName[model.MappedClass] = model.EntityName;
tmpImplementorToEntityName[model.MappedClass] = model.EntityName;
}
}

entityPersisters = new ReadOnlyDictionary<string, IEntityPersister>(tmpEntityPersisters);
implementorToEntityName = new ReadOnlyDictionary<System.Type, string>(tmpImplementorToEntityName);

entityPersistersSpaces = entityPersisters
.SelectMany(x => x.Value.QuerySpaces.Select(y => new { QuerySpace = y, Persister = x.Value }))
.ToLookup(x => x.QuerySpace, x => x.Persister);

classMetadata = new ReadOnlyDictionary<string, IClassMetadata>(classMeta);

Dictionary<string, ISet<string>> tmpEntityToCollectionRoleMap = new Dictionary<string, ISet<string>>();
collectionPersisters = new Dictionary<string, ICollectionPersister>();
var tmpCollectionPersisters = new Dictionary<string, ICollectionPersister>();
foreach (Mapping.Collection model in cfg.CollectionMappings)
{
var cache = GetCacheConcurrencyStrategy(
Expand All @@ -306,7 +309,7 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
model.OwnerEntityName,
caches);
var persister = PersisterFactory.CreateCollectionPersister(model, cache, this);
collectionPersisters[model.Role] = persister;
tmpCollectionPersisters[model.Role] = persister;
IType indexType = persister.IndexType;
if (indexType != null && indexType.IsAssociationType && !indexType.IsAnyType)
{
Expand All @@ -333,6 +336,8 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
}
}

collectionPersisters = new ReadOnlyDictionary<string, ICollectionPersister>(tmpCollectionPersisters);

collectionPersistersSpaces = collectionPersisters
.SelectMany(x => x.Value.CollectionSpaces.Select(y => new { QuerySpace = y, Persister = x.Value }))
.ToLookup(x => x.QuerySpace, x => x.Persister);
Expand All @@ -347,12 +352,12 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
#endregion

#region Named Queries
namedQueries = new Dictionary<string, NamedQueryDefinition>(cfg.NamedQueries);
namedSqlQueries = new Dictionary<string, NamedSQLQueryDefinition>(cfg.NamedSQLQueries);
sqlResultSetMappings = new Dictionary<string, ResultSetMappingDefinition>(cfg.SqlResultSetMappings);
namedQueries = new ReadOnlyDictionary<string, NamedQueryDefinition>(cfg.NamedQueries);
namedSqlQueries = new ReadOnlyDictionary<string, NamedSQLQueryDefinition>(cfg.NamedSQLQueries);
sqlResultSetMappings = new ReadOnlyDictionary<string, ResultSetMappingDefinition>(cfg.SqlResultSetMappings);
#endregion

imports = new Dictionary<string, string>(cfg.Imports);
imports = new ReadOnlyDictionary<string, string>(cfg.Imports);

#region after *all* persisters and named queries are registered
foreach (IEntityPersister persister in entityPersisters.Values)
Expand Down
5 changes: 3 additions & 2 deletions src/NHibernate/Impl/SessionFactoryObjectFactory.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

Expand All @@ -21,8 +22,8 @@ public static class SessionFactoryObjectFactory
{
private static readonly INHibernateLogger log;

private static readonly IDictionary<string, ISessionFactory> Instances = new Dictionary<string, ISessionFactory>();
private static readonly IDictionary<string, ISessionFactory> NamedInstances = new Dictionary<string, ISessionFactory>();
private static readonly IDictionary<string, ISessionFactory> Instances = new ConcurrentDictionary<string, ISessionFactory>();
private static readonly IDictionary<string, ISessionFactory> NamedInstances = new ConcurrentDictionary<string, ISessionFactory>();

/// <summary></summary>
static SessionFactoryObjectFactory()
Expand Down