-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Add datetime read span path for netcore #31044
Conversation
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you please remove line 5- line 9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, they were copied from original non-netcore file so perhaps some cleanup elsewhere might be a good idea.
@@ -18,6 +18,8 @@ | |||
</ItemGroup> | |||
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp'"> | |||
<Compile Include="System\Data\SqlClient\PoolBlockingPeriod.cs" /> | |||
<Compile Include="System\Data\SqlClient\SqlBuffer.NetCoreApp.cs" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to lowercase netcoreapp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we spliting the implementation into different files as netfx and netstandard dont use this implementation ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are using the lowercase netcoreapp
everywhere else in the repo when it is appearing as an extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are pretty inconsistent about using the .netcoreapp.cs suffix for implementation files that are conditionalized with '$(TargetGroup)' == 'netcoreapp'
. The pattern is mainly for test files, since those are more often shared with .NET Framework. Personally I wouldn't use the suffix in implementation files but I don't think it matters although hopefully it's consistent within a project.
Casing should be lower case.
@@ -1109,7 +1109,11 @@ internal void SetToDateTimeOffset(DateTimeOffset dateTimeOffset, byte scale) | |||
_isNull = false; | |||
} | |||
|
|||
#if netcoreapp | |||
private static void FillInTimeInfo(ref TimeInfo timeInfo, ReadOnlySpan<byte> timeBytes, int length, byte scale) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why cant we just keep the span version ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only the netcore build has a dependency on System.Memory which is required for span. Rather than force all netfx and netcore consumers to pull in that and possibly a full set of interdependent assemblies supporting it I talked with @karelz in gitter and he suggested making it netcore specific. If someone wants to make the decision to require span for all versions then everyone can use the span implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The netfx wont use this implementation. AFAIK the implementatation in the src folder is only built and compiled for netcoreapp which makes the if def redundant.
@danmosemsft am i missing something here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stephentoub thoughts about this pattern?
We try to avoid #if platform
in our implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm definitely missing something here. The conditions for inclusion of SqlBuffer and TdsStateParserObject in the project file are simply Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'"
You assert that netfx won't use this, how do you know this and where can I determine this? If this is the case then surely it still needs to build with build -allconfigurations
because, again in the original PR I referenced, it didn't and I was asked to change it to pass the CI.
If neither code level #define's or conditionally included *.netcoreapp.cs files are appropriate to separate out particular functionality just how should it be done? How should this change be made without forcing a dependency on System.Memory on all consumers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This source code is going to be compiled against netstandard, netcoreapp, uap and netfx, however for netfx this will be a partial facade assembly and none of the source files are included for netfx. We know this because IsPartialFacadeAssembly
is set to true when targeting netfx:
<IsPartialFacadeAssembly Condition="'$(TargetsNetFx)' == 'true'">true</IsPartialFacadeAssembly> |
And System.Memory is inbox in Uap and Netcoreapp so there shouldn't be a problem on adding a reference to it:
corefx/src/System.Memory/Directory.Build.props
Lines 9 to 10 in c26eb56
<IsNETCoreApp>true</IsNETCoreApp> | |
<IsUAP>true</IsUAP> |
System.Memory is already referenced in this project when TargetsWindows == true, so it won't hurt moving this to when IsPartialFacade != true and AnyOS != true
. For netstandard it doesn't hurt anything to add this dependency, as System.Data.SqlClient in netstandard is an OOB package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This source code is going to be compiled against netstandard, netcoreapp, uap and netfx, however for netfx this will be a partial facade assembly and none of the source files are included for netfx.
Agreed.
And System.Memory is inbox in Uap and Netcoreapp so there shouldn't be a problem on adding a reference to it
That is correct.
@@ -4540,9 +4540,15 @@ internal bool TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, T | |||
|
|||
private bool TryReadSqlDateTime(SqlBuffer value, byte tdsType, int length, byte scale, TdsParserStateObject stateObj) | |||
{ | |||
#if netcoreapp | |||
Span<byte> datetimeBuffer = length <= 10 ? stackalloc byte[length] : new byte[length]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just the span version ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
System.Memory is only included in specific builds.
} | ||
|
||
AssertValidState(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit extra line
Is more work needed on this to get it merged? |
@stephentoub @safern can you take a final look ? |
General spannification style questions. |
@safern can you please help push it forward? |
I'm waiting for this comment to be addressed: #31044 (comment) @ahsonkhan could you help with the span question? |
You do not need to add netcoreapp specific ifdefs here at all. The only change required is changing the existing internal APIs to take Span<byte> instead of arrays, and potentially remove the offset/length arguments (where possible). You should use Slice/AsSpan to enforce the bounds checks (and simplify some Debug.Asserts). See these commits as an example of what could be done to "spanify" the implementation: 9f6ace6 & 6ae0ffd(which will build successfully for all configurations). Feel free to use this as a starting point and remove offsets/lengths from the callers, however much is feasible.
Feel free to ask additional questions, and I will help as best I can :) |
public bool TryReadByteArray(Span<byte> buff, int len) | ||
{ | ||
int ignored; | ||
return TryReadByteArray(buff, len, out ignored); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, can be changed to:
return TryReadByteArray(buff, len, out _);
Or even:
return TryReadByteArray(buff.Slice(0, len), out _);
@Wraith2 do you plan to address the remaining feedback from @ahsonkhan? |
All addressed, it still needs signoff from @GrabYourPitchforks on the span security changes and @afsanehr to review. |
@Wraith2, since this is a performance improvement (fixing System.Data.SqlClient.TdsParser performance improvement #28270), do you have performance measurements showing the improvement? |
I did have on the original PR. The intent was to remove frequent byte[] allocations and it does that so heap allocs on reading datatime's now don't happen. Any cpu perf would be entirely accidental. Found them, on the references issue: https://github.com/dotnet/corefx/issues/28270#issuecomment-395999251 |
@GrabYourPitchforks @afsanehr can you please take a look so we can get this finished off. |
@afsanehr can you please merge the PR if there is nothing that needs further scrutiny? Thanks! |
Sure, waiting for @GrabYourPitchforks to approve the changes. |
Can anyone in the geographic locale of @GrabYourPitchforks organise a search party? |
/me puts his ears back and hisses as the search party enters his cave, interrupting his hibernation. |
@Wraith2 I am going to hold off merging this pr for now as I noticed some failures in ManualTests in SqlClient. One of them being SplitPacketTest. Could you try the following command to build the test and see if you see the same failure?
|
Yes, I can replicate those test failures. I've no way to debug them though since I can only run tests through the commandline, there's simply too much code to start trying to trace it all the way from the network layer that way. |
Any update? Is it still blocked on test failures? I see CI all green. |
_isNull = false; | ||
} | ||
|
||
internal void SetToTime(TimeSpan timeSpan, byte scale) | ||
internal void SetToDateTime2(ReadOnlySpan<byte> bytes, byte scale) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the 2
mean in this method name? It's not very descriptive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It means that it's using the data layout for an sql type SQLDATETIME2, which represents a datetime2 and I agree that it's a silly name but that's what it's called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh. Ok, thanks.
Still blocked on the manual tests. I've got to find a way to work out why a test is failing without being able to sensibly debug it and the network io being split into individual bytes. After that I will be attempting to juggle flaming chainsaws. |
The span translation of TryReadByteArray wasn't using handling offsets correctly which only surfaced when the manual tests fragmented the input stream so that full reads weren't possible. This is fixed, the standard and manual tests now pass. @afsanehr can you please review? |
{ | ||
Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset + totalRead, bytesToRead); | ||
var copyFrom = new ReadOnlySpan<byte>(_inBuff, _inBytesUsed, bytesToRead); | ||
var copyTo = buff.Slice(totalRead, bytesToRead); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: don't use var here since the right-hand side doesn't indicate the type explicitly.
@Wraith2 Thanks! I can also confirm the manual tests are passing now. Once the comment from @ahsonkhan is addressed we are good to merge this pr. 🎉 |
Done. |
Add datetime read span path for netcore Commit migrated from dotnet/corefx@10ccbc1
Second attempt at the PR with a clean branch and including all feedback from the original at corefx/30371
Locally I'm getting a problem with the allconfigurations build not finding mscorlib but I can't fathom why my changes would be responsible for that so I'm hoping CI doesn't have the same issue.
fixes https://github.com/dotnet/corefx/issues/28270
/cc @EgorBo @afsanehr @cod7alex