From fee561b9d9162b130e662914fcebc9dd99b5c320 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 14 Mar 2013 15:29:18 +0200 Subject: [PATCH] lib-index: mail_index_attribute_[un]set() adds changed attributes' keys to transaction log. This provides them both a modseq (so their changes become visible) as well as an efficient way to see what attributes have changed by reading the transaction log. The values themselves aren't written to the log, because they could be large. --- src/doveadm/doveadm-dump-log.c | 14 ++++++++ src/lib-index/mail-index-modseq.c | 10 +++++- src/lib-index/mail-index-sync-update.c | 5 +++ src/lib-index/mail-index-transaction-export.c | 9 +++++ .../mail-index-transaction-private.h | 1 + src/lib-index/mail-index-transaction-update.c | 27 +++++++++++++++ src/lib-index/mail-index.h | 8 +++++ src/lib-index/mail-transaction-log-file.c | 1 + src/lib-index/mail-transaction-log-view.c | 34 +++++++++++++++++++ src/lib-index/mail-transaction-log.h | 3 +- 10 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/doveadm/doveadm-dump-log.c b/src/doveadm/doveadm-dump-log.c index 429b9acc38..eb4ffa5e4e 100644 --- a/src/doveadm/doveadm-dump-log.c +++ b/src/doveadm/doveadm-dump-log.c @@ -52,6 +52,7 @@ mail_transaction_header_has_modseq(const struct mail_transaction_header *hdr) case MAIL_TRANSACTION_FLAG_UPDATE: case MAIL_TRANSACTION_KEYWORD_UPDATE: case MAIL_TRANSACTION_KEYWORD_RESET: + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: /* these changes increase modseq */ return TRUE; } @@ -114,6 +115,9 @@ static const char *log_record_type(unsigned int type) case MAIL_TRANSACTION_BOUNDARY: name = "boundary"; break; + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: + name = "attribute-update"; + break; default: name = t_strdup_printf("unknown: %x", type); break; @@ -415,6 +419,16 @@ static void log_record_print(const struct mail_transaction_header *hdr, printf(" - size=%u\n", rec->size); break; } + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: { + const char *keys = data; + unsigned int i; + + for (i = 0; i < size && keys[i] != '\0'; ) { + printf(" - %s\n", keys+i); + i += strlen(keys+i) + 1; + } + break; + } default: break; } diff --git a/src/lib-index/mail-index-modseq.c b/src/lib-index/mail-index-modseq.c index 2114f04561..75aecf3255 100644 --- a/src/lib-index/mail-index-modseq.c +++ b/src/lib-index/mail-index-modseq.c @@ -335,6 +335,7 @@ mail_index_modseq_update_old_rec(struct mail_index_modseq_sync *ctx, buffer_t uid_buf; unsigned int i, count; uint32_t seq1, seq2; + uint64_t modseq; switch (thdr->type & MAIL_TRANSACTION_TYPE_MASK) { case MAIL_TRANSACTION_APPEND: { @@ -374,12 +375,19 @@ mail_index_modseq_update_old_rec(struct mail_index_modseq_sync *ctx, array_create_from_buffer(&uids, &uid_buf, sizeof(struct mail_transaction_keyword_reset)); break; + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: + break; default: return; } + /* update highestmodseq regardless of whether any mails were updated */ + modseq = mail_transaction_log_view_get_prev_modseq(ctx->log_view); + if (modseq > ctx->highest_modseq) + ctx->highest_modseq = modseq; + /* update modseqs */ - count = array_count(&uids); + count = array_is_created(&uids) ? array_count(&uids) : 0; for (i = 0; i < count; i++) { rec = array_idx(&uids, i); if (mail_index_lookup_seq_range(ctx->view, rec->seq1, rec->seq2, diff --git a/src/lib-index/mail-index-sync-update.c b/src/lib-index/mail-index-sync-update.c index b206b58080..986d3a1b22 100644 --- a/src/lib-index/mail-index-sync-update.c +++ b/src/lib-index/mail-index-sync-update.c @@ -495,6 +495,7 @@ mail_index_sync_record_real(struct mail_index_sync_map_ctx *ctx, const struct mail_transaction_header *hdr, const void *data) { + uint64_t modseq; int ret = 0; switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { @@ -767,6 +768,10 @@ mail_index_sync_record_real(struct mail_index_sync_map_ctx *ctx, break; case MAIL_TRANSACTION_BOUNDARY: break; + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: + modseq = mail_transaction_log_view_get_prev_modseq(ctx->view->log_view); + mail_index_modseq_update_highest(ctx->modseq_ctx, modseq); + break; default: mail_index_sync_set_corrupted(ctx, "Unknown transaction record type 0x%x", diff --git a/src/lib-index/mail-index-transaction-export.c b/src/lib-index/mail-index-transaction-export.c index 2a8801c0d0..7194836aba 100644 --- a/src/lib-index/mail-index-transaction-export.c +++ b/src/lib-index/mail-index-transaction-export.c @@ -393,6 +393,15 @@ void mail_index_transaction_export(struct mail_index_transaction *t, log_append_buffer(&ctx, log_get_hdr_update_buffer(t, TRUE), MAIL_TRANSACTION_HEADER_UPDATE); } + if (t->attribute_updates != NULL) { + /* need to have 32bit alignment */ + if (t->attribute_updates->used % 4 != 0) { + buffer_append_zero(t->attribute_updates, + 4 - t->attribute_updates->used % 4); + } + log_append_buffer(&ctx, t->attribute_updates, + MAIL_TRANSACTION_ATTRIBUTE_UPDATE); + } if (array_is_created(&t->appends)) { change_mask |= MAIL_INDEX_FSYNC_MASK_APPENDS; log_append_buffer(&ctx, t->appends.arr.buffer, diff --git a/src/lib-index/mail-index-transaction-private.h b/src/lib-index/mail-index-transaction-private.h index 9816a33e3e..aef4765e6e 100644 --- a/src/lib-index/mail-index-transaction-private.h +++ b/src/lib-index/mail-index-transaction-private.h @@ -70,6 +70,7 @@ struct mail_index_transaction { ARRAY(uint32_t) ext_reset_atomic; ARRAY(struct mail_index_transaction_keyword_update) keyword_updates; + buffer_t *attribute_updates; /* [+-][ps]key\0.. */ uint64_t min_highest_modseq; uint64_t max_modseq; diff --git a/src/lib-index/mail-index-transaction-update.c b/src/lib-index/mail-index-transaction-update.c index 03ebed55af..e5a4c318b9 100644 --- a/src/lib-index/mail-index-transaction-update.c +++ b/src/lib-index/mail-index-transaction-update.c @@ -76,6 +76,8 @@ void mail_index_transaction_reset_v(struct mail_index_transaction *t) array_free(&t->ext_reset_ids); if (array_is_created(&t->ext_reset_atomic)) array_free(&t->ext_reset_atomic); + if (t->attribute_updates != NULL) + buffer_free(&t->attribute_updates); t->first_new_seq = mail_index_view_get_messages_count(t->view)+1; t->last_new_seq = 0; @@ -106,6 +108,7 @@ void mail_index_transaction_set_log_updates(struct mail_index_transaction *t) array_is_created(&t->modseq_updates) || array_is_created(&t->expunges) || array_is_created(&t->keyword_updates) || + t->attribute_updates != NULL || t->pre_hdr_changed || t->post_hdr_changed || t->min_highest_modseq != 0; } @@ -647,6 +650,30 @@ void mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq, mail_index_update_flags_range(t, seq, seq, modify_type, flags); } +static void +mail_index_attribute_set_full(struct mail_index_transaction *t, + const char *key, bool pvt, char prefix) +{ + if (t->attribute_updates == NULL) + t->attribute_updates = buffer_create_dynamic(default_pool, 64); + buffer_append_c(t->attribute_updates, prefix); + buffer_append_c(t->attribute_updates, pvt ? 'p' : 's'); + buffer_append(t->attribute_updates, key, strlen(key)+1); + t->log_updates = TRUE; +} + +void mail_index_attribute_set(struct mail_index_transaction *t, + bool pvt, const char *key) +{ + mail_index_attribute_set_full(t, key, pvt, '+'); +} + +void mail_index_attribute_unset(struct mail_index_transaction *t, + bool pvt, const char *key) +{ + mail_index_attribute_set_full(t, key, pvt, '-'); +} + void mail_index_update_header(struct mail_index_transaction *t, size_t offset, const void *data, size_t size, bool prepend) diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index 570bdc25c5..2495559026 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -464,6 +464,14 @@ void mail_index_update_flags_range(struct mail_index_transaction *t, uint32_t seq1, uint32_t seq2, enum modify_type modify_type, enum mail_flags flags); +/* Specified attribute's value was changed. This is just a notification so the + change gets assigned its own modseq and any log readers can find out about + this change. */ +void mail_index_attribute_set(struct mail_index_transaction *t, + bool pvt, const char *key); +/* Attribute was deleted. */ +void mail_index_attribute_unset(struct mail_index_transaction *t, + bool pvt, const char *key); /* Update message's modseq to be at least min_modseq. */ void mail_index_update_modseq(struct mail_index_transaction *t, uint32_t seq, uint64_t min_modseq); diff --git a/src/lib-index/mail-transaction-log-file.c b/src/lib-index/mail-transaction-log-file.c index 9de8a5c04b..4e0bcfa4d7 100644 --- a/src/lib-index/mail-transaction-log-file.c +++ b/src/lib-index/mail-transaction-log-file.c @@ -1022,6 +1022,7 @@ void mail_transaction_update_modseq(const struct mail_transaction_header *hdr, case MAIL_TRANSACTION_FLAG_UPDATE: case MAIL_TRANSACTION_KEYWORD_UPDATE: case MAIL_TRANSACTION_KEYWORD_RESET: + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: /* these changes increase modseq */ *cur_modseq += 1; break; diff --git a/src/lib-index/mail-transaction-log-view.c b/src/lib-index/mail-transaction-log-view.c index 78b7673922..60f594e4d8 100644 --- a/src/lib-index/mail-transaction-log-view.c +++ b/src/lib-index/mail-transaction-log-view.c @@ -608,6 +608,40 @@ log_view_is_record_valid(struct mail_transaction_log_file *file, if ((i % 4) != 0) i += 4 - (i % 4); } + break; + } + case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: { + const char *attr_changes = data; + unsigned int i; + + for (i = 0; i+2 < rec_size && attr_changes[i] != '\0'; ) { + if (attr_changes[i] != '+' && attr_changes[i] != '-') { + mail_transaction_log_file_set_corrupted(file, + "attribute update: Invalid prefix 0x%02x", + attr_changes[i]); + return FALSE; + } + i++; + if (attr_changes[i] != 'p' && attr_changes[i] != 's') { + mail_transaction_log_file_set_corrupted(file, + "attribute update: Invalid type 0x%02x", + attr_changes[i]); + return FALSE; + } + i++; + if (attr_changes[i] == '\0') { + mail_transaction_log_file_set_corrupted(file, + "attribute update: Empty key"); + return FALSE; + } + i += strlen(attr_changes+i) + 1; + } + if (i == 0 || (i < rec_size && attr_changes[i] != '\0')) { + mail_transaction_log_file_set_corrupted(file, + "attribute update doesn't end with NUL"); + return FALSE; + } + break; } default: break; diff --git a/src/lib-index/mail-transaction-log.h b/src/lib-index/mail-transaction-log.h index ee43222b78..69e9b7139d 100644 --- a/src/lib-index/mail-transaction-log.h +++ b/src/lib-index/mail-transaction-log.h @@ -44,8 +44,9 @@ enum mail_transaction_type { MAIL_TRANSACTION_INDEX_DELETED = 0x00020000, MAIL_TRANSACTION_INDEX_UNDELETED = 0x00040000, MAIL_TRANSACTION_BOUNDARY = 0x00080000, + MAIL_TRANSACTION_ATTRIBUTE_UPDATE = 0x00100000, - MAIL_TRANSACTION_TYPE_MASK = 0x000fffff, + MAIL_TRANSACTION_TYPE_MASK = 0x0fffffff, #define MAIL_TRANSACTION_EXT_MASK \ (MAIL_TRANSACTION_EXT_INTRO | MAIL_TRANSACTION_EXT_RESET | \ -- 2.47.3