Skip to content

Commit

Permalink
Make 'cvs ci' lockless in git-cvsserver by using git-update-ref
Browse files Browse the repository at this point in the history
This makes "ci" codepath lockless by following the usual
"remember the tip, do your thing, then compare and swap at the
end" update pattern using update-ref.  Incidentally, by updating
the code that reads where the tip of the head is to use
show-ref, it makes it safe to use in a repository whose refs are
pack-pruned.

I noticed that other parts of the program are not yet pack-refs
safe, but tried to keep the changes to the minimum.

Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Junio C Hamano committed Feb 27, 2007
1 parent 4e4b55d commit ada5ef3
Showing 1 changed file with 16 additions and 27 deletions.
43 changes: 16 additions & 27 deletions git-cvsserver.perl
Original file line number Diff line number Diff line change
Expand Up @@ -1031,36 +1031,35 @@ sub req_ci
exit;
}

my $lockfile = "$state->{CVSROOT}/refs/heads/$state->{module}.lock";
unless ( sysopen(LOCKFILE,$lockfile,O_EXCL|O_CREAT|O_WRONLY) )
{
$log->warn("lockfile '$lockfile' already exists, please try again");
print "error 1 Lock file '$lockfile' already exists, please try again\n";
exit;
}

# Grab a handle to the SQLite db and do any necessary updates
my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
$updater->update();

my $tmpdir = tempdir ( DIR => $TEMP_DIR );
my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
$log->info("Lock successful, basing commit on '$tmpdir', index file is '$file_index'");
$log->info("Lockless commit start, basing commit on '$tmpdir', index file is '$file_index'");

$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
$ENV{GIT_INDEX_FILE} = $file_index;

# Remember where the head was at the beginning.
my $parenthash = `git show-ref -s refs/heads/$state->{module}`;
chomp $parenthash;
if ($parenthash !~ /^[0-9a-f]{40}$/) {
print "error 1 pserver cannot find the current HEAD of module";
exit;
}

chdir $tmpdir;

# populate the temporary index based
system("git-read-tree", $state->{module});
system("git-read-tree", $parenthash);
unless ($? == 0)
{
die "Error running git-read-tree $state->{module} $file_index $!";
}
$log->info("Created index '$file_index' with for head $state->{module} - exit status $?");


my @committedfiles = ();

# foreach file specified on the command line ...
Expand Down Expand Up @@ -1095,8 +1094,6 @@ sub req_ci
{
# fail everything if an up to date check fails
print "error 1 Up to date check failed for $filename\n";
close LOCKFILE;
unlink($lockfile);
chdir "/";
exit;
}
Expand Down Expand Up @@ -1139,16 +1136,12 @@ sub req_ci
{
print "E No files to commit\n";
print "ok\n";
close LOCKFILE;
unlink($lockfile);
chdir "/";
return;
}

my $treehash = `git-write-tree`;
my $parenthash = `cat $ENV{GIT_DIR}refs/heads/$state->{module}`;
chomp $treehash;
chomp $parenthash;

$log->debug("Treehash : $treehash, Parenthash : $parenthash");

Expand All @@ -1165,8 +1158,6 @@ sub req_ci
{
$log->warn("Commit failed (Invalid commit hash)");
print "error 1 Commit failed (unknown reason)\n";
close LOCKFILE;
unlink($lockfile);
chdir "/";
exit;
}
Expand All @@ -1179,14 +1170,17 @@ sub req_ci
{
$log->warn("Commit failed (update hook declined to update ref)");
print "error 1 Commit failed (update hook declined)\n";
close LOCKFILE;
unlink($lockfile);
chdir "/";
exit;
}
}

print LOCKFILE $commithash;
if (system(qw(git update-ref -m), "cvsserver ci",
"refs/heads/$state->{module}", $commithash, $parenthash)) {
$log->warn("update-ref for $state->{module} failed.");
print "error 1 Cannot commit -- update first\n";
exit;
}

$updater->update();

Expand Down Expand Up @@ -1215,12 +1209,7 @@ sub req_ci
}
}

close LOCKFILE;
my $reffile = "$ENV{GIT_DIR}refs/heads/$state->{module}";
unlink($reffile);
rename($lockfile, $reffile);
chdir "/";

print "ok\n";
}

Expand Down

0 comments on commit ada5ef3

Please sign in to comment.