about summary refs log tree commit homepage
path: root/lib/PublicInbox/GitAsyncCat.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/GitAsyncCat.pm')
-rw-r--r--lib/PublicInbox/GitAsyncCat.pm53
1 files changed, 53 insertions, 0 deletions
diff --git a/lib/PublicInbox/GitAsyncCat.pm b/lib/PublicInbox/GitAsyncCat.pm
new file mode 100644
index 00000000..f57e0336
--- /dev/null
+++ b/lib/PublicInbox/GitAsyncCat.pm
@@ -0,0 +1,53 @@
+# Copyright (C) all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+package PublicInbox::GitAsyncCat;
+use v5.12;
+use parent qw(Exporter);
+our @EXPORT = qw(ibx_async_cat ibx_async_prefetch async_check);
+
+our $GCF2C; # singleton PublicInbox::Gcf2Client
+
+sub ibx_async_cat ($$$$) {
+        my ($ibx, $oid, $cb, $arg) = @_;
+        my $isrch = $ibx->{isrch};
+        my $git = $isrch ? $isrch->{es}->git : ($ibx->{git} // $ibx->git);
+        # {topdir} means ExtSearch (likely [extindex "all"]) with potentially
+        # 100K alternates.  git v2.33+ can handle 100k alternates fairly well.
+        if (!$isrch && !defined($ibx->{topdir}) && !defined($git->{-tmp}) &&
+                ($GCF2C //= eval {
+                require PublicInbox::Gcf2Client;
+                PublicInbox::Gcf2Client::new();
+        } // 0)) { # 0: do not retry if libgit2 or Inline::C are missing
+                $GCF2C->gcf2_async("$oid $git->{git_dir}\n", $cb, $arg);
+                \undef;
+        } else { # read-only end of git-cat-file pipe
+                $git->cat_async($oid, $cb, $arg);
+                $git->watch_async;
+        }
+}
+
+sub async_check ($$$$) {
+        my ($ibx, $oidish, $cb, $arg) = @_; # $ibx may be $ctx
+        my $git = $ibx->{git} // $ibx->git;
+        $git->check_async($oidish, $cb, $arg);
+        ($git->{ck} // $git)->watch_async;
+}
+
+# this is safe to call inside $cb, but not guaranteed to enqueue
+# returns true if successful, undef if not.  For fairness, we only
+# prefetch if there's no in-flight requests.
+sub ibx_async_prefetch {
+        my ($ibx, $oid, $cb, $arg) = @_;
+        my $git = $ibx->git;
+        if (!defined($ibx->{topdir}) && $GCF2C) {
+                if (!@{$GCF2C->gcf_inflight // []}) {
+                        $oid .= " $git->{git_dir}\n";
+                        return $GCF2C->gcf2_async($oid, $cb, $arg); # true
+                }
+        } elsif ($git->{epwatch}) {
+                return $git->async_prefetch($oid, $cb, $arg);
+        }
+        undef;
+}
+
+1;