* Avoid a race in the git rcs_commit function, by not assuming HEAD will
stay the same for the duration of the function.master
parent
2a6e353c20
commit
c5d9c0d6b6
|
@ -165,7 +165,10 @@ sub _parse_diff_tree ($@) { #{{{
|
||||||
# Identification lines for the commit.
|
# Identification lines for the commit.
|
||||||
while (my $line = shift @{ $dt_ref }) {
|
while (my $line = shift @{ $dt_ref }) {
|
||||||
# Regexps are semi-stolen from gitweb.cgi.
|
# Regexps are semi-stolen from gitweb.cgi.
|
||||||
if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) {
|
if ($line =~ m/^commit ([0-9a-fA-F]{40})$/) {
|
||||||
|
$ci{'commit'} = $1;
|
||||||
|
}
|
||||||
|
elsif ($line =~ m/^tree ([0-9a-fA-F]{40})$/) {
|
||||||
$ci{'tree'} = $1;
|
$ci{'tree'} = $1;
|
||||||
}
|
}
|
||||||
elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) {
|
elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) {
|
||||||
|
@ -431,12 +434,9 @@ sub rcs_notify () { #{{{
|
||||||
#
|
#
|
||||||
# Here, we rely on a simple fact: we can extract all parts of the
|
# Here, we rely on a simple fact: we can extract all parts of the
|
||||||
# notification content by parsing the "HEAD" commit (which also
|
# notification content by parsing the "HEAD" commit (which also
|
||||||
# triggers a refresh of IkiWiki pages) and we can obtain the diff
|
# triggers a refresh of IkiWiki pages).
|
||||||
# by comparing HEAD and HEAD^ (the previous commit).
|
|
||||||
|
|
||||||
my $sha1 = 'HEAD'; # the commit which triggers this action
|
my $ci = git_commit_info('HEAD');
|
||||||
|
|
||||||
my $ci = git_commit_info($sha1);
|
|
||||||
return if !defined $ci;
|
return if !defined $ci;
|
||||||
|
|
||||||
my @changed_pages = map { $_->{'file'} } @{ $ci->{'details'} };
|
my @changed_pages = map { $_->{'file'} } @{ $ci->{'details'} };
|
||||||
|
@ -451,6 +451,8 @@ sub rcs_notify () { #{{{
|
||||||
$message = join "\n", @{ $ci->{'comment'} };
|
$message = join "\n", @{ $ci->{'comment'} };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $sha1 = $ci->{'commit'};
|
||||||
|
|
||||||
require IkiWiki::UserInfo;
|
require IkiWiki::UserInfo;
|
||||||
send_commit_mails(
|
send_commit_mails(
|
||||||
sub {
|
sub {
|
||||||
|
|
|
@ -5,8 +5,10 @@ ikiwiki (2.12) UNRELEASED; urgency=low
|
||||||
page name to be expired and reused for several distinct guids. When this
|
page name to be expired and reused for several distinct guids. When this
|
||||||
happened, the expiry code counted each past guid that had used that page
|
happened, the expiry code counted each past guid that had used that page
|
||||||
name as a currently existing page, and thus expired too many pages.
|
name as a currently existing page, and thus expired too many pages.
|
||||||
|
* Avoid a race in the git rcs_commit function, by not assuming HEAD will
|
||||||
|
stay the same for the duration of the function.
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Tue, 30 Oct 2007 22:47:36 -0400
|
-- Joey Hess <joeyh@debian.org> Wed, 31 Oct 2007 17:11:12 -0400
|
||||||
|
|
||||||
ikiwiki (2.11) unstable; urgency=low
|
ikiwiki (2.11) unstable; urgency=low
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
I was suprised to receive two mails from ikiwiki about one web edit:
|
||||||
|
|
||||||
|
1 F Oct 30 To joey+ikiwiki update of ikiwiki's plugins/contrib/gallery.mdwn by http://arpitjain11.myopenid.com/
|
||||||
|
1 F Oct 30 To joey+ikiwiki update of ikiwiki's plugins/contrib/gallery.mdwn by http://arpitjain11.myopenid.com/
|
||||||
|
|
||||||
|
The first of these had the correct diff for the changes made by the web
|
||||||
|
edit (00259020061577316895370ee04cf00b634db98a).
|
||||||
|
|
||||||
|
But the second had a diff for modifications I made to ikiwiki code
|
||||||
|
around the same time (2a6e353c205a6c2c8b8e2eaf85fe9c585c1af0cd).
|
||||||
|
|
||||||
|
I'm now fairly sure a race is involved. Note that the name of the modified
|
||||||
|
page is correct, while the diff was not. The git rcs_commit code first
|
||||||
|
gets the list of modified page(s) and then gets the diff, and apparently my
|
||||||
|
other commit happened in the meantime, so HEAD changed.
|
||||||
|
|
||||||
|
Seems that the rcs_notify for git assumes that HEAD is the commit
|
||||||
|
that triggered the ikiwiki run, and that it won't change while the function is
|
||||||
|
running. Both assumptions are bad. Git does no locking and another commit
|
||||||
|
can come in at any time.
|
||||||
|
|
||||||
|
Notice that the equivilant code for subversion is careful to look at $REV.
|
||||||
|
git's post-update hook doesn't have an equivilant of $REV. Its post-receive hook
|
||||||
|
does, but I'm not sure if that's an appropriate hook for ikiwiki to be using
|
||||||
|
for this. Switching existing wikis to use a different hook would be tricky..
|
||||||
|
|
||||||
|
I've avoided part of the race; now the code does:
|
||||||
|
|
||||||
|
1. Get commit info for HEAD commit.
|
||||||
|
2. Extract file list from that.
|
||||||
|
3. Extract sha1 of commit from it too.
|
||||||
|
4. git diff sha1^ sha1
|
||||||
|
|
||||||
|
Still seems like there can be a race if another commit comes in before step #1.
|
||||||
|
In this case, two post-receive hooks could run at the same time, and both
|
||||||
|
see the same sha1 as HEAD, so two diffs might be sent for second commit and no
|
||||||
|
diff for the first commit.
|
||||||
|
|
||||||
|
Ikiwiki's own locking prevents this from happenning if both commits are web
|
||||||
|
edits. At least one of the two commits has to be a non-web commit.
|
Loading…
Reference in New Issue