[Bps-public-commit] r19083 - in Net-IMAP-Server: lib/Net/IMAP/Server
alexmv at bestpractical.com
alexmv at bestpractical.com
Tue Apr 7 13:42:44 EDT 2009
Author: alexmv
Date: Tue Apr 7 13:42:43 2009
New Revision: 19083
Modified:
Net-IMAP-Server/ (props changed)
Net-IMAP-Server/lib/Net/IMAP/Server/Mailbox.pm
Log:
r43850 at kohr-ah: chmrr | 2009-04-07 13:42:31 -0400
Smarter logic for when cardinality of range >> number of messages
Modified: Net-IMAP-Server/lib/Net/IMAP/Server/Mailbox.pm
==============================================================================
--- Net-IMAP-Server/lib/Net/IMAP/Server/Mailbox.pm (original)
+++ Net-IMAP-Server/lib/Net/IMAP/Server/Mailbox.pm Tue Apr 7 13:42:43 2009
@@ -529,6 +529,37 @@
and Net::IMAP::Server->connection->selected eq $self;
}
+=for private
+
+This method exists to choose the most apppriate strategy to take the
+intersection of (uids asked for) n (uids we have), by examining the
+cardinality of each set, and iterating over the smaller of the two.
+This is particularly important, as many clients try to fetch UIDs 1:*,
+which will exhaust memory if the naive approach is taken, and there is
+one message with UID 100_000_000.
+
+=cut
+
+sub _uids_in_range {
+ my $self = shift;
+ my ( $low, $high ) = @_;
+ ( $low, $high ) = ( $high, $low ) if $low > $high;
+
+ my $count = scalar @{ $self->messages };
+ if ( $high - $low > $count ) {
+
+ # More UIDs to enumerate than we actually have; check each
+ # existing UID for being in the range
+ return grep {$_ >= $low and $_ <= $high} map $_->uid, @{ $self->messages };
+ } else {
+
+ # More messages than in the UID range; enumerate the range and
+ # check each against UIDs which exist
+ my $uids = $self->uids;
+ return grep {defined $uids->{$_}} $low .. $high;
+ }
+}
+
=head3 get_uids STR
Parses and returns messages fitting the given UID range.
@@ -540,24 +571,24 @@
my $str = shift;
# Otherwise $self->messages->[-1] explodes
- return () unless @{$self->messages};
+ return () unless @{ $self->messages };
- my %ids;
+ my %found;
+ my $last = $self->messages->[-1]->uid;
+ my $uids = $self->uids;
for ( split ',', $str ) {
if (/^(\d+):(\d+)$/) {
- $ids{$_}++ for $2 > $1 ? $1 .. $2 : $2 .. $1;
+ @found{ $self->_uids_in_range( $1, $2 ) } = ();
} elsif ( /^(\d+):\*$/ or /^\*:(\d+)$/ ) {
- $ids{$_}++
- for $self->messages->[-1]->uid,
- $1 .. $self->messages->[-1]->uid;
+ $found{$last}++;
+ $found{ $self->_uids_in_range( $1, $last ) } = ();
} elsif (/^(\d+)$/) {
- $ids{$1}++;
+ $found{$_}++ if defined $uids->{$1};
} elsif (/^\*$/) {
- $ids{ $self->messages->[-1]->uid }++;
+ $found{$last}++;
}
}
- return
- grep {defined} map { $self->uids->{$_} } sort { $a <=> $b } keys %ids;
+ return map { $uids->{$_} } sort { $a <=> $b } keys %found;
}
=head3 get_messages STR
More information about the Bps-public-commit
mailing list