about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-01-19 05:25:30 +0000
committerEric Wong <e@80x24.org>2019-01-20 04:24:54 +0000
commit915cd090798069a44dbb4b4c243bff9af2ae1b76 (patch)
tree5899b4cc1df3f5b57c989fe75d4dcc35b9a2f406
parent7fa037d0be9d1a8b891084a3c1215a1af5aa886b (diff)
downloadpublic-inbox-915cd090798069a44dbb4b4c243bff9af2ae1b76.tar.gz
A bit messy at the moment, but we need to break this up
into smaller steps for fairness with other clients, as
applying dozens of patches can take several hundred
milliseconds.
-rw-r--r--lib/PublicInbox/SolverGit.pm70
1 files changed, 31 insertions, 39 deletions
diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm
index 71494e07..70d8a934 100644
--- a/lib/PublicInbox/SolverGit.pm
+++ b/lib/PublicInbox/SolverGit.pm
@@ -290,16 +290,35 @@ sub di_url ($) {
         defined($url) ? "$url$mid/" : "<$mid>";
 }
 
-sub apply_patches ($$$$$) {
-        my ($self, $out, $wt, $found, $patches) = @_;
+sub apply_patches_cb ($$$$$) {
+        my ($self, $out, $found, $patches, $oid_b) = @_;
+        my $wt = do_git_init_wt($self);
         my $wt_dir = $wt->dirname;
         my $wt_git = PublicInbox::Git->new("$wt_dir/.git");
         $wt_git->{-wt} = $wt;
 
         my $cur = 0;
         my $tot = scalar @$patches;
+        my ($apply_pid, $rd, $di);
+
+        # returns an empty string if in progress, undef if not found,
+        # or the final [ ::Git, oid_full, type, size, $di ] arrayref
+        # if found
+        sub {
+                if ($rd) {
+                        $found->{$di->{oid_b}} =
+                                        do_apply_end($out, $wt_git, $rd, $di);
+                        $rd = undef;
+                        # continue to shift @$patches
+                } elsif ($apply_pid) {
+                        $rd = do_apply_continue($wt_dir, $apply_pid);
+                        $apply_pid = undef;
+                        return ''; # $rd => do_apply_ned
+                }
+
+                # may return undef here
+                $di = shift @$patches or return $found->{$oid_b};
 
-        foreach my $di (@$patches) {
                 my $i = ++$cur;
                 my $oid_a = $di->{oid_a};
                 my $existing = $found->{$oid_a};
@@ -321,29 +340,10 @@ sub apply_patches ($$$$$) {
                            join('', @{$di->{hdr_lines}}), "\n"
                         or die "print \$out failed: $!";
 
-                # apply the patch!
-                my $apply_pid = do_apply_begin($out, $wt_dir, $di);
-                my $rd = do_apply_continue($wt_dir, $apply_pid);
-                $found->{$di->{oid_b}} = do_apply_end($out, $wt_git, $rd, $di);
-        }
-}
-
-sub dump_found ($$) {
-        my ($out, $found) = @_;
-        foreach my $oid (sort keys %$found) {
-                my ($git, $oid, undef, undef, $di) = @{$found->{$oid}};
-                my $loc = $di ? di_url($di) : $git->src_blob_url($oid);
-                print $out "$oid from $loc\n";
-        }
-}
-
-sub dump_patches ($$) {
-        my ($out, $patches) = @_;
-        my $tot = scalar(@$patches);
-        my $i = 0;
-        foreach my $di (@$patches) {
-                ++$i;
-                print $out "[$i/$tot] ", di_url($di), "\n";
+                # begin the patch application patch!
+                $apply_pid = do_apply_begin($out, $wt_dir, $di);
+                # next call to this callback will call do_apply_continue
+                '';
         }
 }
 
@@ -415,24 +415,16 @@ sub solve ($$$$) {
 
         unless (scalar(@$patches)) {
                 print $out "no patch(es) for $oid_b\n";
-                dump_found($out, $found);
                 return;
         }
 
         # reconstruct the oid_b blob using patches we found:
-        eval {
-                my $wt = do_git_init_wt($self);
-                apply_patches($self, $out, $wt, $found, $patches);
-        };
-        if ($@) {
-                print $out "E: $@\nfound: ";
-                dump_found($out, $found);
-                print $out "patches: ";
-                dump_patches($out, $patches);
-                return;
+        my $cb = apply_patches_cb($self, $out, $found, $patches, $oid_b);
+        my $ret;
+        while (1) {
+                $ret = $cb->();
+                return $ret if (ref($ret) || !defined($ret));
         }
-
-        $found->{$oid_b};
 }
 
 1;