Skip to content

[WIP] Intern string metadata in Session Factory #1503

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 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
<ItemGroup>
<ProjectReference Include="..\NHibernate.DomainModel\NHibernate.DomainModel.csproj" />
<ProjectReference Include="..\NHibernate\NHibernate.csproj" />
<ProjectReference Include="..\RawBencher\Model\NH.Bencher.Model.csproj" />
<ProjectReference Include="..\RawBencher\Persistence\NH.Bencher.Persistence.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Configuration" />
Expand Down
110 changes: 110 additions & 0 deletions src/NHibernate.Test/RawBenchSessionManagerPerfomance.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//#define UPSTREAM
using System;
using System.IO;
using NHibernate.Util;
using NUnit.Framework;


namespace NHibernate.Test
{
[TestFixture]
public class RawBenchSessionManagerPerfomance
{
#if UPSTREAM
[Test]
public void InternLevel_Upstream()
{
//Just to force initialize static ctor and do not calculate memory consumed by Environoment
Cfg.Environment.VerifyProperties(CollectionHelper.EmptyDictionary<string, string>());

RunTest();
}

#else

[Test]
public void InternLevel_Minimal()
{
Cfg.Environment.InternLevel = InternLevel.Minimal;
RunTest();
}

[Test]
public void InternLevel_Default()
{
Cfg.Environment.InternLevel = InternLevel.Default;
RunTest();
}

[Test]
public void InternLevel_SessionFactories()
{
Cfg.Environment.InternLevel = InternLevel.SessionFactories;
RunTest();
}

[Test]
public void InternLevel_AppDomains()
{
Cfg.Environment.InternLevel = InternLevel.AppDomains;
RunTest();
}


#endif

private static void RunTest()
{
var factory = NH.Bencher.SessionManager.SessionFactory;

var setup = new AppDomainSetup();
var si = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = si.ApplicationBase;
setup.ConfigurationFile = si.ConfigurationFile;

AppDomain newDomain = AppDomain.CreateDomain("New Domain", null, si);

#if !UPSTREAM
newDomain.SetData("internLevel", Cfg.Environment.InternLevel);
#endif
try
{
newDomain.DoCallBack(
() =>
{
StringWriter s = new StringWriter();
Console.SetOut(s);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("From new App Domain...");
#if !UPSTREAM
Cfg.Environment.InternLevel = (InternLevel) AppDomain.CurrentDomain.GetData("internLevel");
#endif
try
{

var factory2 = NH.Bencher.SessionManager.SessionFactory;
}
finally
{
AppDomain.CurrentDomain.SetData("log", s.ToString());
AppDomain.CurrentDomain.SetData("memory", NH.Bencher.SessionManager.LastTotalMemoryUsage);
}
});
}
finally
{
Console.WriteLine(newDomain.GetData("log"));
Console.WriteLine("Total Memory Usage in 2 App Domains: " + ToKbSize((long) newDomain.GetData("memory") + NH.Bencher.SessionManager.LastTotalMemoryUsage));

AppDomain.Unload(newDomain);
}
}

private static string ToKbSize(long bytes)
{
return (bytes / 1024.0).ToString("0,0.00") + " Kb";
}
}

}
14 changes: 13 additions & 1 deletion src/NHibernate.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
VisualStudioVersion = 15.0.27130.2003
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{593DCEA7-C933-46F3-939F-D8172399AB05}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -21,6 +21,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.TestDatabaseSetu
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "NHibernate.Test.VisualBasic", "NHibernate.Test.VisualBasic\NHibernate.Test.VisualBasic.vbproj", "{7C2EF610-BCA0-4D1F-898A-DE9908E4970C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NH.Bencher.Model", "RawBencher\Model\NH.Bencher.Model.csproj", "{45DAEB56-B84D-4D7A-BF22-293F1CE07DBB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NH.Bencher.Persistence", "RawBencher\Persistence\NH.Bencher.Persistence.csproj", "{3E9CA88C-03EC-445A-960A-242511B6EF55}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -47,6 +51,14 @@ Global
{7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Any CPU.Build.0 = Release|Any CPU
{45DAEB56-B84D-4D7A-BF22-293F1CE07DBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45DAEB56-B84D-4D7A-BF22-293F1CE07DBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45DAEB56-B84D-4D7A-BF22-293F1CE07DBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45DAEB56-B84D-4D7A-BF22-293F1CE07DBB}.Release|Any CPU.Build.0 = Release|Any CPU
{3E9CA88C-03EC-445A-960A-242511B6EF55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E9CA88C-03EC-445A-960A-242511B6EF55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E9CA88C-03EC-445A-960A-242511B6EF55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E9CA88C-03EC-445A-960A-242511B6EF55}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
55 changes: 54 additions & 1 deletion src/NHibernate/Cfg/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,15 @@ public static string Version
/// </summary>
public const string TrackSessionId = "track_session_id";

public const string StringMetadataInternLevel = "intern_level";

private static readonly Dictionary<string, string> GlobalProperties;

private static IBytecodeProvider BytecodeProviderInstance;
private static bool EnableReflectionOptimizer;

private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(Environment));
private static InternLevel _internLevel;

/// <summary>
/// Issue warnings to user when any obsolete property names are used.
Expand All @@ -299,13 +302,37 @@ static Environment()

BytecodeProviderInstance = BuildBytecodeProvider(GlobalProperties);
EnableReflectionOptimizer = PropertiesHelper.GetBoolean(PropertyUseReflectionOptimizer, GlobalProperties);

//TODO: Proper configuration
SetInternLevelFromConfig();

if (EnableReflectionOptimizer)
{
log.Info("Using reflection optimizer");
}
}

//TODO:
private static InternLevel SetInternLevelFromConfig()
{
return InternLevel.Default;
//string value = System.Configuration.ConfigurationManager.AppSettings["InternLevel"];
//Console.WriteLine("Path to config file: " + ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath);

//if (string.IsNullOrEmpty(value))
//{
// return InternLevel.Default;
//}

//if (!Enum.TryParse<InternLevel>(value, true, out var valueParsed))
//{
// Console.WriteLine("Intern level setting is invalid: " + value);
//}
//Console.WriteLine("Intern level " + valueParsed);
//Console.WriteLine();
//return valueParsed;
}

private static void LoadGlobalPropertiesFromAppConfig()
{
object config = ConfigurationManager.GetSection(CfgXmlHelper.CfgSectionName);
Expand Down Expand Up @@ -388,6 +415,32 @@ public static IBytecodeProvider BytecodeProvider
set { BytecodeProviderInstance = value; }
}

/// <summary>
/// The bytecode provider to use.
/// </summary>
/// <remarks>
/// This property is read from the <c>&lt;nhibernate&gt;</c> section
/// of the application configuration file by default. Since it is not
/// always convenient to configure NHibernate through the application
/// configuration file, it is also possible to set the property value
/// manually. This should only be done before a configuration object
/// is created, otherwise the change may not take effect.
/// </remarks>
public static InternLevel InternLevel
{
get { return _internLevel; }
set
{

if (value != _internLevel)
{
Console.WriteLine("Intern level " + value);
}
_internLevel = value;

}
}

/// <summary>
/// Whether to enable the use of reflection optimizer
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/NHibernate/Dialect/Lock/SelectLockingStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private SqlString GenerateLockString()
{
select.SetComment(lockMode + " lock " + lockable.EntityName);
}
return select.ToSqlString();
return select.ToSqlString(true);
}

#region ILockingStrategy Members
Expand Down Expand Up @@ -110,4 +110,4 @@ public void Lock(object id, object version, object obj, ISessionImplementor sess

#endregion
}
}
}
8 changes: 5 additions & 3 deletions src/NHibernate/Loader/BasicLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public abstract class BasicLoader : Loader
private IEntityAliases[] descriptors;
private ICollectionAliases[] collectionDescriptors;

public BasicLoader(ISessionFactoryImplementor factory) : base(factory) {}
public BasicLoader(ISessionFactoryImplementor factory) : base(factory) { }

protected override sealed IEntityAliases[] EntityAliases
{
Expand All @@ -28,14 +28,16 @@ protected override sealed ICollectionAliases[] CollectionAliases
protected abstract string[] Suffixes { get; }
protected abstract string[] CollectionSuffixes { get; }

protected virtual bool InternStringMetadata => false;

protected override void PostInstantiate()
{
ILoadable[] persisters = EntityPersisters;
string[] suffixes = Suffixes;
descriptors = new IEntityAliases[persisters.Length];
for (int i = 0; i < descriptors.Length; i++)
{
descriptors[i] = new DefaultEntityAliases(persisters[i], suffixes[i]);
descriptors[i] = new DefaultEntityAliases(persisters[i], suffixes[i], InternStringMetadata);
}

ICollectionPersister[] collectionPersisters = CollectionPersisters;
Expand Down Expand Up @@ -69,7 +71,7 @@ protected override void PostInstantiate()
private static bool IsBag(ICollectionPersister collectionPersister)
{
var type = collectionPersister.CollectionType.GetType();
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof (GenericBagType<>);
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(GenericBagType<>);
}

/// <summary>
Expand Down
45 changes: 39 additions & 6 deletions src/NHibernate/Loader/DefaultEntityAliases.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using NHibernate.Persister.Entity;
using NHibernate.Util;

namespace NHibernate.Loader
{
Expand Down Expand Up @@ -34,6 +35,34 @@ public DefaultEntityAliases(IDictionary<string, string[]> userProvidedAliases, I
//rowIdAlias is generated on demand in property
}

/// <summary>
/// Calculate and cache select-clause aliases.
/// </summary>
public DefaultEntityAliases(ILoadable persister, string suffix, bool internAliases) : this(persister, suffix)
{
if (internAliases == false)
return;

const InternLevel internLevel = InternLevel.EntityAlias;

SuffixedKeyAliases = StringHelper.Intern(SuffixedKeyAliases, internLevel);
SuffixedPropertyAliases = InternPropertiesAliases(SuffixedPropertyAliases, internLevel);
SuffixedVersionAliases = StringHelper.Intern(SuffixedVersionAliases, internLevel);
SuffixedDiscriminatorAlias = StringHelper.Intern(SuffixedDiscriminatorAlias, internLevel);
if (persister.HasRowId)
RowIdAlias = StringHelper.Intern(RowIdAlias, internLevel);
}

private string[][] InternPropertiesAliases(string[][] propertiesAliases, InternLevel internLevel)
{
foreach (string[] values in propertiesAliases)
{
StringHelper.Intern(values, internLevel);
}

return propertiesAliases;
}

/// <summary>
/// Returns aliases for subclass persister
/// </summary>
Expand Down Expand Up @@ -63,7 +92,11 @@ public string[][] GetSuffixedPropertyAliases(ILoadable persister)
public string[] SuffixedKeyAliases { get; }

// TODO: not visible to the user!
public string RowIdAlias => _rowIdAlias ?? (_rowIdAlias = Loadable.RowIdAlias + _suffix);
public string RowIdAlias
{
get => _rowIdAlias ?? (_rowIdAlias = Loadable.RowIdAlias + _suffix);
private set => _rowIdAlias = value;
}

/// <summary>
/// Returns default aliases for all the properties
Expand Down Expand Up @@ -100,32 +133,32 @@ private string[] DetermineKeyAliases(ILoadable persister)
if (_userProvidedAliases != null)
{
var result = SafeGetUserProvidedAliases(persister.IdentifierPropertyName) ??
GetUserProvidedAliases(EntityPersister.EntityID);
GetUserProvidedAliases(EntityPersister.EntityID);

if (result != null)
return result;
}

return GetIdentifierAliases(persister, _suffix);
}

private string[][] DeterminePropertyAliases(ILoadable persister)
{
return GetSuffixedPropertyAliases(persister);
}

private string DetermineDiscriminatorAlias(ILoadable persister)
{
if (_userProvidedAliases != null)
{
var columns = GetUserProvidedAliases(AbstractEntityPersister.EntityClass);
if (columns != null)
if (columns != null)
return columns[0];
}

return GetDiscriminatorAlias(persister, _suffix);
}

private string[] SafeGetUserProvidedAliases(string propertyPath)
{
if (propertyPath == null)
Expand Down
2 changes: 2 additions & 0 deletions src/NHibernate/Loader/Entity/CascadeEntityLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ public CascadeEntityLoader(IOuterJoinLoadable persister, CascadingAction action,

log.Debug("Static select for action {0} on entity {1}: {2}", action, entityName, SqlString);
}

protected override bool InternStringMetadata => true;
}
}
Loading