Mercurial > dovecot > core-2.2
changeset 1044:50d258907c99 HEAD
Read the sizes of all messages to memory at startup. More failsafe and
faster.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 27 Jan 2003 08:44:49 +0200 |
parents | cacabd33c68a |
children | be7710b9a819 |
files | src/pop3/client.c src/pop3/client.h src/pop3/commands.c |
diffstat | 3 files changed, 102 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/src/pop3/client.c Mon Jan 27 07:45:47 2003 +0200 +++ b/src/pop3/client.c Mon Jan 27 08:44:49 2003 +0200 @@ -37,10 +37,72 @@ o_stream_close(client->output); } +static int init_mailbox(struct client *client) +{ + struct mail_fetch_context *ctx; + struct mail *mail; + struct mailbox_status status; + const char *messageset; + int i, all_found, failed; + + if (!client->mailbox->get_status(client->mailbox, + STATUS_MESSAGES | STATUS_UIDVALIDITY, + &status)) { + client_send_storage_error(client); + return FALSE; + } + + client->messages_count = status.messages; + client->uidvalidity = status.uidvalidity; + client->message_sizes = i_new(uoff_t, client->messages_count); + + messageset = t_strdup_printf("1:%u", client->messages_count); + for (i = 0; i < 2; i++) { + ctx = client->mailbox->fetch_init(client->mailbox, + MAIL_FETCH_SIZE, + NULL, messageset, FALSE); + if (ctx == NULL) { + client_send_storage_error(client); + return FALSE; + } + + client->total_size = 0; + failed = FALSE; + while ((mail = client->mailbox->fetch_next(ctx)) != NULL) { + uoff_t size = mail->get_size(mail); + + if (size == (uoff_t)-1) { + failed = TRUE; + break; + } + client->total_size += size; + + i_assert(mail->seq <= client->messages_count); + client->message_sizes[mail->seq-1] = size; + } + + if (!client->mailbox->fetch_deinit(ctx, &all_found)) { + client_send_storage_error(client); + return FALSE; + } + + if (!failed && all_found) + return TRUE; + + /* well, sync and try again */ + if (!client->mailbox->sync(client->mailbox, TRUE)) { + client_send_storage_error(client); + return FALSE; + } + } + + client_send_line(client, "-ERR Couldn't sync mailbox."); + return FALSE; +} + struct client *client_create(int hin, int hout, struct mailbox *mailbox) { struct client *client; - struct mailbox_status status; client = i_new(struct client, 1); client->input = i_stream_create_file(hin, default_pool, @@ -64,11 +126,10 @@ i_assert(my_client == NULL); my_client = client; - if (!mailbox->get_status(mailbox, STATUS_MESSAGES, &status)) { + if (!init_mailbox(client)) { client_destroy(client); - return NULL; + client = NULL; } - client->messages_count = status.messages; return client; } @@ -81,8 +142,8 @@ client->mailbox->close(client->mailbox); mail_storage_destroy(client->storage); - if (client->deleted_bitmask != NULL) - i_free(client->deleted_bitmask); + i_free(client->message_sizes); + i_free(client->deleted_bitmask); io_remove(client->io); @@ -117,6 +178,14 @@ va_end(va); } +void client_send_storage_error(struct client *client) +{ + const char *error; + + error = client->storage->get_last_error(client->storage, NULL); + client_send_line(client, "-ERR %s", error); +} + static void client_input(void *context) { struct client *client = context;
--- a/src/pop3/client.h Mon Jan 27 07:45:47 2003 +0200 +++ b/src/pop3/client.h Mon Jan 27 08:44:49 2003 +0200 @@ -16,6 +16,10 @@ unsigned int bad_counter; unsigned int messages_count; + unsigned int uidvalidity; + uoff_t *message_sizes; + uoff_t total_size; + unsigned char *deleted_bitmask; unsigned int deleted:1; @@ -32,6 +36,7 @@ /* Send a line of data to client */ void client_send_line(struct client *client, const char *fmt, ...) __attr_format__(2, 3); +void client_send_storage_error(struct client *client); void clients_init(void); void clients_deinit(void);
--- a/src/pop3/commands.c Mon Jan 27 07:45:47 2003 +0200 +++ b/src/pop3/commands.c Mon Jan 27 08:44:49 2003 +0200 @@ -9,14 +9,6 @@ #define MSGS_BITMASK_SIZE(client) \ ((client->messages_count + (CHAR_BIT-1)) / CHAR_BIT) -static void client_send_storage_error(struct client *client) -{ - const char *error; - - error = client->storage->get_last_error(client->storage, NULL); - client_send_line(client, "-ERR %s", error); -} - static const char *get_msgnum(struct client *client, const char *args, unsigned int *msgnum) { @@ -106,53 +98,25 @@ client_send_line(client, "+OK Marked to be deleted."); } -static void list_sizes(struct client *client, unsigned int message) -{ - struct mail_fetch_context *ctx; - struct mail *mail; - const char *messageset; - int found = FALSE; - - if (client->messages_count == 0 && message == 0) - return; - - messageset = message == 0 ? - t_strdup_printf("1:%u", client->messages_count) : - t_strdup_printf("%u", message); - - ctx = client->mailbox->fetch_init(client->mailbox, MAIL_FETCH_SIZE, - NULL, messageset, FALSE); - if (ctx == NULL) { - client_send_storage_error(client); - return; - } - - while ((mail = client->mailbox->fetch_next(ctx)) != NULL) { - uoff_t size = mail->get_size(mail); - - client_send_line(client, message == 0 ? "%u %"PRIuUOFF_T : - "+OK %u %"PRIuUOFF_T, mail->seq, size); - found = TRUE; - } - - (void)client->mailbox->fetch_deinit(ctx, NULL); - - if (!found && message != 0) - client_send_line(client, "-ERR Message not found."); -} - static void cmd_list(struct client *client, const char *args) { + unsigned int i; + if (*args == '\0') { client_send_line(client, "+OK %u messages:", client->messages_count); - list_sizes(client, 0); + for (i = 0; i < client->messages_count; i++) { + client_send_line(client, "%u %"PRIuUOFF_T, + i, client->message_sizes[i]); + } client_send_line(client, "."); } else { unsigned int msgnum; - if (get_msgnum(client, args, &msgnum) != NULL) - list_sizes(client, msgnum); + if (get_msgnum(client, args, &msgnum) != NULL) { + client_send_line(client, "+OK %u %"PRIuUOFF_T, + msgnum, client->message_sizes[msgnum]); + } } } @@ -223,7 +187,6 @@ struct mail_fetch_context *ctx; struct mail *mail; struct istream *stream; - struct message_size hdr_size, body_size; ctx = client->mailbox->fetch_init(client->mailbox, MAIL_FETCH_STREAM_HEADER | @@ -239,15 +202,18 @@ if (mail == NULL) client_send_line(client, "-ERR Message not found."); else { - stream = mail->get_stream(mail, &hdr_size, &body_size); - message_size_add(&body_size, &hdr_size); + stream = mail->get_stream(mail, NULL, NULL); - client_send_line(client, "+OK %"PRIuUOFF_T" octets", - body_size.virtual_size); + if (max_lines == (uoff_t)-1) { + client_send_line(client, "+OK %"PRIuUOFF_T" octets", + client->message_sizes[msgnum]); + } else { + client_send_line(client, "+OK"); + } // FIXME: "." lines needs to be escaped // FIXME: and send only max_lines - message_send(client->output, stream, &body_size, 0, (uoff_t)-1); + client_send_line(client, "."); } (void)client->mailbox->fetch_deinit(ctx, NULL); @@ -273,35 +239,8 @@ static void cmd_stat(struct client *client, const char *args __attr_unused__) { - struct mail_fetch_context *ctx; - struct mail *mail; - uoff_t size, total_size; - const char *messageset; - - if (client->messages_count == 0) { - client_send_line(client, "+OK 0 0"); - return; - } - - messageset = t_strdup_printf("1:%u", client->messages_count); - ctx = client->mailbox->fetch_init(client->mailbox, MAIL_FETCH_SIZE, - NULL, messageset, FALSE); - if (ctx == NULL) { - client_send_storage_error(client); - return; - } - - total_size = 0; - while ((mail = client->mailbox->fetch_next(ctx)) != NULL) { - size = mail->get_size(mail); - if (size != (uoff_t)-1) - total_size += size; - } - - (void)client->mailbox->fetch_deinit(ctx, NULL); - - client_send_line(client, "+OK %u %"PRIuUOFF_T, - client->messages_count, total_size); + client_send_line(client, "+OK %u %"PRIuUOFF_T, client-> + messages_count, client->total_size); } static void cmd_top(struct client *client, const char *args) @@ -337,7 +276,8 @@ while ((mail = client->mailbox->fetch_next(ctx)) != NULL) { client_send_line(client, message == 0 ? - "%u %u" : "+OK %u %u", mail->seq, mail->uid); + "%u %u.%u" : "+OK %u %u.%u", + mail->seq, client->uidvalidity, mail->uid); found = TRUE; }