mail-index-transaction.c revision a1248a194946f2429f1cb0da7cf22bf73e8a11be
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen Before they're written to transaction log the sequences are changed to
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen UIDs. This is because we're able to compress sequence ranges better. */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen#include "lib.h"
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen#include "array.h"
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen#include "seq-range-array.h"
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen#include "mail-index-view-private.h"
eb5ea3f4513ff2999892b8d904551f58b74f65f9Timo Sirainen#include "mail-transaction-log.h"
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen#include "mail-cache-private.h"
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen#include "mail-index-transaction-private.h"
eb5ea3f4513ff2999892b8d904551f58b74f65f9Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen#include <stddef.h>
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen#include <stdlib.h>
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstruct mail_index_transaction *
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenmail_index_transaction_begin(struct mail_index_view *view,
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen bool hide, bool external)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen{
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen struct mail_index_transaction *t;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* don't allow syncing view while there's ongoing transactions */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen mail_index_view_transaction_ref(view);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen mail_index_view_ref(view);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen t = i_new(struct mail_index_transaction, 1);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen t->refcount = 1;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen t->view = view;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen t->hide_transaction = hide;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen t->external = external;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (view->syncing) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* transaction view cannot work if new records are being added
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen in two places. make sure it doesn't happen. */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen t->no_appends = TRUE;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen return t;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen}
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen{
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_t *recs;
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen unsigned i, count;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->ext_rec_updates)) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen recs = array_get_modifyable(&t->ext_rec_updates, &count);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen for (i = 0; i < count; i++) {
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen if (array_is_created(&recs[i]))
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen array_free(&recs[i]);
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen }
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen array_free(&t->ext_rec_updates);
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen }
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->keyword_updates)) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen struct mail_index_transaction_keyword_update *u;
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen u = array_get_modifyable(&t->keyword_updates, &count);
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen for (i = 0; i < count; i++) {
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen if (array_is_created(&u[i].add_seq))
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen array_free(&u[i].add_seq);
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen if (array_is_created(&u[i].remove_seq))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&u[i].remove_seq);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&t->keyword_updates);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->keyword_resets))
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen array_free(&t->keyword_resets);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen if (array_is_created(&t->appends))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&t->appends);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->expunges))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&t->expunges);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->updates))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&t->updates);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->ext_resizes))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&t->ext_resizes);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&t->ext_resets))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_free(&t->ext_resets);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen mail_index_view_transaction_unref(t->view);
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen mail_index_view_close(&t->view);
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen i_free(t);
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen}
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen{
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen t->refcount++;
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen}
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction **_t)
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen{
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen struct mail_index_transaction *t = *_t;
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen *_t = NULL;
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen if (--t->refcount == 0)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen mail_index_transaction_free(t);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen}
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainenbool mail_index_seq_array_lookup(const array_t *array, uint32_t seq,
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen unsigned int *idx_r)
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen{
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen ARRAY_SET_TYPE(array, uint32_t);
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen unsigned int idx, left_idx, right_idx, count;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen const uint32_t *seq_p;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen
605eca549c08af753e05c25937bcccd66079c321Timo Sirainen count = array_count(array);
605eca549c08af753e05c25937bcccd66079c321Timo Sirainen if (count == 0) {
605eca549c08af753e05c25937bcccd66079c321Timo Sirainen *idx_r = 0;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen return FALSE;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen }
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen /* we're probably appending it, check */
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen seq_p = array_idx(array, count-1);
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen if (*seq_p < seq)
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen idx = count;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen else {
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen idx = 0; left_idx = 0; right_idx = count;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen while (left_idx < right_idx) {
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen idx = (left_idx + right_idx) / 2;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen seq_p = array_idx(array, idx);
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen if (*seq_p < seq)
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen left_idx = idx+1;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen else if (*seq_p > seq)
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen right_idx = idx;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen else {
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen *idx_r = idx;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen return TRUE;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen }
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen }
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen }
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen *idx_r = idx;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen return FALSE;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen}
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainenstatic bool mail_index_seq_array_add(array_t *array, uint32_t seq,
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen const void *record, size_t record_size,
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen void *old_record)
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen{
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen ARRAY_SET_TYPE(array, void *);
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen void *p;
605eca549c08af753e05c25937bcccd66079c321Timo Sirainen unsigned int idx;
605eca549c08af753e05c25937bcccd66079c321Timo Sirainen
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen if (!array_is_created(array)) {
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen array_create(array, default_pool,
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen sizeof(seq) + record_size,
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen 1024 / (sizeof(seq) + record_size));
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen }
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen i_assert(array->element_size == sizeof(seq) + record_size);
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen if (mail_index_seq_array_lookup(array, seq, &idx)) {
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen /* already there, update */
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen p = array_idx_modifyable(array, idx);
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (old_record != NULL) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen /* save the old record before overwriting it */
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen record_size);
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen return TRUE;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen } else {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* insert */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen p = array_insert_space(array, idx);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen memcpy(p, &seq, sizeof(seq));
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen return FALSE;
e8ecd8f24ffc612f5d0be10f7931ac619f1eab88Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen}
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstatic void
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenmail_index_buffer_convert_to_uids(struct mail_index_transaction *t,
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_t *array, bool range)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen ARRAY_SET_TYPE(array, uint32_t);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen struct mail_index_view *view = t->view;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen const struct mail_index_record *rec;
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen uint32_t *seq;
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen unsigned int i, j, count, range_count;
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen if (!array_is_created(array))
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen return;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen count = array_count(array);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen range_count = range ? 1 : 0;
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen for (i = 0; i < count; i++) {
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen seq = array_idx_modifyable(array, i);
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen for (j = 0; j <= range_count; j++, seq++) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen i_assert(*seq > 0);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (*seq >= t->first_new_seq)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen rec = mail_index_transaction_lookup(t, *seq);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen else {
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen i_assert(*seq <= view->map->records_count);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, *seq - 1);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (rec->uid == 0) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* FIXME: replace with simple assert once we
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen figure out why this happens.. */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen i_panic("seq = %u, rec->uid = %u, "
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen "first_new_seq = %u, records = %u",
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen *seq, rec->uid, t->first_new_seq,
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen view->map->records_count);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen *seq = rec->uid;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen}
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstatic void arrays_convert_to_uids(struct mail_index_transaction *t,
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_t *array, bool range)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen{
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen ARRAY_SET_TYPE(array, array_t);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen array_t *updates;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen unsigned int i, count;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (!array_is_created(array))
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen return;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen updates = array_get_modifyable(array, &count);
4c9a72e0988d462df49810984dc93b3fd4a24c23Timo Sirainen for (i = 0; i < count; i++) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (array_is_created(&updates[i])) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mail_index_buffer_convert_to_uids(t, &updates[i],
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen range);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen}
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainenstatic void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen{
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen struct mail_index_transaction_keyword_update *updates;
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen unsigned int i, count;
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen if (!array_is_created(&t->keyword_updates))
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen return;
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen updates = array_get_modifyable(&t->keyword_updates, &count);
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen for (i = 0; i < count; i++) {
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen if (array_is_created(&updates[i].add_seq)) {
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen mail_index_buffer_convert_to_uids(t,
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen &updates[i].add_seq, TRUE);
749a9676d265a517c7a731f5b9336c524a49e6a6Timo Sirainen }
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen if (array_is_created(&updates[i].remove_seq)) {
749a9676d265a517c7a731f5b9336c524a49e6a6Timo Sirainen mail_index_buffer_convert_to_uids(t,
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen &updates[i].remove_seq, TRUE);
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen }
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen }
5e85a6a1349177c613dea55aabb20d857b8240a5Timo Sirainen}
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainenstatic int
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen{
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen if (mail_index_view_lock(t->view) < 0)
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen return -1;
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen arrays_convert_to_uids(t, &t->ext_rec_updates, FALSE);
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen keyword_updates_convert_to_uids(t);
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen mail_index_buffer_convert_to_uids(t, &t->expunges, TRUE);
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen mail_index_buffer_convert_to_uids(t, &t->updates, TRUE);
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen mail_index_buffer_convert_to_uids(t, &t->keyword_resets, TRUE);
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen return 0;
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen}
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainenstruct uid_map {
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen uint32_t idx;
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen uint32_t uid;
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen};
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainenstatic int uid_map_cmp(const void *p1, const void *p2)
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen{
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen const struct uid_map *m1 = p1, *m2 = p2;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen return m1->uid < m2->uid ? -1 :
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen (m1->uid > m2->uid ? 1 : 0);
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen}
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainenstatic void
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainenmail_index_transaction_sort_appends(struct mail_index_transaction *t)
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen{
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen struct mail_index_record *recs, *sorted_recs;
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen struct uid_map *new_uid_map;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen array_t *ext_rec_arrays;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen uint32_t *old_to_new_map;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen unsigned int i, j, count, ext_rec_array_count;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* first make a copy of the UIDs and map them to sequences */
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen recs = array_get_modifyable(&t->appends, &count);
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen new_uid_map = i_new(struct uid_map, count);
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen for (i = 0; i < count; i++) {
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen new_uid_map[i].idx = i;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen new_uid_map[i].uid = recs[i].uid;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen }
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* now sort the UID map */
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen qsort(new_uid_map, count, sizeof(*new_uid_map), uid_map_cmp);
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen old_to_new_map = i_new(uint32_t, count);
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen for (i = 0; i < count; i++)
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen old_to_new_map[new_uid_map[i].idx] = i;
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* sort mail records */
eb5ea3f4513ff2999892b8d904551f58b74f65f9Timo Sirainen sorted_recs = i_new(struct mail_index_record, count);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen for (i = 0; i < count; i++)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen sorted_recs[i] = recs[new_uid_map[i].idx];
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen buffer_write(t->appends.buffer, 0, sorted_recs,
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen sizeof(*sorted_recs) * count);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen i_free(sorted_recs);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen /* fix the order in extensions */
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen ext_rec_arrays = array_get_modifyable(&t->ext_rec_updates,
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen &ext_rec_array_count);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen for (j = 0; j < ext_rec_array_count; j++) {
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen array_t *old_array = &ext_rec_arrays[j];
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen ARRAY_SET_TYPE(old_array, void *);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen array_t ARRAY_DEFINE(new_array, void *);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen unsigned int ext_count;
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen const uint32_t *ext_rec;
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen uint32_t seq;
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen if (!array_is_created(old_array))
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen continue;
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen ext_count = array_count(old_array);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen array_create(&new_array, default_pool,
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen old_array->element_size, ext_count);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen for (i = 0; i < ext_count; i++) {
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen ext_rec = array_idx(old_array, i);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen seq = *ext_rec < t->first_new_seq ? *ext_rec :
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen (t->first_new_seq +
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen old_to_new_map[*ext_rec - t->first_new_seq]);
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen mail_index_seq_array_add(&new_array, seq, ext_rec+1,
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen old_array->element_size -
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen sizeof(*ext_rec), NULL);
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen }
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_free(old_array);
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen ext_rec_arrays[j] = new_array;
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen }
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen /* FIXME: fix the order in keywords */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen i_free(new_uid_map);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen i_free(old_to_new_map);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen}
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenint mail_index_transaction_commit(struct mail_index_transaction **_t,
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen uint32_t *log_file_seq_r,
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen uoff_t *log_file_offset_r)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen{
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen struct mail_index_transaction *t = *_t;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen int ret;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen mail_index_transaction_rollback(_t);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen return -1;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen }
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen if (t->cache_trans_ctx != NULL) {
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen mail_cache_transaction_commit(t->cache_trans_ctx);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen t->cache_trans_ctx = NULL;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen }
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen if (t->appends_nonsorted)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen mail_index_transaction_sort_appends(t);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen if (mail_index_transaction_convert_to_uids(t) < 0)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen ret = -1;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen else {
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen ret = mail_transaction_log_append(t, log_file_seq_r,
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen log_file_offset_r);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen }
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen mail_index_transaction_unref(_t);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen return ret;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen}
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction **_t)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen{
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen struct mail_index_transaction *t = *_t;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen if (t->cache_trans_ctx != NULL) {
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen mail_cache_transaction_rollback(t->cache_trans_ctx);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen t->cache_trans_ctx = NULL;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen }
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen mail_index_transaction_unref(_t);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen}
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenstruct mail_index_record *
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainenmail_index_transaction_lookup(struct mail_index_transaction *t, uint32_t seq)
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen{
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen i_assert(seq >= t->first_new_seq && seq <= t->last_new_seq);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen return array_idx_modifyable(&t->appends, seq - t->first_new_seq);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen}
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainenvoid mail_index_append(struct mail_index_transaction *t, uint32_t uid,
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen uint32_t *seq_r)
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen{
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen struct mail_index_record *rec;
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen i_assert(!t->no_appends);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen t->log_updates = TRUE;
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen if (!array_is_created(&t->appends)) {
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen ARRAY_CREATE(&t->appends, default_pool,
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen struct mail_index_record, 32);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen }
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen /* sequence number is visible only inside given view,
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen so let it generate it */
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen if (t->last_new_seq != 0)
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen *seq_r = ++t->last_new_seq;
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen else
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen *seq_r = t->last_new_seq = t->first_new_seq;
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen rec = array_append_space(&t->appends);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen if (uid != 0) {
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen rec->uid = uid;
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen if (!t->appends_nonsorted &&
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen t->last_new_seq != t->first_new_seq) {
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen /* if previous record's UID is larger than this one,
we'll have to sort the appends later */
rec = mail_index_transaction_lookup(t, *seq_r - 1);
if (rec->uid > uid)
t->appends_nonsorted = TRUE;
}
}
}
void mail_index_append_assign_uids(struct mail_index_transaction *t,
uint32_t first_uid, uint32_t *next_uid_r)
{
struct mail_index_record *recs;
unsigned int i, count;
if (!array_is_created(&t->appends))
return;
recs = array_get_modifyable(&t->appends, &count);
/* find the first mail with uid = 0 */
for (i = 0; i < count; i++) {
if (recs[i].uid == 0)
break;
}
for (; i < count; i++) {
i_assert(recs[i].uid == 0);
recs[i].uid = first_uid++;
}
*next_uid_r = first_uid;
}
void mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
{
i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
t->log_updates = TRUE;
/* expunges is a sorted array of {seq1, seq2, ..}, .. */
seq_range_array_add(&t->expunges, 128, seq);
}
static void
mail_index_insert_flag_update(struct mail_index_transaction *t,
struct mail_transaction_flag_update u,
uint32_t left_idx, uint32_t right_idx)
{
struct mail_transaction_flag_update *updates, tmp_update;
unsigned int count;
uint32_t idx, move;
updates = array_get_modifyable(&t->updates, &count);
i_assert(left_idx <= right_idx && right_idx <= count);
/* find the first update with either overlapping range,
or the update which will come after our insert */
idx = left_idx;
while (left_idx < right_idx) {
idx = (left_idx + right_idx) / 2;
if (updates[idx].uid2 < u.uid1)
left_idx = idx+1;
else if (updates[idx].uid1 > u.uid1)
right_idx = idx;
else
break;
}
if (idx < count && updates[idx].uid2 < u.uid1)
idx++;
/* overlapping ranges, split/merge them */
i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
i_assert(idx == count || updates[idx].uid2 >= u.uid1);
for (; idx < count && u.uid2 >= updates[idx].uid1; idx++) {
if (u.uid1 != updates[idx].uid1 &&
(updates[idx].add_flags != u.add_flags ||
updates[idx].remove_flags != u.remove_flags)) {
if (u.uid1 < updates[idx].uid1) {
/* insert new update */
tmp_update = u;
tmp_update.uid2 = updates[idx].uid1 - 1;
move = 0;
} else {
/* split existing update from beginning */
tmp_update = updates[idx];
tmp_update.uid2 = u.uid1 - 1;
updates[idx].uid1 = u.uid1;
move = 1;
}
i_assert(tmp_update.uid1 <= tmp_update.uid2);
i_assert(updates[idx].uid1 <= updates[idx].uid2);
array_insert(&t->updates, idx, &tmp_update, 1);
updates = array_get_modifyable(&t->updates, &count);
idx += move;
} else if (u.uid1 < updates[idx].uid1) {
updates[idx].uid1 = u.uid1;
}
if (u.uid2 < updates[idx].uid2 &&
(updates[idx].add_flags != u.add_flags ||
updates[idx].remove_flags != u.remove_flags)) {
/* split existing update from end */
tmp_update = updates[idx];
tmp_update.uid2 = u.uid2;
updates[idx].uid1 = u.uid2 + 1;
i_assert(tmp_update.uid1 <= tmp_update.uid2);
i_assert(updates[idx].uid1 <= updates[idx].uid2);
array_insert(&t->updates, idx, &tmp_update, 1);
updates = array_get_modifyable(&t->updates, &count);
}
updates[idx].add_flags =
(updates[idx].add_flags | u.add_flags) &
~u.remove_flags;
updates[idx].remove_flags =
(updates[idx].remove_flags | u.remove_flags) &
~u.add_flags;
u.uid1 = updates[idx].uid2 + 1;
if (u.uid1 > u.uid2) {
/* break here before idx++ so last_update_idx is set
correctly */
break;
}
}
i_assert(idx <= count);
if (u.uid1 <= u.uid2) {
i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
i_assert(idx == count || updates[idx].uid1 > u.uid2);
array_insert(&t->updates, idx, &u, 1);
}
t->last_update_idx = idx;
}
static void mail_index_record_modify_flags(struct mail_index_record *rec,
enum modify_type modify_type,
enum mail_flags flags)
{
switch (modify_type) {
case MODIFY_REPLACE:
rec->flags = flags;
break;
case MODIFY_ADD:
rec->flags |= flags;
break;
case MODIFY_REMOVE:
rec->flags &= ~flags;
break;
}
}
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)
{
struct mail_index_record *rec;
struct mail_transaction_flag_update u, *last_update;
unsigned int count;
t->log_updates = TRUE;
if (seq2 >= t->first_new_seq) {
/* updates for appended messages, modify them directly */
uint32_t seq;
for (seq = I_MAX(t->first_new_seq, seq1); seq <= seq2; seq++) {
rec = mail_index_transaction_lookup(t, seq);
mail_index_record_modify_flags(rec, modify_type, flags);
}
if (seq1 >= t->first_new_seq)
return;
/* range contains also existing messages. update them next. */
seq2 = t->first_new_seq - 1;
}
i_assert(seq1 <= seq2 && seq1 > 0);
i_assert(seq2 <= mail_index_view_get_messages_count(t->view));
memset(&u, 0, sizeof(u));
u.uid1 = seq1;
u.uid2 = seq2;
switch (modify_type) {
case MODIFY_REPLACE:
u.add_flags = flags;
u.remove_flags = ~flags & MAIL_INDEX_FLAGS_MASK;
break;
case MODIFY_ADD:
u.add_flags = flags;
break;
case MODIFY_REMOVE:
u.remove_flags = flags;
break;
}
if (!array_is_created(&t->updates)) {
ARRAY_CREATE(&t->updates, default_pool,
struct mail_transaction_flag_update, 256);
array_append(&t->updates, &u, 1);
return;
}
last_update = array_get_modifyable(&t->updates, &count);
if (t->last_update_idx < count) {
/* fast path - hopefully we're updating the next message,
or a message that is to be appended as last update */
last_update += t->last_update_idx;
if (seq1 - 1 == last_update->uid2) {
if (u.add_flags == last_update->add_flags &&
u.remove_flags == last_update->remove_flags &&
(t->last_update_idx + 1 == count ||
last_update[1].uid1 > seq2)) {
/* we can just update the UID range */
last_update->uid2 = seq2;
return;
}
} else if (seq1 > last_update->uid2) {
/* hopefully we can just append it */
t->last_update_idx++;
last_update++;
}
}
if (t->last_update_idx == count) {
array_append(&t->updates, &u, 1);
return;
}
/* slow path */
if (seq1 > last_update->uid2) {
/* added after this */
mail_index_insert_flag_update(t, u, t->last_update_idx + 1,
count);
} else {
/* added before this or on top of this */
mail_index_insert_flag_update(t, u, 0, t->last_update_idx + 1);
}
}
void mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
enum mail_flags flags)
{
mail_index_update_flags_range(t, seq, seq, modify_type, flags);
}
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size,
bool prepend)
{
i_assert(offset < sizeof(t->pre_hdr_change));
i_assert(size <= sizeof(t->pre_hdr_change) - offset);
t->log_updates = TRUE;
if (prepend) {
t->pre_hdr_changed = TRUE;
memcpy(t->pre_hdr_change + offset, data, size);
for (; size > 0; size--)
t->pre_hdr_mask[offset++] = 1;
} else {
t->post_hdr_changed = TRUE;
memcpy(t->post_hdr_change + offset, data, size);
for (; size > 0; size--)
t->post_hdr_mask[offset++] = 1;
}
}
void mail_index_ext_resize(struct mail_index_transaction *t, uint32_t ext_id,
uint32_t hdr_size, uint16_t record_size,
uint16_t record_align)
{
struct mail_transaction_ext_intro intro;
uint32_t old_record_size, old_record_align;
memset(&intro, 0, sizeof(intro));
/* get ext_id from transaction's map if it's there */
if (!mail_index_map_get_ext_idx(t->view->map, ext_id, &intro.ext_id)) {
/* have to create it */
const struct mail_index_registered_ext *rext;
intro.ext_id = (uint32_t)-1;
rext = array_idx(&t->view->index->extensions, ext_id);
old_record_size = rext->record_size;
old_record_align = rext->record_align;
} else {
const struct mail_index_ext *ext;
ext = array_idx(&t->view->map->extensions, ext_id);
old_record_size = ext->record_size;
old_record_align = ext->record_align;
}
/* allow only header size changes if extension records have already
been changed in transaction */
i_assert(!array_is_created(&t->ext_rec_updates) ||
(old_record_size == record_size &&
old_record_align == record_align));
t->log_updates = TRUE;
if (!array_is_created(&t->ext_resizes)) {
ARRAY_CREATE(&t->ext_resizes, default_pool,
struct mail_transaction_ext_intro, ext_id + 2);
}
intro.hdr_size = hdr_size;
intro.record_size = record_size;
intro.record_align = record_align;
intro.name_size = 1;
array_idx_set(&t->ext_resizes, ext_id, &intro);
}
void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
uint32_t reset_id)
{
i_assert(reset_id != 0);
t->log_updates = TRUE;
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_t *array;
array = array_idx_modifyable(&t->ext_rec_updates, ext_id);
if (array_is_created(array))
array_clear(array);
}
if (!array_is_created(&t->ext_resets)) {
ARRAY_CREATE(&t->ext_resets, default_pool,
uint32_t, ext_id + 2);
}
array_idx_set(&t->ext_resets, ext_id, &reset_id);
}
void mail_index_update_header_ext(struct mail_index_transaction *t,
uint32_t ext_id, size_t offset,
const void *data, size_t size)
{
// FIXME
}
void mail_index_update_ext(struct mail_index_transaction *t, uint32_t seq,
uint32_t ext_id, const void *data, void *old_data_r)
{
struct mail_index *index = t->view->index;
const struct mail_index_registered_ext *rext;
const struct mail_transaction_ext_intro *intro;
uint16_t record_size;
array_t *array;
unsigned int count;
i_assert(seq > 0 &&
(seq <= mail_index_view_get_messages_count(t->view) ||
seq <= t->last_new_seq));
i_assert(ext_id < array_count(&index->extensions));
t->log_updates = TRUE;
if (!array_is_created(&t->ext_resizes)) {
intro = NULL;
count = 0;
} else {
intro = array_get(&t->ext_resizes, &count);
}
if (ext_id < count && intro[ext_id].name_size != 0) {
/* resized record */
record_size = intro[ext_id].record_size;
} else {
rext = array_idx(&index->extensions, ext_id);
record_size = rext->record_size;
}
if (!array_is_created(&t->ext_rec_updates)) {
ARRAY_CREATE(&t->ext_rec_updates, default_pool,
array_t, ext_id + 2);
}
array = array_idx_modifyable(&t->ext_rec_updates, ext_id);
/* @UNSAFE */
if (!mail_index_seq_array_add(array, seq, data, record_size,
old_data_r)) {
/* not found, clear old_data if it was given */
if (old_data_r != NULL)
memset(old_data_r, 0, record_size);
}
}
struct mail_keywords *
mail_index_keywords_create(struct mail_index_transaction *t,
const char *const keywords[])
{
struct mail_index *index = t->view->index;
struct mail_keywords *k;
unsigned int i, count;
count = strarray_length(keywords);
if (count == 0) {
k = i_new(struct mail_keywords, 1);
k->index = index;
return k;
}
/* @UNSAFE */
k = i_malloc(sizeof(struct mail_keywords) +
(sizeof(k->idx) * (count-1)));
k->index = index;
k->count = count;
/* look up the keywords from index. they're never removed from there
so we can permanently store indexes to them. */
for (i = 0; i < count; i++) {
(void)mail_index_keyword_lookup(index, keywords[i],
TRUE, &k->idx[i]);
}
return k;
}
struct mail_keywords *
mail_index_keywords_create_from_indexes(struct mail_index_transaction *t,
const array_t *keyword_indexes)
{
ARRAY_SET_TYPE(keyword_indexes, unsigned int);
struct mail_keywords *k;
unsigned int count;
count = array_count(keyword_indexes);
if (count == 0) {
k = i_new(struct mail_keywords, 1);
k->index = t->view->index;
return k;
}
/* @UNSAFE */
k = i_malloc(sizeof(struct mail_keywords) +
(sizeof(k->idx) * (count-1)));
k->index = t->view->index;
k->count = count;
memcpy(k->idx, array_get(keyword_indexes, NULL),
count * sizeof(k->idx[0]));
return k;
}
void mail_index_keywords_free(struct mail_keywords **keywords)
{
i_free(*keywords);
*keywords = NULL;
}
void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
struct mail_keywords *keywords)
{
struct mail_index_transaction_keyword_update **ku, *u;
unsigned int i, ku_count;
i_assert(seq > 0 &&
(seq <= mail_index_view_get_messages_count(t->view) ||
seq <= t->last_new_seq));
i_assert(keywords->count > 0 || modify_type == MODIFY_REPLACE);
i_assert(keywords->index == t->view->index);
if (!array_is_created(&t->keyword_updates) && keywords->count > 0) {
uint32_t max_idx = keywords->idx[keywords->count-1];
ARRAY_CREATE(&t->keyword_updates, default_pool,
struct mail_index_transaction_keyword_update,
max_idx + 1);
}
/* Update add_seq and remove_seq arrays which describe the keyword
changes. Don't bother updating remove_seq or keyword resets for
newly added messages since they default to not having any
keywords anyway. */
switch (modify_type) {
case MODIFY_ADD:
for (i = 0; i < keywords->count; i++) {
u = array_idx_modifyable(&t->keyword_updates,
keywords->idx[i]);
seq_range_array_add(&u->add_seq, 16, seq);
if (seq < t->first_new_seq)
seq_range_array_remove(&u->remove_seq, seq);
}
break;
case MODIFY_REMOVE:
for (i = 0; i < keywords->count; i++) {
u = array_idx_modifyable(&t->keyword_updates,
keywords->idx[i]);
seq_range_array_remove(&u->add_seq, seq);
if (seq < t->first_new_seq)
seq_range_array_add(&u->remove_seq, 16, seq);
}
break;
case MODIFY_REPLACE:
/* Remove sequence from all add/remove arrays */
if (array_is_created(&t->keyword_updates)) {
ku = array_get_modifyable(&t->keyword_updates,
&ku_count);
for (i = 0; i < ku_count; i++) {
seq_range_array_remove(&ku[i]->add_seq, seq);
if (seq < t->first_new_seq) {
seq_range_array_remove(
&ku[i]->remove_seq, seq);
}
}
}
/* Add the wanted keyword back */
for (i = 0; i < keywords->count; i++) {
u = array_idx_modifyable(&t->keyword_updates,
keywords->idx[i]);
seq_range_array_add(&u->add_seq, 16, seq);
}
if (seq < t->first_new_seq)
seq_range_array_add(&t->keyword_resets, 16, seq);
break;
}
t->log_updates = TRUE;
}