+use PublicInbox::MID qw(mid2path);
+use PublicInbox::MIME;
+
+# Long-running "git-cat-file --batch" processes won't notice
+# unlinked packs, so we need to restart those processes occasionally.
+# Xapian and SQLite file handles are mostly stable, but sometimes an
+# admin will attempt to replace them atomically after compact/vacuum
+# and we need to be prepared for that.
+my $cleanup_timer;
+my $cleanup_avail = -1; # 0, or 1
+my $have_devel_peek;
+my $CLEANUP = {}; # string(inbox) -> inbox
+sub cleanup_task () {
+ $cleanup_timer = undef;
+ my $next = {};
+ for my $ibx (values %$CLEANUP) {
+ my $again;
+ if ($have_devel_peek) {
+ foreach my $f (qw(mm search over)) {
+ # we bump refcnt by assigning tmp, here:
+ my $tmp = $ibx->{$f} or next;
+ next if Devel::Peek::SvREFCNT($tmp) > 2;
+ delete $ibx->{$f};
+ # refcnt is zero when tmp is out-of-scope
+ }
+ }
+ if (my $git = $ibx->{git}) {
+ $again = $git->cleanup;
+ }
+ if (my $gits = $ibx->{-repo_objs}) {
+ foreach my $git (@$gits) {
+ $again = 1 if $git->cleanup;
+ }
+ }
+ if ($have_devel_peek) {
+ $again ||= !!($ibx->{over} || $ibx->{mm} ||
+ $ibx->{search});
+ }
+ $next->{"$ibx"} = $ibx if $again;
+ }
+ $CLEANUP = $next;
+}
+
+sub cleanup_possible () {
+ # no need to require EvCleanup, here, if it were enabled another
+ # module would've require'd it, already
+ eval { PublicInbox::EvCleanup::enabled() } or return 0;
+
+ eval {
+ require Devel::Peek; # needs separate package in Fedora
+ $have_devel_peek = 1;
+ };
+ 1;
+}
+
+sub _cleanup_later ($) {
+ my ($self) = @_;
+ $cleanup_avail = cleanup_possible() if $cleanup_avail < 0;
+ return if $cleanup_avail != 1;
+ $cleanup_timer ||= PublicInbox::EvCleanup::later(*cleanup_task);
+ $CLEANUP->{"$self"} = $self;
+}
+
+sub _set_uint ($$$) {
+ my ($opts, $field, $default) = @_;
+ my $val = $opts->{$field};
+ if (defined $val) {
+ $val = $val->[-1] if ref($val) eq 'ARRAY';
+ $val = undef if $val !~ /\A[0-9]+\z/;
+ }
+ $opts->{$field} = $val || $default;
+}
+
+sub _set_limiter ($$$) {
+ my ($self, $pi_config, $pfx) = @_;
+ my $lkey = "-${pfx}_limiter";
+ $self->{$lkey} ||= eval {
+ # full key is: publicinbox.$NAME.httpbackendmax
+ my $mkey = $pfx.'max';
+ my $val = $self->{$mkey} or return;
+ my $lim;
+ if ($val =~ /\A[0-9]+\z/) {
+ require PublicInbox::Qspawn;
+ $lim = PublicInbox::Qspawn::Limiter->new($val);
+ } elsif ($val =~ /\A[a-z][a-z0-9]*\z/) {
+ $lim = $pi_config->limiter($val);
+ warn "$mkey limiter=$val not found\n" if !$lim;
+ } else {
+ warn "$mkey limiter=$val not understood\n";
+ }
+ $lim;
+ }
+}