# HG changeset patch # User Timo Sirainen # Date 1043127455 -7200 # Node ID 21788a1e9e3902ae265dff0b65bcb83c552b9508 # Parent 9c8df18fb2a9324b5dba7f3d63dbb038cbcf61f4 Partial fetches are working fast again - faster than ever actually. diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/imap/client.h --- a/src/imap/client.h Tue Jan 21 07:36:32 2003 +0200 +++ b/src/imap/client.h Tue Jan 21 07:37:35 2003 +0200 @@ -16,6 +16,7 @@ struct mail_storage *storage; struct mailbox *mailbox; + unsigned int select_counter; /* increased when mailbox is changed */ time_t last_input; unsigned int bad_counter; diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/imap/cmd-select.c --- a/src/imap/cmd-select.c Tue Jan 21 07:36:32 2003 +0200 +++ b/src/imap/cmd-select.c Tue Jan 21 07:37:35 2003 +0200 @@ -36,6 +36,7 @@ /* set client's mailbox only after getting status to make sure we're not sending any expunge/exists replies too early to client */ client->mailbox = box; + client->select_counter++; client_send_mailbox_flags(client, box, status.custom_flags, status.custom_flags_count); diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/imap/imap-fetch-body-section.c --- a/src/imap/imap-fetch-body-section.c Tue Jan 21 07:36:32 2003 +0200 +++ b/src/imap/imap-fetch-body-section.c Tue Jan 21 07:37:35 2003 +0200 @@ -31,6 +31,46 @@ int (*match_func) (const char *const *, const unsigned char *, size_t); }; +struct partial_cache { + unsigned int select_counter; + unsigned int uid; + + uoff_t physical_start; + struct message_size pos; +}; + +static struct partial_cache partial = { 0, 0, 0, { 0, 0, 0 } }; + +static int seek_partial(unsigned int select_counter, unsigned int uid, + struct partial_cache *partial, struct istream *stream, + uoff_t physical_start, uoff_t virtual_skip) +{ + int cr_skipped; + + if (select_counter == partial->select_counter && uid == partial->uid && + physical_start == partial->physical_start && + virtual_skip >= partial->pos.virtual_size) { + /* we can use the cache */ + virtual_skip -= partial->pos.virtual_size; + } else { + partial->select_counter = select_counter; + partial->uid = uid; + partial->physical_start = physical_start; + memset(&partial->pos, 0, sizeof(partial->pos)); + } + + i_warning("skipping %lld", virtual_skip); + + i_stream_seek(stream, partial->physical_start + + partial->pos.physical_size); + message_skip_virtual(stream, virtual_skip, &partial->pos, &cr_skipped); + + if (cr_skipped) + partial->pos.virtual_size--; + + return cr_skipped; +} + /* fetch BODY[] or BODY[TEXT] */ static int fetch_body(struct imap_fetch_context *ctx, const struct imap_fetch_body_data *body, @@ -39,6 +79,8 @@ struct message_size hdr_size, body_size; struct istream *stream; const char *str; + int skip_cr; + off_t ret; stream = mail->get_stream(mail, &hdr_size, &body_size); if (stream == NULL) @@ -54,9 +96,16 @@ if (o_stream_send_str(ctx->output, str) < 0) return FALSE; - /* FIXME: SLOW! we need some cache for this. */ - return message_send(ctx->output, stream, &body_size, - body->skip, body->max_size); + skip_cr = seek_partial(ctx->select_counter, mail->uid, + &partial, stream, 0, body->skip); + ret = message_send(ctx->output, stream, &body_size, + skip_cr, body->max_size); + if (ret > 0) { + partial.pos.physical_size = + stream->v_offset - partial.physical_start; + partial.pos.virtual_size += ret; + } + return ret >= 0; } static const char **get_fields_array(const char *fields) @@ -258,7 +307,7 @@ if (o_stream_send_str(ctx->output, str) < 0) return FALSE; return message_send(ctx->output, input, size, - body->skip, body->max_size); + body->skip, body->max_size) >= 0; } /* partial headers - copy the wanted fields into memory, inserting @@ -386,23 +435,28 @@ static int fetch_part_body(struct imap_fetch_context *ctx, struct istream *stream, const struct imap_fetch_body_data *body, - const struct message_part *part) + struct mail *mail, const struct message_part *part) { const char *str; - - /* jump to beginning of part body */ - i_stream_seek(stream, part->physical_pos + - part->header_size.physical_size); + int skip_cr; + off_t ret; str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", ctx->prefix, part->body_size.virtual_size); if (o_stream_send_str(ctx->output, str) < 0) return FALSE; - /* FIXME: potential performance problem with big messages: - FETCH BODY[1]<100000..1024>, hopefully no clients do this */ - return message_send(ctx->output, stream, &part->body_size, - body->skip, body->max_size); + skip_cr = seek_partial(ctx->select_counter, mail->uid, + &partial, stream, part->physical_pos + + part->header_size.physical_size, body->skip); + ret = message_send(ctx->output, stream, &part->body_size, + skip_cr, body->max_size); + if (ret > 0) { + partial.pos.physical_size = + stream->v_offset - partial.physical_start; + partial.pos.virtual_size += ret; + } + return ret >= 0; } static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail, @@ -421,7 +475,7 @@ return FALSE; if (*section == '\0' || strcmp(section, "TEXT") == 0) - return fetch_part_body(ctx, stream, body, part); + return fetch_part_body(ctx, stream, body, mail, part); if (strncmp(section, "HEADER", 6) == 0 || strcmp(section, "MIME") == 0) { diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/imap/imap-fetch.c --- a/src/imap/imap-fetch.c Tue Jan 21 07:36:32 2003 +0200 +++ b/src/imap/imap-fetch.c Tue Jan 21 07:37:35 2003 +0200 @@ -112,7 +112,8 @@ if (o_stream_send_str(ctx->output, str) < 0) return FALSE; - return message_send(ctx->output, stream, &body_size, 0, (uoff_t)-1); + return message_send(ctx->output, stream, &body_size, + 0, (uoff_t)-1) >= 0; } static int fetch_send_rfc822_header(struct imap_fetch_context *ctx, @@ -134,7 +135,7 @@ if (o_stream_send_str(ctx->output, str) < 0) return FALSE; - return message_send(ctx->output, stream, &hdr_size, 0, (uoff_t)-1); + return message_send(ctx->output, stream, &hdr_size, 0, (uoff_t)-1) >= 0; } static int fetch_send_rfc822_text(struct imap_fetch_context *ctx, @@ -157,7 +158,8 @@ return FALSE; i_stream_seek(stream, hdr_size.physical_size); - return message_send(ctx->output, stream, &body_size, 0, (uoff_t)-1); + return message_send(ctx->output, stream, &body_size, + 0, (uoff_t)-1) >= 0; } static int fetch_mail(struct imap_fetch_context *ctx, struct mail *mail) @@ -258,6 +260,7 @@ ctx.imap_data = imap_data; ctx.bodies = bodies; ctx.output = client->output; + ctx.select_counter = client->select_counter; ctx.str = t_str_new(8192); ctx.fetch_ctx = client->mailbox-> diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/imap/imap-fetch.h --- a/src/imap/imap-fetch.h Tue Jan 21 07:36:32 2003 +0200 +++ b/src/imap/imap-fetch.h Tue Jan 21 07:37:35 2003 +0200 @@ -28,6 +28,7 @@ string_t *str; struct ostream *output; const char *prefix; + unsigned int select_counter; int first, failed; }; diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/lib-mail/message-send.c --- a/src/lib-mail/message-send.c Tue Jan 21 07:36:32 2003 +0200 +++ b/src/lib-mail/message-send.c Tue Jan 21 07:37:35 2003 +0200 @@ -7,18 +7,19 @@ #include "message-send.h" #include "message-size.h" -int message_send(struct ostream *output, struct istream *input, - const struct message_size *msg_size, - uoff_t virtual_skip, uoff_t max_virtual_size) +off_t message_send(struct ostream *output, struct istream *input, + const struct message_size *msg_size, + uoff_t virtual_skip, uoff_t max_virtual_size) { const unsigned char *msg; uoff_t old_limit, limit; size_t i, size; - int cr_skipped, add_cr, ret; + off_t ret; + int cr_skipped, add_cr; if (msg_size->physical_size == 0 || virtual_skip >= msg_size->virtual_size) - return TRUE; + return 0; if (max_virtual_size > msg_size->virtual_size - virtual_skip) max_virtual_size = msg_size->virtual_size - virtual_skip; @@ -39,6 +40,7 @@ message_skip_virtual(input, virtual_skip, NULL, &cr_skipped); /* go through the message data and insert CRs where needed. */ + ret = 0; while (max_virtual_size > 0 && i_stream_read_data(input, &msg, &size, 0) > 0) { add_cr = FALSE; @@ -55,12 +57,14 @@ } } + ret += i; if (o_stream_send(output, msg, i) < 0) - return FALSE; + return -1; if (add_cr) { + ret++; if (o_stream_send(output, "\r", 1) < 0) - return FALSE; + return -1; cr_skipped = TRUE; } else { cr_skipped = i > 0 && msg[i-1] == '\r'; @@ -69,5 +73,5 @@ i_stream_skip(input, i); } - return TRUE; + return ret; } diff -r 9c8df18fb2a9 -r 21788a1e9e39 src/lib-mail/message-send.h --- a/src/lib-mail/message-send.h Tue Jan 21 07:36:32 2003 +0200 +++ b/src/lib-mail/message-send.h Tue Jan 21 07:37:35 2003 +0200 @@ -6,9 +6,10 @@ /* Send message to client inserting CRs if needed. Only max_virtual_size bytes if sent (relative to virtual_skip), if you want it unlimited, use (uoff_t)-1. Remember that if input begins with LF, CR is inserted - before it unless virtual_skip = 1. Returns TRUE if successful. */ -int message_send(struct ostream *output, struct istream *input, - const struct message_size *msg_size, - uoff_t virtual_skip, uoff_t max_virtual_size); + before it unless virtual_skip = 1. Returns number of bytes sent, or -1 + if error. */ +off_t message_send(struct ostream *output, struct istream *input, + const struct message_size *msg_size, + uoff_t virtual_skip, uoff_t max_virtual_size); #endif