about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2020-06-10 07:04:57 +0000
committerEric Wong <e@yhbt.net>2020-06-13 07:55:45 +0000
commite2d88cc7ee7f71d014a2be1a35e06dcb7fc77fd9 (patch)
treebcc57f635d6b9b5d038ff3d4cd8df40bcaf114ec
parent86c9cf7328b9e48501dabd1fb464b5e763e8f4b4 (diff)
downloadpublic-inbox-e2d88cc7ee7f71d014a2be1a35e06dcb7fc77fd9.tar.gz
We can speed up this common mutt request by another 2-3x by not
loading the entire smsg from SQLite, just the UID.
-rw-r--r--lib/PublicInbox/IMAP.pm42
1 files changed, 38 insertions, 4 deletions
diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm
index 0fe31a77..0d553da9 100644
--- a/lib/PublicInbox/IMAP.pm
+++ b/lib/PublicInbox/IMAP.pm
@@ -41,8 +41,9 @@ sub LINE_MAX () { 512 } # does RFC 3501 have a limit like RFC 977?
 sub UID_BLOCK () { 50_000 }
 
 # these values area also used for sorting
-sub NEED_BLOB () { 1 }
-sub NEED_EML () { NEED_BLOB|2 }
+sub NEED_SMSG () { 1 }
+sub NEED_BLOB () { NEED_SMSG|2 }
+sub NEED_EML () { NEED_BLOB|4 }
 my $OP_EML_NEW = [ NEED_EML - 1, \&op_eml_new ];
 
 my %FETCH_NEED = (
@@ -57,7 +58,7 @@ my %FETCH_NEED = (
         BODYSTRUCTURE => [ NEED_EML, \&emit_bodystructure ],
         ENVELOPE => [ NEED_EML, \&emit_envelope ],
         FLAGS => [ 0, \&emit_flags ],
-        INTERNALDATE => [ 0, \&emit_internaldate ],
+        INTERNALDATE => [ NEED_SMSG, \&emit_internaldate ],
 );
 my %FETCH_ATT = map { $_ => [ $_ ] } keys %FETCH_NEED;
 
@@ -578,6 +579,38 @@ sub uid_fetch_smsg { # long_response
         1; # more
 }
 
+sub uid_fetch_uid { # long_response
+        my ($self, $tag, $uids, $range_info, $ops) = @_;
+        while (!@$uids) { # rare
+                my ($beg, $end, $range_csv) = @$range_info;
+                if (scalar(@$uids = @{$self->{ibx}->over->
+                                        uid_range($beg, $end)})) {
+                        $range_info->[0] = $uids->[-1] + 1;
+                } elsif (!$range_csv) {
+                        $self->write(\"$tag OK Fetch done\r\n");
+                        return;
+                } else {
+                        my $next_range = range_step($self, \$range_csv);
+                        if (!ref($next_range)) { # error
+                                $self->write(\"$tag $next_range\r\n");
+                                return;
+                        }
+                        @$range_info = @$next_range;
+                }
+                # continue looping
+        }
+        for (@$uids) {
+                $self->msg_more("* $_ FETCH (UID $_");
+                for (my $i = 0; $i < @$ops;) {
+                        my $k = $ops->[$i++];
+                        $ops->[$i++]->($self, $k);
+                }
+                $self->msg_more(")\r\n");
+        }
+        @$uids = ();
+        1; # more
+}
+
 sub cmd_status ($$$;@) {
         my ($self, $tag, $mailbox, @items) = @_;
         return "$tag BAD no items\r\n" if !scalar(@items);
@@ -794,7 +827,8 @@ sub fetch_compile ($) {
                 $r[2] = [ map { [ $_, @{$partial{$_}} ] } sort keys %partial ];
         }
 
-        $r[0] = $need ? \&uid_fetch_msg : \&uid_fetch_smsg;
+        $r[0] = $need & NEED_BLOB ? \&uid_fetch_msg :
+                ($need & NEED_SMSG ? \&uid_fetch_smsg : \&uid_fetch_uid);
 
         # r[1] = [ $key1, $cb1, $key2, $cb2, ... ]
         use sort 'stable'; # makes output more consistent