We want to minimize the time any large objects or strings
are referenced. We can do threading entirely from the
mini_mime-generated messages and lazilly load full messages
when rendering the display.
my $mid = mid_compressed($ctx->{mid});
my $res = $srch->get_thread($mid);
my $rv = '';
my $mid = mid_compressed($ctx->{mid});
my $res = $srch->get_thread($mid);
my $rv = '';
- my $msgs = load_results($ctx, $res);
+ my $msgs = load_results($res);
my $nr = scalar @$msgs;
return $rv if $nr == 0;
require PublicInbox::Thread;
my $nr = scalar @$msgs;
return $rv if $nr == 0;
require PublicInbox::Thread;
$th->thread;
$th->order(*PublicInbox::Thread::sort_ts);
my $state = [ $srch, { root_anchor => anchor_for($mid) }, undef, 0 ];
$th->thread;
$th->order(*PublicInbox::Thread::sort_ts);
my $state = [ $srch, { root_anchor => anchor_for($mid) }, undef, 0 ];
- thread_entry(\$rv, $state, $_, 0) for $th->rootset;
+ {
+ require PublicInbox::GitCatFile;
+ my $git = PublicInbox::GitCatFile->new($ctx->{git_dir});
+ thread_entry(\$rv, $git, $state, $_, 0) for $th->rootset;
+ }
my $final_anchor = $state->[3];
my $next = "<a\nid=\"s$final_anchor\">";
my $final_anchor = $state->[3];
my $next = "<a\nid=\"s$final_anchor\">";
my $path = $ctx->{subject_path};
my $res = $srch->get_subject_path($path);
my $rv = '';
my $path = $ctx->{subject_path};
my $res = $srch->get_subject_path($path);
my $rv = '';
- my $msgs = load_results($ctx, $res);
+ my $msgs = load_results($res);
my $nr = scalar @$msgs;
return $rv if $nr == 0;
require PublicInbox::Thread;
my $nr = scalar @$msgs;
return $rv if $nr == 0;
require PublicInbox::Thread;
$th->thread;
$th->order(*PublicInbox::Thread::sort_ts);
my $state = [ $srch, { root_anchor => 'dummy' }, undef, 0 ];
$th->thread;
$th->order(*PublicInbox::Thread::sort_ts);
my $state = [ $srch, { root_anchor => 'dummy' }, undef, 0 ];
- thread_entry(\$rv, $state, $_, 0) for $th->rootset;
+ {
+ require PublicInbox::GitCatFile;
+ my $git = PublicInbox::GitCatFile->new($ctx->{git_dir});
+ thread_entry(\$rv, $git, $state, $_, 0) for $th->rootset;
+ }
my $final_anchor = $state->[3];
my $next = "<a\nid=\"s$final_anchor\">end of thread</a>\n";
my $final_anchor = $state->[3];
my $next = "<a\nid=\"s$final_anchor\">end of thread</a>\n";
my $ct = $part->content_type;
# account for filter bugs...
my $ct = $part->content_type;
# account for filter bugs...
- return '' if defined $ct && $ct =~ m!\btext/[xh]+tml\b!i;
+ if (defined $ct && $ct =~ m!\btext/[xh]+tml\b!i) {
+ $part->body_set('');
+ return '';
+ }
my $enc = enc_for($ct, $enc_msg);
my $enc = enc_for($ct, $enc_msg);
# kill per-line trailing whitespace
$s =~ s/[ \t]+$//sgm;
# kill per-line trailing whitespace
$s =~ s/[ \t]+$//sgm;
+ $rv .= $s;
+ $s = undef;
+ $rv .= "\n";
sub add_text_body {
my ($enc, $part, $part_nr, $full_pfx) = @_;
my $n = 0;
sub add_text_body {
my ($enc, $part, $part_nr, $full_pfx) = @_;
my $n = 0;
- my $s = ascii_html($enc->decode($part->body));
+ my $nr = 0;
+ my $s = $part->body;
+ $part->body_set('');
+ $s = $enc->decode($s);
+ $s = ascii_html($s);
my @lines = split(/\n/, $s);
$s = '';
my @lines = split(/\n/, $s);
$s = '';
my @quot;
while (defined(my $cur = shift @lines)) {
if ($cur !~ /^>/) {
my @quot;
while (defined(my $cur = shift @lines)) {
if ($cur !~ /^>/) {
sub thread_followups {
my ($dst, $root, $res) = @_;
sub thread_followups {
my ($dst, $root, $res) = @_;
- my @msgs = map { $_->mini_mime } @{$res->{msgs}};
+ my $msgs = load_results($res);
require PublicInbox::Thread;
$root->header_set('X-PI-TS', '0');
require PublicInbox::Thread;
$root->header_set('X-PI-TS', '0');
- my $th = PublicInbox::Thread->new($root, @msgs);
+ my $th = PublicInbox::Thread->new($root, @$msgs);
$th->thread;
$th->order(*PublicInbox::Thread::sort_ts);
my $srch = $res->{srch};
$th->thread;
$th->order(*PublicInbox::Thread::sort_ts);
my $srch = $res->{srch};
- my ($dst, $state, $node, $level) = @_;
+ my ($dst, $git, $state, $node, $level) = @_;
# $state = [ $search_res, $seen, undef, 0 (msg_nr) ];
# $seen is overloaded with 3 types of fields:
# 1) "root_anchor" => anchor_for(Message-ID),
# 2) seen subject hashes: sha1(subject) => 1
# 3) anchors hashes: "#$sha1_hex" (same as $seen in index_entry)
if (my $mime = $node->message) {
# $state = [ $search_res, $seen, undef, 0 (msg_nr) ];
# $seen is overloaded with 3 types of fields:
# 1) "root_anchor" => anchor_for(Message-ID),
# 2) seen subject hashes: sha1(subject) => 1
# 3) anchors hashes: "#$sha1_hex" (same as $seen in index_entry)
if (my $mime = $node->message) {
- if (length($$dst) == 0) {
- $$dst .= thread_html_head($mime);
+
+ # lazy load the full message from mini_mime:
+ my $path = mid2path(mid_clean($mime->header('Message-ID')));
+ $mime = eval { Email::MIME->new($git->cat_file("HEAD:$path")) };
+ if ($mime) {
+ if (length($$dst) == 0) {
+ $$dst .= thread_html_head($mime);
+ }
+ $$dst .= index_entry(undef, $mime, $level, $state);
- $$dst .= index_entry(undef, $mime, $level, $state);
- thread_entry($dst, $state, $node->child, $level + 1) if $node->child;
- thread_entry($dst, $state, $node->next, $level) if $node->next;
+ my $cur;
+ $cur = $node->child and
+ thread_entry($dst, $git, $state, $cur, $level + 1);
+ $cur = $node->next and
+ thread_entry($dst, $git, $state, $cur, $level);
- my ($ctx, $res) = @_;
-
- require PublicInbox::GitCatFile;
- my $git = PublicInbox::GitCatFile->new($ctx->{git_dir});
- my @msgs;
- while (my $smsg = shift @{$res->{msgs}}) {
- my $m = $smsg->mid;
- my $path = mid2path($m);
-
- # FIXME: duplicated code from Feed.pm
- my $mime = eval {
- my $str = $git->cat_file("HEAD:$path");
- Email::MIME->new($str);
- };
- unless ($@) {
- $mime->header_set('X-PI-TS', msg_timestamp($mime));
- push @msgs, $mime;
- }
- }
- \@msgs;
+ my ($res) = @_;
+
+ [ map { $_->mini_mime } @{delete $res->{msgs}} ];