dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.94k stars 4.64k forks source link

[help]NET 8 from Xamarin.Mac, there is a problem writing to NAS. #106448

Open DogFortune opened 4 weeks ago

DogFortune commented 4 weeks ago

If there is a different place to originate the issue, please let me know.

Description

NET 6, there was a problem with writing files when migrating from Xamarin.Mac to. NET 8 and am still having trouble with no improvement.

var InputBufferSize = 1 << 20;
var bytesWrote = 0L;
using (var srcFs = File.OpenRead(source.FullName))
using (var dstFs = File.OpenWrite(destination.FullName))
{
    var buffer = new byte[InputBufferSize];
    int bytesRead;
    while ((bytesRead = srcFs.Read(buffer, 0, InputBufferSize)) > 0)
    {
        dstFs.Write(buffer, 0, bytesRead);
        bytesWrote += bytesRead;
        progress?.Report(new CopyProgress
        {
            BytesProcessed = bytesWrote,
            BytesTransferred = bytesRead
        });
    }
}

This code works fine when built as a class library in Xamarin.Mac, but when the write destination is NAS, the write speed slows down and eventually the OS freezes. If the write destination is an SSD or HDD, the process is completed without problems.

We have also verified asynchronization and changing the buffer size, but could not resolve the issue. My knowledge is limited and I need help. I want to get out of this problem as soon as possible. I would appreciate comments on any additional information needed. We will gather and provide as much information as possible.

work environment

SMB Info

smbutil statshares -a

==================================================================================================
SHARE                         ATTRIBUTE TYPE                VALUE
==================================================================================================
Volume01                      
                              SERVER_NAME                   10.100.192.1
                              USER_ID                       502
                              SMB_NEGOTIATE                 SMBV_NEG_SMB1_ENABLED
                              SMB_NEGOTIATE                 SMBV_NEG_SMB2_ENABLED
                              SMB_NEGOTIATE                 SMBV_NEG_SMB3_ENABLED
                              SMB_VERSION                   SMB_2.002
                              SMB_ENCRYPT_ALGORITHMS        AES_128_CCM_ENABLED
                              SMB_ENCRYPT_ALGORITHMS        AES_128_GCM_ENABLED
                              SMB_ENCRYPT_ALGORITHMS        AES_256_CCM_ENABLED
                              SMB_ENCRYPT_ALGORITHMS        AES_256_GCM_ENABLED
                              SMB_CURR_ENCRYPT_ALGORITHM    OFF
                              SMB_SHARE_TYPE                DISK
                              SIGNING_SUPPORTED             TRUE
                              EXTENDED_SECURITY_SUPPORTED   TRUE
                              LARGE_FILE_SUPPORTED          TRUE
                              OS_X_SERVER                   TRUE
                              DFS_SUPPORTED                 TRUE

--------------------------------------------------------------------------------------------------

developer environment

Due to machine translation, some sentences may not be understood.

huoyaoyuan commented 4 weeks ago

We have also verified asynchronization and changing the buffer size, but could not resolve the issue.

Does srcFs.CopyTo{Async}(dstFs) make any change?

the write speed slows down and eventually the OS freezes.

It it freezing beyond the process? What about copying with other tools/programming language?

DogFortune commented 4 weeks ago

Does srcFs.CopyTo{Async}(dstFs) make any change?

I haven't tried it yet because progress needs to be reflected in the UI. Xamarin was able to write files without problems, so the process of copying in two streams was used as a basis for improvement. I'll give it a try. Thank you.

It it freezing beyond the process? What about copying with other tools/programming language?

We have not tried other programming languages. The tool was tested but no problems occurred. The following tools were tested. https://rapidcopy.jp/rapidcopy-en

DogFortune commented 3 weeks ago

Sorry. It is difficult to use the srcFs.CopyTo{Async}(dstFs) because we need to implement a IProgress.Report and a CancellationToken.

adamsitnik commented 3 weeks ago

but when the write destination is NAS, the write speed slows down and eventually the OS freezes. If the write destination is an SSD or HDD, the process is completed without problems

From the .NET perspective, we don't treat NAS vs local drives differently, we just call pwrite and pread sys calls and they ask OS to perform the job, which asks the right driver to do it.

Are you sure the NAS is not running out of disk space?

Xamarin was able to write files without problems

They only possible difference I see is Xamarin using different sys-calls: write and read. We used them until .NET 5. Could you please try to run a .NET 6 app with .NET 5 compat mode and see if there are any differences? It can be achieved by setting env var (it's ignored by .NET 7+).

set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1
DogFortune commented 3 weeks ago

They only possible difference I see is Xamarin using different sys-calls: write and read. We used them until .NET 5. Could you please try to run a .NET 6 app with .NET 5 compat mode and see if there are any differences? It can be achieved by setting env var (it's ignored by .NET 7+).

OK. Let's verify this once we get set up with .NET6. Thank you.

DogFortune commented 2 weeks ago

They only possible difference I see is Xamarin using different sys-calls: write and read. We used them until .NET 5. Could you please try to run a .NET 6 app with .NET 5 compat mode and see if there are any differences? It can be achieved by setting env var (it's ignored by .NET 7+).

set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1

@adamsitnik Sorry, I have tried applying environment variables, but it is difficult to determine if the application behavior has changed. Is there any way to verify that the environment variables are loaded correctly and that we have switched to .NET 5 compatibility mode ?

Using [appname].runtimeconfig.json.

{
  "runtimeOptions": {
    "tfm": "net6.0",
    "includedFrameworks": [
      {
        "name": "Microsoft.NETCore.App",
        "version": "6.0.33"
      },
      {
        "name": "Microsoft.macOS",
        "version": "**FromWorkload**"
      }
    ],
    "configProperties": {
      "System.IO.UseNet5CompatFileStream": true
    }
  }
}
DogFortune commented 1 week ago

Sorry for rushing your response. My clients are asking me to "hurry up and respond."

Is there any way to confirm that I have switched to .NET 5 compatibility mode?

DogFortune commented 1 week ago

I'm thinking of trying it this way, no problem?

// SetValue
AppContext.SetSwitch("System.IO.UseNet5CompatFileStream",  true);

// GetValue
AppContext.TryGetSwitch("System.IO.UseNet5CompatFileStream", out var mode);
huoyaoyuan commented 1 week ago

Is there any way to confirm that I have switched to .NET 5 compatibility mode?

I think you can check the result of AppContext.GetSwitch without setting manually.

DogFortune commented 1 day ago

I recently tried it in a customer's environment and found no difference in behavior with respect to .NET 5 compatibility mode. Only one interesting thing turned out to be true.

The file copy process succeeds when the terminal is equipped with an Intel CPU. If the device is equipped with Apple silicon, it will fail. Below are the specifications of the computer.

As you can see, the macOS versions are different, so at this time we have not been able to determine if the difference is due to differences in CPU or macOS. We plan to test the system at a later date using a Mac with an Intel CPU running macOS 12. Hopefully this test will reveal the cause of the problem.

That's all for the report. Thank you.