0

My environment is: Windows, MsSQL and PHP 5.4.

My scenario: I'm doing a small shell script that creates a full backup from my wanted database to a temp folder and then moves it to a new location.

The backup goes fine and the file is created to my temp folder. Then I rename it to the 2nd folder and sometimes it goes ok, sometimes it cannot find the source file.

Of course at this point I know that I could skip the temporary location alltogether, but the actual problem with not finding the file bothers me. Why is it so random and might it also affect other file functions I've written before this one... Also i need to be able to control how and when the files move to the destination.

The base code is simple as it should be (although this is a simplified version of my actual code, since I doubt anyone would be interested in my error handling/logging conditions):

$query = "use test; backup database test to disk '//server01/temp/backups/file.bak', COMPRESSION;";

if($SQLClass->query($query)) { 

    $source="////server01//temp//backups//file.bak";
    $destination="////server02//storage//backups//file.bak";

    if(!rename($source , $destination)) {
        //handleError is just a class function of mine that logs and outputs errors.
        $this->handleError("Moving {$source} to {$destination} failed.");
    }
}
else {
    die('backup failed');
}

What I have tried is:

  • I added a file_exists before it and it can't find the source file either, when rename can't.
  • As the file can't be found, copy() and unlink() will not work either
  • Tried clearstatcache()
  • Tried sleep(10) after the sql backup completes

None of these didn't help at all. I and google seem to be out of ideas on what to do or try next. Of course I could some shell_execing, but that wouldn't remove my worries about my earlier products.

I only noticed this problem when I tried to run the command multiple times in a row. Is there some sort of cache for filenames that clearstatcache() won't touch ? It seems to be related to some sort of ghost file phenomena, where php is late to refresh the file system contents or such.

I would appreciate any ideas on what to try next and if you read this far thank you :).

MacRedrum
  • 1
  • 1
  • Have you checked the privileges for the file in the server for your current user? – Javad Mar 07 '14 at 14:59
  • Have you tried putting the rename call in a loop that sleeps for a bit and retries 3-5 times before calling `handleError`? Sometimes this helps with file operations that occasionally time out. – Dan Bechard Mar 07 '14 at 15:08
  • Yes I have and the rights are good. That was one my early thoughts also, but the result was that the file just can't be found sometimes. I haven't tried looping it, but I did try sleeping for 10 seconds. I'll try that and see if it works, maybe calling the same function twice resets something. – MacRedrum Mar 07 '14 at 15:09
  • Try my solution below, hopefully it works – Javad Mar 07 '14 at 15:10

3 Answers3

0

You may try calling system's copy command. I had once problem like yours (on Linux box) when i had to copy files between two NFS shares. It just failed from time to time with no visible reasons. After i switched to cp (analog of Windows copy) problem has gone.

Surely it is not perfect, but it worked for me.

Andrew
  • 1,756
  • 3
  • 18
  • 31
  • This might be the only solution. I've always been a little wary of php's file functions. But since I really never had anything to go wrong with them before, I've used them. – MacRedrum Mar 07 '14 at 15:14
  • 1
    I wrote a small file_move($source, $dest) function. Even that seems to be too fast sometimes, but at least it is much more stable than the php file functions so far. – MacRedrum Mar 07 '14 at 16:35
0

Try

$source = "\\server01\temp\backups\file.bak";
$destination = "\\server02\storage\backups\file.bak";
$content = file_get_content($source);
file_put_contents($destination, $content);
Javad
  • 4,339
  • 3
  • 21
  • 36
  • Just tried this and it randomly gets the same sort of random error with: "failed to open stream: No such file or directory". Just like with rename(), this too works sometimes. – MacRedrum Mar 07 '14 at 15:28
  • Do you know if this issue occurs on reading from `$source` or on saving into `$destination`? – Javad Mar 07 '14 at 15:35
  • Yes the source. Full error: "ERROR: file_get_contents(//server01/temp/backups/file.bak): failed to open stream: No such file or directory". Also I have some functions making sure that the destination folder exists ( and of course after the 1st run it always does too ) – MacRedrum Mar 07 '14 at 15:41
  • Oh I think it's because of windows which you need to change */* to \ for windows server. I edited my solution code, too – Javad Mar 07 '14 at 16:02
  • Nah it's not the path,as it does find it every now and then :). – MacRedrum Mar 07 '14 at 16:28
  • Oops, you're right. How about using a rand number or something at the end of the source to get rid of cache (e.g. `$source.time();`) I know this works for URL paths but not sure if it may works for this type of path – Javad Mar 07 '14 at 16:31
0

It might be cache-related, or the mysql process has not yet released the file. mysql will dump the file into another temp file, first and finally moves it to your temp folder. While the file is beeing moved, it might be inaccessible by other processes.

First I would try to glob() all the files inside temp dir, when the error appears. Maybe you notice, its still not finished.

Also have you tried to implemente something like 10 retry iterations, with some delay?

$notMoved = 0;
while($notMoved < 10){
    $source="////server01//temp//backups//file.bak";
    $destination="////server02//storage//backups//file.bak";

    if(!rename($source , $destination)) {
        //handleError is just a class function of mine that logs and outputs errors.
        if ($notMoved++ < 10){
           sleep(20);
        } else {
           $this->handleError("Moving {$source} to {$destination} failed.");
           break;
        }
    }else{
       break;
    }
}

To bypass the issue:

  • Don't dump and move
  • Move then dump :-)

(ofc. your backup store would be one behind then)

    $source="////server01//temp//backups//file.bak";
    $destination="////server02//storage//backups//file.bak";

    if(!rename($source , $destination)) {
        //handleError is just a class function of mine that logs and outputs errors.
        $this->handleError("Moving {$source} to {$destination} failed.");
    }

$query = "use test; backup database test to disk '//server01/temp/backups/file.bak', COMPRESSION;";

if($SQLClass->query($query)) { 
  //done :-)
}
else {
    die('backup failed');
}
dognose
  • 20,360
  • 9
  • 61
  • 107
  • Ok i tried a 10 try loop, with 5 seconds sleep in each. The results are suspicious. Sometimes it takes a few loops to move the file. Sometimes it goes through all 10 iterations. Putting something like this to production is scary :). – MacRedrum Mar 07 '14 at 16:13
  • @MacRedrum How big is the dump? Depending on the Serverload and size it may take some to many seconds until the temp file is copied there. And if the first moving is async, your second move attempt will encounter problems. – dognose Mar 07 '14 at 16:17
  • Around 8 megs at the moment. It takes a fraction of a second to make it. According to SQL server, it processes the backup around 50mb/s. That's why it's funny why it doesn't find it even after 50 seconds of sleep. – MacRedrum Mar 07 '14 at 16:26