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

Perf | Reduce memory allocations in SerializeEncodingChar/WriteEncodingChar and some options boxing #785

Merged
merged 3 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -7384,6 +7384,7 @@ private Task WriteEncodingChar(string s, Encoding encoding, TdsParserStateObject

private byte[] SerializeEncodingChar(string s, int numChars, int offset, Encoding encoding)
{
#if NETFRAMEWORK || NETSTANDARD2_0
char[] charData;
johnnypham marked this conversation as resolved.
Show resolved Hide resolved
byte[] byteData = null;

Expand All @@ -7398,33 +7399,38 @@ private byte[] SerializeEncodingChar(string s, int numChars, int offset, Encodin
encoding.GetBytes(charData, 0, charData.Length, byteData, 0);

return byteData;
#else
return encoding.GetBytes(s, offset, numChars);
#endif
}

private Task WriteEncodingChar(string s, int numChars, int offset, Encoding encoding, TdsParserStateObject stateObj, bool canAccumulate = true)
{
char[] charData;
byte[] byteData;

// if hitting 7.0 server, encoding will be null in metadata for columns or return values since
// 7.0 has no support for multiple code pages in data - single code page support only
if (encoding == null)
encoding = _defaultEncoding;

charData = s.ToCharArray(offset, numChars);

// Optimization: if the entire string fits in the current buffer, then copy it directly
int bytesLeft = stateObj._outBuff.Length - stateObj._outBytesUsed;
if ((numChars <= bytesLeft) && (encoding.GetMaxByteCount(charData.Length) <= bytesLeft))
if ((numChars <= bytesLeft) && (encoding.GetMaxByteCount(numChars) <= bytesLeft))
{
int bytesWritten = encoding.GetBytes(charData, 0, charData.Length, stateObj._outBuff, stateObj._outBytesUsed);
int bytesWritten = encoding.GetBytes(s, offset, numChars, stateObj._outBuff, stateObj._outBytesUsed);
stateObj._outBytesUsed += bytesWritten;
return null;
}
else
{
byteData = encoding.GetBytes(charData, 0, numChars);
#if NETFRAMEWORK || NETSTANDARD2_0
var charData = s.ToCharArray(offset, numChars);
var byteData = encoding.GetBytes(charData, 0, numChars);
Debug.Assert(byteData != null, "no data from encoding");
return stateObj.WriteByteArray(byteData, byteData.Length, 0, canAccumulate);
#else
var byteData = encoding.GetBytes(s, offset, numChars);
cheenamalhotra marked this conversation as resolved.
Show resolved Hide resolved
Debug.Assert(byteData != null, "no data from encoding");
return stateObj.WriteByteArray(byteData, byteData.Length, 0, canAccumulate);
#endif
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,37 +469,37 @@ public bool IsReadOnly

public bool IsDifferentName
{
get => flags.HasFlag(_SqlMetadataFlags.IsDifferentName);
get => (flags & _SqlMetadataFlags.IsDifferentName) != 0;
set => Set(_SqlMetadataFlags.IsDifferentName, value);
}

public bool IsKey
{
get => flags.HasFlag(_SqlMetadataFlags.IsKey);
get => (flags & _SqlMetadataFlags.IsKey) != 0;
set => Set(_SqlMetadataFlags.IsKey, value);
}

public bool IsHidden
{
get => flags.HasFlag(_SqlMetadataFlags.IsHidden);
get => (flags & _SqlMetadataFlags.IsHidden) != 0;
set => Set(_SqlMetadataFlags.IsHidden, value);
}

public bool IsExpression
{
get => flags.HasFlag(_SqlMetadataFlags.IsExpression);
get => (flags & _SqlMetadataFlags.IsExpression) != 0;
set => Set(_SqlMetadataFlags.IsExpression, value);
}

public bool IsIdentity
{
get => flags.HasFlag(_SqlMetadataFlags.IsIdentity);
get => (flags & _SqlMetadataFlags.IsIdentity) != 0;
set => Set(_SqlMetadataFlags.IsIdentity, value);
}

public bool IsColumnSet
{
get => flags.HasFlag(_SqlMetadataFlags.IsColumnSet);
get => (flags & _SqlMetadataFlags.IsColumnSet) != 0;
set => Set(_SqlMetadataFlags.IsColumnSet, value);
}

Expand Down Expand Up @@ -746,13 +746,13 @@ internal SqlMetaDataPriv()

public bool IsNullable
{
get => flags.HasFlag(SqlMetaDataPrivFlags.IsNullable);
get => (flags & SqlMetaDataPrivFlags.IsNullable) != 0;
set => Set(SqlMetaDataPrivFlags.IsNullable, value);
}

public bool IsMultiValued
{
get => flags.HasFlag(SqlMetaDataPrivFlags.IsMultiValued);
get => (flags & SqlMetaDataPrivFlags.IsMultiValued) != 0;
set => Set(SqlMetaDataPrivFlags.IsMultiValued, value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1164,31 +1164,31 @@ private void SetSnapshottedState(SnapshottedStateFlags flag, bool value)

internal bool HasOpenResult
{
get => _snapshottedState.HasFlag(SnapshottedStateFlags.OpenResult);
get => (_snapshottedState & SnapshottedStateFlags.OpenResult) != 0;
set => SetSnapshottedState(SnapshottedStateFlags.OpenResult, value);
}

internal bool HasPendingData
{
get => _snapshottedState.HasFlag(SnapshottedStateFlags.PendingData);
get => (_snapshottedState & SnapshottedStateFlags.PendingData) != 0;
set => SetSnapshottedState(SnapshottedStateFlags.PendingData, value);
}

internal bool HasReceivedError
{
get => _snapshottedState.HasFlag(SnapshottedStateFlags.ErrorTokenReceived);
get => (_snapshottedState & SnapshottedStateFlags.ErrorTokenReceived) != 0;
set => SetSnapshottedState(SnapshottedStateFlags.ErrorTokenReceived, value);
}

internal bool HasReceivedAttention
{
get => _snapshottedState.HasFlag(SnapshottedStateFlags.AttentionReceived);
get => (_snapshottedState & SnapshottedStateFlags.AttentionReceived) != 0;
set => SetSnapshottedState(SnapshottedStateFlags.AttentionReceived, value);
}

internal bool HasReceivedColumnMetadata
{
get => _snapshottedState.HasFlag(SnapshottedStateFlags.ColMetaDataReceived);
get => (_snapshottedState & SnapshottedStateFlags.ColMetaDataReceived) != 0;
set => SetSnapshottedState(SnapshottedStateFlags.ColMetaDataReceived, value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8142,6 +8142,7 @@ private Task WriteEncodingChar(string s, Encoding encoding, TdsParserStateObject

private byte[] SerializeEncodingChar(string s, int numChars, int offset, Encoding encoding)
{
#if NETFRAMEWORK || NETSTANDARD2_0
char[] charData;
byte[] byteData = null;

Expand All @@ -8156,33 +8157,38 @@ private byte[] SerializeEncodingChar(string s, int numChars, int offset, Encodin
encoding.GetBytes(charData, 0, charData.Length, byteData, 0);

return byteData;
#else
return encoding.GetBytes(s, offset, numChars);
#endif
}

private Task WriteEncodingChar(string s, int numChars, int offset, Encoding encoding, TdsParserStateObject stateObj, bool canAccumulate = true)
{
char[] charData;
byte[] byteData;

// if hitting 7.0 server, encoding will be null in metadata for columns or return values since
// 7.0 has no support for multiple code pages in data - single code page support only
if (encoding == null)
encoding = _defaultEncoding;

charData = s.ToCharArray(offset, numChars);

// Optimization: if the entire string fits in the current buffer, then copy it directly
int bytesLeft = stateObj._outBuff.Length - stateObj._outBytesUsed;
if ((numChars <= bytesLeft) && (encoding.GetMaxByteCount(charData.Length) <= bytesLeft))
if ((numChars <= bytesLeft) && (encoding.GetMaxByteCount(numChars) <= bytesLeft))
{
int bytesWritten = encoding.GetBytes(charData, 0, charData.Length, stateObj._outBuff, stateObj._outBytesUsed);
int bytesWritten = encoding.GetBytes(s, offset, numChars, stateObj._outBuff, stateObj._outBytesUsed);
stateObj._outBytesUsed += bytesWritten;
return null;
}
else
{
byteData = encoding.GetBytes(charData, 0, numChars);
#if NETFRAMEWORK || NETSTANDARD2_0
var charData = s.ToCharArray(offset, numChars);
var byteData = encoding.GetBytes(charData, 0, numChars);
Debug.Assert(byteData != null, "no data from encoding");
return stateObj.WriteByteArray(byteData, byteData.Length, 0, canAccumulate);
#else
var byteData = encoding.GetBytes(s, offset, numChars);
Debug.Assert(byteData != null, "no data from encoding");
return stateObj.WriteByteArray(byteData, byteData.Length, 0, canAccumulate);
#endif
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -644,37 +644,37 @@ public bool IsReadOnly

public bool IsDifferentName
{
get => flags.HasFlag(_SqlMetadataFlags.IsDifferentName);
get => (flags & _SqlMetadataFlags.IsDifferentName) != 0;
set => Set(_SqlMetadataFlags.IsDifferentName, value);
}

public bool IsKey
{
get => flags.HasFlag(_SqlMetadataFlags.IsKey);
get => (flags & _SqlMetadataFlags.IsKey) != 0;
set => Set(_SqlMetadataFlags.IsKey, value);
}

public bool IsHidden
{
get => flags.HasFlag(_SqlMetadataFlags.IsHidden);
get => (flags & _SqlMetadataFlags.IsHidden) != 0;
set => Set(_SqlMetadataFlags.IsHidden, value);
}

public bool IsExpression
{
get => flags.HasFlag(_SqlMetadataFlags.IsExpression);
get => (flags & _SqlMetadataFlags.IsExpression) != 0;
set => Set(_SqlMetadataFlags.IsExpression, value);
}

public bool IsIdentity
{
get => flags.HasFlag(_SqlMetadataFlags.IsIdentity);
get => (flags & _SqlMetadataFlags.IsIdentity) != 0;
set => Set(_SqlMetadataFlags.IsIdentity, value);
}

public bool IsColumnSet
{
get => flags.HasFlag(_SqlMetadataFlags.IsColumnSet);
get => (flags & _SqlMetadataFlags.IsColumnSet) != 0;
set => Set(_SqlMetadataFlags.IsColumnSet, value);
}

Expand Down Expand Up @@ -1054,13 +1054,13 @@ internal SqlMetaDataPriv()

public bool IsNullable
{
get => flags.HasFlag(SqlMetaDataPrivFlags.IsNullable);
get => (flags & SqlMetaDataPrivFlags.IsNullable) != 0;
set => Set(SqlMetaDataPrivFlags.IsNullable, value);
}

public bool IsMultiValued
{
get => flags.HasFlag(SqlMetaDataPrivFlags.IsMultiValued);
get => (flags & SqlMetaDataPrivFlags.IsMultiValued) != 0;
set => Set(SqlMetaDataPrivFlags.IsMultiValued, value);
}

Expand Down