Skip to content

Commit 8466783

Browse files
committed
Replace Context class with IServerCapabilities interface.
This avoids an unnecessary small allocation per ServerSession. Signed-off-by: Bradley Grainger <[email protected]>
1 parent b19f1ee commit 8466783

File tree

8 files changed

+64
-73
lines changed

8 files changed

+64
-73
lines changed

src/MySqlConnector/Core/ConcatenatedCommandPayloadCreator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDict
1717

1818
// ConcatenatedCommandPayloadCreator is only used by MySqlBatch, and MySqlBatchCommand doesn't expose attributes,
1919
// so just write an empty attribute set if the server needs it.
20-
if (commandListPosition.CommandAt(commandListPosition.CommandIndex).Connection!.Session.Context.SupportsQueryAttributes)
20+
if (commandListPosition.CommandAt(commandListPosition.CommandIndex).Connection!.Session.SupportsQueryAttributes)
2121
{
2222
// attribute count
2323
writer.WriteLengthEncodedInteger(0);

src/MySqlConnector/Core/Context.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace MySqlConnector.Core;
2+
3+
internal interface IServerCapabilities
4+
{
5+
bool SupportsDeprecateEof { get; }
6+
bool SupportsSessionTrack { get; }
7+
}

src/MySqlConnector/Core/ResultSet.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
3838
var firstByte = payload.HeaderByte;
3939
if (firstByte == OkPayload.Signature)
4040
{
41-
var ok = OkPayload.Create(payload.Span, Session.Context);
41+
var ok = OkPayload.Create(payload.Span, Session);
4242

4343
// if we've read a result set header then this is a SELECT statement, so we shouldn't overwrite RecordsAffected
4444
// (which should be -1 for SELECT) unless the server reports a non-zero count
@@ -109,7 +109,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
109109
}
110110
else
111111
{
112-
var columnCountPacket = ColumnCountPayload.Create(payload.Span, Session.Context.SupportsCachedPreparedMetadata);
112+
var columnCountPacket = ColumnCountPayload.Create(payload.Span, Session.SupportsCachedPreparedMetadata);
113113
var columnCount = columnCountPacket.ColumnCount;
114114
if (!columnCountPacket.MetadataFollows)
115115
{
@@ -132,7 +132,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
132132
m_columnDefinitions = m_columnDefinitionPayloadCache.AsMemory(0, columnCount);
133133

134134
// if the server supports metadata caching but has re-sent it, something has changed since last prepare/execution and we need to update the columns
135-
var preparedColumns = Session.Context.SupportsCachedPreparedMetadata ? DataReader.LastUsedPreparedStatement?.Columns : null;
135+
var preparedColumns = Session.SupportsCachedPreparedMetadata ? DataReader.LastUsedPreparedStatement?.Columns : null;
136136

137137
for (var column = 0; column < columnCount; column++)
138138
{
@@ -156,7 +156,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
156156
}
157157
}
158158

159-
if (!Session.Context.SupportsDeprecateEof)
159+
if (!Session.SupportsDeprecateEof)
160160
{
161161
payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
162162
_ = EofPayload.Create(payload.Span);
@@ -252,13 +252,13 @@ public async Task<bool> ReadAsync(IOBehavior ioBehavior, CancellationToken cance
252252

253253
if (payload.HeaderByte == EofPayload.Signature)
254254
{
255-
if (Session.Context.SupportsDeprecateEof && OkPayload.IsOk(payload.Span, Session.Context))
255+
if (Session.SupportsDeprecateEof && OkPayload.IsOk(payload.Span, Session))
256256
{
257-
var ok = OkPayload.Create(payload.Span, Session.Context);
257+
var ok = OkPayload.Create(payload.Span, Session);
258258
BufferState = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData;
259259
return null;
260260
}
261-
if (!Session.Context.SupportsDeprecateEof && EofPayload.IsEof(payload))
261+
if (!Session.SupportsDeprecateEof && EofPayload.IsEof(payload))
262262
{
263263
var eof = EofPayload.Create(payload.Span);
264264
BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData;

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace MySqlConnector.Core;
2323

2424
#pragma warning disable CA1001 // Types that own disposable fields should be disposable
2525

26-
internal sealed partial class ServerSession
26+
internal sealed partial class ServerSession : IServerCapabilities
2727
{
2828
public ServerSession(ILogger logger)
2929
: this(logger, null, 0, Interlocked.Increment(ref s_lastId))
@@ -44,7 +44,6 @@ public ServerSession(ILogger logger, ConnectionPool? pool, int poolGeneration, i
4444
m_activityTags = [];
4545
DataReader = new();
4646
Log.CreatedNewSession(m_logger, Id);
47-
Context = new Context(default);
4847
}
4948

5049
public string Id { get; }
@@ -60,13 +59,14 @@ public ServerSession(ILogger logger, ConnectionPool? pool, int poolGeneration, i
6059
public long LastLeasedTimestamp { get; set; }
6160
public long LastReturnedTimestamp { get; private set; }
6261
public string? DatabaseOverride { get; set; }
63-
6462
public string HostName { get; private set; }
6563
public IPEndPoint? IPEndPoint => m_tcpClient?.Client.RemoteEndPoint as IPEndPoint;
6664
public string? UserID { get; private set; }
6765
public WeakReference<MySqlConnection>? OwningConnection { get; set; }
68-
public Context Context { get; private set; }
69-
66+
public bool SupportsDeprecateEof { get; private set; }
67+
public bool SupportsCachedPreparedMetadata { get; private set; }
68+
public bool SupportsQueryAttributes { get; private set; }
69+
public bool SupportsSessionTrack { get; private set; }
7070
public bool ProcAccessDenied { get; set; }
7171
public ICollection<KeyValuePair<string, object?>> ActivityTags => m_activityTags;
7272
public MySqlDataReader DataReader { get; set; }
@@ -241,7 +241,7 @@ public async Task PrepareAsync(IMySqlCommand command, IOBehavior ioBehavior, Can
241241
ColumnDefinitionPayload.Initialize(ref parameters[i], new(columnsAndParameters, columnsAndParametersSize, payloadLength));
242242
columnsAndParametersSize += payloadLength;
243243
}
244-
if (!Context.SupportsDeprecateEof)
244+
if (!SupportsDeprecateEof)
245245
{
246246
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
247247
EofPayload.Create(payload.Span);
@@ -261,7 +261,7 @@ public async Task PrepareAsync(IMySqlCommand command, IOBehavior ioBehavior, Can
261261
ColumnDefinitionPayload.Initialize(ref columns[i], new(columnsAndParameters, columnsAndParametersSize, payloadLength));
262262
columnsAndParametersSize += payloadLength;
263263
}
264-
if (!Context.SupportsDeprecateEof)
264+
if (!SupportsDeprecateEof)
265265
{
266266
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
267267
EofPayload.Create(payload.Span);
@@ -315,12 +315,12 @@ public void FinishQuerying()
315315
// In order to handle this case, we issue a dummy query that will consume the pending cancellation.
316316
// See https://bugs.mysql.com/bug.php?id=45679
317317
Log.SendingSleepToClearPendingCancellation(m_logger, Id);
318-
var payload = Context.SupportsQueryAttributes ? s_sleepWithAttributesPayload : s_sleepNoAttributesPayload;
318+
var payload = SupportsQueryAttributes ? s_sleepWithAttributesPayload : s_sleepNoAttributesPayload;
319319
#pragma warning disable CA2012 // Safe because method completes synchronously
320320
SendAsync(payload, IOBehavior.Synchronous, CancellationToken.None).GetAwaiter().GetResult();
321321
payload = ReceiveReplyAsync(IOBehavior.Synchronous, CancellationToken.None).GetAwaiter().GetResult();
322322
#pragma warning restore CA2012
323-
OkPayload.Verify(payload.Span, Context);
323+
OkPayload.Verify(payload.Span, this);
324324
}
325325

326326
lock (m_lock)
@@ -455,7 +455,6 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
455455

456456
ServerVersion = new(initialHandshake.ServerVersion);
457457
ConnectionId = initialHandshake.ConnectionId;
458-
Context = new Context(initialHandshake.ProtocolCapabilities);
459458
AuthPluginData = initialHandshake.AuthPluginData;
460459
m_useCompression = cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) != 0;
461460
CancellationTimeout = cs.CancellationTimeout;
@@ -470,11 +469,15 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
470469
}
471470

472471
m_supportsConnectionAttributes = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.ConnectionAttributes) != 0;
472+
SupportsDeprecateEof = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.DeprecateEof) != 0;
473+
SupportsCachedPreparedMetadata = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.MariaDbCacheMetadata) != 0;
474+
SupportsQueryAttributes = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.QueryAttributes) != 0;
475+
SupportsSessionTrack = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.SessionTrack) != 0;
473476
var serverSupportsSsl = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Ssl) != 0;
474477
m_characterSet = ServerVersion.Version >= ServerVersions.SupportsUtf8Mb4 ? CharacterSet.Utf8Mb4GeneralCaseInsensitive : CharacterSet.Utf8Mb3GeneralCaseInsensitive;
475478
m_setNamesPayload = ServerVersion.Version >= ServerVersions.SupportsUtf8Mb4 ?
476-
(Context.SupportsQueryAttributes ? s_setNamesUtf8mb4WithAttributesPayload : s_setNamesUtf8mb4NoAttributesPayload) :
477-
(Context.SupportsQueryAttributes ? s_setNamesUtf8WithAttributesPayload : s_setNamesUtf8NoAttributesPayload);
479+
(SupportsQueryAttributes ? s_setNamesUtf8mb4WithAttributesPayload : s_setNamesUtf8mb4NoAttributesPayload) :
480+
(SupportsQueryAttributes ? s_setNamesUtf8WithAttributesPayload : s_setNamesUtf8NoAttributesPayload);
478481

479482
// disable pipelining for RDS MySQL 5.7 (assuming Aurora); otherwise take it from the connection string or default to true
480483
if (!cs.Pipelining.HasValue && ServerVersion.Version.Major == 5 && ServerVersion.Version.Minor == 7 && HostName.EndsWith(".rds.amazonaws.com", StringComparison.OrdinalIgnoreCase))
@@ -502,7 +505,7 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
502505
}
503506
}
504507

505-
Log.SessionMadeConnection(m_logger, Id, ServerVersion.OriginalString, ConnectionId, m_useCompression, m_supportsConnectionAttributes, Context.SupportsDeprecateEof, Context.SupportsCachedPreparedMetadata, serverSupportsSsl, Context.SupportsSessionTrack, m_supportsPipelining, Context.SupportsQueryAttributes);
508+
Log.SessionMadeConnection(m_logger, Id, ServerVersion.OriginalString, ConnectionId, m_useCompression, m_supportsConnectionAttributes, SupportsDeprecateEof, SupportsCachedPreparedMetadata, serverSupportsSsl, SupportsSessionTrack, m_supportsPipelining, SupportsQueryAttributes);
506509

507510
if (cs.SslMode != MySqlSslMode.None && (cs.SslMode != MySqlSslMode.Preferred || serverSupportsSsl))
508511
{
@@ -529,7 +532,7 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
529532
payload = await SwitchAuthenticationAsync(cs, password, payload, ioBehavior, cancellationToken).ConfigureAwait(false);
530533
}
531534

532-
var ok = OkPayload.Create(payload.Span, Context);
535+
var ok = OkPayload.Create(payload.Span, this);
533536
var statusInfo = ok.StatusInfo;
534537

535538
if (m_useCompression)
@@ -540,7 +543,7 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
540543
// set 'collation_connection' to the server default
541544
await SendAsync(m_setNamesPayload, ioBehavior, cancellationToken).ConfigureAwait(false);
542545
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
543-
OkPayload.Verify(payload.Span, Context);
546+
OkPayload.Verify(payload.Span, this);
544547
}
545548

546549
if (ShouldGetRealServerDetails(cs))
@@ -591,18 +594,18 @@ public async Task<bool> TryResetConnectionAsync(ConnectionSettings cs, MySqlConn
591594

592595
// read two OK replies
593596
payload = await ReceiveReplyAsync(1, ioBehavior, cancellationToken).ConfigureAwait(false);
594-
OkPayload.Verify(payload.Span, Context);
597+
OkPayload.Verify(payload.Span, this);
595598

596599
payload = await ReceiveReplyAsync(1, ioBehavior, cancellationToken).ConfigureAwait(false);
597-
OkPayload.Verify(payload.Span, Context);
600+
OkPayload.Verify(payload.Span, this);
598601

599602
return true;
600603
}
601604

602605
Log.SendingResetConnectionRequest(m_logger, Id, ServerVersion.OriginalString);
603606
await SendAsync(ResetConnectionPayload.Instance, ioBehavior, cancellationToken).ConfigureAwait(false);
604607
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
605-
OkPayload.Verify(payload.Span, Context);
608+
OkPayload.Verify(payload.Span, this);
606609
}
607610
else
608611
{
@@ -626,13 +629,13 @@ public async Task<bool> TryResetConnectionAsync(ConnectionSettings cs, MySqlConn
626629
Log.OptimisticReauthenticationFailed(m_logger, Id);
627630
payload = await SwitchAuthenticationAsync(cs, password, payload, ioBehavior, cancellationToken).ConfigureAwait(false);
628631
}
629-
OkPayload.Verify(payload.Span, Context);
632+
OkPayload.Verify(payload.Span, this);
630633
}
631634

632635
// set 'collation_connection' to the server default
633636
await SendAsync(m_setNamesPayload, ioBehavior, cancellationToken).ConfigureAwait(false);
634637
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
635-
OkPayload.Verify(payload.Span, Context);
638+
OkPayload.Verify(payload.Span, this);
636639

637640
return true;
638641
}
@@ -691,7 +694,7 @@ private async Task<PayloadData> SwitchAuthenticationAsync(ConnectionSettings cs,
691694
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
692695

693696
// OK payload can be sent immediately (e.g., if password is empty) bypassing even the fast authentication path
694-
if (OkPayload.IsOk(payload.Span, Context))
697+
if (OkPayload.IsOk(payload.Span, this))
695698
return payload;
696699

697700
var cachingSha2ServerResponsePayload = CachingSha2ServerResponsePayload.Create(payload.Span);
@@ -831,7 +834,7 @@ public async ValueTask<bool> TryPingAsync(bool logInfo, IOBehavior ioBehavior, C
831834
Log.PingingServer(m_logger, Id);
832835
await SendAsync(PingPayload.Instance, ioBehavior, cancellationToken).ConfigureAwait(false);
833836
var payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
834-
OkPayload.Verify(payload.Span, Context);
837+
OkPayload.Verify(payload.Span, this);
835838
Log.SuccessfullyPingedServer(m_logger, logInfo ? LogLevel.Information : LogLevel.Trace, Id);
836839
return true;
837840
}
@@ -1639,7 +1642,7 @@ private async Task GetRealServerDetailsAsync(IOBehavior ioBehavior, Cancellation
16391642
Log.DetectedProxy(m_logger, Id);
16401643
try
16411644
{
1642-
var payload = Context.SupportsQueryAttributes ? s_selectConnectionIdVersionWithAttributesPayload : s_selectConnectionIdVersionNoAttributesPayload;
1645+
var payload = SupportsQueryAttributes ? s_selectConnectionIdVersionWithAttributesPayload : s_selectConnectionIdVersionNoAttributesPayload;
16431646
await SendAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);
16441647

16451648
// column count: 2
@@ -1649,7 +1652,7 @@ private async Task GetRealServerDetailsAsync(IOBehavior ioBehavior, Cancellation
16491652
_ = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
16501653
_ = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
16511654

1652-
if (!Context.SupportsDeprecateEof)
1655+
if (!SupportsDeprecateEof)
16531656
{
16541657
payload = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
16551658
_ = EofPayload.Create(payload.Span);
@@ -1669,8 +1672,8 @@ static void ReadRow(ReadOnlySpan<byte> span, out int? connectionId, out ServerVe
16691672

16701673
// OK/EOF payload
16711674
payload = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
1672-
if (OkPayload.IsOk(payload.Span, Context))
1673-
OkPayload.Verify(payload.Span, Context);
1675+
if (OkPayload.IsOk(payload.Span, this))
1676+
OkPayload.Verify(payload.Span, this);
16741677
else
16751678
EofPayload.Create(payload.Span);
16761679

src/MySqlConnector/Core/SingleCommandPayloadCreator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDict
2424
Log.PreparingCommandPayload(command.Logger, command.Connection!.Session.Id, command.CommandText!);
2525

2626
writer.Write((byte) CommandKind.Query);
27-
var supportsQueryAttributes = command.Connection!.Session.Context.SupportsQueryAttributes;
27+
var supportsQueryAttributes = command.Connection!.Session.SupportsQueryAttributes;
2828
if (supportsQueryAttributes)
2929
{
3030
// attribute count
@@ -83,7 +83,7 @@ private static void WritePreparedStatement(IMySqlCommand command, PreparedStatem
8383
Log.PreparingCommandPayloadWithId(command.Logger, command.Connection!.Session.Id, preparedStatement.StatementId, command.CommandText!);
8484

8585
var attributes = command.RawAttributes;
86-
var supportsQueryAttributes = command.Connection!.Session.Context.SupportsQueryAttributes;
86+
var supportsQueryAttributes = command.Connection!.Session.SupportsQueryAttributes;
8787
writer.Write(preparedStatement.StatementId);
8888

8989
// NOTE: documentation is not updated yet, but due to bugs in MySQL Server 8.0.23-8.0.25, the PARAMETER_COUNT_AVAILABLE (0x08)

0 commit comments

Comments
 (0)