Mercurial > dovecot > core-2.2
changeset 8929:9c50e7303513 HEAD
Added mail_index_atomic_inc_ext() for atomically incrementing numbers in extensions.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 04 Mar 2009 17:40:24 -0500 |
parents | 0fc03e326ccc |
children | cb37f2732abc |
files | src/lib-index/mail-index-sync-ext.c src/lib-index/mail-index-sync-private.h src/lib-index/mail-index-sync-update.c src/lib-index/mail-index-sync.c src/lib-index/mail-index-transaction-private.h src/lib-index/mail-index-transaction.c src/lib-index/mail-index.h src/lib-index/mail-transaction-log-append.c src/lib-index/mail-transaction-log.h src/util/logview.c |
diffstat | 10 files changed, 228 insertions(+), 47 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/mail-index-sync-ext.c Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index-sync-ext.c Wed Mar 04 17:40:24 2009 -0500 @@ -686,3 +686,63 @@ memcpy(old_data, u + 1, ext->record_size); return 1; } + +int +mail_index_sync_ext_atomic_inc(struct mail_index_sync_map_ctx *ctx, + const struct mail_transaction_ext_atomic_inc *u) +{ + struct mail_index_view *view = ctx->view; + struct mail_index_record *rec; + const struct mail_index_ext *ext; + void *data; + uint32_t seq; + + i_assert(ctx->cur_ext_map_idx != (uint32_t)-1); + i_assert(!ctx->cur_ext_ignore); + + if (u->uid == 0 || u->uid >= view->map->hdr.next_uid) { + mail_index_sync_set_corrupted(ctx, + "Extension record inc for invalid uid=%u", u->uid); + return -1; + } + + if (!mail_index_lookup_seq(view, u->uid, &seq)) + return 1; + + ext = array_idx(&view->map->extensions, ctx->cur_ext_map_idx); + i_assert(ext->record_offset + ext->record_size <= + view->map->hdr.record_size); + + rec = MAIL_INDEX_MAP_IDX(view->map, seq-1); + data = PTR_OFFSET(rec, ext->record_offset); + + switch (ext->record_size) { + case 1: { + uint8_t *num = data; + *num += u->diff; + break; + } + case 2: { + uint16_t *num = data; + *num += u->diff; + break; + } + case 4: { + uint32_t *num = data; + *num += u->diff; + break; + } + case 8: { + uint64_t *num = data; + *num += u->diff; + break; + } + default: + mail_index_sync_set_corrupted(ctx, + "Extension record inc with invalid size=%u", + ext->record_size); + return -1; + } + mail_index_sync_write_seq_update(ctx, seq, seq); + return 1; +}
--- a/src/lib-index/mail-index-sync-private.h Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index-sync-private.h Wed Mar 04 17:40:24 2009 -0500 @@ -82,6 +82,9 @@ int mail_index_sync_ext_rec_update(struct mail_index_sync_map_ctx *ctx, const struct mail_transaction_ext_rec_update *u); +int +mail_index_sync_ext_atomic_inc(struct mail_index_sync_map_ctx *ctx, + const struct mail_transaction_ext_atomic_inc *u); int mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx, const struct mail_transaction_header *hdr,
--- a/src/lib-index/mail-index-sync-update.c Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index-sync-update.c Wed Mar 04 17:40:24 2009 -0500 @@ -630,6 +630,31 @@ } break; } + case MAIL_TRANSACTION_EXT_ATOMIC_INC: { + const struct mail_transaction_ext_atomic_inc *rec, *end; + + if (ctx->cur_ext_map_idx == (uint32_t)-1) { + mail_index_sync_set_corrupted(ctx, + "Extension record updated " + "without intro prefix"); + ret = -1; + break; + } + + if (ctx->cur_ext_ignore) { + ret = 1; + break; + } + + rec = data; + end = CONST_PTR_OFFSET(data, hdr->size); + for (rec = data; rec < end; rec++) { + ret = mail_index_sync_ext_atomic_inc(ctx, rec); + if (ret <= 0) + break; + } + break; + } case MAIL_TRANSACTION_KEYWORD_UPDATE: { const struct mail_transaction_keyword_update *rec = data;
--- a/src/lib-index/mail-index-sync.c Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index-sync.c Wed Mar 04 17:40:24 2009 -0500 @@ -504,6 +504,7 @@ switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { case MAIL_TRANSACTION_EXT_REC_UPDATE: + case MAIL_TRANSACTION_EXT_ATOMIC_INC: /* extension record updates aren't exactly needed to be synced, but cache syncing relies on tail offsets being updated. */
--- a/src/lib-index/mail-index-transaction-private.h Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index-transaction-private.h Wed Mar 04 17:40:24 2009 -0500 @@ -4,6 +4,8 @@ #include "seq-range-array.h" #include "mail-transaction-log.h" +ARRAY_DEFINE_TYPE(seq_array_array, ARRAY_TYPE(seq_array)); + struct mail_index_transaction_keyword_update { ARRAY_TYPE(seq_range) add_seq; ARRAY_TYPE(seq_range) remove_seq; @@ -52,7 +54,8 @@ ARRAY_DEFINE(ext_hdr_updates, struct mail_index_transaction_ext_hdr_update); - ARRAY_DEFINE(ext_rec_updates, ARRAY_TYPE(seq_array)); + ARRAY_TYPE(seq_array_array) ext_rec_updates; + ARRAY_TYPE(seq_array_array) ext_rec_atomics; ARRAY_DEFINE(ext_resizes, struct mail_transaction_ext_intro); ARRAY_DEFINE(ext_resets, struct mail_transaction_ext_reset); ARRAY_DEFINE(ext_reset_ids, uint32_t);
--- a/src/lib-index/mail-index-transaction.c Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index-transaction.c Wed Mar 04 17:40:24 2009 -0500 @@ -33,16 +33,22 @@ if (array_is_created(&t->ext_rec_updates)) { recs = array_get_modifiable(&t->ext_rec_updates, &count); - for (i = 0; i < count; i++) { if (array_is_created(&recs[i])) array_free(&recs[i]); } array_free(&t->ext_rec_updates); } + if (array_is_created(&t->ext_rec_atomics)) { + recs = array_get_modifiable(&t->ext_rec_atomics, &count); + for (i = 0; i < count; i++) { + if (array_is_created(&recs[i])) + array_free(&recs[i]); + } + array_free(&t->ext_rec_atomics); + } if (array_is_created(&t->ext_hdr_updates)) { ext_hdrs = array_get_modifiable(&t->ext_hdr_updates, &count); - for (i = 0; i < count; i++) { i_free(ext_hdrs[i].data); i_free(ext_hdrs[i].mask); @@ -54,7 +60,6 @@ struct mail_index_transaction_keyword_update *u; u = array_get_modifiable(&t->keyword_updates, &count); - for (i = 0; i < count; i++) { if (array_is_created(&u[i].add_seq)) array_free(&u[i].add_seq); @@ -313,6 +318,11 @@ for (i = 0; i < count; i++) mail_index_convert_to_uids(t, (void *)&updates[i]); } + if (array_is_created(&t->ext_rec_atomics)) { + updates = array_get_modifiable(&t->ext_rec_atomics, &count); + for (i = 0; i < count; i++) + mail_index_convert_to_uids(t, (void *)&updates[i]); + } keyword_updates_convert_to_uids(t); @@ -382,6 +392,7 @@ static void mail_index_transaction_sort_appends_ext(struct mail_index_transaction *t, + ARRAY_TYPE(seq_array_array) *updates, const uint32_t *old_to_newseq_map) { ARRAY_TYPE(seq_array) *ext_rec_arrays; @@ -392,10 +403,10 @@ uint32_t seq; unsigned int i, j, count; - if (!array_is_created(&t->ext_rec_updates)) + if (!array_is_created(updates)) return; - ext_rec_arrays = array_get_modifiable(&t->ext_rec_updates, &count); + ext_rec_arrays = array_get_modifiable(updates, &count); for (j = 0; j < count; j++) { old_array = &ext_rec_arrays[j]; if (!array_is_created(old_array)) @@ -527,7 +538,10 @@ old_to_newseq_map[new_uid_map[i].idx] = i + t->first_new_seq; i_free(new_uid_map); - mail_index_transaction_sort_appends_ext(t, old_to_newseq_map); + mail_index_transaction_sort_appends_ext(t, &t->ext_rec_updates, + old_to_newseq_map); + mail_index_transaction_sort_appends_ext(t, &t->ext_rec_atomics, + old_to_newseq_map); mail_index_transaction_sort_appends_keywords(t, old_to_newseq_map); i_free(old_to_newseq_map); @@ -704,24 +718,37 @@ } static void -mail_index_expunge_last_append(struct mail_index_transaction *t, uint32_t seq) +mail_index_expunge_last_append_ext(struct mail_index_transaction *t, + ARRAY_TYPE(seq_array_array) *updates, + uint32_t seq) { ARRAY_TYPE(seq_array) *seqs; + unsigned int i, count, idx; + + if (!array_is_created(updates)) + return; + + seqs = array_get_modifiable(&t->ext_rec_updates, &count); + for (i = 0; i < count; i++) { + if (array_is_created(&seqs[i]) && + mail_index_seq_array_lookup(&seqs[i], seq, &idx)) + array_delete(&seqs[i], idx, 1); + } +} + +static void +mail_index_expunge_last_append(struct mail_index_transaction *t, uint32_t seq) +{ struct mail_index_transaction_keyword_update *kw_updates; - unsigned int i, idx, count; + unsigned int i, count; i_assert(seq == t->last_new_seq); /* remove extension updates */ - if (array_is_created(&t->ext_rec_updates)) { - seqs = array_get_modifiable(&t->ext_rec_updates, &count); - for (i = 0; i < count; i++) { - if (array_is_created(&seqs[i]) && - mail_index_seq_array_lookup(&seqs[i], seq, &idx)) - array_delete(&seqs[i], idx, 1); - } - t->log_ext_updates = mail_index_transaction_has_ext_changes(t); - } + mail_index_expunge_last_append_ext(t, &t->ext_rec_updates, seq); + mail_index_expunge_last_append_ext(t, &t->ext_rec_atomics, seq); + t->log_ext_updates = mail_index_transaction_has_ext_changes(t); + /* remove keywords */ if (array_is_created(&t->keyword_resets)) seq_range_array_remove(&t->keyword_resets, seq); @@ -1146,23 +1173,35 @@ } static bool -mail_index_transaction_has_ext_changes(struct mail_index_transaction *t) +mail_index_transaction_has_ext_updates(const ARRAY_TYPE(seq_array_array) *arr) { + const ARRAY_TYPE(seq_array) *array; unsigned int i, count; - if (array_is_created(&t->ext_rec_updates)) { - const ARRAY_TYPE(seq_array) *array; - - array = array_get(&t->ext_rec_updates, &count); + if (array_is_created(arr)) { + array = array_get(arr, &count); for (i = 0; i < count; i++) { if (array_is_created(&array[i])) return TRUE; } } + return FALSE; +} + +static bool +mail_index_transaction_has_ext_changes(struct mail_index_transaction *t) +{ + unsigned int i, count; + + if (mail_index_transaction_has_ext_updates(&t->ext_rec_updates)) + return TRUE; + if (mail_index_transaction_has_ext_updates(&t->ext_rec_atomics)) + return TRUE; + if (array_is_created(&t->ext_hdr_updates)) { const struct mail_index_transaction_ext_hdr_update *hdr; - hdr = array_get(&t->ext_hdr_updates, &count); + hdr = array_get(&t->ext_hdr_updates, &count); for (i = 0; i < count; i++) { if (hdr[i].alloc_size > 0) return TRUE; @@ -1189,18 +1228,24 @@ return FALSE; } +static void +mail_index_ext_update_reset(ARRAY_TYPE(seq_array_array) *arr, uint32_t ext_id) +{ + if (array_is_created(arr) && ext_id < array_count(arr)) { + /* if extension records have been updated, clear them */ + ARRAY_TYPE(seq_array) *array; + + array = array_idx_modifiable(arr, ext_id); + if (array_is_created(array)) + array_clear(array); + } +} + void mail_index_ext_set_reset_id(struct mail_index_transaction *t, uint32_t ext_id, uint32_t reset_id) { - if (array_is_created(&t->ext_rec_updates) && - ext_id < array_count(&t->ext_rec_updates)) { - /* if extension records have been updated, clear them */ - ARRAY_TYPE(seq_array) *array; - - array = array_idx_modifiable(&t->ext_rec_updates, ext_id); - if (array_is_created(array)) - array_clear(array); - } + mail_index_ext_update_reset(&t->ext_rec_updates, ext_id); + mail_index_ext_update_reset(&t->ext_rec_atomics, ext_id); if (array_is_created(&t->ext_hdr_updates) && ext_id < array_count(&t->ext_hdr_updates)) { /* if extension headers have been updated, clear them */ @@ -1302,6 +1347,24 @@ } } +void mail_index_atomic_inc_ext(struct mail_index_transaction *t, uint32_t seq, + uint32_t ext_id, int diff) +{ + ARRAY_TYPE(seq_array) *array; + int32_t diff32 = diff; + + i_assert(seq > 0 && + (seq <= mail_index_view_get_messages_count(t->view) || + seq <= t->last_new_seq)); + i_assert(ext_id < array_count(&t->view->index->extensions)); + + t->log_ext_updates = TRUE; + if (!array_is_created(&t->ext_rec_atomics)) + i_array_init(&t->ext_rec_atomics, ext_id + 2); + array = array_idx_modifiable(&t->ext_rec_atomics, ext_id); + mail_index_seq_array_add(array, seq, &diff32, sizeof(diff32), NULL); +} + struct mail_keywords * mail_index_keywords_create(struct mail_index *index, const char *const keywords[])
--- a/src/lib-index/mail-index.h Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-index.h Wed Mar 04 17:40:24 2009 -0500 @@ -498,5 +498,8 @@ now overwriting. */ void mail_index_update_ext(struct mail_index_transaction *t, uint32_t seq, uint32_t ext_id, const void *data, void *old_data); +/* Increase/decrease number in extension atomically. */ +void mail_index_atomic_inc_ext(struct mail_index_transaction *t, uint32_t seq, + uint32_t ext_id, int diff); #endif
--- a/src/lib-index/mail-transaction-log-append.c Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-transaction-log-append.c Wed Mar 04 17:40:24 2009 -0500 @@ -428,21 +428,16 @@ } } -static void log_append_ext_rec_updates(struct log_append_context *ctx) +static void log_append_ext_recs(struct log_append_context *ctx, + const ARRAY_TYPE(seq_array_array) *arr, + enum mail_transaction_type type) { struct mail_index_transaction *t = ctx->trans; - ARRAY_TYPE(seq_array) *updates; + const ARRAY_TYPE(seq_array) *updates; const uint32_t *reset_ids; unsigned int ext_id, count, reset_id_count; uint32_t reset_id; - if (!array_is_created(&t->ext_rec_updates)) { - updates = NULL; - count = 0; - } else { - updates = array_get_modifiable(&t->ext_rec_updates, &count); - } - if (!array_is_created(&t->ext_reset_ids)) { reset_ids = NULL; reset_id_count = 0; @@ -451,6 +446,7 @@ &reset_id_count); } + updates = array_get(arr, &count); for (ext_id = 0; ext_id < count; ext_id++) { if (!array_is_created(&updates[ext_id])) continue; @@ -458,8 +454,7 @@ reset_id = ext_id < reset_id_count ? reset_ids[ext_id] : 0; log_append_ext_intro(ctx, ext_id, reset_id); - log_append_buffer(ctx, updates[ext_id].arr.buffer, NULL, - MAIL_TRANSACTION_EXT_REC_UPDATE); + log_append_buffer(ctx, updates[ext_id].arr.buffer, NULL, type); } } @@ -637,8 +632,14 @@ MAIL_TRANSACTION_FLAG_UPDATE); } - if (array_is_created(&t->ext_rec_updates)) - log_append_ext_rec_updates(&ctx); + if (array_is_created(&t->ext_rec_updates)) { + log_append_ext_recs(&ctx, &t->ext_rec_updates, + MAIL_TRANSACTION_EXT_REC_UPDATE); + } + if (array_is_created(&t->ext_rec_atomics)) { + log_append_ext_recs(&ctx, &t->ext_rec_atomics, + MAIL_TRANSACTION_EXT_ATOMIC_INC); + } /* keyword resets before updates */ if (array_is_created(&t->keyword_resets)) {
--- a/src/lib-index/mail-transaction-log.h Wed Mar 04 12:03:19 2009 -0500 +++ b/src/lib-index/mail-transaction-log.h Wed Mar 04 17:40:24 2009 -0500 @@ -36,12 +36,14 @@ MAIL_TRANSACTION_EXT_REC_UPDATE = 0x00000200, MAIL_TRANSACTION_KEYWORD_UPDATE = 0x00000400, MAIL_TRANSACTION_KEYWORD_RESET = 0x00000800, + MAIL_TRANSACTION_EXT_ATOMIC_INC = 0x00001000, MAIL_TRANSACTION_TYPE_MASK = 0x0000ffff, #define MAIL_TRANSACTION_EXT_MASK \ (MAIL_TRANSACTION_EXT_INTRO | MAIL_TRANSACTION_EXT_RESET | \ - MAIL_TRANSACTION_EXT_HDR_UPDATE | MAIL_TRANSACTION_EXT_REC_UPDATE) + MAIL_TRANSACTION_EXT_HDR_UPDATE | MAIL_TRANSACTION_EXT_REC_UPDATE | \ + MAIL_TRANSACTION_EXT_ATOMIC_INC) /* since we'll expunge mails based on data read from transaction log, try to avoid the possibility of corrupted transaction log expunging @@ -124,6 +126,10 @@ uint32_t uid; /* unsigned char data[]; */ }; +struct mail_transaction_ext_atomic_inc { + uint32_t uid; + int32_t diff; +}; #define LOG_IS_BEFORE(seq1, offset1, seq2, offset2) \ (((offset1) < (offset2) && (seq1) == (seq2)) || (seq1) < (seq2))
--- a/src/util/logview.c Wed Mar 04 12:03:19 2009 -0500 +++ b/src/util/logview.c Wed Mar 04 17:40:24 2009 -0500 @@ -102,6 +102,9 @@ case MAIL_TRANSACTION_KEYWORD_RESET: name = "keyword-reset"; break; + case MAIL_TRANSACTION_EXT_ATOMIC_INC: + name = "ext-atomic-inc"; + break; default: name = t_strdup_printf("unknown: %x", type); break; @@ -323,6 +326,19 @@ } break; } + case MAIL_TRANSACTION_EXT_ATOMIC_INC: { + const struct mail_transaction_ext_atomic_inc *rec = data, *end; + + end = CONST_PTR_OFFSET(data, size); + for (; rec < end; rec++) { + printf(" - %u: ", rec->uid); + if (rec->diff > 0) + printf("+%d\n", rec->diff); + else + printf("%d\n", rec->diff); + } + break; + } case MAIL_TRANSACTION_KEYWORD_UPDATE: { const struct mail_transaction_keyword_update *u = data; const uint32_t *uid;