X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FGcf2.pm;h=d13e6b1a2a6cc1a11582a90c1931ab1016a8e281;hb=refs%2Fheads%2Fmaster;hp=64945ca69cff7fa3cec96539fad0ac0a8f9bfe9d;hpb=c9c1aabe239378e50043e2a3d2e11c4e166cdda0;p=public-inbox.git diff --git a/lib/PublicInbox/Gcf2.pm b/lib/PublicInbox/Gcf2.pm index 64945ca6..d13e6b1a 100644 --- a/lib/PublicInbox/Gcf2.pm +++ b/lib/PublicInbox/Gcf2.pm @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2021 all contributors +# Copyright (C) all contributors # License: AGPL-3.0+ # backend for a git-cat-file-workalike based on libgit2, @@ -8,11 +8,14 @@ use strict; use v5.10.1; use PublicInbox::Spawn qw(which popen_rd); # may set PERL_INLINE_DIRECTORY use Fcntl qw(LOCK_EX SEEK_SET); +use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC); use IO::Handle; # autoflush +use PublicInbox::Git; + BEGIN { my (%CFG, $c_src); # PublicInbox::Spawn will set PERL_INLINE_DIRECTORY - # to ~/.cache/public-inbox/inline-c if it exists + # to ~/.cache/public-inbox/inline-c if it exists and Inline::C works my $inline_dir = $ENV{PERL_INLINE_DIRECTORY} // die 'PERL_INLINE_DIRECTORY not defined'; my $f = "$inline_dir/.public-inbox.lock"; @@ -77,7 +80,8 @@ EOM } sub add_alt ($$) { - my ($gcf2, $objdir) = @_; + my ($gcf2, $git_dir) = @_; + my $objdir = PublicInbox::Git->new($git_dir)->git_path('objects'); # libgit2 (tested 0.27.7+dfsg.1-0.2 and 0.28.3+dfsg.1-1~bpo10+1 # in Debian) doesn't handle relative epochs properly when nested @@ -96,33 +100,54 @@ sub add_alt ($$) { 1; } -# Usage: $^X -MPublicInbox::Gcf2 -e PublicInbox::Gcf2::loop +sub have_unlinked_files () { + # FIXME: port gcf2-like over to git.git so we won't need to + # deal with libgit2 + return 1 if $^O ne 'linux'; + open my $fh, '<', "/proc/$$/maps" or return; + while (<$fh>) { return 1 if /\.(?:idx|pack) \(deleted\)$/ } + undef; +} + +# Usage: $^X -MPublicInbox::Gcf2 -e PublicInbox::Gcf2::loop [EXPIRE-TIMEOUT] # (see lib/PublicInbox/Gcf2Client.pm) -sub loop () { +sub loop (;$) { + my $exp = $_[0] || $ARGV[0] || 60; # seconds my $gcf2 = new(); - my %seen; + my (%seen, $check_at); STDERR->autoflush(1); STDOUT->autoflush(1); while () { chomp; my ($oid, $git_dir) = split(/ /, $_, 2); - $seen{$git_dir} //= add_alt($gcf2, "$git_dir/objects"); + $seen{$git_dir} //= add_alt($gcf2, $git_dir); if (!$gcf2->cat_oid(1, $oid)) { # retry once if missing. We only get unabbreviated OIDs # from SQLite or Xapian DBs, here, so malicious clients # can't trigger excessive retries: - warn "I: $$ $oid missing, retrying in $git_dir\n"; + warn "# $$ $oid missing, retrying in $git_dir\n"; $gcf2 = new(); - %seen = ($git_dir => add_alt($gcf2,"$git_dir/objects")); + %seen = ($git_dir => add_alt($gcf2, $git_dir)); + $check_at = clock_gettime(CLOCK_MONOTONIC) + $exp; if ($gcf2->cat_oid(1, $oid)) { - warn "I: $$ $oid found after retry\n"; + warn "# $$ $oid found after retry\n"; } else { warn "W: $$ $oid missing after retry\n"; print "$oid missing\n"; # mimic git-cat-file } + } else { # check expiry to deal with deleted pack files + my $now = clock_gettime(CLOCK_MONOTONIC); + $check_at //= $now + $exp; + if ($now > $check_at) { + undef $check_at; + if (have_unlinked_files()) { + $gcf2 = new(); + %seen = (); + } + } } } }