]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Inbox.pm
search: remove {over_ro} field
[public-inbox.git] / lib / PublicInbox / Inbox.pm
index 186eb420255e481c8adc5a3faea0d98c433f1ac5..3b5ac970d07cf43af6d86b656d92606f108cefc9 100644 (file)
@@ -7,7 +7,7 @@ use strict;
 use warnings;
 use PublicInbox::Git;
 use PublicInbox::MID qw(mid2path);
-use PublicInbox::MIME;
+use PublicInbox::Eml;
 
 # Long-running "git-cat-file --batch" processes won't notice
 # unlinked packs, so we need to restart those processes occasionally.
@@ -18,13 +18,20 @@ my $cleanup_timer;
 my $cleanup_avail = -1; # 0, or 1
 my $have_devel_peek;
 my $CLEANUP = {}; # string(inbox) -> inbox
+
+sub git_cleanup ($) {
+       my ($self) = @_;
+       my $git = $self->{git} or return;
+       $git->cleanup;
+}
+
 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)) {
+                       foreach my $f (qw(search)) {
                                # we bump refcnt by assigning tmp, here:
                                my $tmp = $ibx->{$f} or next;
                                next if Devel::Peek::SvREFCNT($tmp) > 2;
@@ -32,17 +39,15 @@ sub cleanup_task () {
                                # refcnt is zero when tmp is out-of-scope
                        }
                }
-               if (my $git = $ibx->{git}) {
-                       $again = $git->cleanup;
-               }
+               git_cleanup($ibx);
                if (my $gits = $ibx->{-repo_objs}) {
                        foreach my $git (@$gits) {
                                $again = 1 if $git->cleanup;
                        }
                }
+               check_inodes($ibx);
                if ($have_devel_peek) {
-                       $again ||= !!($ibx->{over} || $ibx->{mm} ||
-                                     $ibx->{search});
+                       $again ||= !!$ibx->{search};
                }
                $next->{"$ibx"} = $ibx if $again;
        }
@@ -102,7 +107,7 @@ sub _set_limiter ($$$) {
 
 sub new {
        my ($class, $opts) = @_;
-       my $v = $opts->{address} ||= 'public-inbox@example.com';
+       my $v = $opts->{address} ||= [ 'public-inbox@example.com' ];
        my $p = $opts->{-primary_address} = ref($v) eq 'ARRAY' ? $v->[0] : $v;
        $opts->{domain} = ($p =~ /\@(\S+)\z/) ? $1 : 'localhost';
        my $pi_config = delete $opts->{-pi_config};
@@ -157,7 +162,7 @@ sub max_git_epoch {
        my $cur = $self->{-max_git_epoch};
        my $changed = git($self)->alternates_changed;
        if (!defined($cur) || $changed) {
-               $self->git->cleanup if $changed;
+               git_cleanup($self) if $changed;
                my $gits = "$self->{inboxdir}/git";
                if (opendir my $dh, $gits) {
                        my $max = -1;
@@ -177,7 +182,6 @@ sub mm {
        my ($self) = @_;
        $self->{mm} ||= eval {
                require PublicInbox::Msgmap;
-               _cleanup_later($self);
                my $dir = $self->{inboxdir};
                if ($self->version >= 2) {
                        PublicInbox::Msgmap->new_file("$dir/msgmap.sqlite3");
@@ -187,24 +191,28 @@ sub mm {
        };
 }
 
-sub search ($;$) {
-       my ($self, $over_only) = @_;
+sub search ($;$$) {
+       my ($self, $over_only, $ctx) = @_;
        my $srch = $self->{search} ||= eval {
                _cleanup_later($self);
                require PublicInbox::Search;
                PublicInbox::Search->new($self);
        };
-       ($over_only || eval { $srch->xdb }) ? $srch : undef;
+       ($over_only || eval { $srch->xdb }) ? $srch : do {
+               $ctx and $ctx->{env}->{'psgi.errors'}->print(<<EOF);
+`$self->{name}' search went away unexpectedly
+EOF
+               undef;
+       };
 }
 
-sub over ($) {
-       my ($self) = @_;
-       my $srch = search($self, 1) or return;
-       $self->{over} ||= eval {
-               my $over = $srch->{over_ro};
-               $over->dbh_new; # may fail
+sub over {
+       $_[0]->{over} //= eval {
+               my $srch = search($_[0], 1) or return;
+               my $over = PublicInbox::Over->new("$srch->{xpfx}/over.sqlite3");
+               $over->dbh; # may fail
                $over;
-       }
+       };
 }
 
 sub try_cat {
@@ -223,6 +231,7 @@ sub description {
                my $desc = try_cat("$self->{inboxdir}/description");
                local $/ = "\n";
                chomp $desc;
+               utf8::decode($desc);
                $desc =~ s/\s+/ /smg;
                $desc eq '' ? undef : $desc;
        }) // '($INBOX_DIR/description missing)';
@@ -309,28 +318,28 @@ sub nntp_usable {
 }
 
 # for v1 users w/o SQLite only
-sub msg_by_path ($$;$) {
-       my ($self, $path, $ref) = @_;
-       git($self)->cat_file('HEAD:'.$path, $ref);
+sub msg_by_path ($$) {
+       my ($self, $path) = @_;
+       git($self)->cat_file('HEAD:'.$path);
 }
 
-sub msg_by_smsg ($$;$) {
-       my ($self, $smsg, $ref) = @_;
+sub msg_by_smsg ($$) {
+       my ($self, $smsg) = @_;
 
        # ghosts may have undef smsg (from SearchThread.node) or
        # no {blob} field
        return unless defined $smsg;
        defined(my $blob = $smsg->{blob}) or return;
 
-       git($self)->cat_file($blob, $ref);
+       git($self)->cat_file($blob);
 }
 
-sub smsg_mime {
-       my ($self, $smsg, $ref) = @_;
-       if (my $s = msg_by_smsg($self, $smsg, $ref)) {
-               $smsg->{mime} = PublicInbox::MIME->new($s);
-               return $smsg;
-       }
+sub smsg_eml {
+       my ($self, $smsg) = @_;
+       my $bref = msg_by_smsg($self, $smsg) or return;
+       my $eml = PublicInbox::Eml->new($bref);
+       $smsg->populate($eml) unless exists($smsg->{num}); # v1 w/o SQLite
+       $eml;
 }
 
 sub mid2num($$) {
@@ -348,14 +357,14 @@ sub smsg_by_mid ($$) {
        PublicInbox::Smsg::psgi_cull($smsg);
 }
 
-sub msg_by_mid ($$;$) {
-       my ($self, $mid, $ref) = @_;
+sub msg_by_mid ($$) {
+       my ($self, $mid) = @_;
 
        over($self) or
-               return msg_by_path($self, mid2path($mid), $ref);
+               return msg_by_path($self, mid2path($mid));
 
        my $smsg = smsg_by_mid($self, $mid);
-       $smsg ? msg_by_smsg($self, $smsg, $ref) : undef;
+       $smsg ? msg_by_smsg($self, $smsg) : undef;
 }
 
 sub recent {
@@ -390,4 +399,33 @@ sub altid_map ($) {
        } // {};
 }
 
+# $obj must respond to ->on_inbox_unlock, which takes Inbox ($self) as an arg
+sub subscribe_unlock {
+       my ($self, $ident, $obj) = @_;
+       $self->{unlock_subs}->{$ident} = $obj;
+}
+
+sub unsubscribe_unlock {
+       my ($self, $ident) = @_;
+       delete $self->{unlock_subs}->{$ident};
+}
+
+sub check_inodes ($) {
+       my ($self) = @_;
+       for (qw(over mm)) { # TODO: search
+               $self->{$_}->check_inodes if $self->{$_};
+       }
+}
+
+# called by inotify
+sub on_unlock {
+       my ($self) = @_;
+       check_inodes($self);
+       my $subs = $self->{unlock_subs} or return;
+       for (values %$subs) {
+               eval { $_->on_inbox_unlock($self) };
+               warn "E: $@ ($self->{inboxdir})\n" if $@;
+       }
+}
+
 1;