+ my $gitish = $GCF2C //= eval {
+ require PublicInbox::Gcf2;
+ require PublicInbox::Gcf2Client;
+ PublicInbox::Gcf2Client::new();
+ } // 0; # 0: do not retry if libgit2 or Inline::C are missing
+ if ($gitish) { # Gcf2 active, {inflight} may be unset due to errors
+ $GCF2C->{inflight} or
+ $gitish = $GCF2C = PublicInbox::Gcf2Client::new();
+ $oid .= " $git->{git_dir}";
+ } else {
+ $gitish = $git;
+ }
+ $gitish->cat_async($oid, $cb, $arg);
+ $gitish->{async_cat} //= do {
+ # read-only end of pipe (Gcf2Client is write-only end)
+ my $self = bless { gitish => $gitish }, __PACKAGE__;
+ $gitish->{in}->blocking(0);
+ $self->SUPER::new($gitish->{in}, EPOLLIN|EPOLLET);
+ \undef; # this is a true ref()
+ };
+}
+
+# this is safe to call inside $cb, but not guaranteed to enqueue
+# returns true if successful, undef if not.
+sub git_async_prefetch {
+ my ($git, $oid, $cb, $arg) = @_;
+ if ($GCF2C) {
+ if ($GCF2C->{async_cat} && !$GCF2C->{wbuf}) {
+ $oid .= " $git->{git_dir}";
+ return $GCF2C->cat_async($oid, $cb, $arg);
+ }
+ } elsif ($git->{async_cat} && (my $inflight = $git->{inflight})) {
+ # we could use MAX_INFLIGHT here w/o the halving,
+ # but lets not allow one client to monopolize a git process
+ if (@$inflight < int(PublicInbox::Git::MAX_INFLIGHT/2)) {
+ print { $git->{out} } $oid, "\n" or
+ $git->fail("write error: $!");
+ return push(@$inflight, $oid, $cb, $arg);
+ }
+ }
+ undef;