From: Eric Wong Date: Wed, 31 Jan 2007 21:54:23 +0000 (-0800) Subject: git-svn: do our best to ensure that our ref and rev_db are consistent X-Git-Tag: v1.5.1-rc1~200 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=373274f978a48b62549f20059bff630d85533533;p=git.git git-svn: do our best to ensure that our ref and rev_db are consistent Defer any signals that cause termination while they are updating; and put the update-ref call as close to the rename() as possible. Also, make things extra-safe (but slower) for people using --no-metadata since they can't rely on .rev_db being rebuilt if it's clobbered (well, I'm calling update-ref with the -m flag for reflogs, we don't yet have a way to rebuild .rev_db from reflogs. Signed-off-by: Eric Wong --- diff --git a/git-svn.perl b/git-svn.perl index 1fd65526d..2206f1b25 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -631,6 +631,7 @@ use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent $_repack $_repack_flags/; use Carp qw/croak/; use File::Path qw/mkpath/; +use File::Copy qw/copy/; use IPC::Open3; my $_repack_nr; @@ -645,6 +646,9 @@ BEGIN { svn:entry:committed-date/; } +my %LOCKFILES; +END { unlink keys %LOCKFILES if %LOCKFILES } + sub fetch_all { my ($repo_id, $url, $fetch) = @_; my @gs; @@ -1030,8 +1034,7 @@ sub do_git_commit { die "Failed to commit, invalid sha1: $commit\n"; } - command_noisy('update-ref',$self->refname, $commit); - $self->rev_db_set($log_entry->{revision}, $commit); + $self->rev_db_set($log_entry->{revision}, $commit, 1); $self->{last_rev} = $log_entry->{revision}; $self->{last_commit} = $commit; @@ -1353,11 +1356,28 @@ sub rebuild { # to a revision: (41 * rev) is the byte offset. # A record of 40 0s denotes an empty revision. # And yes, it's still pretty fast (faster than Tie::File). +# These files are disposable unless --no-metadata is set sub rev_db_set { - my ($self, $rev, $commit) = @_; + my ($self, $rev, $commit, $update_ref) = @_; length $commit == 40 or croak "arg3 must be a full SHA1 hexsum\n"; - open my $fh, '+<', $self->{db_path} or croak $!; + my ($db, $db_lock) = ($self->{db_path}, "$self->{db_path}.lock"); + my $sig; + if ($update_ref) { + $SIG{INT} = $SIG{HUP} = $SIG{TERM} = $SIG{ALRM} = $SIG{PIPE} = + $SIG{USR1} = $SIG{USR2} = sub { $sig = $_[0] }; + } + $LOCKFILES{$db_lock} = 1; + if ($_no_metadata) { + copy($db, $db_lock) or die "rev_db_set(@_): ", + "Failed to copy: ", + "$db => $db_lock ($!)\n"; + } else { + rename $db, $db_lock or die "rev_db_set(@_): ", + "Failed to rename: ", + "$db => $db_lock ($!)\n"; + } + open my $fh, '+<', $db_lock or croak $!; my $offset = $rev * 41; # assume that append is the common case: seek $fh, 0, 2 or croak $!; @@ -1370,6 +1390,18 @@ sub rev_db_set { seek $fh, $offset, 0 or croak $!; print $fh $commit,"\n" or croak $!; close $fh or croak $!; + if ($update_ref) { + command_noisy('update-ref', '-m', "r$rev", + $self->refname, $commit); + } + rename $db_lock, $db or die "rev_db_set(@_): ", "Failed to rename: ", + "$db_lock => $db ($!)\n"; + delete $LOCKFILES{$db_lock}; + if ($update_ref) { + $SIG{INT} = $SIG{HUP} = $SIG{TERM} = $SIG{ALRM} = $SIG{PIPE} = + $SIG{USR1} = $SIG{USR2} = 'DEFAULT'; + kill $sig, $$ if defined $sig; + } } sub rev_db_get {