dovecot-1.2: pop3: Track \Seen flag changes in a bitmask and do ...

dovecot at dovecot.org dovecot at dovecot.org
Wed Feb 4 22:36:40 EET 2009


details:   http://hg.dovecot.org/dovecot-1.2/rev/6f29380ba3a0
changeset: 8717:6f29380ba3a0
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Feb 04 15:28:31 2009 -0500
description:
pop3: Track \Seen flag changes in a bitmask and do the changes at QUIT.
This way RSET doesn't need to rollback the transaction.

diffstat:

3 files changed, 28 insertions(+), 21 deletions(-)
src/pop3/client.c   |    4 ++++
src/pop3/client.h   |    7 +++++--
src/pop3/commands.c |   38 +++++++++++++++++++-------------------

diffs (150 lines):

diff -r 8cca2bf6ab76 -r 6f29380ba3a0 src/pop3/client.c
--- a/src/pop3/client.c	Wed Feb 04 15:13:01 2009 -0500
+++ b/src/pop3/client.c	Wed Feb 04 15:28:31 2009 -0500
@@ -197,6 +197,9 @@ struct client *client_create(int fd_in, 
 		return NULL;
 	}
 
+	if (!no_flag_updates)
+		client->seen_bitmask = i_malloc(MSGS_BITMASK_SIZE(client));
+
 	i_assert(my_client == NULL);
 	my_client = client;
 
@@ -276,6 +279,7 @@ void client_destroy(struct client *clien
 
 	i_free(client->message_sizes);
 	i_free(client->deleted_bitmask);
+	i_free(client->seen_bitmask);
 
 	if (client->io != NULL)
 		io_remove(&client->io);
diff -r 8cca2bf6ab76 -r 6f29380ba3a0 src/pop3/client.h
--- a/src/pop3/client.h	Wed Feb 04 15:13:01 2009 -0500
+++ b/src/pop3/client.h	Wed Feb 04 15:28:31 2009 -0500
@@ -5,6 +5,9 @@ struct mail_storage;
 struct mail_storage;
 
 typedef void command_func_t(struct client *client);
+
+#define MSGS_BITMASK_SIZE(client) \
+	(((client)->messages_count + (CHAR_BIT-1)) / CHAR_BIT)
 
 struct client {
 	int fd_in, fd_out;
@@ -27,8 +30,7 @@ struct client {
 
 	unsigned int uid_validity;
 	unsigned int messages_count;
-	unsigned int deleted_count;
-	unsigned int expunged_count;
+	unsigned int deleted_count, expunged_count, seen_change_count;
 	uoff_t *message_sizes;
 	uoff_t total_size;
 	uoff_t deleted_size;
@@ -43,6 +45,7 @@ struct client {
 	uoff_t byte_counter_offset;
 
 	unsigned char *deleted_bitmask;
+	unsigned char *seen_bitmask;
 
 	unsigned int disconnected:1;
 	unsigned int deleted:1;
diff -r 8cca2bf6ab76 -r 6f29380ba3a0 src/pop3/commands.c
--- a/src/pop3/commands.c	Wed Feb 04 15:13:01 2009 -0500
+++ b/src/pop3/commands.c	Wed Feb 04 15:28:31 2009 -0500
@@ -12,9 +12,6 @@
 #include "capability.h"
 #include "commands.h"
 
-#define MSGS_BITMASK_SIZE(client) \
-	((client->messages_count + (CHAR_BIT-1)) / CHAR_BIT)
-
 static const char *get_msgnum(struct client *client, const char *args,
 			      unsigned int *msgnum)
 {
@@ -198,15 +195,12 @@ pop3_search_build(struct client *client,
 	return search_args;
 }
 
-static bool expunge_mails(struct client *client)
+static bool update_mails(struct client *client)
 {
 	struct mail_search_args *search_args;
 	struct mail_search_context *ctx;
 	struct mail *mail;
-	uint32_t idx;
-
-	if (client->deleted_bitmask == NULL)
-		return TRUE;
+	uint32_t idx, bit;
 
 	if (mailbox_is_readonly(client->mailbox)) {
 		/* silently ignore */
@@ -220,10 +214,14 @@ static bool expunge_mails(struct client 
 	mail = mail_alloc(client->trans, 0, NULL);
 	while (mailbox_search_next(ctx, mail) > 0) {
 		idx = mail->seq - 1;
-		if ((client->deleted_bitmask[idx / CHAR_BIT] &
-		     1 << (idx % CHAR_BIT)) != 0) {
+		bit = 1 << (idx % CHAR_BIT);
+		if (client->deleted_bitmask != NULL &&
+		    (client->deleted_bitmask[idx / CHAR_BIT] & bit) != 0) {
 			mail_expunge(mail);
 			client->expunged_count++;
+		} else if (client->seen_bitmask != NULL &&
+			   (client->seen_bitmask[idx / CHAR_BIT] & bit) != 0) {
+			mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
 		}
 	}
 	mail_free(&mail);
@@ -233,8 +231,8 @@ static bool expunge_mails(struct client 
 
 static int cmd_quit(struct client *client, const char *args ATTR_UNUSED)
 {
-	if (client->deleted) {
-		if (!expunge_mails(client)) {
+	if (client->deleted || client->seen_bitmask != NULL) {
+		if (!update_mails(client)) {
 			client_send_storage_error(client);
 			client_disconnect(client,
 				"Storage error during logout.");
@@ -408,11 +406,11 @@ static int fetch(struct client *client, 
 		return ret;
 	}
 
-	if (body_lines == (uoff_t)-1 && !no_flag_updates) {
+	if (body_lines == (uoff_t)-1 && client->seen_bitmask != NULL) {
 		if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) {
 			/* mark the message seen with RETR command */
-			(void)mail_update_flags(ctx->mail,
-						MODIFY_ADD, MAIL_SEEN);
+			client->seen_bitmask[msgnum / CHAR_BIT] |= 1 << (msgnum % CHAR_BIT);
+			client->seen_change_count++;
 		}
 	}
 
@@ -462,6 +460,10 @@ static int cmd_rset(struct client *clien
 		client->deleted_count = 0;
 		client->deleted_size = 0;
 	}
+	if (client->seen_change_count > 0) {
+		memset(client->seen_bitmask, 0, MSGS_BITMASK_SIZE(client));
+		client->seen_change_count = 0;
+	}
 
 	if (enable_last_command) {
 		/* remove all \Seen flags (as specified by RFC 1460) */
@@ -475,10 +477,8 @@ static int cmd_rset(struct client *clien
 			mail_update_flags(mail, MODIFY_REMOVE, MAIL_SEEN);
 		mail_free(&mail);
 		(void)mailbox_search_deinit(&search_ctx);
-	} else {
-		/* forget all our seen flag updates.
-		   FIXME: is this needed? it loses data added to cache file */
-		mailbox_transaction_rollback(&client->trans);
+
+		mailbox_transaction_commit(&client->trans);
 		client->trans = mailbox_transaction_begin(client->mailbox, 0);
 	}
 


More information about the dovecot-cvs mailing list