@matheusbsbs / matheus-bagliano / commits / 0b19138ba3
Fork 0

git-svn: Make it incrementally faster by minimizing temp files

Currently, git-svn would create a temp file on four occasions: 1. Reading a blob out of the object db 2. Creating a delta from svn 3. Hashing and writing a blob into the object db 4. Reading a blob out of the object db (in another place in code) Any time git-svn did the above, it would dutifully create and then delete said temp file. Unfortunately, this means that between 2-4 temporary files are created/deleted per file 'add/modify'-ed in svn (O(n)). This causes significant overhead and helps the inode counter to spin beautifully. By its nature, git-svn is a serial beast. Thus, reusing a temp file does not pose significant problems. "truncate and seek" takes much less time than "unlink and create". This patch centralizes the tempfile creation and holds onto the tempfile until they are deleted on exit. This significantly reduces file overhead, now requiring at most three (3) temp files per run (O(1)). Signed-off-by: Marcus Griep <marcus@griep.us> Acked-by: Eric Wong <normalperson@yhbt.net>

Marcus Griep committed Aug 12, 2008 at 12:00 UTC 0b19138ba3e4c129770565d364df65ec25ca0a8e
1 file changed +18 -17
git-svn.perl
+18 -17
@@ -1265,7 +1265,7 @@ sub md5sum {
1265 my $arg = shift;
1266 my $ref = ref $arg;
1267 my $md5 = Digest::MD5->new();
1268 - if ($ref eq 'GLOB' || $ref eq 'IO::File') {
1268 + if ($ref eq 'GLOB' || $ref eq 'IO::File' || $ref eq 'File::Temp') {
1269 $md5->addfile($arg) or croak $!;
1270 } elsif ($ref eq 'SCALAR') {
1271 $md5->add($$arg) or croak $!;
@@ -1328,6 +1328,7 @@ BEGIN {
1328 }
1329 }
1330
1331 +
1332 my (%LOCKFILES, %INDEX_FILES);
1333 END {
1334 unlink keys %LOCKFILES if %LOCKFILES;
@@ -3230,13 +3231,11 @@ sub change_file_prop {
3231
3232 sub apply_textdelta {
3233 my ($self, $fb, $exp) = @_;
3233 - my $fh = IO::File->new_tmpfile;
3234 - $fh->autoflush(1);
3234 + my $fh = Git::temp_acquire('svn_delta');
3235 # $fh gets auto-closed() by SVN::TxDelta::apply(),
3236 # (but $base does not,) so dup() it for reading in close_file
3237 open my $dup, '<&', $fh or croak $!;
3238 - my $base = IO::File->new_tmpfile;
3239 - $base->autoflush(1);
3238 + my $base = Git::temp_acquire('git_blob');
3239 if ($fb->{blob}) {
3240 print $base 'link ' if ($fb->{mode_a} == 120000);
3241 my $size = $::_repository->cat_blob($fb->{blob}, $base);
@@ -3251,9 +3250,9 @@ sub apply_textdelta {
3250 }
3251 }
3252 seek $base, 0, 0 or croak $!;
3254 - $fb->{fh} = $dup;
3253 + $fb->{fh} = $fh;
3254 $fb->{base} = $base;
3256 - [ SVN::TxDelta::apply($base, $fh, undef, $fb->{path}, $fb->{pool}) ];
3255 + [ SVN::TxDelta::apply($base, $dup, undef, $fb->{path}, $fb->{pool}) ];
3256 }
3257
3258 sub close_file {
@@ -3282,22 +3281,25 @@ sub close_file {
3281 }
3282 }
3283
3285 - my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1);
3284 + my $tmp_fh = Git::temp_acquire('svn_hash');
3285 my $result;
3286 while ($result = sysread($fh, my $string, 1024)) {
3287 my $wrote = syswrite($tmp_fh, $string, $result);
3288 defined($wrote) && $wrote == $result
3290 - or croak("write $tmp_filename: $!\n");
3289 + or croak("write ",
3290 + $tmp_fh->filename, ": $!\n");
3291 }
3292 defined $result or croak $!;
3293 - close $tmp_fh or croak $!;
3293
3295 - close $fh or croak $!;
3294
3297 - $hash = $::_repository->hash_and_insert_object($tmp_filename);
3298 - unlink($tmp_filename);
3295 + Git::temp_release($fh, 1);
3296 +
3297 + $hash = $::_repository->hash_and_insert_object(
3298 + $tmp_fh->filename);
3299 $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
3300 - close $fb->{base} or croak $!;
3300 +
3301 + Git::temp_release($fb->{base}, 1);
3302 + Git::temp_release($tmp_fh, 1);
3303 } else {
3304 $hash = $fb->{blob} or die "no blob information\n";
3305 }
@@ -3667,7 +3669,7 @@ sub chg_file {
3669 } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) {
3670 $self->change_file_prop($fbat,'svn:executable',undef);
3671 }
3670 - my $fh = IO::File->new_tmpfile or croak $!;
3672 + my $fh = Git::temp_acquire('git_blob');
3673 if ($m->{mode_b} =~ /^120/) {
3674 print $fh 'link ' or croak $!;
3675 $self->change_file_prop($fbat,'svn:special','*');
@@ -3686,9 +3688,8 @@ sub chg_file {
3688 my $atd = $self->apply_textdelta($fbat, undef, $pool);
3689 my $got = SVN::TxDelta::send_stream($fh, @$atd, $pool);
3690 die "Checksum mismatch\nexpected: $exp\ngot: $got\n" if ($got ne $exp);
3691 + Git::temp_release($fh, 1);
3692 $pool->clear;
3690 -
3691 - close $fh or croak $!;
3693 }
3694
3695 sub D {