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

FileStream optimizations #49975

Merged
merged 12 commits into from
Mar 23, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -306,15 +306,7 @@ private unsafe Task WriteAsyncInternalCore(ReadOnlyMemory<byte> source, Cancella
}

completionSource.ReleaseNativeResource();

if (errorCode == ERROR_HANDLE_EOF)
{
ThrowHelper.ThrowEndOfFileException();
}
else
{
throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
adamsitnik marked this conversation as resolved.
Show resolved Hide resolved
throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
else if (cancellationToken.CanBeCanceled) // ERROR_IO_PENDING
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,6 @@ internal static unsafe int WriteFileNative(SafeFileHandle handle, ReadOnlySpan<b
if (r == 0)
{
errorCode = GetLastWin32ErrorAndDisposeHandleIfInvalid(handle);

if (syncUsingOverlapped && errorCode == Interop.Errors.ERROR_HANDLE_EOF)
{
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile#synchronization-and-file-position :
// "If lpOverlapped is not NULL, then when a synchronous read operation reaches the end of a file,
// ReadFile returns FALSE and GetLastError returns ERROR_HANDLE_EOF"
return numBytesWritten;
}

return -1;
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1037,15 +1037,7 @@ private unsafe Task WriteAsyncInternalCore(ReadOnlyMemory<byte> source, Cancella
}

completionSource.ReleaseNativeResource();

if (errorCode == ERROR_HANDLE_EOF)
{
ThrowHelper.ThrowEndOfFileException();
}
else
{
throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
jozkee marked this conversation as resolved.
Show resolved Hide resolved
throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
else if (cancellationToken.CanBeCanceled) // ERROR_IO_PENDING
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal abstract class WindowsFileStreamStrategy : FileStreamStrategy

protected long _filePosition;
private long _appendStart; // When appending, prevent overwriting file.
private long _length = -1; // When the FileStream blocks the handle (_share <= FileShare.Read) keep file length in-memory, negative means that hasn't been fetched.
private long _length = -1; // When the handle blocks the file (_share <= FileShare.Read) keep file length in-memory, negative means that hasn't been fetched.
jozkee marked this conversation as resolved.
Show resolved Hide resolved

internal WindowsFileStreamStrategy(SafeFileHandle handle, FileAccess access, FileShare share)
{
Expand Down Expand Up @@ -75,13 +75,15 @@ internal WindowsFileStreamStrategy(string path, FileMode mode, FileAccess access

public sealed override bool CanWrite => !_fileHandle.IsClosed && (_access & FileAccess.Write) != 0;

// When the handle blocks the file we can keep file length in memory
jozkee marked this conversation as resolved.
Show resolved Hide resolved
// and avoid subsequent native calls which are expensive.
public unsafe sealed override long Length => _share > FileShare.Read ?
jozkee marked this conversation as resolved.
Show resolved Hide resolved
FileStreamHelpers.GetFileLength(_fileHandle, _path) :
_length < 0 ? _length = FileStreamHelpers.GetFileLength(_fileHandle, _path) : _length;

protected void UpdateLengthOnChangePosition()
{
// Do not update the cached length if the file can be written somewhere else
// Do not update the cached length if the file is not blocked
jozkee marked this conversation as resolved.
Show resolved Hide resolved
// or if the length hasn't been fetched.
if (_share > FileShare.Read || _length < 0)
{
Expand Down Expand Up @@ -112,8 +114,12 @@ internal sealed override SafeFileHandle SafeFileHandle
{
get
{
// Update the file offset in the handle before exposing it.
FileStreamHelpers.Seek(_fileHandle, _path, _filePosition, SeekOrigin.Begin);
if (CanSeek)
{
// Update the file offset before exposing it since it's possible that
// in memory position is out-of-sync with the actual file position.
FileStreamHelpers.Seek(_fileHandle, _path, _filePosition, SeekOrigin.Begin);
}
return _fileHandle;
}
}
Expand Down