Compare commits

...

2 Commits

Author SHA1 Message Date
Aleks-Daniel Jakimenko
73d04103c4 Added missing “use sigtrap” 2015-08-19 10:28:32 +03:00
Aleks-Daniel Jakimenko
b58f83351d Stop leaving locks behind
If you want to leave the thing locked when it is suddenly stopped (that is,
interrupting the process will lead to bad consequences, and the admin should
get in and make sure that everything is ok), then use **0**. **0** (or other
falsie) means do nothing if it is suddenly interrupted and leave the lock
in place.

**1** means that your lock will be removed automatically if the whole thing
is interrupted in the middle of the process. ##CleanLock('yourlock')##
function will be called, which means that you can add your own cleanup
logic by wrapping this subroutine (which I did in Modlue:private-wiki.pl).
2015-08-19 06:56:21 +03:00
5 changed files with 44 additions and 14 deletions

View File

@@ -149,7 +149,7 @@ sub JoinerGetPasswordHash {
sub JoinerRequestLockOrError {
my ($name) = @_;
# 10 tries, 3 second wait, die on error
return RequestLockDir($name, 10, 3, 1);
return RequestLockDir($name, 0, 10, 3, 1);
}
sub JoinerGetEmailFile {

View File

@@ -99,7 +99,7 @@ sub GetPermanentAnchor {
ScriptLink(UrlEncode($resolved), $text, 'alias')) . ']';
} elsif ($PermanentAnchors{$id} ne $OpenPageName
# 10 tries, 3 second wait, die on error
and RequestLockDir('permanentanchors', 10, 3, 1)) {
and RequestLockDir('permanentanchors', 1, 10, 3, 1)) {
# Somebody may have added a permanent anchor in the mean time.
# Comparing $LastUpdate to the $IndexFile mtime does not work for
# subsecond changes and updates are rare, so just reread the file!
@@ -190,7 +190,7 @@ sub NewPermanentAnchorsSave {
sub DeletePermanentAnchors {
my $id = shift;
# 10 tries, 3 second wait, die on error
RequestLockDir('permanentanchors', 10, 3, 1);
RequestLockDir('permanentanchors', 1, 10, 3, 1);
foreach (keys %PermanentAnchors) {
if ($PermanentAnchors{$_} eq $id and !$PagePermanentAnchors{$_}) {
delete($PermanentAnchors{$_}) ;

View File

@@ -246,6 +246,25 @@ sub MergeRevisions { # merge change from file2 to file3 into file1
return $output;
}
*OldPrivateWikiCleanLock = \&CleanLock;
*CleanLock = \&NewPrivateWikiCleanLock;
sub NewPrivateWikiCleanLock {
my ($name) = @_;
if ($name eq 'diff') {
my $oldName = "$TempDir/old";
my $newName = "$TempDir/new";
unlink $oldName if -f $oldName;
unlink $newName if -f $newName;
} elsif ($name eq 'merge') {
my ($name1, $name2, $name3) = ("$TempDir/file1", "$TempDir/file2", "$TempDir/file3");
unlink $name1 if -f $name1;
unlink $name2 if -f $name2;
unlink $name3 if -f $name3;
}
OldPrivateWikiCleanLock(@_);
}
# Surge protection has to be unencrypted because in the context of this module
# it is a tool against people who have no password set (thus we have no key
# to do encryption).

View File

@@ -57,7 +57,7 @@ sub DoUpgrade {
'403 FORBIDDEN', 0,
$q->p(T('Did the previous upgrade end with an error? A lock was left behind.'))
. $q->p(ScriptLink('action=unlock', T('Unlock wiki'), 'unlock')))
unless RequestLockDir('main');
unless RequestLockDir('main', 0);
print GetHeader('', T('Upgrading Database')),
$q->start_div({-class=>'content upgrade'});

31
wiki.pl
View File

@@ -35,6 +35,7 @@ use utf8; # in case anybody ever addes UTF8 characters to the source
use CGI qw/-utf8/;
use CGI::Carp qw(fatalsToBrowser);
use File::Glob ':glob';
use sigtrap 'handler' => \&HandleSignals, 'normal-signals';
local $| = 1; # Do not buffer output (localized for mod_perl)
# Options:
@@ -728,7 +729,7 @@ sub PrintWikiToHTML {
and $Page{blocks} ne $blocks and $Page{flags} ne $flags) {
$Page{blocks} = $blocks;
$Page{flags} = $flags;
if ($is_locked or RequestLockDir('main')) { # not fatal!
if ($is_locked or RequestLockDir('main', 0)) { # not fatal!
SavePage();
ReleaseLock() unless $is_locked;
}
@@ -2883,7 +2884,8 @@ sub GetLockedPageFile {
}
sub RequestLockDir {
my ($name, $tries, $wait, $error, $retried) = @_;
my ($name, $autoclean, $tries, $wait, $error, $retried) = @_; # $retried is used for recursion
$autoclean //= 1;
$tries ||= 4;
$wait ||= 2;
CreateDir($TempDir);
@@ -2892,9 +2894,9 @@ sub RequestLockDir {
while (mkdir($lock, 0555) == 0) {
if ($n++ >= $tries) {
my $ts = (stat($lock))[9];
if ($Now - $ts > $LockExpiration and $LockExpires{$name} and not $retried) {
if ($Now - $ts > $LockExpiration and $LockExpires{$name} and not $retried) { # XXX should we remove this now?
ReleaseLockDir($name); # try to expire lock (no checking)
return 1 if RequestLockDir($name, undef, undef, undef, 1);
return 1 if RequestLockDir($name, $autoclean, undef, undef, undef, 1);
}
return 0 unless $error;
ReportError(Ts('Could not get %s lock', $name) . ": $!. ",
@@ -2907,10 +2909,19 @@ sub RequestLockDir {
}
sleep($wait);
}
$Locks{$name} = 1;
$Locks{$name} = $autoclean ? 2 : 1;
return 1;
}
sub HandleSignals {
CleanLock($_) foreach grep { $Locks{$_} == 2 } keys %Locks;
}
sub CleanLock {
my ($name) = @_;
ReleaseLockDir($name);
}
sub ReleaseLockDir {
my $name = shift; # We don't check whether we succeeded.
rmdir($LockDir . $name); # Before fixing, make sure we only call this
@@ -2918,11 +2929,11 @@ sub ReleaseLockDir {
}
sub RequestLockOrError {
return RequestLockDir('main', 10, 3, 1); # 10 tries, 3 second wait, die on error
return RequestLockDir('main', 0, 10, 3, 1); # 10 tries, 3 second wait, die on error
}
sub ReleaseLock {
ReleaseLockDir('main');
ReleaseLockDir('main', 0);
}
sub ForceReleaseLock {
@@ -2930,8 +2941,8 @@ sub ForceReleaseLock {
my $forced;
foreach my $name (bsd_glob $pattern) {
# First try to obtain lock (in case of normal edit lock)
$forced = 1 unless RequestLockDir($name, 5, 3, 0);
ReleaseLockDir($name); # Release the lock, even if we didn't get it.
$forced = 1 unless RequestLockDir($name, 0, 5, 3, 0);
LockCleanup($name); # Release the lock, even if we didn't get it.
}
return $forced;
}
@@ -3338,7 +3349,7 @@ sub RefreshIndex {
@IndexList = ();
%IndexHash = ();
# If file exists and cannot be changed, error!
my $locked = RequestLockDir('index', undef, undef, -f $IndexFile);
my $locked = RequestLockDir('index', 0, undef, undef, -f $IndexFile);
foreach (bsd_glob("$PageDir/*.pg"), bsd_glob("$PageDir/.*.pg")) {
next unless m|/.*/(.+)\.pg$|;
my $id = $1;