dovecot-1.1: Added mail_index_ext_reset_inc() to atomically incr...

dovecot at dovecot.org dovecot at dovecot.org
Thu May 29 06:37:15 EEST 2008


details:   http://hg.dovecot.org/dovecot-1.1/rev/6de1aed24ce5
changeset: 7563:6de1aed24ce5
user:      Timo Sirainen <tss at iki.fi>
date:      Thu May 29 04:47:53 2008 +0300
description:
Added mail_index_ext_reset_inc() to atomically increase extension's
reset_id. Added clear_data parameter to mail_index_ext_reset*().

diffstat:

9 files changed, 157 insertions(+), 50 deletions(-)
src/lib-index/mail-cache-compress.c            |    2 
src/lib-index/mail-index-sync-ext.c            |   55 +++++++++--------
src/lib-index/mail-index-sync-update.c         |   13 ++--
src/lib-index/mail-index-transaction-private.h |    3 
src/lib-index/mail-index-transaction.c         |   34 ++++++++--
src/lib-index/mail-index.h                     |   21 ++++--
src/lib-index/mail-transaction-log-append.c    |   75 ++++++++++++++++++++++--
src/lib-index/mail-transaction-log.h           |    2 
src/lib-storage/index/dbox/dbox-sync-rebuild.c |    2 

diffs (truncated from 378 to 300 lines):

diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-cache-compress.c
--- a/src/lib-index/mail-cache-compress.c	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-cache-compress.c	Thu May 29 04:47:53 2008 +0300
@@ -414,7 +414,7 @@ static int mail_cache_compress_locked(st
 
 	/* once we're sure that the compression was successful,
 	   update the offsets */
-	mail_index_ext_reset(trans, cache->ext_id, file_seq);
+	mail_index_ext_reset(trans, cache->ext_id, file_seq, TRUE);
 	offsets = array_get(&ext_offsets, &count);
 	for (i = 0; i < count; i++) {
 		if (offsets[i] != 0) {
diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-index-sync-ext.c
--- a/src/lib-index/mail-index-sync-ext.c	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-index-sync-ext.c	Thu May 29 04:47:53 2008 +0300
@@ -424,7 +424,8 @@ int mail_index_sync_ext_intro(struct mai
 			ctx->cur_ext_ignore = FALSE;
 		} else {
 			/* extension was reset and this transaction hadn't
-			   yet seen it. ignore this update. */
+			   yet seen it. ignore this update (except for
+			   resets). */
 			ctx->cur_ext_ignore = TRUE;
 		}
 
@@ -476,30 +477,12 @@ int mail_index_sync_ext_intro(struct mai
 	return 1;
 }
 
-int mail_index_sync_ext_reset(struct mail_index_sync_map_ctx *ctx,
-			      const struct mail_transaction_ext_reset *u)
-{
-	struct mail_index_view *view = ctx->view;
-	struct mail_index_map *map = view->map;
-	struct mail_index_ext_header *ext_hdr;
-        struct mail_index_ext *ext;
+static void mail_index_sync_ext_clear(struct mail_index_view *view,
+				      struct mail_index_map *map,
+				      struct mail_index_ext *ext)
+{
 	struct mail_index_record *rec;
 	uint32_t i;
-
-	if (ctx->cur_ext_map_idx == (uint32_t)-1) {
-		mail_index_sync_set_corrupted(ctx,
-			"Extension reset without intro prefix");
-		return -1;
-	}
-	if (ctx->cur_ext_ignore)
-		return 1;
-
-	/* a new index file will be created, so the old data won't be
-	   accidentally used by other processes. */
-	map = mail_index_sync_get_atomic_map(ctx);
-
-	ext = array_idx_modifiable(&map->extensions, ctx->cur_ext_map_idx);
-	ext->reset_id = u->new_reset_id;
 
 	memset(buffer_get_space_unsafe(map->hdr_copy_buf, ext->hdr_offset,
 				       ext->hdr_size), 0, ext->hdr_size);
@@ -512,10 +495,34 @@ int mail_index_sync_ext_reset(struct mai
 	}
 	map->rec_map->write_seq_first = 1;
 	map->rec_map->write_seq_last = view->map->rec_map->records_count;
+}
+
+int mail_index_sync_ext_reset(struct mail_index_sync_map_ctx *ctx,
+			      const struct mail_transaction_ext_reset *u)
+{
+	struct mail_index_map *map = ctx->view->map;
+	struct mail_index_ext_header *ext_hdr;
+        struct mail_index_ext *ext;
+
+	if (ctx->cur_ext_map_idx == (uint32_t)-1) {
+		mail_index_sync_set_corrupted(ctx,
+			"Extension reset without intro prefix");
+		return -1;
+	}
+	/* since we're resetting the extension, don't check cur_ext_ignore */
+
+	/* a new index file will be created, so the old data won't be
+	   accidentally used by other processes. */
+	map = mail_index_sync_get_atomic_map(ctx);
+
+	ext = array_idx_modifiable(&map->extensions, ctx->cur_ext_map_idx);
+	ext->reset_id = u->new_reset_id;
+
+	if (!u->preserve_data)
+		mail_index_sync_ext_clear(ctx->view, map, ext);
 
 	ext_hdr = get_ext_header(map, ext);
 	ext_hdr->reset_id = u->new_reset_id;
-
 	return 1;
 }
 
diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-index-sync-update.c
--- a/src/lib-index/mail-index-sync-update.c	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-index-sync-update.c	Thu May 29 04:47:53 2008 +0300
@@ -532,15 +532,17 @@ int mail_index_sync_record(struct mail_i
 		break;
 	}
 	case MAIL_TRANSACTION_EXT_RESET: {
-		const struct mail_transaction_ext_reset *rec = data;
-
-		if (hdr->size != sizeof(*rec)) {
+		struct mail_transaction_ext_reset rec;
+
+		/* old versions have only new_reset_id */
+		if (hdr->size < sizeof(uint32_t)) {
 			mail_index_sync_set_corrupted(ctx,
 				"ext reset: invalid record size");
 			ret = -1;
 			break;
 		}
-		ret = mail_index_sync_ext_reset(ctx, rec);
+		memcpy(&rec, data, I_MIN(hdr->size, sizeof(rec)));
+		ret = mail_index_sync_ext_reset(ctx, &rec);
 		break;
 	}
 	case MAIL_TRANSACTION_EXT_HDR_UPDATE: {
@@ -781,6 +783,9 @@ int mail_index_sync_map(struct mail_inde
 		map->hdr_base = map->hdr_copy_buf->data;
 	}
 
+	mail_transaction_log_view_get_prev_pos(view->log_view,
+					       &prev_seq, &prev_offset);
+
 	mail_index_sync_map_init(&sync_map_ctx, view, type);
 	if (reset) {
 		/* Reset the entire index. Leave only indexid and
diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-index-transaction-private.h
--- a/src/lib-index/mail-index-transaction-private.h	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-index-transaction-private.h	Thu May 29 04:47:53 2008 +0300
@@ -51,8 +51,9 @@ struct mail_index_transaction {
 		     struct mail_index_transaction_ext_hdr_update *);
 	ARRAY_DEFINE(ext_rec_updates, ARRAY_TYPE(seq_array));
 	ARRAY_DEFINE(ext_resizes, struct mail_transaction_ext_intro);
-	ARRAY_DEFINE(ext_resets, uint32_t);
+	ARRAY_DEFINE(ext_resets, struct mail_transaction_ext_reset);
 	ARRAY_DEFINE(ext_reset_ids, uint32_t);
+	ARRAY_DEFINE(ext_reset_atomic, uint32_t);
 
 	ARRAY_DEFINE(keyword_updates,
 		     struct mail_index_transaction_keyword_update);
diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-index-transaction.c
--- a/src/lib-index/mail-index-transaction.c	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-index-transaction.c	Thu May 29 04:47:53 2008 +0300
@@ -75,6 +75,8 @@ void mail_index_transaction_reset(struct
 		array_free(&t->ext_resets);
 	if (array_is_created(&t->ext_reset_ids))
 		array_free(&t->ext_reset_ids);
+	if (array_is_created(&t->ext_reset_atomic))
+		array_free(&t->ext_reset_atomic);
 
 	t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
 	t->last_new_seq = 0;
@@ -1087,16 +1089,34 @@ void mail_index_ext_resize(struct mail_i
 }
 
 void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
-			  uint32_t reset_id)
-{
+			  uint32_t reset_id, bool clear_data)
+{
+	struct mail_transaction_ext_reset reset;
+
 	i_assert(reset_id != 0);
+
+	memset(&reset, 0, sizeof(reset));
+	reset.new_reset_id = reset_id;
+	reset.preserve_data = !clear_data;
 
 	mail_index_ext_set_reset_id(t, ext_id, reset_id);
 
 	if (!array_is_created(&t->ext_resets))
 		i_array_init(&t->ext_resets, ext_id + 2);
-	array_idx_set(&t->ext_resets, ext_id, &reset_id);
+	array_idx_set(&t->ext_resets, ext_id, &reset);
 	t->log_ext_updates = TRUE;
+}
+
+void mail_index_ext_reset_inc(struct mail_index_transaction *t, uint32_t ext_id,
+			      uint32_t prev_reset_id, bool clear_data)
+{
+	uint32_t expected_reset_id = prev_reset_id + 1;
+
+	mail_index_ext_reset(t, ext_id, (uint32_t)-1, clear_data);
+
+	if (!array_is_created(&t->ext_reset_atomic))
+		i_array_init(&t->ext_reset_atomic, ext_id + 2);
+	array_idx_set(&t->ext_reset_atomic, ext_id, &expected_reset_id);
 }
 
 static bool
@@ -1123,11 +1143,11 @@ mail_index_transaction_has_ext_changes(s
 		}
 	}
 	if (array_is_created(&t->ext_resets)) {
-		const uint32_t *ids;
-
-		ids = array_get(&t->ext_resets, &count);
+		const struct mail_transaction_ext_reset *resets;
+
+		resets = array_get(&t->ext_resets, &count);
 		for (i = 0; i < count; i++) {
-			if (ids[i] != 0)
+			if (resets[i].new_reset_id != 0)
 				return TRUE;
 		}
 	}
diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-index.h
--- a/src/lib-index/mail-index.h	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-index.h	Thu May 29 04:47:53 2008 +0300
@@ -428,14 +428,21 @@ void mail_index_ext_resize(struct mail_i
 			   uint32_t hdr_size, uint16_t record_size,
 			   uint16_t record_align);
 
-/* Reset extension records and header. Any updates for this extension which
-   were issued before the writer had seen this reset are discarded. reset_id is
-   used to figure this out, so it must be different every time. */
+/* Reset extension. Any updates for this extension which were issued before the
+   writer had seen this reset are discarded. reset_id is used to figure this
+   out, so it must be different every time. If clear_data=TRUE, records and
+   header is zeroed. */
 void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
-			  uint32_t reset_id);
-/* Discard existing extension updates and write new updates using the given
-   reset_id. The difference to mail_index_ext_reset() is that this doesn't
-   clear any existing record or header data. */
+			  uint32_t reset_id, bool clear_data);
+/* Like mail_index_ext_reset(), but increase extension's reset_id atomically
+   when the transaction is being committed. If prev_reset_id doesn't match the
+   latest reset_id, the reset_id isn't increased and all extension changes are
+   ignored. */
+void mail_index_ext_reset_inc(struct mail_index_transaction *t, uint32_t ext_id,
+			      uint32_t prev_reset_id, bool clear_data);
+/* Discard existing extension updates in this transaction and write new updates
+   using the given reset_id. The difference to mail_index_ext_reset() is that
+   this doesn't clear any existing record or header data. */
 void mail_index_ext_set_reset_id(struct mail_index_transaction *t,
 				 uint32_t ext_id, uint32_t reset_id);
 /* Get the current reset_id for given extension. Returns TRUE if it exists. */
diff -r 4c702defc245 -r 6de1aed24ce5 src/lib-index/mail-transaction-log-append.c
--- a/src/lib-index/mail-transaction-log-append.c	Wed May 28 19:03:42 2008 +0300
+++ b/src/lib-index/mail-transaction-log-append.c	Thu May 29 04:47:53 2008 +0300
@@ -166,6 +166,58 @@ log_get_hdr_update_buffer(struct mail_in
 	return buf;
 }
 
+static void
+ext_reset_update_atomic(struct mail_index_transaction *t,
+			uint32_t ext_id, uint32_t expected_reset_id)
+{
+	const struct mail_index_ext *map_ext;
+	struct mail_transaction_ext_reset *reset;
+	uint32_t idx, reset_id;
+
+	if (!mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) {
+		/* new extension */
+		reset_id = 1;
+	} else {
+		map_ext = array_idx(&t->view->index->map->extensions, idx);
+		reset_id = map_ext->reset_id + 1;
+	}
+	if (reset_id != expected_reset_id) {
+		/* ignore this extension update */
+		mail_index_ext_set_reset_id(t, ext_id, 0);
+		return;
+	}
+
+	if (reset_id == 0)
+		reset_id++;
+
+	array_idx_set(&t->ext_reset_ids, ext_id, &reset_id);
+
+	/* reseting existing data is optional */
+	if (array_is_created(&t->ext_resets)) {
+		reset = array_idx_modifiable(&t->ext_resets, ext_id);
+		if (reset->new_reset_id == (uint32_t)-1)
+			reset->new_reset_id = reset_id;
+	}
+}
+
+static void
+transaction_update_atomic_reset_ids(struct mail_index_transaction *t)
+{
+	const uint32_t *expected_reset_ids;
+	unsigned int ext_id, count;
+
+	if (!array_is_created(&t->ext_reset_atomic))
+		return;
+
+	expected_reset_ids = array_get(&t->ext_reset_atomic, &count);
+	for (ext_id = 0; ext_id < count; ext_id++) {
+		if (expected_reset_ids[ext_id] != 0) {
+			ext_reset_update_atomic(t, ext_id,
+						expected_reset_ids[ext_id]);
+		}
+	}


More information about the dovecot-cvs mailing list