user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH 03/30] qspawn: remove some anonymous subs for psgi_qx
Date: Wed, 25 Dec 2019 07:50:37 +0000	[thread overview]
Message-ID: <20191225075104.22184-4-e@80x24.org> (raw)
In-Reply-To: <20191225075104.22184-1-e@80x24.org>

By passing a user-supplied arg to $qx_cb, we can eliminate the
callers' need to capture on-stack variables with a closure.
This saves several kilobytes of memory allocation at the expense
of some extra hash table lookups in user-supplied callbacks.  It
also reduces the risk of memory leaks by eliminating a common
source of circular references.
---
 lib/PublicInbox/Qspawn.pm    |  4 +-
 lib/PublicInbox/SolverGit.pm | 88 ++++++++++++++++++++----------------
 lib/PublicInbox/ViewVCS.pm   | 33 ++++++++------
 3 files changed, 71 insertions(+), 54 deletions(-)

diff --git a/lib/PublicInbox/Qspawn.pm b/lib/PublicInbox/Qspawn.pm
index c2856609..22603ca7 100644
--- a/lib/PublicInbox/Qspawn.pm
+++ b/lib/PublicInbox/Qspawn.pm
@@ -155,13 +155,13 @@ sub start {
 # $env is the PSGI env.  As with ``/qx; only use this when output is small
 # and safe to slurp.
 sub psgi_qx {
-	my ($self, $env, $limiter, $qx_cb) = @_;
+	my ($self, $env, $limiter, $qx_cb, $cb_arg) = @_;
 	my $scalar = '';
 	open(my $qx, '+>', \$scalar) or die; # PerlIO::scalar
 	my $end = sub {
 		my $err = $_[0]; # $!
 		log_err($env, "psgi_qx: $err") if defined($err);
-		finish($self, $env, sub { $qx_cb->(\$scalar) });
+		finish($self, $env, sub { $qx_cb->(\$scalar, $cb_arg) });
 		$qx = undef;
 	};
 	my $rpipe; # comes from popen_rd
diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm
index d59320bc..f81f69ca 100644
--- a/lib/PublicInbox/SolverGit.pm
+++ b/lib/PublicInbox/SolverGit.pm
@@ -221,6 +221,16 @@ sub find_extract_diffs ($$$) {
 	@di ? \@di : undef;
 }
 
+sub update_index_result ($$) {
+	my ($bref, $self) = @_;
+	my ($qsp, $msg) = delete @$self{qw(-qsp -msg)};
+	if (my $err = $qsp->{err}) {
+		ERR($self, "git update-index error: $err");
+	}
+	dbg($self, $msg);
+	next_step($self); # onto do_git_apply
+}
+
 sub prepare_index ($) {
 	my ($self) = @_;
 	my $patches = $self->{patches};
@@ -248,15 +258,10 @@ sub prepare_index ($) {
 	my $rdr = { 0 => fileno($in), -hold => $in };
 	my $cmd = [ qw(git update-index -z --index-info) ];
 	my $qsp = PublicInbox::Qspawn->new($cmd, $self->{git_env}, $rdr);
-	$qsp->psgi_qx($self->{psgi_env}, undef, sub {
-		my ($bref) = @_;
-		if (my $err = $qsp->{err}) {
-			ERR($self, "git update-index error: $err");
-		}
-		dbg($self, "index prepared:\n" .
-			"$mode_a $oid_full\t" . git_quote($path_a));
-		next_step($self); # onto do_git_apply
-	});
+	$path_a = git_quote($path_a);
+	$self->{-qsp} = $qsp;
+	$self->{-msg} = "index prepared:\n$mode_a $oid_full\t$path_a";
+	$qsp->psgi_qx($self->{psgi_env}, undef, \&update_index_result, $self);
 }
 
 # pure Perl "git init"
@@ -383,8 +388,9 @@ sub mark_found ($$$) {
 	}
 }
 
-sub parse_ls_files ($$$$) {
-	my ($self, $qsp, $bref, $di) = @_;
+sub parse_ls_files ($$) {
+	my ($self, $bref) = @_;
+	my ($qsp, $di) = delete @$self{qw(-qsp -cur_di)};
 	if (my $err = $qsp->{err}) {
 		die "git ls-files error: $err";
 	}
@@ -410,15 +416,10 @@ sub parse_ls_files ($$$$) {
 	next_step($self); # onto the next patch
 }
 
-sub start_ls_files ($$) {
-	my ($self, $di) = @_;
-	my $cmd = [qw(git ls-files -s -z)];
-	my $qsp = PublicInbox::Qspawn->new($cmd, $self->{git_env});
-	$qsp->psgi_qx($self->{psgi_env}, undef, sub {
-		my ($bref) = @_;
-		eval { parse_ls_files($self, $qsp, $bref, $di) };
-		ERR($self, $@) if $@;
-	});
+sub ls_files_result {
+	my ($bref, $self) = @_;
+	eval { parse_ls_files($self, $bref) };
+	ERR($self, $@) if $@;
 }
 
 sub oids_same_ish ($$) {
@@ -438,6 +439,31 @@ sub skip_identical ($$$) {
 	}
 }
 
+sub apply_result ($$) {
+	my ($bref, $self) = @_;
+	my ($qsp, $di) = delete @$self{qw(-qsp -cur_di)};
+	dbg($self, $$bref);
+	my $patches = $self->{patches};
+	if (my $err = $qsp->{err}) {
+		my $msg = "git apply error: $err";
+		my $nxt = $patches->[0];
+		if ($nxt && oids_same_ish($nxt->{oid_b}, $di->{oid_b})) {
+			dbg($self, $msg);
+			dbg($self, 'trying '.di_url($self, $nxt));
+		} else {
+			ERR($self, $msg);
+		}
+	} else {
+		skip_identical($self, $patches, $di->{oid_b});
+	}
+
+	my @cmd = qw(git ls-files -s -z);
+	$qsp = PublicInbox::Qspawn->new(\@cmd, $self->{git_env});
+	$self->{-cur_di} = $di;
+	$self->{-qsp} = $qsp;
+	$qsp->psgi_qx($self->{psgi_env}, undef, \&ls_files_result, $self);
+}
+
 sub do_git_apply ($) {
 	my ($self) = @_;
 	my $dn = $self->{tmp}->dirname;
@@ -465,24 +491,9 @@ sub do_git_apply ($) {
 
 	my $rdr = { 2 => 1 };
 	my $qsp = PublicInbox::Qspawn->new(\@cmd, $self->{git_env}, $rdr);
-	$qsp->psgi_qx($self->{psgi_env}, undef, sub {
-		my ($bref) = @_;
-		dbg($self, $$bref);
-		if (my $err = $qsp->{err}) {
-			my $msg = "git apply error: $err";
-			my $nxt = $patches->[0];
-			if ($nxt && oids_same_ish($nxt->{oid_b}, $prv_oid_b)) {
-				dbg($self, $msg);
-				dbg($self, 'trying '.di_url($self, $nxt));
-			} else {
-				ERR($self, $msg);
-			}
-		} else {
-			skip_identical($self, $patches, $di->{oid_b});
-		}
-		eval { start_ls_files($self, $di) };
-		ERR($self, $@) if $@;
-	});
+	$self->{-cur_di} = $di;
+	$self->{-qsp} = $qsp;
+	$qsp->psgi_qx($self->{psgi_env}, undef, \&apply_result, $self);
 }
 
 sub di_url ($$) {
@@ -564,6 +575,7 @@ sub new {
 	bless {
 		gits => $ibx->{-repo_objs},
 		user_cb => $user_cb,
+		# -cur_di, -qsp, -msg => temporary fields for Qspawn callbacks
 
 		# TODO: config option for searching related inboxes
 		inboxes => [ $ibx ],
diff --git a/lib/PublicInbox/ViewVCS.pm b/lib/PublicInbox/ViewVCS.pm
index 842c873c..886e10cb 100644
--- a/lib/PublicInbox/ViewVCS.pm
+++ b/lib/PublicInbox/ViewVCS.pm
@@ -73,6 +73,22 @@ sub stream_large_blob ($$$$) {
 	});
 }
 
+sub show_other_result ($$) {
+	my ($bref, $ctx) = @_;
+	my ($qsp, $logref) = delete @$ctx{qw(-qsp -logref)};
+	if (my $err = $qsp->{err}) {
+		utf8::decode($$err);
+		$$logref .= "git show error: $err";
+		return html_page($ctx, 500, $logref);
+	}
+	my $l = PublicInbox::Linkify->new;
+	utf8::decode($$bref);
+	$l->linkify_1($$bref);
+	$$bref = '<pre>'. $l->linkify_2(ascii_html($$bref));
+	$$bref .= '</pre><hr>' . $$logref;
+	html_page($ctx, 200, $bref);
+}
+
 sub show_other ($$$$) {
 	my ($ctx, $res, $logref, $fn) = @_;
 	my ($git, $oid, $type, $size) = @$res;
@@ -84,20 +100,9 @@ sub show_other ($$$$) {
 		qw(show --encoding=UTF-8 --no-color --no-abbrev), $oid ];
 	my $qsp = PublicInbox::Qspawn->new($cmd);
 	my $env = $ctx->{env};
-	$qsp->psgi_qx($env, undef, sub {
-		my ($bref) = @_;
-		if (my $err = $qsp->{err}) {
-			utf8::decode($$err);
-			$$logref .= "git show error: $err";
-			return html_page($ctx, 500, $logref);
-		}
-		my $l = PublicInbox::Linkify->new;
-		utf8::decode($$bref);
-		$l->linkify_1($$bref);
-		$$bref = '<pre>'. $l->linkify_2(ascii_html($$bref));
-		$$bref .= '</pre><hr>' . $$logref;
-		html_page($ctx, 200, $bref);
-	});
+	$ctx->{-qsp} = $qsp;
+	$ctx->{-logref} = $logref;
+	$qsp->psgi_qx($env, undef, \&show_other_result, $ctx);
 }
 
 sub solve_result {

  parent reply	other threads:[~2019-12-25  7:51 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-25  7:50 [PATCH 00/30] www: eliminate most per-request closures Eric Wong
2019-12-25  7:50 ` [PATCH 01/30] git: allow async_cat to pass arg to callback Eric Wong
2019-12-25  7:50 ` [PATCH 02/30] httpd/async: support passing arg to callbacks Eric Wong
2019-12-26  7:53   ` Eric Wong
2019-12-25  7:50 ` Eric Wong [this message]
2019-12-25  7:50 ` [PATCH 04/30] qspawn: disambiguate command vs PSGI env Eric Wong
2019-12-25  7:50 ` [PATCH 05/30] qspawn: replace anonymous $end callbacks w/ event_step Eric Wong
2019-12-25  7:50 ` [PATCH 06/30] msg_iter: provide means to stop using anonymous subs Eric Wong
2019-12-25  7:50 ` [PATCH 07/30] qspawn: reduce local vars, de-anonymize rd_hdr Eric Wong
2019-12-25  7:50 ` [PATCH 08/30] httpd/async: get rid of ephemeral main_cb Eric Wong
2019-12-25  7:50 ` [PATCH 09/30] qspawn: psgi_return: initial cb can be named Eric Wong
2019-12-25  7:50 ` [PATCH 10/30] qspawn: psgi_return_start: hoist out from psgi_return Eric Wong
2019-12-25  7:50 ` [PATCH 11/30] qspawn: psgi_qx: eliminate anonymous subs Eric Wong
2019-12-25  7:50 ` [PATCH 12/30] qspawn: drop "qspawn.filter" support, for now Eric Wong
2019-12-25  7:50 ` [PATCH 13/30] qspawn: psgi_return: allow non-anon parse_hdr callback Eric Wong
2019-12-25  7:50 ` [PATCH 14/30] githttpbackend: split out wwwstatic Eric Wong
2019-12-26 12:50   ` Eric Wong
2019-12-27 10:36     ` Eric Wong
2019-12-25  7:50 ` [PATCH 15/30] www: lazy load Plack::Util Eric Wong
2019-12-25  7:50 ` [PATCH 16/30] mboxgz: pass $ctx to callback to avoid anon subs Eric Wong
2019-12-25  7:50 ` [PATCH 17/30] feed: avoid anonymous subs Eric Wong
2019-12-25  7:50 ` [PATCH 18/30] config: each_inbox: pass user arg to callback Eric Wong
2019-12-26  6:48   ` Eric Wong
2019-12-25  7:50 ` [PATCH 19/30] view: avoid anon sub in stream_thread Eric Wong
2019-12-25  7:50 ` [PATCH 20/30] view: msg_html: stop using an anonymous sub Eric Wong
2019-12-25  7:50 ` [PATCH 21/30] contentid: no " Eric Wong
2019-12-25  7:50 ` [PATCH 22/30] wwwtext: avoid anonymous sub in response Eric Wong
2019-12-25  7:50 ` [PATCH 23/30] searchview: pass named subs to Www*Stream Eric Wong
2019-12-25  7:50 ` [PATCH 24/30] view: thread_html: pass named sub to WwwStream Eric Wong
2019-12-25  7:50 ` [PATCH 25/30] searchview: remove anonymous sub when sorting threads by relevance Eric Wong
2019-12-25  7:51 ` [PATCH 26/30] view: msg_iter calls add_body_text directly Eric Wong
2019-12-25  7:51 ` [PATCH 27/30] wwwattach: avoid anonymous sub for msg_iter Eric Wong
2019-12-25  7:51 ` [PATCH 28/30] viewvcs: avoid anonymous sub for HTML response Eric Wong
2019-12-25  7:51 ` [PATCH 29/30] solvergit: allow passing arg to user-supplied callback Eric Wong
2019-12-28  9:17   ` Eric Wong
2019-12-25  7:51 ` [PATCH 30/30] search: retry_reopen passes user arg to callback Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://public-inbox.org/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191225075104.22184-4-e@80x24.org \
    --to=e@80x24.org \
    --cc=meta@public-inbox.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).