Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server slowdown when copying files

I have a C# program which queries a database (server3) to determine the files a user is after, then copies those files from (server1) to (server2).

To simplify that further

  • C# application is executed on a desktop computer
  • Original files are on server1
  • Files are to be copied to server2
  • Server3 contains the database

When I run this program on my desktop, everything works fine except server1, which seems to almost grind to a holt after about 5 minutes, even though the copying process continues working fine even after 5 minutes. Any other application/user who try to connect to that server can't.

They just get a spinning cursor which only stops if I stop running the program on my desktop. For the first 5 minutes into the copying process, everything is fine for everyone. When going beyond the 5 minute range, the files continue to copy, but that's when others start experiencing connection problems to server1.

I have even tried using sleep as I assumed that the slow down was because of too much network activity and/or too much disk I/O activity on server1. sleep did nothing to help, the same problem continues. So I'm guessing the problem is happening for some other reason.

I am using code similar to this to copy the files

while (reader1.read(){
    // system.threading.thread.sleep(2000);
    system.io.file.copy(source, destination);
}

Why is this happening?

like image 482
oshirowanen Avatar asked Jul 12 '26 04:07

oshirowanen


1 Answers

According to this article, the main cause of the slowdown is the use of buffering by the file copy.

On Windows Vista or later, it's possible to avoid using buffering by specifying COPY_FILE_NO_BUFFERING to the CopyFileEx() Windows API function.

You can specify the P/Invoke as follows:

enum CopyProgressResult: uint
{
    PROGRESS_CONTINUE = 0,
    PROGRESS_CANCEL   = 1,
    PROGRESS_STOP     = 2,
    PROGRESS_QUIET    = 3
}

enum CopyProgressCallbackReason: uint
{
    CALLBACK_CHUNK_FINISHED = 0x00000000,
    CALLBACK_STREAM_SWITCH  = 0x00000001
}

delegate CopyProgressResult CopyProgressRoutine(
    long TotalFileSize,
    long TotalBytesTransferred,
    long StreamSize,
    long StreamBytesTransferred,
    uint dwStreamNumber,
    CopyProgressCallbackReason dwCallbackReason,
    IntPtr hSourceFile,
    IntPtr hDestinationFile,
    IntPtr lpData);

[Flags]
enum CopyFileFlags: uint
{
    COPY_FILE_FAIL_IF_EXISTS              = 0x00000001,
    COPY_FILE_RESTARTABLE                 = 0x00000002,
    COPY_FILE_OPEN_SOURCE_FOR_WRITE       = 0x00000004,
    COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008,
    COPY_FILE_COPY_SYMLINK                = 0x00000800, //NT 6.0+
    COPY_FILE_NO_BUFFERING                = 0x00001000
}

[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFileEx
(
    string lpExistingFileName,
    string lpNewFileName,
    CopyProgressRoutine lpProgressRoutine, 
    IntPtr lpData,
    ref Int32 pbCancel,
    CopyFileFlags dwCopyFlags
);

Then call it like this (substituting your own file names);

int cancel = 0;
CopyFileEx(@"C:\tmp\test.bin", @"F:\test.bin", null, IntPtr.Zero, ref cancel, CopyFileFlags.COPY_FILE_NO_BUFFERING);

It might be worth trying this and seeing if it helps.

like image 200
Matthew Watson Avatar answered Jul 14 '26 17:07

Matthew Watson