From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 6AC4B1FBDF for ; Wed, 10 Jun 2020 07:07:30 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 59/82] imap: UID FETCH: optimize for smsg-only case Date: Wed, 10 Jun 2020 07:04:56 +0000 Message-Id: <20200610070519.18252-60-e@yhbt.net> In-Reply-To: <20200610070519.18252-1-e@yhbt.net> References: <20200610070519.18252-1-e@yhbt.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: 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 | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index 3fae81112aa..0fe31a77244 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -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