Skip to content

Commit bee5e0d

Browse files
authored
Perf: Add cached SqlReferenceCollection find delegate and context objects (#380)
1 parent 7912581 commit bee5e0d

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -567,17 +567,6 @@ internal SqlDataReader FindLiveReader(SqlCommand command)
567567
return reader;
568568
}
569569

570-
internal SqlCommand FindLiveCommand(TdsParserStateObject stateObj)
571-
{
572-
SqlCommand command = null;
573-
SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection;
574-
if (null != referenceCollection)
575-
{
576-
command = referenceCollection.FindLiveCommand(stateObj);
577-
}
578-
return command;
579-
}
580-
581570
abstract protected byte[] GetDTCAddress();
582571

583572
static private byte[] GetTransactionCookie(Transaction transaction, byte[] whereAbouts)

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlReferenceCollection.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,38 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Diagnostics;
7+
using System.Threading;
68
using Microsoft.Data.ProviderBase;
79

810
namespace Microsoft.Data.SqlClient
911
{
1012
sealed internal class SqlReferenceCollection : DbReferenceCollection
1113
{
14+
private sealed class FindLiveReaderContext
15+
{
16+
public readonly Func<SqlDataReader, bool> Func;
17+
18+
private SqlCommand _command;
19+
20+
public FindLiveReaderContext() => Func = Predicate;
21+
22+
public void Setup(SqlCommand command) => _command = command;
23+
24+
public void Clear() => _command = null;
25+
26+
private bool Predicate(SqlDataReader reader) => (!reader.IsClosed) && (_command == reader.Command);
27+
}
28+
1229
internal const int DataReaderTag = 1;
1330
internal const int CommandTag = 2;
1431
internal const int BulkCopyTag = 3;
1532

16-
override public void Add(object value, int tag)
33+
private readonly static Func<SqlDataReader, bool> s_hasOpenReaderFunc = HasOpenReaderPredicate;
34+
private static FindLiveReaderContext s_cachedFindLiveReaderContext;
35+
36+
public override void Add(object value, int tag)
1737
{
1838
Debug.Assert(DataReaderTag == tag || CommandTag == tag || BulkCopyTag == tag, "unexpected tag?");
1939
Debug.Assert(DataReaderTag != tag || value is SqlDataReader, "tag doesn't match object type: SqlDataReader");
@@ -30,25 +50,24 @@ internal void Deactivate()
3050

3151
internal SqlDataReader FindLiveReader(SqlCommand command)
3252
{
33-
if (command == null)
53+
if (command is null)
3454
{
3555
// if null == command, will find first live datareader
36-
return FindItem<SqlDataReader>(DataReaderTag, (dataReader) => (!dataReader.IsClosed));
56+
return FindItem(DataReaderTag, s_hasOpenReaderFunc);
3757
}
3858
else
3959
{
4060
// else will find live datareader associated with the command
41-
return FindItem<SqlDataReader>(DataReaderTag, (dataReader) => ((!dataReader.IsClosed) && (command == dataReader.Command)));
61+
FindLiveReaderContext context = Interlocked.Exchange(ref s_cachedFindLiveReaderContext, null) ?? new FindLiveReaderContext();
62+
context.Setup(command);
63+
SqlDataReader retval = FindItem(DataReaderTag, context.Func);
64+
context.Clear();
65+
Interlocked.CompareExchange(ref s_cachedFindLiveReaderContext, context, null);
66+
return retval;
4267
}
4368
}
4469

45-
// Finds a SqlCommand associated with the given StateObject
46-
internal SqlCommand FindLiveCommand(TdsParserStateObject stateObj)
47-
{
48-
return FindItem<SqlCommand>(CommandTag, (command) => (command.StateObject == stateObj));
49-
}
50-
51-
override protected void NotifyItem(int message, int tag, object value)
70+
protected override void NotifyItem(int message, int tag, object value)
5271
{
5372
Debug.Assert(0 == message, "unexpected message?");
5473
Debug.Assert(DataReaderTag == tag || CommandTag == tag || BulkCopyTag == tag, "unexpected tag?");
@@ -74,11 +93,13 @@ override protected void NotifyItem(int message, int tag, object value)
7493
}
7594
}
7695

77-
override public void Remove(object value)
96+
public override void Remove(object value)
7897
{
7998
Debug.Assert(value is SqlDataReader || value is SqlCommand || value is SqlBulkCopy, "SqlReferenceCollection.Remove expected a SqlDataReader or SqlCommand or SqlBulkCopy");
8099

81100
base.RemoveItem(value);
82101
}
102+
103+
private static bool HasOpenReaderPredicate(SqlDataReader reader) => !reader.IsClosed;
83104
}
84105
}

0 commit comments

Comments
 (0)