-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Update position before ReadAsync starts, but fix it after incomplete read #56531
Conversation
Tagging subscribers to this area: @dotnet/area-system-io Issue Details
|
@@ -99,6 +99,10 @@ public unsafe sealed override long Length | |||
} | |||
} | |||
|
|||
// in case of concurrent incomplete reads, there can be multiple threads trying to update the position | |||
// at the same time. That is why we are using Interlocked here. | |||
internal void OnIncompleteRead(int expectedBytesRead, int actualBytesRead) => Interlocked.Add(ref _filePosition, actualBytesRead - expectedBytesRead); |
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 I've used Interlocked
here as the new IncompleteReadCantSetPositionBeyondEndOfFile
test was simply failing without it. I know that we are never going to be 100% thread safe, but the alternative was to call Length
which would result in an extra sys-call.
_filePosition = Math.Min(Length, _filePosition - expectedBytesRead + actualBytesRead);
the test is failing on Windows 7 and 8, I am going to apply no merge until I fix it |
…dating file position before performing async write can lead to invalid cached length value
a296615
to
30b5768
Compare
e0a8bf4
to
c513ce5
Compare
Setting file position and length via I've disabled |
@stephentoub all tests are passing, PTAL |
@@ -286,6 +288,13 @@ internal static unsafe (SafeFileHandle.OverlappedValueTaskSource? vts, int error | |||
vts.Dispose(); | |||
throw; | |||
} | |||
finally | |||
{ | |||
if (errorCode != Interop.Errors.ERROR_IO_PENDING && errorCode != Interop.Errors.ERROR_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.
Nit: this function is initializing errorCode to '0' but then checking against 'ERROR_SUCCESS'. Style-wise, it'd be nice if they were consistent.
{ | ||
// Update Position... it could be anywhere. | ||
_filePosition = positionBefore; | ||
Interlocked.Exchange(ref _filePosition, positionBefore); | ||
} |
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 is precarious regardless of the interlocked, e.g. if someone did kick off concurrent operations, they could all fight to reset this to their starting position. It's not clear there's a "right" answer.
Did this PR effectively negate the breaking change listed here? dotnet/docs#23858 |
Yes and no. IIRC we wanted to update the position after the operations are completed, but then we realized that some users use My main goal with dotnet/docs#23858 was to give the users a clear message: stop relying on that, don't use |
No description provided.