Skip to content

Commit 9b45f98

Browse files
maca88hazzik
authored andcommitted
Added the ability to disable capturing the current session id (#1394)
Closes #1391
1 parent 1b410b2 commit 9b45f98

File tree

8 files changed

+224
-4
lines changed

8 files changed

+224
-4
lines changed

doc/reference/modules/configuration.xml

+23
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,29 @@ var session = sessions.OpenSession(conn);
10261026
</para>
10271027
</entry>
10281028
</row>
1029+
<row>
1030+
<entry>
1031+
<literal>track_session_id</literal>
1032+
</entry>
1033+
<entry>
1034+
Set whether the session id should be tracked in logs or not. When <literal>true</literal>, each
1035+
session will have an unique <literal>Guid</literal> that can be retrieved with
1036+
<literal>ISessionImplementor.SessionId</literal>, otherwise <literal>ISessionImplementor.SessionId</literal>
1037+
will be <literal>Guid.Empty</literal>.
1038+
<para>
1039+
Session id is used for logging purpose and can also be retrieved on the static property
1040+
<literal>NHibernate.Impl.SessionIdLoggingContext.SessionId</literal>, when tracking is enabled.
1041+
</para>
1042+
<para>
1043+
Disabling tracking by setting <literal>track_session_id</literal> to <literal>false</literal>
1044+
increases performances. Default is <literal>true</literal>.
1045+
</para>
1046+
<para>
1047+
<emphasis role="strong">eg.</emphasis>
1048+
<literal>true</literal> | <literal>false</literal>
1049+
</para>
1050+
</entry>
1051+
</row>
10291052
<row>
10301053
<entry>
10311054
<literal>sql_types.keep_datetime</literal>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using System.Xml;
5+
using NHibernate.Cfg;
6+
using NHibernate.Impl;
7+
using NHibernate.Util;
8+
using NUnit.Framework;
9+
using Environment = NHibernate.Cfg.Environment;
10+
11+
namespace NHibernate.Test.NHSpecificTest.GH1391
12+
{
13+
public class Fixture
14+
{
15+
private readonly Random _random = new Random();
16+
17+
[Test]
18+
public void Concurrent()
19+
{
20+
// Simulating two session factories, where one has tracking enabled and the other disabled
21+
Parallel.For(0, 100, i =>
22+
{
23+
if (_random.Next(2) == 0)
24+
{
25+
Enabled();
26+
}
27+
else
28+
{
29+
Disabled();
30+
}
31+
});
32+
}
33+
34+
[Test]
35+
public void ConcurrentAsync()
36+
{
37+
async Task RunAsync(bool enabled)
38+
{
39+
for (var i = 0; i < 50; i++)
40+
{
41+
if (enabled)
42+
{
43+
await EnabledAsync().ConfigureAwait(false);
44+
}
45+
else
46+
{
47+
await DisabledAsync().ConfigureAwait(false);
48+
}
49+
}
50+
}
51+
// Simulating two session factories, where one has tracking enabled and the other disabled
52+
Task.WaitAll(RunAsync(true), RunAsync(false));
53+
}
54+
55+
[Test]
56+
public void Enabled()
57+
{
58+
var guid = Guid.NewGuid();
59+
using (new SessionIdLoggingContext(guid))
60+
{
61+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid));
62+
var guid2 = Guid.NewGuid();
63+
using (new SessionIdLoggingContext(guid2))
64+
{
65+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid2));
66+
}
67+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid));
68+
}
69+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
70+
}
71+
72+
[Test]
73+
public async Task EnabledAsync()
74+
{
75+
var guid = Guid.NewGuid();
76+
using (new SessionIdLoggingContext(guid))
77+
{
78+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid));
79+
await Task.Delay(1).ConfigureAwait(false);
80+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid));
81+
82+
var guid2 = Guid.NewGuid();
83+
using (new SessionIdLoggingContext(guid2))
84+
{
85+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid2));
86+
await Task.Delay(1).ConfigureAwait(false);
87+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid2));
88+
}
89+
Assert.That(SessionIdLoggingContext.SessionId, Is.EqualTo(guid));
90+
}
91+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
92+
}
93+
94+
[Test]
95+
public void Disabled()
96+
{
97+
var guid = Guid.Empty;
98+
using (new SessionIdLoggingContext(guid))
99+
{
100+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
101+
using (new SessionIdLoggingContext(guid))
102+
{
103+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
104+
}
105+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
106+
}
107+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
108+
}
109+
110+
[Test]
111+
public async Task DisabledAsync()
112+
{
113+
var guid = Guid.Empty;
114+
using (new SessionIdLoggingContext(guid))
115+
{
116+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
117+
await Task.Delay(1).ConfigureAwait(false);
118+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
119+
120+
using (new SessionIdLoggingContext(guid))
121+
{
122+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
123+
await Task.Delay(1).ConfigureAwait(false);
124+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
125+
}
126+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
127+
}
128+
Assert.That(SessionIdLoggingContext.SessionId, Is.Null);
129+
}
130+
131+
[Test]
132+
public void XmlConfiguration()
133+
{
134+
const string xml = @"<?xml version='1.0' encoding='utf-8' ?>
135+
<hibernate-configuration xmlns='urn:nhibernate-configuration-2.2'>
136+
<session-factory name='NHibernate.Test'>
137+
<property name='track_session_id'>
138+
false
139+
</property>
140+
</session-factory>
141+
</hibernate-configuration>";
142+
143+
var cfgXml = new XmlDocument();
144+
cfgXml.LoadXml(xml);
145+
146+
var cfg = new Configuration();
147+
using (var xtr = new XmlTextReader(xml, XmlNodeType.Document, null))
148+
{
149+
cfg.Configure(xtr);
150+
Assert.That(PropertiesHelper.GetBoolean(Environment.TrackSessionId, cfg.Properties, true), Is.False);
151+
}
152+
}
153+
}
154+
}

src/NHibernate/Cfg/Environment.cs

+12
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,18 @@ public static string Version
258258
/// </remarks>
259259
public const string OracleUseNPrefixedTypesForUnicode = "oracle.use_n_prefixed_types_for_unicode";
260260

261+
/// <summary>
262+
/// <para>Set whether tracking the session id or not. When <see langword="true"/>, each session
263+
/// will have an unique <see cref="Guid"/> that can be retrieved by <see cref="ISessionImplementor.SessionId"/>,
264+
/// otherwise <see cref="ISessionImplementor.SessionId"/> will always be <see cref="Guid.Empty"/>. Session id
265+
/// is used for logging purpose that can be also retrieved in a static context by
266+
/// <see cref="NHibernate.Impl.SessionIdLoggingContext.SessionId"/>, where the current session id is stored,
267+
/// when tracking is enabled.</para>
268+
/// In case the current session id won't be used, it is recommended to disable it, in order to increase performance.
269+
/// <para>Default is <see langword="true"/>.</para>
270+
/// </summary>
271+
public const string TrackSessionId = "track_session_id";
272+
261273
private static readonly Dictionary<string, string> GlobalProperties;
262274

263275
private static IBytecodeProvider BytecodeProviderInstance;

src/NHibernate/Cfg/Settings.cs

+2
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ public Settings()
126126
public IsolationLevel IsolationLevel { get; internal set; }
127127

128128
public bool IsOuterJoinFetchEnabled { get; internal set; }
129+
130+
public bool TrackSessionId { get; internal set; }
129131

130132
/// <summary>
131133
/// Get the registry to provide Hql-Generators for known properties/methods.

src/NHibernate/Cfg/SettingsFactory.cs

+4
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ public Settings BuildSettings(IDictionary<string, string> properties)
303303

304304
// NHibernate-specific:
305305
settings.IsolationLevel = isolation;
306+
307+
bool trackSessionId = PropertiesHelper.GetBoolean(Environment.TrackSessionId, properties, true);
308+
log.Debug("Track session id: " + EnabledDisabled(trackSessionId));
309+
settings.TrackSessionId = trackSessionId;
306310

307311
return settings;
308312
}

src/NHibernate/Impl/AbstractSessionImpl.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public ITransactionContext TransactionContext
4040

4141
private static readonly IInternalLogger logger = LoggerProvider.LoggerFor(typeof(AbstractSessionImpl));
4242

43-
public Guid SessionId { get; } = Guid.NewGuid();
43+
public Guid SessionId { get; }
4444

4545
internal AbstractSessionImpl() { }
4646

@@ -50,6 +50,7 @@ protected internal AbstractSessionImpl(ISessionFactoryImplementor factory, ISess
5050
Timestamp = factory.Settings.CacheProvider.NextTimestamp();
5151
_flushMode = options.InitialSessionFlushMode;
5252
Interceptor = options.SessionInterceptor ?? EmptyInterceptor.Instance;
53+
SessionId = factory.Settings.TrackSessionId ? Guid.NewGuid() : Guid.Empty;
5354
}
5455

5556
#region ISessionImplementor Members

src/NHibernate/Impl/SessionIdLoggingContext.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ namespace NHibernate.Impl
55
{
66
public class SessionIdLoggingContext : IDisposable
77
{
8-
private static readonly AsyncLocal<Guid?> _currentSessionId = new AsyncLocal<Guid?>();
8+
private static readonly Lazy<AsyncLocal<Guid?>> _currentSessionId =
9+
new Lazy<AsyncLocal<Guid?>>(() => new AsyncLocal<Guid?>(), true);
910

1011
private readonly Guid? _oldSessonId;
12+
private readonly bool _tracking;
1113

1214
public SessionIdLoggingContext(Guid id)
1315
{
16+
_tracking = id != Guid.Empty;
17+
if (!_tracking)
18+
{
19+
return;
20+
}
1421
_oldSessonId = SessionId;
1522
SessionId = id;
1623
}
@@ -24,14 +31,18 @@ public SessionIdLoggingContext(Guid id)
2431
/// </summary>
2532
public static Guid? SessionId
2633
{
27-
get => _currentSessionId.Value;
28-
set => _currentSessionId.Value = value;
34+
get => _currentSessionId.IsValueCreated ? _currentSessionId.Value.Value : null;
35+
set => _currentSessionId.Value.Value = value;
2936
}
3037

3138
#region IDisposable Members
3239

3340
public void Dispose()
3441
{
42+
if (!_tracking)
43+
{
44+
return;
45+
}
3546
SessionId = _oldSessonId;
3647
}
3748

src/NHibernate/nhibernate-configuration.xsd

+13
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,19 @@
193193
</xs:documentation>
194194
</xs:annotation>
195195
</xs:enumeration>
196+
<xs:enumeration value="track_session_id">
197+
<xs:annotation>
198+
<xs:documentation>
199+
Set whether tracking the session id or not. When true, each session will have an unique Guid
200+
that can be retrieved by ISessionImplementor.SessionId, otherwise ISessionImplementor.SessionId will
201+
always be Guid.Empty. Session id is used for logging purpose that can be also retrieved in a static
202+
context by SessionIdLoggingContext.SessionId, where the current session id is stored, when tracking
203+
is enabled. In case the current session id won't be used, it is recommended to disable it, in order
204+
to increase performance.
205+
True by default.
206+
</xs:documentation>
207+
</xs:annotation>
208+
</xs:enumeration>
196209
</xs:restriction>
197210
</xs:simpleType>
198211
</xs:attribute>

0 commit comments

Comments
 (0)