Skip to content
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

Merge to shared - TdsParserSessionPool #1595

Merged
merged 9 commits into from
Oct 5, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,9 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs">
<Link>Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\TdsParserSessionPool.cs">
<Link>Microsoft\Data\SqlClient\TdsParserSessionPool.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\TdsValueSetter.cs">
<Link>Microsoft\Data\SqlClient\TdsValueSetter.cs</Link>
</Compile>
Expand Down Expand Up @@ -643,7 +646,6 @@
<Compile Include="Microsoft\Data\SqlClient\TdsParser.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.RegisterEncoding.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserHelperClasses.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserSessionPool.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserStateObject.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserStateObjectManaged.cs" />
<Compile Include="Microsoft\Data\SqlTypes\SqlTypeWorkarounds.netcore.cs" />
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,9 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs">
<Link>Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\TdsParserSessionPool.cs">
<Link>Microsoft\Data\SqlClient\TdsParserSessionPool.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\TdsValueSetter.cs">
<Link>Microsoft\Data\SqlClient\TdsValueSetter.cs</Link>
</Compile>
Expand Down Expand Up @@ -653,7 +656,6 @@
<Compile Include="Microsoft\Data\SqlClient\SqlUtil.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserHelperClasses.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserSessionPool.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParserStateObject.cs" />
<Compile Include="Microsoft\Data\SqlTypes\SqlFileStream.cs" />
<Compile Include="Microsoft\Data\SqlTypes\SqlStreamChars.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ internal class TdsParserSessionPool
// NOTE: This is a very simplistic, lightweight pooler. It wasn't
// intended to handle huge number of items, just to keep track
// of the session objects to ensure that they're cleaned up in
// a timely manner, to avoid holding on to an unacceptible
// a timely manner, to avoid holding on to an unacceptable
// amount of server-side resources in the event that consumers
// let their data readers be GC'd, instead of explicitly
// closing or disposing of them

private const int MaxInactiveCount = 10; // pick something, preferably small...

private static int _objectTypeCount; // EventSource Counter
private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
private static int s_objectTypeCount; // EventSource Counter
private readonly int _objectID = System.Threading.Interlocked.Increment(ref s_objectTypeCount);

private readonly TdsParser _parser; // parser that owns us
private readonly List<TdsParserStateObject> _cache; // collection of all known sessions
Expand Down Expand Up @@ -89,23 +89,6 @@ internal void Deactivate()
}
}

// This is called from a ThreadAbort - ensure that it can be run from a CER Catch
internal void BestEffortCleanup()
{
for (int i = 0; i < _cache.Count; i++)
{
TdsParserStateObject session = _cache[i];
if (null != session)
{
var sessionHandle = session.Handle;
if (sessionHandle != null)
{
sessionHandle.Dispose();
}
}
}
}

internal void Dispose()
{
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParserSessionPool.Dispose|ADV> {0} disposing cachedCount={1}", ObjectID, _cachedCount);
Expand Down Expand Up @@ -140,7 +123,6 @@ internal void Dispose()
}
_cache.Clear();
_cachedCount = 0;

// Any active sessions will take care of themselves
// (It's too dangerous to dispose them, as this can cause AVs)
}
Expand Down Expand Up @@ -175,6 +157,7 @@ internal TdsParserStateObject GetSession(object owner)

session.Activate(owner);
}

SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParserSessionPool.GetSession|ADV> {0} using session {1}", ObjectID, session.ObjectID);
return session;
}
Expand All @@ -190,16 +173,19 @@ internal void PutSession(TdsParserStateObject session)
{
if (IsDisposed)
{
// We're diposed - just clean out the session
// We're disposed - just clean out the session
Debug.Assert(_cachedCount == 0, "SessionPool is disposed, but there are still sessions in the cache?");
session.Dispose();
}
else if ((okToReuse) && (_freeStateObjectCount < MaxInactiveCount))
{
// Session is good to re-use and our cache has space
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParserSessionPool.PutSession|ADV> {0} keeping session {1} cachedCount={2}", ObjectID, session.ObjectID, _cachedCount);
#if NETFRAMEWORK
Debug.Assert(!session._pendingData, "pending data on a pooled session?");

#else
Debug.Assert(!session.HasPendingData, "pending data on a pooled session?");
#endif
_freeStateObjects[_freeStateObjectCount] = session;
_freeStateObjectCount++;
}
Expand All @@ -218,23 +204,37 @@ internal void PutSession(TdsParserStateObject session)
}
}


internal int ActiveSessionsCount => _cachedCount - _freeStateObjectCount;

internal string TraceString()
{
return String.Format(/*IFormatProvider*/ null,
return string.Format(/*IFormatProvider*/ null,
"(ObjID={0}, free={1}, cached={2}, total={3})",
_objectID,
null == _freeStateObjects ? "(null)" : _freeStateObjectCount.ToString((IFormatProvider)null),
_cachedCount,
_cache.Count);
}

internal int ActiveSessionsCount
#if NETFRAMEWORK
// This is called from a ThreadAbort - ensure that it can be run from a CER Catch
internal void BestEffortCleanup()
{
get
for (int i = 0; i < _cache.Count; i++)
{
return _cachedCount - _freeStateObjectCount;
TdsParserStateObject session = _cache[i];
if (null != session)
{
SNIHandle sessionHandle = session.Handle;
if (sessionHandle != null)
{
sessionHandle.Dispose();
}
}
}
}
#endif
}
}

Expand Down