]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added mail_index_atomic_inc_ext() for atomically incrementing numbers in extensions.
authorTimo Sirainen <tss@iki.fi>
Wed, 4 Mar 2009 22:40:24 +0000 (17:40 -0500)
committerTimo Sirainen <tss@iki.fi>
Wed, 4 Mar 2009 22:40:24 +0000 (17:40 -0500)
--HG--
branch : HEAD

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

index bdb873b006bc07bfcdbd05748049efa6c9488e05..57d18222fbd09bde89d1b431c64a8b0c58d1f572 100644 (file)
@@ -686,3 +686,63 @@ mail_index_sync_ext_rec_update(struct mail_index_sync_map_ctx *ctx,
        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;
+}
index 23f7202c1f374bea64ff07d3a42b76660e1a4747..328fa34f749c0e2c85fb325d69ebdef827eb7542 100644 (file)
@@ -82,6 +82,9 @@ mail_index_sync_ext_hdr_update(struct mail_index_sync_map_ctx *ctx,
 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,
index d82613d3523e3262cd80e9540f45d1e19aa1ce21..cae0a978ed9a47ee1598ed4c764d66893c83f17f 100644 (file)
@@ -630,6 +630,31 @@ int mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
                }
                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;
 
index 7c4f5d26f3dcce3dd3c0cdee36f59cb29e3fb10e..c1e4b3209277c348fa971a9f99fb52f5e1e1715e 100644 (file)
@@ -504,6 +504,7 @@ static bool mail_index_sync_view_have_any(struct mail_index_view *view,
 
                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. */
index 7b1e07000e12c20485f5182737f16f729e2af912..cd213d67f30d85d9c3ff9efd523483ec7fe4a066 100644 (file)
@@ -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 @@ struct mail_index_transaction {
 
        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);
index b7f73af8d7abb531a5662dbe7c4d0aeab0f85375..1f349ab3e980f51958a47dc301f12dbc68cdfc9e 100644 (file)
@@ -33,16 +33,22 @@ void mail_index_transaction_reset(struct mail_index_transaction *t)
 
        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 @@ void mail_index_transaction_reset(struct mail_index_transaction *t)
                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 @@ void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
                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 @@ mail_index_update_day_headers(struct mail_index_transaction *t)
 
 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 @@ mail_index_transaction_sort_appends_ext(struct mail_index_transaction *t,
        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 @@ void mail_index_transaction_sort_appends(struct mail_index_transaction *t)
                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 @@ void mail_index_append_assign_uids(struct mail_index_transaction *t,
 }
 
 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 @@ void mail_index_ext_reset_inc(struct mail_index_transaction *t, uint32_t ext_id,
 }
 
 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 =\v 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 @@ mail_index_transaction_has_ext_changes(struct mail_index_transaction *t)
        return FALSE;
 }
 
-void mail_index_ext_set_reset_id(struct mail_index_transaction *t,
-                                uint32_t ext_id, uint32_t reset_id)
+static void
+mail_index_ext_update_reset(ARRAY_TYPE(seq_array_array) *arr, uint32_t ext_id)
 {
-       if (array_is_created(&t->ext_rec_updates) &&
-           ext_id < array_count(&t->ext_rec_updates)) {
+       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(&t->ext_rec_updates, ext_id);
+               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)
+{
+       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_update_ext(struct mail_index_transaction *t, uint32_t seq,
        }
 }
 
+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[])
index 1c1aa58cd24e168da6e3a1816f2d5a7cc3f3ddaf..073fb6e92f75521ee7f1d93b5a6e05eb946d182d 100644 (file)
@@ -498,5 +498,8 @@ void mail_index_update_header_ext(struct mail_index_transaction *t,
    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
index d4a000727a7769e2d0f35dec47963edc4d45b130..65f44831baa9792533e1b108d90dc6513d9f87fa 100644 (file)
@@ -428,21 +428,16 @@ mail_transaction_log_append_ext_intros(struct log_append_context *ctx)
        }
 }
 
-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 @@ static void log_append_ext_rec_updates(struct log_append_context *ctx)
                                                 &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 @@ static void log_append_ext_rec_updates(struct log_append_context *ctx)
                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_log_append_locked(struct mail_index_transaction *t,
                                  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)) {
index 35d2fc62cca819fa92c2629ec86959927c1e570b..0886f81da56b5b40b67c622bfaa786aa1ed0b3fe 100644 (file)
@@ -36,12 +36,14 @@ enum mail_transaction_type {
        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 @@ struct mail_transaction_ext_rec_update {
        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))
index be9165c8f3e01e53345885f63fe1fb622e0a290a..0a74883a8d9ee1b4b87744f01a27f4afca6acd29 100644 (file)
@@ -102,6 +102,9 @@ static const char *log_record_type(unsigned int type)
        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 @@ static void log_record_print(const struct mail_transaction_header *hdr,
                }
                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;