aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>2007-02-21 08:55:28 +0000
committerjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>2007-02-21 08:55:28 +0000
commitc60477228c6b4d5e00c7bdb3b895e9f30d00ea97 (patch)
tree03b0c2eceadcc57a732eca6a054dff92fbd4eb56
parent24b83435061f94c6e203ed1b31b114b53ab8b8a3 (diff)
downloadikiwiki-c60477228c6b4d5e00c7bdb3b895e9f30d00ea97.tar
ikiwiki-c60477228c6b4d5e00c7bdb3b895e9f30d00ea97.tar.gz
* Since the CGI had to drop the wiki lock to avoid deadlocking the
commit hook, it was possible for one CGI to race another one and "win" the commit of both their files. This race has been fixed by adding a new commitlock, which when locked by the CGI, disables the commit hook (except for commit mails). The CGI then takes care of the updates the commit hook would have done.
-rw-r--r--IkiWiki.pm26
-rw-r--r--IkiWiki/CGI.pm65
-rw-r--r--IkiWiki/Plugin/poll.pm14
-rw-r--r--IkiWiki/Setup/Standard.pm3
-rw-r--r--debian/changelog10
-rwxr-xr-xikiwiki.in6
-rw-r--r--po/ikiwiki.pot20
7 files changed, 92 insertions, 52 deletions
diff --git a/IkiWiki.pm b/IkiWiki.pm
index 40622a5be..c8d959edd 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
@@ -38,6 +38,7 @@ sub defaultconfig () { #{{{
wikiname => "wiki",
default_pageext => "mdwn",
cgi => 0,
+ post_commit => 0,
rcs => '',
notify => 0,
url => '',
@@ -601,7 +602,7 @@ sub lockwiki () { #{{{
}
open(WIKILOCK, ">$config{wikistatedir}/lockfile") ||
error ("cannot write to $config{wikistatedir}/lockfile: $!");
- if (! flock(WIKILOCK, 2 | 4)) {
+ if (! flock(WIKILOCK, 2 | 4)) { # LOCK_EX | LOCK_NB
debug("wiki seems to be locked, waiting for lock");
my $wait=600; # arbitrary, but don't hang forever to
# prevent process pileup
@@ -617,6 +618,29 @@ sub unlockwiki () { #{{{
close WIKILOCK;
} #}}}
+sub commit_hook_enabled () { #{{{
+ open(COMMITLOCK, "+>$config{wikistatedir}/commitlock") ||
+ error ("cannot write to $config{wikistatedir}/commitlock: $!");
+ if (! flock(WIKILOCK, 1 | 4)) { # LOCK_SH | LOCK_NB to test
+ close WIKILOCK;
+ return 0;
+ }
+ close WIKILOCK;
+ return 1;
+} #}}}
+
+sub disable_commit_hook () { #{{{
+ open(COMMITLOCK, ">$config{wikistatedir}/commitlock") ||
+ error ("cannot write to $config{wikistatedir}/commitlock: $!");
+ if (! flock(COMMITLOCK, 2)) { # LOCK_EX
+ error("failed to get commit lock");
+ }
+} #}}}
+
+sub enable_commit_hook () { #{{{
+ close COMMITLOCK;
+} #}}}
+
sub loadindex () { #{{{
open (IN, "$config{wikistatedir}/index") || return;
while (<IN>) {
diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm
index e23ef8afd..e62bcf477 100644
--- a/IkiWiki/CGI.pm
+++ b/IkiWiki/CGI.pm
@@ -513,6 +513,7 @@ sub cgi_editpage ($$) { #{{{
return;
}
+ my $conflict;
if ($config{rcs}) {
my $message="";
if (defined $form->field('comments') &&
@@ -523,44 +524,44 @@ sub cgi_editpage ($$) { #{{{
if ($newfile) {
rcs_add($file);
}
- # prevent deadlock with post-commit hook
- unlockwiki();
- # presumably the commit will trigger an update
- # of the wiki
- my $conflict=rcs_commit($file, $message,
+
+ # Prevent deadlock with post-commit hook by
+ # signaling to it that it should not try to
+ # do anything (except send commit mails).
+ disable_commit_hook();
+ $conflict=rcs_commit($file, $message,
$form->field("rcsinfo"),
$session->param("name"), $ENV{REMOTE_ADDR});
+ enable_commit_hook();
+ rcs_update();
+ }
- if (defined $conflict) {
- $form->field(name => "rcsinfo", value => rcs_prepedit($file),
- force => 1);
- $form->tmpl_param("page_conflict", 1);
- $form->field("editcontent", value => $conflict, force => 1);
- $form->field(name => "comments", value => $form->field('comments'), force => 1);
- $form->field("do", "edit)");
- $form->tmpl_param("page_select", 0);
- $form->field(name => "page", type => 'hidden');
- $form->field(name => "type", type => 'hidden');
- $form->title(sprintf(gettext("editing %s"), $page));
- print $form->render(submit => \@buttons);
- return;
- }
- else {
- # Make sure that the repo is up-to-date;
- # locking prevents the post-commit hook
- # from updating it.
- rcs_update();
- }
+ # Refresh even if there was a conflict, since other changes
+ # may have been committed while the post-commit hook was
+ # disabled.
+ require IkiWiki::Render;
+ refresh();
+ saveindex();
+
+ if (defined $conflict) {
+ $form->field(name => "rcsinfo", value => rcs_prepedit($file),
+ force => 1);
+ $form->tmpl_param("page_conflict", 1);
+ $form->field("editcontent", value => $conflict, force => 1);
+ $form->field(name => "comments", value => $form->field('comments'), force => 1);
+ $form->field("do", "edit)");
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->field(name => "type", type => 'hidden');
+ $form->title(sprintf(gettext("editing %s"), $page));
+ print $form->render(submit => \@buttons);
+ return;
}
else {
- require IkiWiki::Render;
- refresh();
- saveindex();
+ # The trailing question mark tries to avoid broken
+ # caches and get the most recent version of the page.
+ redirect($q, "$config{url}/".htmlpage($page)."?updated");
}
-
- # The trailing question mark tries to avoid broken
- # caches and get the most recent version of the page.
- redirect($q, "$config{url}/".htmlpage($page)."?updated");
}
} #}}}
diff --git a/IkiWiki/Plugin/poll.pm b/IkiWiki/Plugin/poll.pm
index a3321a32e..4eae6a349 100644
--- a/IkiWiki/Plugin/poll.pm
+++ b/IkiWiki/Plugin/poll.pm
@@ -125,17 +125,17 @@ sub cgi ($) { #{{{
IkiWiki::cgi_savesession($session);
$oldchoice=$session->param($choice_param);
if ($config{rcs}) {
- # prevent deadlock with post-commit hook
- IkiWiki::unlockwiki();
+ disable_commit_hook();
IkiWiki::rcs_commit($pagesources{$page}, "poll vote ($choice)",
IkiWiki::rcs_prepedit($pagesources{$page}),
$session->param("name"), $ENV{REMOTE_ADDR});
+ enable_commit_hook();
+ rcs_update();
}
- else {
- require IkiWiki::Render;
- IkiWiki::refresh();
- IkiWiki::saveindex();
- }
+ require IkiWiki::Render;
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+
# Need to set cookie in same http response that does the
# redir.
eval q{use CGI::Cookie};
diff --git a/IkiWiki/Setup/Standard.pm b/IkiWiki/Setup/Standard.pm
index 0c4272286..f3f7bae5a 100644
--- a/IkiWiki/Setup/Standard.pm
+++ b/IkiWiki/Setup/Standard.pm
@@ -36,6 +36,9 @@ sub setup_standard {
foreach my $wrapper (@wrappers) {
%config=(%startconfig, verbose => 0, %setup, %{$wrapper});
checkconfig();
+ if (! $config{cgi} && ! $config{post_commit}) {
+ $config{post_commit}=1;
+ }
gen_wrapper();
}
%config=(%startconfig);
diff --git a/debian/changelog b/debian/changelog
index 6a6dc8f82..3625d4c91 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -27,8 +27,14 @@ ikiwiki (1.44) UNRELEASED; urgency=low
* Smarter detection of no-op changes to po files.
* Elegant patch from Ethan to clean up the display of page names in the
dropdown when creating a new page.
-
- -- Joey Hess <joeyh@debian.org> Tue, 20 Feb 2007 19:14:39 -0500
+ * Since the CGI had to drop the wiki lock to avoid deadlocking the
+ commit hook, it was possible for one CGI to race another one and "win"
+ the commit of both their files. This race has been fixed by adding a new
+ commitlock, which when locked by the CGI, disables the commit hook
+ (except for commit mails). The CGI then takes care of the updates the
+ commit hook would have done.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 21 Feb 2007 03:35:52 -0500
ikiwiki (1.43) unstable; urgency=low
diff --git a/ikiwiki.in b/ikiwiki.in
index 24b02bc41..5dd1064f9 100755
--- a/ikiwiki.in
+++ b/ikiwiki.in
@@ -117,6 +117,12 @@ sub main () { #{{{
require IkiWiki::Render;
commandline_render();
}
+ elsif ($config{post_commit} && ! commit_hook_enabled()) {
+ if ($config{notify}) {
+ loadindex();
+ rcs_notify();
+ }
+ }
else {
lockwiki();
loadindex();
diff --git a/po/ikiwiki.pot b/po/ikiwiki.pot
index 76337ff7e..4399a0317 100644
--- a/po/ikiwiki.pot
+++ b/po/ikiwiki.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-02-20 19:07-0500\n"
+"POT-Creation-Date: 2007-02-21 03:51-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -41,16 +41,16 @@ msgstr ""
msgid "creating %s"
msgstr ""
-#: ../IkiWiki/CGI.pm:483 ../IkiWiki/CGI.pm:511 ../IkiWiki/CGI.pm:544
+#: ../IkiWiki/CGI.pm:483 ../IkiWiki/CGI.pm:511 ../IkiWiki/CGI.pm:556
#, perl-format
msgid "editing %s"
msgstr ""
-#: ../IkiWiki/CGI.pm:652
+#: ../IkiWiki/CGI.pm:653
msgid "You are banned."
msgstr ""
-#: ../IkiWiki/CGI.pm:684
+#: ../IkiWiki/CGI.pm:685
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
@@ -380,15 +380,15 @@ msgstr ""
msgid "generating wrappers.."
msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:68
+#: ../IkiWiki/Setup/Standard.pm:71
msgid "rebuilding wiki.."
msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:71
+#: ../IkiWiki/Setup/Standard.pm:74
msgid "refreshing wiki.."
msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:80
+#: ../IkiWiki/Setup/Standard.pm:83
msgid "done"
msgstr ""
@@ -437,11 +437,11 @@ msgstr ""
msgid "usage: ikiwiki [options] source dest"
msgstr ""
-#: ../IkiWiki.pm:103
+#: ../IkiWiki.pm:104
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
-#: ../IkiWiki.pm:150 ../IkiWiki.pm:151
+#: ../IkiWiki.pm:151 ../IkiWiki.pm:152
msgid "Error"
msgstr ""
@@ -449,7 +449,7 @@ msgstr ""
#. translators: preprocessor directive name,
#. translators: the second a page name, the
#. translators: third a number.
-#: ../IkiWiki.pm:560
+#: ../IkiWiki.pm:561
#, perl-format
msgid "%s preprocessing loop detected on %s at depth %i"
msgstr ""