-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[Breaking change] FileStream does not synchronize file offset with OS anymore #50860
Comments
Tagging subscribers to this area: @carlossanlop Issue DetailsBefore .NET 6, A blog post from Windows Performance Team from 2008 calls it an anachronism:
In order to improve the performance of async reads and writes and solve the following issues:
[DllImport("kernel32.dll")]
private static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, uint dwMoveMethod);
byte[] bytes = new byte[10_000];
string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true))
{
await fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position);
if (SetFilePointerEx(fs.SafeFileHandle, 0, out long currentOffset, 1 /* get current offset */))
{
Console.WriteLine(currentOffset);
}
} Pre-change behavior:
Post-change behavior:
It works in the other direction as well: if the user obtains filehandle and performs a syscall that moves the file offset, the offset returned by To enable the .NET 5 behavior, users can specify an {
"configProperties": {
"System.IO.UseNet5CompatFileStream": true
}
}
set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1 @dotnet/compat @stephentoub @jozkee @carlossanlop @jeffhandley FWIW I've ensured that this change is not breaking ASP.NET (dotnet/aspnetcore#31441), WinForms (dotnet/winforms#4756) and the SDK (dotnet/sdk#16684)
|
@adamsitnik since both #16354 and #25905 got fixed, is there anything else we should address before we close this issue? Since this is a breaking change that needs to be documented, I opened this issue in dotnet/docs: dotnet/docs#23857 |
The current code doesn't actually shows that the Position is not being synchronized with the OS because you are accessing the We should expose the handle before writing: using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true))
{
+ SafeFileHandle handle = fs.SafeFileHandle;
await fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position);
+ if (SetFilePointerEx(handle, 0, out long currentOffset, 1 /* get current offset */))
- if (SetFilePointerEx(fs.SafeFileHandle, 0, out long currentOffset, 1 /* get current offset */))
{
Console.WriteLine(currentOffset);
Console.WriteLine(fs.Position);
}
} |
@jozkee great point! It just shows how hard it is to hit the breaking change scenario ;) |
Closing (dotnet/docs#24060) |
Before .NET 6,
FileStream
was using expensive syscall calledSetFilePointer
to synchronize it's private offset with Windows OS.A blog post from Windows Performance Team from 2008 calls it an anachronism:
In order to improve the performance of async reads and writes and solve the following issues:
FileStream
is no longer doing that (#49975) and the offset is just kept in memory. This has allowed for up to two times faster ReadAsync and up to five time faster WriteAsync! See #49975 for full details.FileStream.Position
always returns the current offset, but if the user obtains the file handle via call toFileStream.SafeFileHandle
and asks the OS for the current file offset of the given handle by performing a syscall, the value will return0
.Pre-change behavior:
Post-change behavior:
It works in the other direction as well: if the user obtains filehandle and performs a syscall that moves the file offset, the offset returned by
FileStream.Position
won't be changed.To enable the .NET 5 behavior, users can specify an
AppContext
switch or an environment variable:@dotnet/compat @stephentoub @jozkee @carlossanlop @jeffhandley
FWIW I've ensured that this change is not breaking ASP.NET (dotnet/aspnetcore#31441), WinForms (dotnet/winforms#4756) and the SDK (dotnet/sdk#16684)
The text was updated successfully, but these errors were encountered: