]> Sergey Matveev's repositories - public-inbox.git/commitdiff
imap: UID FETCH: optimize for smsg-only case
authorEric Wong <e@yhbt.net>
Wed, 10 Jun 2020 07:04:56 +0000 (07:04 +0000)
committerEric Wong <e@yhbt.net>
Sat, 13 Jun 2020 07:55:45 +0000 (07:55 +0000)
We can avoid loading the entire message from git when mutt makes
a "UID FETCH" request for "(UID FLAGS)".  This speeds mutt up by
more than an order-of-magnitude in informal measurements.

lib/PublicInbox/IMAP.pm

index 3fae81112aaae403472c6af1a6755b1afaa133e2..0fe31a77244d16b07e211763b6e4cd4d256a546a 100644 (file)
@@ -45,7 +45,7 @@ sub NEED_BLOB () { 1 }
 sub NEED_EML () { NEED_BLOB|2 }
 my $OP_EML_NEW = [ NEED_EML - 1, \&op_eml_new ];
 
-my %FETCH_NEED = ( # for future optimization
+my %FETCH_NEED = (
        'BODY[HEADER]' => [ NEED_EML, \&emit_rfc822_header ],
        'BODY[TEXT]' => [ NEED_EML, \&emit_rfc822_text ],
        'BODY[]' => [ NEED_BLOB, \&emit_rfc822 ],
@@ -546,7 +546,7 @@ sub refill_range ($$$) {
        undef; # keep looping
 }
 
-sub uid_fetch_m { # long_response
+sub uid_fetch_msg { # long_response
        my ($self, $tag, $msgs, $range_info) = @_; # \@ops, \@partial
        while (!@$msgs) { # rare
                if (my $end = refill_range($self, $msgs, $range_info)) {
@@ -558,6 +558,26 @@ sub uid_fetch_m { # long_response
                        \&uid_fetch_cb, \@_);
 }
 
+sub uid_fetch_smsg { # long_response
+       my ($self, $tag, $msgs, $range_info, $ops) = @_;
+       while (!@$msgs) { # rare
+               if (my $end = refill_range($self, $msgs, $range_info)) {
+                       $self->write(\"$tag $end\r\n");
+                       return;
+               }
+       }
+       for my $smsg (@$msgs) {
+               $self->msg_more("* $smsg->{num} FETCH (UID $smsg->{num}");
+               for (my $i = 0; $i < @$ops;) {
+                       my $k = $ops->[$i++];
+                       $ops->[$i++]->($self, $k, $smsg);
+               }
+               $self->msg_more(")\r\n");
+       }
+       @$msgs = ();
+       1; # more
+}
+
 sub cmd_status ($$$;@) {
        my ($self, $tag, $mailbox, @items) = @_;
        return "$tag BAD no items\r\n" if !scalar(@items);
@@ -774,7 +794,7 @@ sub fetch_compile ($) {
                $r[2] = [ map { [ $_, @{$partial{$_}} ] } sort keys %partial ];
        }
 
-       $r[0] = $need;
+       $r[0] = $need ? \&uid_fetch_msg : \&uid_fetch_smsg;
 
        # r[1] = [ $key1, $cb1, $key2, $cb2, ... ]
        use sort 'stable'; # makes output more consistent
@@ -785,15 +805,13 @@ sub fetch_compile ($) {
 sub cmd_uid_fetch ($$$;@) {
        my ($self, $tag, $range_csv, @want) = @_;
        my $ibx = $self->{ibx} or return "$tag BAD No mailbox selected\r\n";
-       my ($need, $ops, $partial) = fetch_compile(\@want);
-       return "$tag $need\r\n" unless $ops;
+       my ($cb, $ops, $partial) = fetch_compile(\@want);
+       return "$tag $cb\r\n" unless $ops;
 
        $range_csv = 'bad' if $range_csv !~ $valid_range;
        my $range_info = range_step($self, \$range_csv);
        return "$tag $range_info\r\n" if !ref($range_info);
-
-       long_response($self, \&uid_fetch_m,
-                       $tag, [], $range_info, $ops, $partial);
+       long_response($self, $cb, $tag, [], $range_info, $ops, $partial);
 }
 
 sub parse_date ($) { # 02-Oct-1993