dovecot-2.2: mail-index: optimise memmoves in expunge, only move...

dovecot at dovecot.org dovecot at dovecot.org
Mon Jun 2 11:53:55 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/0b653039d3b9
changeset: 17426:0b653039d3b9
user:      Phil Carmody <phil at dovecot.fi>
date:      Mon Jun 02 14:50:34 2014 +0300
description:
mail-index: optimise memmoves in expunge, only move each region once
Rather than shifting things back and back and back with potentially O(N^2)
(more precisely O(count*rec_count')) work factor, move each slice of memory
only once, directly where we want it to end up (O(rec_count') work factor).

Based on draft patch by Timo Sirainen.

Signed-off-by: Phil Carmody <phil at dovecot.fi>

diffstat:

 src/lib-index/mail-index-sync-update.c |  27 ++++++++++++++++++++-------
 1 files changed, 20 insertions(+), 7 deletions(-)

diffs (58 lines):

diff -r 1466daa29957 -r 0b653039d3b9 src/lib-index/mail-index-sync-update.c
--- a/src/lib-index/mail-index-sync-update.c	Mon Jun 02 14:50:34 2014 +0300
+++ b/src/lib-index/mail-index-sync-update.c	Mon Jun 02 14:50:34 2014 +0300
@@ -241,7 +241,7 @@
 	struct mail_index_map *map;
 	const struct seq_range *range;
 	unsigned int i, count;
-	uint32_t prev_seq2;
+	uint32_t dest_seq1, prev_seq2, orig_rec_count;
 
 	map = mail_index_sync_get_atomic_map(ctx);
 
@@ -255,8 +255,9 @@
 		}
 	}
 
-	/* Preparatory HACK - do this in forward order so the memmove()s are pessimal! */
 	prev_seq2 = 0;
+	dest_seq1 = 1;
+	orig_rec_count = map->rec_map->records_count;
 	for (i = 0; i < count; i++) {
 		uint32_t seq1 = range[i].seq1;
 		uint32_t seq2 = range[i].seq2;
@@ -270,17 +271,29 @@
 			mail_index_sync_header_update_counts(ctx, rec->uid, rec->flags, 0);
 		}
 
-		/* @UNSAFE */
-		memmove(MAIL_INDEX_MAP_IDX(map, seq1-1),
-			MAIL_INDEX_MAP_IDX(map, seq2),
-			(map->rec_map->records_count - seq2) * map->hdr.record_size);
-
+		if (prev_seq2+1 <= seq1-1) {
+			/* @UNSAFE: move (prev_seq2+1) .. (seq1-1) to its
+			   final location in the map if necessary */
+			uint32_t move_count = (seq1-1) - (prev_seq2+1) + 1;
+			if (prev_seq2+1-1 != dest_seq1-1)
+				memmove(MAIL_INDEX_MAP_IDX(map, dest_seq1-1),
+					MAIL_INDEX_MAP_IDX(map, prev_seq2+1-1),
+					move_count * map->hdr.record_size);
+			dest_seq1 += move_count;
+		}
 		seq_count = seq2 - seq1 + 1;
 		map->rec_map->records_count -= seq_count;
 		map->hdr.messages_count -= seq_count;
 		mail_index_modseq_expunge(ctx->modseq_ctx, seq1, seq2);
 		prev_seq2 = seq2;
 	}
+	/* Final stragglers */
+	if (orig_rec_count > prev_seq2) {
+		uint32_t final_move_count = orig_rec_count - prev_seq2;
+		memmove(MAIL_INDEX_MAP_IDX(map, dest_seq1-1),
+			MAIL_INDEX_MAP_IDX(map, prev_seq2+1-1),
+			final_move_count * map->hdr.record_size);
+	}
 }
 
 static void *sync_append_record(struct mail_index_map *map)


More information about the dovecot-cvs mailing list