-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Conversation
Test Innerloop Windows_NT Debug Build and Test |
bool lockTaken = false; | ||
try | ||
{ | ||
Monitor.Enter(s_dllLock, ref lockTaken); |
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 code is using:
bool lockTaken = false;
try
{
Monitor.Enter(s_dllLock, ref lockTaken);
... // protected code
}
finally
{
if (lockTaken) Monitor.Exit(s_dllLock);
}
That's exactly what lock
does, so it could just be:
lock (s_dllLock)
{
... // protected code
}
if (s_userInstanceDLLHandle != IntPtr.Zero) | ||
{ | ||
} | ||
else |
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 if (s_userInstanceDLLHandle == IntPtr.Zero)
rather than having an empty if block?
{ | ||
SNINativeMethodWrapper.SNI_Error sniError; | ||
SNINativeMethodWrapper.SNIGetLastError(out sniError); | ||
throw CreateLocalDBException(errorMessage: SR.GetString("LocalDB_FailedGetDLLHandle"), sniError: (int)sniError.sniError); |
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'd be great to move to an SR approach that the rest of the repo uses. Is there a plan to do so?
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 is no such formal plan to do so. I will move to SR in the LocalDB files
@@ -48,45 +48,7 @@ internal static void ReleaseDLLHandles() | |||
private static IntPtr s_userInstanceDLLHandle = IntPtr.Zero; | |||
|
|||
private static object s_dllLock = new object(); |
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: readonly... I personally like to see readonly whenever possible, but in particular on lock objects, as if they're accidentally changed the results can be quite bad and hard to track down.
/// <param name="packet">SNI packet</param> | ||
public void PacketReset(SNIHandle handle, bool write, SNIPacket packet) | ||
public void PacketReset(SNIPacket packet) | ||
{ | ||
packet.Reset(); | ||
} |
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.
Is this method still needed, or could the callers just do packet.Reset()
instead of proxy.PacketReset(packet)
?
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.
Looking at the calls to SNIPacket, I think the original idea was to have all operations to SNI internals like SNIPacket and SNIHandle to go through the SNIProxy. I wanted to leave it that way.
@corivera do you have any preferences 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.
Just calling packet.Reset() in place of this method call seems fine. There's no complex logic in this method that merits keeping it.
uint error = TdsEnums.SNI_SUCCESS; | ||
|
||
try { } | ||
finally |
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: there aren't thread aborts in coreclr. You could get rid of the try { } finally.
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 aren't thread aborts in coreclr.
Is this one of the things which were removed and can be added in future or Thread Aborts have been replaced with something else which removes the need for empty try{} finally{ //Dosomething} pattern?
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's no plan for thread aborts to come back.
cc: @jkotas
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 want to leave these try {} finally{..}
blocks as is.
I understand that the reason for which this coding pattern was followed didn't exist, but the pattern means that the code in finally must execute.
I don't see any significant advantage of removing this pattern.
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 have a tracking issue to remove all try{} code. so it would be better to fix this from now.
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.
@tarekgh Can you provide the issue number?
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.
Thank you. Updated the PR
_pMarsPhysicalConObj.ReleasePacket(temp); | ||
} | ||
} | ||
Debug.Assert(IntPtr.Zero == temp, "unexpected syncReadPacket without corresponding SNIPacketRelease"); |
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 confused by this assert. The code just above it has code that checks whether temp is not zero, so why do we expect it to be zero 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.
I moved this code from TdsParser.cs
I don't know exactly what the intention of the original author was, but it seems like the Assert was in place to hint that temp
should not be empty after the finally block has executed. If it was non-empty, then a packet release would have happened and everything would be alright. If it was not empty then a Debug Assert would catch the problem.
{ | ||
sealed internal partial class TdsParser | ||
{ | ||
private static bool s_fSSPILoaded = false; // bool to indicate whether library has been loaded |
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.
Technically this should be volatile.
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.
Good point.
|
||
using MSS = Microsoft.SqlServer.Server; | ||
|
||
namespace System.Data.SqlClient | ||
{ | ||
|
||
struct SNIErrorDetails |
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: internal
// The TdsParser Object controls reading/writing to the netlib, parsing the tds, | ||
// and surfacing objects to the user. | ||
sealed internal class TdsParser | ||
sealed internal partial class TdsParser |
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: internal sealed
rather than sealed internal
// The TdsParser Object controls reading/writing to the netlib, parsing the tds, | ||
// and surfacing objects to the user. | ||
sealed internal class TdsParser | ||
sealed internal partial class TdsParser | ||
{ | ||
static TdsParser() | ||
{ | ||
// For CoreCLR, we need to register the ANSI Code Page encoding provider before attempting to get an Encoding from a CodePage | ||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); |
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.
@tarekgh, is this still necessary in .NET Core 2.0?
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 think registering the encoding provider should be the app decision and not the library decision. having the library registering the provider means any app using the library will pay the cost of the encoding even if the app not using the non-Unicode encodings.
@stephentoub encoding handling didn't change in Net core 2.0. the only change we did is we have made the console support non-Unicode encodings but this is limited to the console only.
In reply to: 103917083 [](ancestors = 103917083)
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.
@saurabh500 just want to make sure you have seen the comments here regarding using the encoding provider.
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.
@tarekgh SqlClient needs to provide the encoding related abstractions to the consumers of Sql client based on the exchange with SqlServer.
I don't think it makes sense for SqlClient to expect consumers to set the encoding provider.
Am I missing something here? Regardless if this needs to be addresses I will open another issue for this item.
Let me know if my understanding is incorrect.
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 am fine to track this as separate issue but I am still seeing the clinet consuming the library can decide about the encoding. if you have a client using Unicode only DBs why you want them pay for the encoding cost? this is similar to the networking libraries which is up to the consumer of the library to decide about the encoding but not forcing every app consume the library to pay for the encoding even if they are not using it or need it.
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.
Opened an issue #16842
@@ -80,7 +85,7 @@ private static Task CompletedTask | |||
|
|||
internal Encoding _defaultEncoding = null; // for sql character data | |||
|
|||
private static EncryptionOptions s_sniSupportedEncryptionOption = SNILoadHandle.SingletonInstance.Options; | |||
private static EncryptionOptions s_sniSupportedEncryptionOption = TdsParserStateObjectFactory.Singleton.EncryptionOptions;// SNILoadHandle.SingletonInstance.Options; |
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 comment mean?
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.
Will Remove
{ | ||
sessionHandle.Dispose(); | ||
} | ||
session.DisposeHandle(); |
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: Could just be:
_cache[i]?.DisposeHandle();
@@ -89,11 +85,7 @@ internal void BestEffortCleanup() | |||
TdsParserStateObject session = _cache[i]; |
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.
GitHub won't let me comment on it, but the comment above says "This is called from a ThreadAbort - ensure that it can be run from a CER catch"... thread aborts don't exist in coreclr.
@@ -64,9 +52,12 @@ sealed internal class TdsParserStateObject | |||
internal int _outBytesUsed = TdsEnums.HEADER_LEN; // number of bytes used in internal write buffer - | |||
// - initialize past header | |||
// In buffer variables | |||
private byte[] _inBuff; // internal read buffer - initialize on login | |||
protected byte[] _inBuff; // internal read buffer - initialize on login |
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: comment indentation looks off
#endif // MANAGED_SNI | ||
private object _writePacketLockObject = new object(); // Used to synchronize access to _writePacketCache and _pendingWritePackets | ||
|
||
protected object _writePacketLockObject = new object(); // Used to synchronize access to _writePacketCache and _pendingWritePackets |
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.
readonly?
@@ -195,7 +175,7 @@ sealed internal class TdsParserStateObject | |||
internal SqlErrorCollection _preAttentionWarnings; | |||
|
|||
volatile private TaskCompletionSource<object> _writeCompletionSource = null; | |||
volatile private int _asyncWriteCount = 0; | |||
volatile protected int _asyncWriteCount = 0; |
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: style-wise, the visibility should come first, e.g. protected volatile
instead of volatile protected
|
||
public static readonly TdsParserStateObjectFactory Singleton = new TdsParserStateObjectFactory(); | ||
|
||
public EncryptionOptions EncryptionOptions { |
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: brace style
private SNIHandle _sessionHandle = null; // the SNI handle we're to work on | ||
private SNIPacket _sniPacket = null; // Will have to re-vamp this for MARS | ||
internal SNIPacket _sniAsyncAttnPacket = null; // Packet to use to send Attn | ||
private Dictionary<SNIPacket, SNIPacket> _pendingWritePackets = new Dictionary<SNIPacket, SNIPacket>(); // Stores write packets that have been sent to SNI, but have not yet finished writing (i.e. we are waiting for SNI's callback) |
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.
readonly?
internal SNIPacket _sniAsyncAttnPacket = null; // Packet to use to send Attn | ||
private Dictionary<SNIPacket, SNIPacket> _pendingWritePackets = new Dictionary<SNIPacket, SNIPacket>(); // Stores write packets that have been sent to SNI, but have not yet finished writing (i.e. we are waiting for SNI's callback) | ||
|
||
protected WritePacketCache _writePacketCache = new WritePacketCache(); // Store write packets that are ready to be re-used |
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.
readonly?
if (asyncAttnPacket != null) | ||
{ | ||
asyncAttnPacket.Dispose(); | ||
} |
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:
packetHandle?.Dispose();
asyncAttnPacket?.Dispose();
if (null != sessionHandle || null != packetHandle) | ||
{ | ||
try { } | ||
finally |
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: same try/finally thread abort comment as earlier
|
||
internal override void DisposePacketCache() | ||
{ | ||
if (_writePacketCache != null) |
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.
In what situation will this be null?
internal override object ReadAsync(out uint error, ref object handle) | ||
{ | ||
SNIPacket packet = null; | ||
error = SNIProxy.Singleton.ReadAsync((SNIHandle)handle, ref packet); |
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.
Should ReadAsync take the packet via out rather than ref?
if (asyncAttnPacket != null) | ||
{ | ||
asyncAttnPacket.Dispose(); | ||
} |
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.
Same nit as earlier
|
||
internal override void DisposePacketCache() | ||
{ | ||
if (_writePacketCache != null) |
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.
Same question as earlier
if (sessionHandle != null) | ||
{ | ||
sessionHandle.Dispose(); | ||
} |
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:
Handle?.Dispose();
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 think I can get rid of DisposeHandle() This is called by BestEffortCleanUp from the TdsParserSessionPool.cs which is not called by any caller.
The BestEffortCleanUp existed in NetFx for Thread Aborts.
try | ||
{ | ||
Monitor.Enter(s_dllLock, ref lockTaken); | ||
lock (s_dllLock) { |
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.
You should do an auto-format pass on the changed files (for spacing, tabs, etc; this curly brace).
|
||
namespace System.Data.SqlClient | ||
{ | ||
internal sealed class TdsParserStateObjectFactory |
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.
Should the filename for this class be TdsParserStateObjectFactory.Windows.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.
Will do.
{ | ||
get | ||
{ | ||
return useManagedSni ? SNILoadHandle.SingletonInstance.Status : SNI.SNILoadHandle.SingletonInstance.Status; |
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.
Should the SNI.SNILoadHandle come first here?
{ | ||
private SNIHandle _sessionHandle = null; // the SNI handle we're to work on | ||
|
||
private SNIPacket _sniPacket = null; // Will have to re-vamp this for MARS |
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.
Do we still need this comment at the end of this line? Not sure what it's referring to.
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 comment with this field declaration. Looks like a sort of TODO for MARS.
This has propagated since the time the SqlClient code was ported to CoreFx and has been in the framework code as well.
I don't think this is going to be changed or revamped.
if (s_userInstanceDLLHandle == IntPtr.Zero) | ||
{ | ||
|
||
lock (s_dllLock) { |
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.
Curly brace on new line
|
||
namespace System.Data.SqlClient | ||
{ | ||
sealed internal partial class TdsParser |
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.
sealed comes after internal.
{ | ||
lock (_writePacketLockObject) | ||
{ | ||
try { } |
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.
Do we still need this empty try-finally?
|
||
if (null != sessionHandle || null != packetHandle) | ||
{ | ||
try { } |
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.
Empty try-finally
{ | ||
lock (_writePacketLockObject) | ||
{ | ||
try { } |
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.
Empty try-finally
|
||
WaitForSSLHandShakeToComplete(ref error); | ||
|
||
// create a new packet encryption changes the internal packet size | ||
try { } // EmptyTry/Finally to avoid FXCop violation |
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.
Empty try-finally
@@ -2443,23 +2300,19 @@ internal void ReadSni(TaskCompletionSource<object> completion) | |||
ChangeNetworkPacketTimeout(msecsRemaining, Timeout.Infinite); | |||
} | |||
|
|||
SNIHandle handle = null; | |||
object handle = null; | |||
|
|||
try { } |
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.
empty try-finally
IntPtr temp = IntPtr.Zero; | ||
uint error = TdsEnums.SNI_SUCCESS; | ||
|
||
|
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.
Extra line 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.
Approved pending my other comments
Refactor code for Read async Cleaning up
objects in the respective sub classes
Formatting changes Changes for Code Review comments
Additional CR comments
ab3b131
to
8a9c7ac
Compare
Make Native and Managed SNI coexist on Windows and make Native SNI the default implementation of the networking interface. Commit migrated from dotnet/corefx@bb05af4
The changes include refactoring in SqlClient to build Managed SNI on Windows along with Native SNI.
This is the first step towards addressing #16129
The changes involve refactoring TdsParserStateObject into sub classes which contain the SNI specific logic and encapsulate the usage of SNIPacket and SNIHandle
There were changes done to extract parts of TdsParser into platform specific files so that the right behavior can be invoked.
The current behavior on Windows is under the flag TdsParserNativeObjectFactory.useManagedSni.
I will be adding changes to incorporate an AppContext flag to control the SNI behavior.
I ran the Functional and Manual tests to validate these changes.
cc @corivera @YoungGah @geleems