git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 9/9] git-svn: Make fetch ~1.7x faster

From
Adam Roben <aroben@apple.com>
Date
Oct 23, 2007, 05:46 UTC
Message-ID
<1193118397-4696-10-git-send-email-aroben@apple.com>
In-Reply-To
<1193118397-4696-9-git-send-email-aroben@apple.com>

We were spending a lot of time forking/execing git-cat-file and git-hash-object. We now use command_bidi_pipe to keep one instance of each running and feed it input on stdin.

Signed-off-by: Adam Roben <aroben@apple.com>
---
 git-svn.perl |   94 ++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 72 insertions(+), 22 deletions(-)
diff --git a/git-svn.perl b/git-svn.perl
index 22bb47b..8b72046 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -236,6 +236,8 @@ eval {
 };
 fatal $@ if $@;
 post_fetch_checkout();
+Git::Commands->close_cat_blob();
+Git::Commands->close_hash_object();
 exit 0;
 
 ####################### primary functions ######################
@@ -2683,14 +2685,8 @@ sub apply_textdelta {
 	my $base = IO::File->new_tmpfile;
 	$base->autoflush(1);
 	if ($fb->{blob}) {
-		defined (my $pid = fork) or croak $!;
-		if (!$pid) {
-			open STDOUT, '>&', $base or croak $!;
-			print STDOUT 'link ' if ($fb->{mode_a} == 120000);
-			exec qw/git-cat-file blob/, $fb->{blob} or croak $!;
-		}
-		waitpid $pid, 0;
-		croak $? if $?;
+		my $contents = Git::Commands->cat_blob($fb->{blob});
+		print $base $contents;
 
 		if (defined $exp) {
 			seek $base, 0, 0 or croak $!;
@@ -2729,13 +2725,7 @@ sub close_file {
 			$buf eq 'link ' or die "$path has mode 120000",
 			                       "but is not a link\n";
 		}
-		defined(my $pid = open my $out,'-|') or die "Can't fork: $!\n";
-		if (!$pid) {
-			open STDIN, '<&', $fh or croak $!;
-			exec qw/git-hash-object -w --stdin/ or croak $!;
-		}
-		chomp($hash = do { local $/; <$out> });
-		close $out or croak $!;
+		$hash = Git::Commands->hash_object($fh);
 		close $fh or croak $!;
 		$hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
 		close $fb->{base} or croak $!;
@@ -3063,13 +3053,8 @@ sub chg_file {
 	} elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) {
 		$self->change_file_prop($fbat,'svn:special',undef);
 	}
-	defined(my $pid = fork) or croak $!;
-	if (!$pid) {
-		open STDOUT, '>&', $fh or croak $!;
-		exec qw/git-cat-file blob/, $m->{sha1_b} or croak $!;
-	}
-	waitpid $pid, 0;
-	croak $? if $?;
+	my $blob = Git::Commands->cat_blob($m->{sha1_b});
+	print $fh $blob;
 	$fh->flush == 0 or croak $!;
 	seek $fh, 0, 0 or croak $!;
 
@@ -4272,6 +4257,71 @@ sub full_path {
 	       $path . (length $self->{right} ? "/$self->{right}" : '');
 }
 
+package Git::Commands;
+use vars qw/$_cat_blob_pid $_cat_blob_in $_cat_blob_out $_cat_blob_ctx $_cat_blob_separator
+	    $_hash_object_pid $_hash_object_in $_hash_object_out $_hash_object_ctx/;
+use strict;
+use warnings;
+use File::Temp qw/tempfile/;
+use Git qw/command_bidi_pipe command_close_bidi_pipe/;
+
+sub _open_cat_blob_if_needed {
+	return if defined($_cat_blob_pid);
+	$_cat_blob_separator = "--------------GITCATFILESEPARATOR-----------";
+
+	($_cat_blob_pid, $_cat_blob_in, $_cat_blob_out, $_cat_blob_ctx) = command_bidi_pipe(qw(git-cat-file blob --stdin --separator), $_cat_blob_separator);
+}
+
+sub close_cat_blob {
+	return unless defined($_cat_blob_pid);
+
+	command_close_bidi_pipe($_cat_blob_pid, $_cat_blob_in, $_cat_blob_out, $_cat_blob_ctx);
+}
+
+sub cat_blob {
+	my (undef, $sha1) = @_;
+
+	_open_cat_blob_if_needed();
+	print $_cat_blob_out "$sha1\n";
+	my @file = ();
+	while (my $line = <$_cat_blob_in>) {
+		my $last = 0;
+		if ($line =~ s/\Q$_cat_blob_separator\E$//) {
+			chomp($line);
+			$last = 1;
+		}
+		push(@file, $line);
+		last if $last;
+	}
+	return join('', @file);
+}
+
+sub _open_hash_object_if_needed {
+	return if defined($_hash_object_pid);
+
+	($_hash_object_pid, $_hash_object_in, $_hash_object_out, $_hash_object_ctx) = command_bidi_pipe(qw(git-hash-object -w --stdin-paths));
+}
+
+sub close_hash_object {
+	return unless defined($_hash_object_pid);
+
+	command_close_bidi_pipe($_hash_object_pid, $_hash_object_in, $_hash_object_out, $_hash_object_ctx);
+}
+
+sub hash_object {
+	my (undef, $fh) = @_;
+
+	my ($tmp_fh, $tmp_filename) = tempfile(UNLINK => 1);
+	while (my $line = <$fh>) {
+		print $tmp_fh $line;
+	}
+	close($tmp_fh);
+	_open_hash_object_if_needed();
+	print $_hash_object_out $tmp_filename . "\n";
+	chomp(my $hash = <$_hash_object_in>);
+	return $hash;
+}
+
 __END__
 
 Data structures:
-- 
1.5.3.4.1333.ga2f32
Previous: Adam RobenNext: Johannes Sixt
Message 10 of 24 in “Make git-svn fetch ~1.7x faster”
  1. 0/9 Make git-svn fetch ~1.7x fasterAdam Roben, Oct 23, 2007
  2. 1/9 Add tests for git cat-fileAdam Roben, Oct 23, 2007
  3. 2/9 git-cat-file: Small refactor of cmd_cat_fileAdam Roben, Oct 23, 2007
  4. 3/9 git-cat-file: Make option parsing a little more flexibleAdam Roben, Oct 23, 2007
  5. 4/9 git-cat-file: Add --stdin optionAdam Roben, Oct 23, 2007
  6. 5/9 git-cat-file: Add --separator optionAdam Roben, Oct 23, 2007
  7. 6/9 Add tests for git hash-objectAdam Roben, Oct 23, 2007
  8. 7/9 git-hash-object: Add --stdin-paths optionAdam Roben, Oct 23, 2007
  9. 8/9 Git.pm: Add command_bidi_pipe and command_close_bidi_pipeAdam Roben, Oct 23, 2007
  10. 9/9 git-svn: Make fetch ~1.7x fasterAdam Roben, Oct 23, 2007
  11. Johannes SixtOct 23, 2007
  12. Eric WongOct 24, 2007
  13. Adam RobenOct 24, 2007
  14. Shawn O. PearceOct 23, 2007
  15. Adam RobenOct 23, 2007
  16. Shawn O. PearceOct 23, 2007
  17. Eric WongOct 24, 2007
  18. Johannes SixtOct 23, 2007
  19. Brian DowningOct 24, 2007
  20. Adam RobenOct 24, 2007
  21. Johannes SixtOct 23, 2007
  22. Mike HommeyOct 23, 2007
  23. Adam RobenOct 23, 2007
  24. Sam VilainOct 24, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.