Mercurial > dovecot > original-hg > dovecot-1.2
changeset 2722:8c5bcd6585a4 HEAD
Use only a single transaction for the whole duration of pop3 session. Avoids
constant locking/unlocking the indexes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 10 Oct 2004 19:25:06 +0300 |
parents | 4ec77eca761d |
children | 12b503fbb8af |
files | src/pop3/client.c src/pop3/client.h src/pop3/commands.c |
diffstat | 3 files changed, 72 insertions(+), 119 deletions(-) [+] |
line wrap: on
line diff
--- a/src/pop3/client.c Sun Oct 10 18:56:00 2004 +0300 +++ b/src/pop3/client.c Sun Oct 10 19:25:06 2004 +0300 @@ -1,6 +1,7 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "common.h" +#include "buffer.h" #include "ioloop.h" #include "network.h" #include "istream.h" @@ -54,43 +55,33 @@ struct mailbox_transaction_context *t; struct mail_search_context *ctx; struct mail *mail; - struct mailbox_status status; + buffer_t *message_sizes_buf; int i, failed; + message_sizes_buf = buffer_create_dynamic(default_pool, 512); + memset(&search_arg, 0, sizeof(search_arg)); search_arg.type = SEARCH_ALL; for (i = 0; i < 2; i++) { if (sync_mailbox(client->mailbox) < 0) { client_send_storage_error(client); - return FALSE; - } - if (mailbox_get_status(client->mailbox, STATUS_MESSAGES, - &status) < 0) { - client_send_storage_error(client); - return FALSE; + break; } - client->last_seen = 0; - client->messages_count = status.messages; - client->total_size = 0; - client->deleted_size = 0; - - if (client->messages_count == 0) - return TRUE; - - i_free(client->message_sizes); - client->message_sizes = i_new(uoff_t, client->messages_count); - t = mailbox_transaction_begin(client->mailbox, FALSE); ctx = mailbox_search_init(t, NULL, &search_arg, NULL, MAIL_FETCH_VIRTUAL_SIZE, NULL); if (ctx == NULL) { client_send_storage_error(client); - mailbox_transaction_rollback(t); - return FALSE; + mailbox_transaction_rollback(t); + break; } + client->last_seen = 0; + client->total_size = 0; + buffer_set_used_size(message_sizes_buf, 0); + failed = FALSE; while ((mail = mailbox_search_next(ctx)) != NULL) { uoff_t size = mail->get_virtual_size(mail); @@ -107,18 +98,21 @@ client->last_seen = mail->seq; client->total_size += size; - i_assert(mail->seq <= client->messages_count); - client->message_sizes[mail->seq-1] = size; + buffer_append(message_sizes_buf, &size, sizeof(size)); } + client->messages_count = + message_sizes_buf->used / sizeof(uoff_t); if (mailbox_search_deinit(ctx) < 0) { client_send_storage_error(client); - mailbox_transaction_rollback(t); - return FALSE; + mailbox_transaction_rollback(t); + break; } if (!failed) { - mailbox_transaction_commit(t, 0); + client->trans = t; + client->message_sizes = + buffer_free_without_data(message_sizes_buf); return TRUE; } @@ -126,67 +120,12 @@ mailbox_transaction_rollback(t); } - client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox."); + if (i == 2) + client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox."); + buffer_free(message_sizes_buf); return FALSE; } -int client_update_mailbox(struct client *client, struct mailbox *box, - int delete_mails) -{ - struct mail_search_arg search_arg; - struct mailbox_transaction_context *t; - struct mail_search_context *ctx; - struct mail *mail; - struct mail_full_flags seen_flag; - uint32_t i, bitmask; - int failed = FALSE; - - if (delete_mails && client->deleted_bitmask == NULL) - delete_mails = FALSE; - - memset(&search_arg, 0, sizeof(search_arg)); - search_arg.type = SEARCH_ALL; - - t = mailbox_transaction_begin(box, FALSE); - ctx = mailbox_search_init(t, NULL, &search_arg, NULL, 0, NULL); - if (ctx == NULL) { - mailbox_transaction_rollback(t); - return FALSE; - } - - memset(&seen_flag, 0, sizeof(seen_flag)); - seen_flag.flags = MAIL_SEEN; - - while ((mail = mailbox_search_next(ctx)) != NULL) { - i = mail->seq-1; - - bitmask = 1 << (i % CHAR_BIT); - if (delete_mails && - (client->deleted_bitmask[i/CHAR_BIT] & bitmask) != 0) { - if (mail->expunge(mail) < 0) { - failed = TRUE; - break; - } - } else if (client->seen_bitmask != NULL && - (client->seen_bitmask[i/CHAR_BIT] & bitmask) != 0) { - if (mail->update_flags(mail, &seen_flag, - MODIFY_ADD) < 0) { - failed = TRUE; - break; - } - } - } - - if (mailbox_search_deinit(ctx) < 0 || failed) { - mailbox_transaction_rollback(t); - return FALSE; - } - - mailbox_transaction_commit(t, MAILBOX_SYNC_FLAG_FULL_READ | - MAILBOX_SYNC_FLAG_FULL_WRITE); - return TRUE; -} - struct client *client_create(int hin, int hout, struct mail_storage *storage) { struct client *client; @@ -244,18 +183,14 @@ client->cmd(client); i_assert(client->cmd == NULL); } - if (client->mailbox != NULL) { - if (client->seen_bitmask != NULL) { - (void)client_update_mailbox(client, client->mailbox, - FALSE); - } + if (client->trans != NULL) + mailbox_transaction_rollback(client->trans); + if (client->mailbox != NULL) mailbox_close(client->mailbox); - } mail_storage_destroy(client->storage); i_free(client->message_sizes); i_free(client->deleted_bitmask); - i_free(client->seen_bitmask); if (client->io != NULL) io_remove(client->io);
--- a/src/pop3/client.h Sun Oct 10 18:56:00 2004 +0300 +++ b/src/pop3/client.h Sun Oct 10 19:25:06 2004 +0300 @@ -17,6 +17,7 @@ struct mail_storage *storage; struct mailbox *mailbox; + struct mailbox_transaction_context *trans; time_t last_input, last_output; unsigned int bad_counter; @@ -29,7 +30,6 @@ uint32_t last_seen; unsigned char *deleted_bitmask; - unsigned char *seen_bitmask; unsigned int deleted:1; unsigned int waiting_input:1; @@ -43,9 +43,6 @@ /* Disconnect client connection */ void client_disconnect(struct client *client); -int client_update_mailbox(struct client *client, struct mailbox *box, - int delete_mails); - /* Send a line of data to client */ int client_send_line(struct client *client, const char *fmt, ...) __attr_format__(2, 3);
--- a/src/pop3/commands.c Sun Oct 10 18:56:00 2004 +0300 +++ b/src/pop3/commands.c Sun Oct 10 19:25:06 2004 +0300 @@ -178,19 +178,45 @@ return TRUE; } +static int expunge_mails(struct client *client) +{ + struct mail_search_arg search_arg; + struct mail_search_context *ctx; + struct mail *mail; + uint32_t idx; + + if (client->deleted_bitmask == NULL) + return TRUE; + + memset(&search_arg, 0, sizeof(search_arg)); + search_arg.type = SEARCH_ALL; + + ctx = mailbox_search_init(client->trans, NULL, &search_arg, + NULL, 0, NULL); + while ((mail = mailbox_search_next(ctx)) != NULL) { + idx = mail->seq - 1; + if ((client->deleted_bitmask[idx / CHAR_BIT] & + 1 << (idx % CHAR_BIT)) != 0) { + if (mail->expunge(mail) < 0) + return FALSE; + } + } + + return mailbox_search_deinit(ctx) == 0; +} + static int cmd_quit(struct client *client, const char *args __attr_unused__) { if (client->deleted) { - if (!client_update_mailbox(client, client->mailbox, TRUE)) { + if (!expunge_mails(client)) { client_send_storage_error(client); client_disconnect(client); return TRUE; } + } - /* don't sync them again at client_destroy() */ - i_free(client->seen_bitmask); - client->seen_bitmask = NULL; - } + mailbox_transaction_commit(client->trans, MAILBOX_SYNC_FLAG_FULL_WRITE); + client->trans = NULL; if (!client->deleted) client_send_line(client, "+OK Logging out."); @@ -202,7 +228,6 @@ } struct fetch_context { - struct mailbox_transaction_context *t; struct mail_search_context *search_ctx; struct istream *stream; uoff_t body_lines; @@ -217,7 +242,6 @@ static void fetch_deinit(struct fetch_context *ctx) { (void)mailbox_search_deinit(ctx->search_ctx); - (void)mailbox_transaction_commit(ctx->t, 0); i_free(ctx); } @@ -320,8 +344,8 @@ ctx->search_arg.type = SEARCH_SEQSET; ctx->search_arg.value.seqset = &ctx->seqset; - ctx->t = mailbox_transaction_begin(client->mailbox, FALSE); - ctx->search_ctx = mailbox_search_init(ctx->t, NULL, &ctx->search_arg, + ctx->search_ctx = mailbox_search_init(client->trans, NULL, + &ctx->search_arg, NULL, MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY, NULL); mail = mailbox_search_next(ctx->search_ctx); @@ -334,12 +358,11 @@ if (body_lines == (uoff_t)-1 && !no_flag_updates) { /* mark the message seen with RETR command */ - if (client->seen_bitmask == NULL) { - client->seen_bitmask = - i_malloc(MSGS_BITMASK_SIZE(client)); - } - client->seen_bitmask[msgnum / CHAR_BIT] |= - 1 << (msgnum % CHAR_BIT); + struct mail_full_flags seen_flag; + memset(&seen_flag, 0, sizeof(seen_flag)); + seen_flag.flags = MAIL_SEEN; + + (void)mail->update_flags(mail, &seen_flag, MODIFY_ADD); } ctx->body_lines = body_lines; @@ -372,7 +395,6 @@ static int cmd_rset(struct client *client, const char *args __attr_unused__) { - struct mailbox_transaction_context *t; struct mail_search_context *search_ctx; struct mail *mail; struct mail_search_arg search_arg; @@ -387,6 +409,10 @@ client->deleted_size = 0; } + /* forget all our seen flag updates as well.. */ + mailbox_transaction_rollback(client->trans); + client->trans = mailbox_transaction_begin(client->mailbox, FALSE); + if (enable_last_command) { /* remove all \Seen flags */ memset(&search_arg, 0, sizeof(search_arg)); @@ -395,16 +421,14 @@ memset(&seen_flag, 0, sizeof(seen_flag)); seen_flag.flags = MAIL_SEEN; - t = mailbox_transaction_begin(client->mailbox, FALSE); - search_ctx = mailbox_search_init(t, NULL, &search_arg, - NULL, 0, NULL); + search_ctx = mailbox_search_init(client->trans, NULL, + &search_arg, NULL, 0, NULL); while ((mail = mailbox_search_next(search_ctx)) != NULL) { if (mail->update_flags(mail, &seen_flag, MODIFY_REMOVE) < 0) break; } (void)mailbox_search_deinit(search_ctx); - (void)mailbox_transaction_commit(t, 0); } client_send_line(client, "+OK"); @@ -435,7 +459,6 @@ } struct cmd_uidl_context { - struct mailbox_transaction_context *t; struct mail_search_context *search_ctx; unsigned int message; @@ -474,7 +497,6 @@ /* finished */ (void)mailbox_search_deinit(ctx->search_ctx); - (void)mailbox_transaction_commit(ctx->t, 0); client->cmd = NULL; @@ -507,9 +529,8 @@ ctx->search_arg.value.seqset = &ctx->seqset; } - ctx->t = mailbox_transaction_begin(client->mailbox, FALSE); - ctx->search_ctx = mailbox_search_init(ctx->t, NULL, &ctx->search_arg, - NULL, 0, NULL); + ctx->search_ctx = mailbox_search_init(client->trans, NULL, + &ctx->search_arg, NULL, 0, NULL); if (message == 0) { client->cmd = cmd_uidl_callback; client->cmd_context = ctx;