about summary refs log tree commit homepage
path: root/lib/PublicInbox/Inbox.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/Inbox.pm')
-rw-r--r--lib/PublicInbox/Inbox.pm101
1 files changed, 87 insertions, 14 deletions
diff --git a/lib/PublicInbox/Inbox.pm b/lib/PublicInbox/Inbox.pm
index 2ec2be69..706089ca 100644
--- a/lib/PublicInbox/Inbox.pm
+++ b/lib/PublicInbox/Inbox.pm
@@ -8,6 +8,8 @@ use warnings;
 use PublicInbox::Git;
 use PublicInbox::MID qw(mid2path);
 use Devel::Peek qw(SvREFCNT);
+use PublicInbox::MIME;
+use POSIX qw(strftime);
 
 my $cleanup_timer;
 eval {
@@ -29,6 +31,7 @@ sub cleanup_task () {
 
 sub _cleanup_later ($) {
         my ($self) = @_;
+        return unless PublicInbox::EvCleanup::enabled();
         $cleanup_timer ||= PublicInbox::EvCleanup::later(*cleanup_task);
         $CLEANUP->{"$self"} = $self;
 }
@@ -73,24 +76,71 @@ sub new {
         _set_limiter($opts, $pi_config, 'httpbackend');
         _set_uint($opts, 'feedmax', 25);
         $opts->{nntpserver} ||= $pi_config->{'publicinbox.nntpserver'};
+        my $dir = $opts->{mainrepo};
+        if (defined $dir && -f "$dir/inbox.lock") {
+                $opts->{version} = 2;
+        }
         bless $opts, $class;
 }
 
+sub git_part {
+        my ($self, $part) = @_;
+        ($self->{version} || 1) == 2 or return;
+        $self->{"$part.git"} ||= eval {
+                my $git_dir = "$self->{mainrepo}/git/$part.git";
+                my $g = PublicInbox::Git->new($git_dir);
+                $g->{-httpbackend_limiter} = $self->{-httpbackend_limiter};
+                # no cleanup needed, we never cat-file off this, only clone
+                $g;
+        };
+}
+
 sub git {
         my ($self) = @_;
         $self->{git} ||= eval {
-                my $g = PublicInbox::Git->new($self->{mainrepo});
+                my $git_dir = $self->{mainrepo};
+                $git_dir .= '/all.git' if (($self->{version} || 1) == 2);
+                my $g = PublicInbox::Git->new($git_dir);
                 $g->{-httpbackend_limiter} = $self->{-httpbackend_limiter};
                 _cleanup_later($self);
                 $g;
         };
 }
 
+sub max_git_part {
+        my ($self) = @_;
+        my $v = $self->{version};
+        return unless defined($v) && $v == 2;
+        my $part = $self->{-max_git_part};
+        my $changed = git($self)->alternates_changed;
+        if (!defined($part) || $changed) {
+                $self->git->cleanup if $changed;
+                my $gits = "$self->{mainrepo}/git";
+                if (opendir my $dh, $gits) {
+                        my $max = -1;
+                        while (defined(my $git_dir = readdir($dh))) {
+                                $git_dir =~ m!\A(\d+)\.git\z! or next;
+                                $max = $1 if $1 > $max;
+                        }
+                        $part = $self->{-max_git_part} = $max if $max >= 0;
+                } else {
+                        warn "opendir $gits failed: $!\n";
+                }
+        }
+        $part;
+}
+
 sub mm {
         my ($self) = @_;
         $self->{mm} ||= eval {
+                require PublicInbox::Msgmap;
                 _cleanup_later($self);
-                PublicInbox::Msgmap->new($self->{mainrepo});
+                my $dir = $self->{mainrepo};
+                if (($self->{version} || 1) >= 2) {
+                        PublicInbox::Msgmap->new_file("$dir/msgmap.sqlite3");
+                } else {
+                        PublicInbox::Msgmap->new($dir);
+                }
         };
 }
 
@@ -98,7 +148,7 @@ sub search {
         my ($self) = @_;
         $self->{search} ||= eval {
                 _cleanup_later($self);
-                PublicInbox::Search->new($self->{mainrepo}, $self->{altid});
+                PublicInbox::Search->new($self, $self->{altid});
         };
 }
 
@@ -120,7 +170,7 @@ sub description {
         local $/ = "\n";
         chomp $desc;
         $desc =~ s/\s+/ /smg;
-        $desc = '($GIT_DIR/description missing)' if $desc eq '';
+        $desc = '($REPO_DIR/description missing)' if $desc eq '';
         $self->{description} = $desc;
 }
 
@@ -222,26 +272,49 @@ sub msg_by_path ($$;$) {
 sub msg_by_smsg ($$;$) {
         my ($self, $smsg, $ref) = @_;
 
-        return unless defined $smsg; # ghost
-
-        # backwards compat to fallback to msg_by_mid
-        # TODO: remove if we bump SCHEMA_VERSION in Search.pm:
-        defined(my $blob = $smsg->{blob}) or
-                        return msg_by_mid($self, $smsg->mid);
+        # ghosts may have undef smsg (from SearchThread.node) or
+        # no {blob} field
+        return unless defined $smsg;
+        defined(my $blob = $smsg->{blob}) or return;
 
         my $str = git($self)->cat_file($blob, $ref);
         $$str =~ s/\A[\r\n]*From [^\r\n]*\r?\n//s if $str;
         $str;
 }
 
-sub path_check {
-        my ($self, $path) = @_;
-        git($self)->check('HEAD:'.$path);
+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 mid2num($$) {
+        my ($self, $mid) = @_;
+        my $mm = mm($self) or return;
+        $mm->num_for($mid);
+}
+
+sub smsg_by_mid ($$) {
+        my ($self, $mid) = @_;
+        my $srch = search($self) or return;
+        # favor the Message-ID we used for the NNTP article number:
+        my $num = mid2num($self, $mid);
+        defined $num ? $srch->lookup_article($num) : undef;
 }
 
 sub msg_by_mid ($$;$) {
         my ($self, $mid, $ref) = @_;
-        msg_by_path($self, mid2path($mid), $ref);
+        my $srch = search($self) or
+                return msg_by_path($self, mid2path($mid), $ref);
+        my $smsg = smsg_by_mid($self, $mid);
+        $smsg ? msg_by_smsg($self, $smsg, $ref) : undef;
+}
+
+sub recent {
+        my ($self, $opts, $after, $before) = @_;
+        search($self)->{over_ro}->recent($opts, $after, $before);
 }
 
 1;