2

I am running a script which copies one folder from a specific location if it does not exist( or is not consistent). The problems appears when I run concurently the script 2+ times. As the first script is trying to copy the files, the second comes and tryes the same thing resulting in a mess. How could I avoid this situation? Something like system wide mutex.

I tryed a simple test with -w, I manually copied the folder and while the folder was copying I run the script:

use strict;
use warnings;

my $filename = 'd:\\folder_to_copy';
if (-w $filename) {
  print "i can write to the file\n";
} else {
  print "yikes, i can't write to the file!\n";
}

Of course this won't work, cuz I still have write acces to that folder. Any ideea of how could I check if the folder is being copied in Perl or usingbatch commands?

nwellnhof
  • 32,319
  • 7
  • 89
  • 113
John Doe
  • 1,058
  • 8
  • 30

4 Answers4

7

Sounds like a job for a lock file. There are myriads of CPAN modules that implement lock files, but most of them don't work on Windows. Here are a few that seem to support Windows according to CPAN Testers:

After having a quick view at the source code, the only module I can recommend is File::Flock::Tiny. The others seem racy.

nwellnhof
  • 32,319
  • 7
  • 89
  • 113
  • 1
    So in order to know that I am still copying in that folder, I would keep a specific file locked until I finish copying the whole folder and the check would be on that file? – John Doe Oct 13 '16 at 13:00
  • @JohnDoe Yes, you have to use a separate file as lock file. – nwellnhof Oct 13 '16 at 13:01
4

If you need a systemwide mutex, then one "trick" is to (ab)use a directory. The command mkdir is usually atomic and either works or doesn't (if the directory already exists).

Change your script as follows:

my $mutex_dir = '/tmp/my-mutex-dir';
if ( mkdir $mutex_dir ) {

    # run your copy-code here

    # when finished:
    rmdir $mutex_dir;
} else {
    print "another instance is already running.\n";
}

The only thing you need to make sure is that you're allowed to create a directory in /tmp (or wherever).

Note that I intentionally do NOT firstly test for the existence of $mutex_dir because between the if (not -d $mutex_dir) and the mkdir someone else could create the directory and the mkdir would fail anyway. So simply call mkdir. If it worked then you can do your stuff. Don't forget to remove the $mutex_dir after you're done.

That's also the downside of this approach: If your copy-code crashes and the script prematurely dies then the directory isn't deleted. Presumably the lock file mechanism suggested in nwellnhof's answer behaves better in that case and automatically unlocks the file.

Community
  • 1
  • 1
PerlDuck
  • 5,610
  • 3
  • 20
  • 39
  • Are there any cases when this might fail? Any special conditions? – John Doe Oct 13 '16 at 13:32
  • The whole thing depends on the atomicity of `mkdir`. Under Unix that operation is atomic. Under Windows I'm not perfectly sure and Google stopped being helpful here. I found both statements. _If_ `mkdir` is atomic under Windows, then I don't know of a case where this approach would fail (except for missing permissions). – PerlDuck Oct 13 '16 at 14:04
3

As the first script is trying to copy the files, the second comes and tries the same thing resulting in a mess

A simplest approach would be to create a file which will contain 1 if another instance of script is running. Then you can add a conditional based on that.

{local $/; open my $fh, "<", 'flag' or die $!; $data = <$fh>};
die "another instance of script is running" if $data == 1;

Another approach would be to set an environment variable within the script and check it in BEGIN block.

Chankey Pathak
  • 21,187
  • 12
  • 85
  • 133
1

You can use Windows-Mutex or Windows-Semaphore Objects of the package http://search.cpan.org/~cjm/Win32-IPC-1.11/

use Win32::Mutex;
use Digest::MD5 qw (md5_hex);
my $mutex = Win32::Mutex->new(0, md5_hex $filename);
if ($mutex) {
     do_your_job();
     $mutex->release
} else {
     #fail...
}
Georg Mavridis
  • 2,312
  • 1
  • 15
  • 23
  • This is also an interesting approach, but I'd like to stick with the modules which came by default. – John Doe Oct 19 '16 at 08:31