2015-04-22 22:39:53 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# LOCK MODULE
|
|
|
|
####################################################################################################################################
|
|
|
|
package BackRest::Lock;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
|
|
|
|
2015-06-14 00:25:49 +02:00
|
|
|
use Exporter qw(import);
|
2015-04-22 22:39:53 +02:00
|
|
|
use Fcntl qw(:DEFAULT :flock);
|
|
|
|
use File::Basename qw(dirname);
|
|
|
|
|
|
|
|
use lib dirname($0) . '/../lib';
|
|
|
|
use BackRest::Config;
|
2015-06-14 00:25:49 +02:00
|
|
|
use BackRest::Exception;
|
2015-04-22 22:39:53 +02:00
|
|
|
use BackRest::Utility;
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Exported Functions
|
|
|
|
####################################################################################################################################
|
|
|
|
our @EXPORT = qw(lockAcquire lockRelease);
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Global lock type and handle
|
|
|
|
####################################################################################################################################
|
|
|
|
my $strCurrentLockType;
|
|
|
|
my $strCurrentLockFile;
|
|
|
|
my $hCurrentLockHandle;
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# lockPathName
|
|
|
|
#
|
|
|
|
# Get the base path where the lock file will be stored.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub lockPathName
|
|
|
|
{
|
|
|
|
my $strRepoPath = shift;
|
|
|
|
|
|
|
|
return "${strRepoPath}/lock";
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# lockFileName
|
|
|
|
#
|
|
|
|
# Get the lock file name.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub lockFileName
|
|
|
|
{
|
|
|
|
my $strLockType = shift;
|
|
|
|
my $strStanza = shift;
|
|
|
|
my $strRepoPath = shift;
|
|
|
|
|
|
|
|
return lockPathName($strRepoPath) . "/${strStanza}-${strLockType}.lock";
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# lockAcquire
|
|
|
|
#
|
|
|
|
# Attempt to acquire the specified lock. If the lock is taken by another process return false, else take the lock and return true.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub lockAcquire
|
|
|
|
{
|
|
|
|
my $strLockType = shift;
|
2015-05-29 22:31:12 +02:00
|
|
|
my $bFailOnNoLock = shift;
|
2015-04-22 22:39:53 +02:00
|
|
|
|
|
|
|
# Cannot proceed if a lock is currently held
|
|
|
|
if (defined($strCurrentLockType))
|
|
|
|
{
|
|
|
|
confess &lock(ASSERT, "${strCurrentLockType} lock is already held");
|
|
|
|
}
|
|
|
|
|
2015-07-23 19:11:38 +02:00
|
|
|
# Create the lock path if it does not exist. Use 770 so that members of the group can run read-only processes.
|
2015-04-22 22:39:53 +02:00
|
|
|
if (! -e lockPathName(optionGet(OPTION_REPO_PATH)))
|
|
|
|
{
|
2015-07-23 19:11:38 +02:00
|
|
|
mkdir (lockPathName(optionGet(OPTION_REPO_PATH)), 0770)
|
2015-04-22 22:39:53 +02:00
|
|
|
or confess(ERROR, 'unable to create lock path ' . lockPathName(optionGet(OPTION_REPO_PATH)), ERROR_PATH_CREATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Attempt to open the lock file
|
|
|
|
$strCurrentLockFile = lockFileName($strLockType, optionGet(OPTION_STANZA), optionGet(OPTION_REPO_PATH));
|
|
|
|
|
2015-07-23 19:11:38 +02:00
|
|
|
sysopen($hCurrentLockHandle, $strCurrentLockFile, O_WRONLY | O_CREAT, 0660)
|
2015-05-29 22:31:12 +02:00
|
|
|
or confess &log(ERROR, "unable to open lock file ${strCurrentLockFile}", ERROR_FILE_OPEN);
|
2015-04-22 22:39:53 +02:00
|
|
|
|
|
|
|
# Attempt to lock the lock file
|
|
|
|
if (!flock($hCurrentLockHandle, LOCK_EX | LOCK_NB))
|
|
|
|
{
|
|
|
|
close($hCurrentLockHandle);
|
2015-05-29 22:31:12 +02:00
|
|
|
|
|
|
|
if (!defined($bFailOnNoLock) || $bFailOnNoLock)
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "unable to acquire ${strLockType} lock", ERROR_LOCK_ACQUIRE);
|
|
|
|
}
|
|
|
|
|
2015-04-22 22:39:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set current lock type so we know we have a lock
|
|
|
|
$strCurrentLockType = $strLockType;
|
|
|
|
|
|
|
|
# Lock was successful
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# lockRelease
|
|
|
|
####################################################################################################################################
|
|
|
|
sub lockRelease
|
|
|
|
{
|
|
|
|
my $strLockType = shift;
|
|
|
|
|
|
|
|
# Fail if there is no lock
|
|
|
|
if (!defined($strCurrentLockType))
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, 'no lock is currently held');
|
|
|
|
}
|
|
|
|
|
|
|
|
# # Fail if the lock being released is not the one held
|
|
|
|
# if ($strLockType ne $strCurrentLockType)
|
|
|
|
# {
|
|
|
|
# confess &log(ASSERT, "cannot remove lock ${strLockType} since ${strCurrentLockType} is currently held");
|
|
|
|
# }
|
|
|
|
|
|
|
|
# Remove the file
|
|
|
|
unlink($strCurrentLockFile);
|
|
|
|
close($hCurrentLockHandle);
|
|
|
|
|
|
|
|
# Undef lock variables
|
|
|
|
undef($strCurrentLockType);
|
|
|
|
undef($hCurrentLockHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|