mail-index-transaction.c revision 19f2cdd797b1ed206eb007bd245e857a7e68c2fc
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen Before they're written to transaction log the sequences are changed to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen UIDs. This is because we're able to compress sequence ranges better. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "array.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "seq-range-array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-view-private.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "mail-transaction-log.h"
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen#include "mail-cache-private.h"
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen#include "mail-index-transaction-private.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen#include <stddef.h>
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen#include <stdlib.h>
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen#include <time.h>
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenvoid (*hook_mail_index_transaction_created)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen (struct mail_index_transaction *t) = NULL;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenvoid mail_index_transaction_reset(struct mail_index_transaction *t)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ARRAY_TYPE(seq_array) *recs;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen struct mail_index_transaction_ext_hdr_update **ext_hdrs;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen unsigned i, count;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen if (array_is_created(&t->ext_rec_updates)) {
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen recs = array_get_modifiable(&t->ext_rec_updates, &count);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen for (i = 0; i < count; i++) {
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen if (array_is_created(&recs[i]))
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen array_free(&recs[i]);
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen }
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen array_free(&t->ext_rec_updates);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (array_is_created(&t->ext_hdr_updates)) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ext_hdrs = array_get_modifiable(&t->ext_hdr_updates, &count);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen for (i = 0; i < count; i++)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_free(ext_hdrs[i]);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen array_free(&t->ext_hdr_updates);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (array_is_created(&t->keyword_updates)) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen struct mail_index_transaction_keyword_update *u;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen u = array_get_modifiable(&t->keyword_updates, &count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen for (i = 0; i < count; i++) {
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen if (array_is_created(&u[i].add_seq))
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen array_free(&u[i].add_seq);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (array_is_created(&u[i].remove_seq))
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen array_free(&u[i].remove_seq);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen }
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen array_free(&t->keyword_updates);
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (array_is_created(&t->keyword_resets))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_free(&t->keyword_resets);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (array_is_created(&t->appends))
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen array_free(&t->appends);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (array_is_created(&t->expunges))
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen array_free(&t->expunges);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (array_is_created(&t->updates))
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen array_free(&t->updates);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (array_is_created(&t->ext_resizes))
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen array_free(&t->ext_resizes);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (array_is_created(&t->ext_resets))
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen array_free(&t->ext_resets);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen t->last_new_seq = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen t->last_update_idx = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen memset(t->pre_hdr_mask, 0, sizeof(t->pre_hdr_mask));
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen memset(t->post_hdr_mask, 0, sizeof(t->post_hdr_mask));
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (t->cache_trans_ctx != NULL) {
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen mail_cache_transaction_rollback(t->cache_trans_ctx);
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen t->cache_trans_ctx = NULL;
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen }
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->appends_nonsorted = FALSE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen t->pre_hdr_changed = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->post_hdr_changed = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->reset = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->log_updates = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->log_ext_updates = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_transaction_reset(t);
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen array_free(&t->module_contexts);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen mail_index_view_transaction_unref(t->view);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen mail_index_view_close(&t->view);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen i_free(t);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen}
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenstruct mail_index_view *
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainenmail_index_transaction_get_view(struct mail_index_transaction *t)
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen{
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen return t->view;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen return array_is_created(&t->expunges) &&
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen seq_range_exists(&t->expunges, seq);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen}
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->refcount++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction **_t)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_transaction *t = *_t;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen *_t = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (--t->refcount == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_transaction_free(t);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq, unsigned int *idx_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int idx, left_idx, right_idx, count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const uint32_t *seq_p;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen count = array_count(array);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (count == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *idx_r = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we're probably appending it, check */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq_p = array_idx(array, count-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*seq_p < seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen idx = count;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen else {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen idx = 0; left_idx = 0; right_idx = count;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen while (left_idx < right_idx) {
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen idx = (left_idx + right_idx) / 2;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen seq_p = array_idx(array, idx);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (*seq_p < seq)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen left_idx = idx+1;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen else if (*seq_p > seq)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen right_idx = idx;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen else {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen *idx_r = idx;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return TRUE;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen *idx_r = idx;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen return FALSE;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen}
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainenstatic bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen const void *record, size_t record_size,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen void *old_record)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen{
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen void *p;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned int idx, aligned_record_size;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* records need to be 32bit aligned */
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen aligned_record_size = (record_size + 3) & ~3;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (!array_is_created(array)) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen array_create(array, default_pool,
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen sizeof(seq) + aligned_record_size,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen 1024 / (sizeof(seq) + aligned_record_size));
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen i_assert(array->arr.element_size == sizeof(seq) + aligned_record_size);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (mail_index_seq_array_lookup(array, seq, &idx)) {
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen /* already there, update */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen p = array_idx_modifiable(array, idx);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if (old_record != NULL) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* save the old record before overwriting it */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen record_size);
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen return TRUE;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen } else {
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen /* insert */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p = array_insert_space(array, idx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(p, &seq, sizeof(seq));
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return FALSE;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_buffer_convert_to_uids(struct mail_index_transaction *t,
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen ARRAY_TYPE(seq_array) *array, bool range)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen struct mail_index_view *view = t->view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *seq;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen unsigned int i, j, count, range_count;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen if (!array_is_created(array))
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen return;
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen count = array_count(array);
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen range_count = range ? 1 : 0;
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen for (i = 0; i < count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq = array_idx_modifiable(array, i);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen for (j = 0; j <= range_count; j++, seq++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(*seq > 0);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*seq >= t->first_new_seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = mail_index_transaction_lookup(t, *seq);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(*seq <= view->map->records_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, *seq - 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* we're using only rec->uid, no need to bother locking
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen the index. */
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (rec->uid == 0) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* FIXME: replace with simple assert once we
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen figure out why this happens.. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_panic("seq = %u, rec->uid = %u, "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "first_new_seq = %u, records = %u",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *seq, rec->uid, t->first_new_seq,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen view->map->records_count);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen *seq = rec->uid;
5529671faac3c5672a948be93091056736c7afffTimo Sirainen }
5529671faac3c5672a948be93091056736c7afffTimo Sirainen }
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen}
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenstatic void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen{
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct mail_index_transaction_keyword_update *updates;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen unsigned int i, count;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!array_is_created(&t->keyword_updates))
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen updates = array_get_modifiable(&t->keyword_updates, &count);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen for (i = 0; i < count; i++) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (array_is_created(&updates[i].add_seq)) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen mail_index_buffer_convert_to_uids(t,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen (void *)&updates[i].add_seq, TRUE);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen if (array_is_created(&updates[i].remove_seq)) {
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen mail_index_buffer_convert_to_uids(t,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen (void *)&updates[i].remove_seq, TRUE);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen }
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen}
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ARRAY_TYPE(seq_array) *updates;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i, count;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (array_is_created(&t->ext_rec_updates)) {
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen updates = array_get_modifiable(&t->ext_rec_updates, &count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!array_is_created(&updates[i]))
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_buffer_convert_to_uids(t, &updates[i],
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen keyword_updates_convert_to_uids(t);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen mail_index_buffer_convert_to_uids(t, (void *)&t->expunges, TRUE);
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen mail_index_buffer_convert_to_uids(t, (void *)&t->updates, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_buffer_convert_to_uids(t, (void *)&t->keyword_resets, TRUE);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen return 0;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainenstruct uid_map {
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen uint32_t idx;
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen uint32_t uid;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen};
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int uid_map_cmp(const void *p1, const void *p2)
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen{
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen const struct uid_map *m1 = p1, *m2 = p2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return m1->uid < m2->uid ? -1 :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (m1->uid > m2->uid ? 1 : 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_update_day_headers(struct mail_index_transaction *t)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_header hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const int max_days =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(hdr.day_first_uid) / sizeof(hdr.day_first_uid[0]);
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen struct tm tm;
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen time_t stamp;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen int i, days;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr = *mail_index_get_header(t->view);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = array_idx(&t->appends, 0);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen /* get beginning of today */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tm = *localtime(&ioloop_time);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tm.tm_hour = 0;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen tm.tm_min = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tm.tm_sec = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stamp = mktime(&tm);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(stamp != (time_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((time_t)hdr.day_stamp >= stamp)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* get number of days since last message */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen days = (stamp - hdr.day_stamp) / (3600*24);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (days > max_days)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen days = max_days;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE: move days forward and fill the missing days with old
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen day_first_uid[0]. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(hdr.day_first_uid + days, hdr.day_first_uid, max_days - days);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 1; i < days; i++)
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen hdr.day_first_uid[i] = hdr.day_first_uid[0];
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen hdr.day_stamp = stamp;
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen hdr.day_first_uid[0] = rec->uid;
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen mail_index_update_header(t,
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen offsetof(struct mail_index_header, day_stamp),
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen &hdr.day_stamp, sizeof(hdr.day_stamp), FALSE);
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen mail_index_update_header(t,
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen offsetof(struct mail_index_header, day_first_uid),
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen hdr.day_first_uid, sizeof(hdr.day_first_uid), FALSE);
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen}
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainenvoid mail_index_transaction_sort_appends(struct mail_index_transaction *t)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen struct mail_index_record *recs, *sorted_recs;
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen struct uid_map *new_uid_map;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen ARRAY_TYPE(seq_array) *ext_rec_arrays;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen uint32_t *old_to_new_map;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen unsigned int i, j, count, ext_rec_array_count;
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!t->appends_nonsorted)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen /* first make a copy of the UIDs and map them to sequences */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen recs = array_get_modifiable(&t->appends, &count);
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen new_uid_map = i_new(struct uid_map, count);
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen for (i = 0; i < count; i++) {
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen new_uid_map[i].idx = i;
e107b65e7d36ae18571de61a4dbd8609b2883a21Timo Sirainen new_uid_map[i].uid = recs[i].uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* now sort the UID map */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen qsort(new_uid_map, count, sizeof(*new_uid_map), uid_map_cmp);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen old_to_new_map = i_new(uint32_t, count);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (i = 0; i < count; i++)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen old_to_new_map[new_uid_map[i].idx] = i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* sort mail records */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sorted_recs = i_new(struct mail_index_record, count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < count; i++)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sorted_recs[i] = recs[new_uid_map[i].idx];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_write(t->appends.arr.buffer, 0, sorted_recs,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(*sorted_recs) * count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(sorted_recs);
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* fix the order in extensions */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!array_is_created(&t->ext_rec_updates)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext_rec_arrays = NULL;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ext_rec_array_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ext_rec_arrays = array_get_modifiable(&t->ext_rec_updates,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &ext_rec_array_count);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (j = 0; j < ext_rec_array_count; j++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY_TYPE(seq_array) *old_array = &ext_rec_arrays[j];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY_TYPE(seq_array) new_array;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int ext_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const uint32_t *ext_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!array_is_created(old_array))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext_count = array_count(old_array);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_create(&new_array, default_pool,
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen old_array->arr.element_size, ext_count);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen for (i = 0; i < ext_count; i++) {
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen ext_rec = array_idx(old_array, i);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq = *ext_rec < t->first_new_seq ? *ext_rec :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (t->first_new_seq +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen old_to_new_map[*ext_rec - t->first_new_seq]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_seq_array_add(&new_array, seq, ext_rec+1,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen old_array->arr.element_size -
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(*ext_rec), NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_free(old_array);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ext_rec_arrays[j] = new_array;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* FIXME: fix the order in keywords */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_free(new_uid_map);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_free(old_to_new_map);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen t->appends_nonsorted = FALSE;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenuint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const struct mail_index_header *hdr;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen const struct mail_index_record *recs;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen unsigned int count, offset;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen uint32_t next_uid;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen next_uid = t->reset ? 1 : t->view->map->hdr.next_uid;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (array_is_created(&t->appends)) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen /* get next_uid from appends if they have UIDs */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mail_index_transaction_sort_appends(t);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen recs = array_get(&t->appends, &count);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (count > 0 && recs[count-1].uid != 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(recs[count-1].uid >= next_uid);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen next_uid = recs[count-1].uid + 1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* see if it's been updated in pre/post header changes */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen offset = offsetof(struct mail_index_header, next_uid);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (t->post_hdr_mask[offset] != 0) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen hdr = (const void *)t->post_hdr_change;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (hdr->next_uid > next_uid)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen next_uid = hdr->next_uid;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (t->pre_hdr_mask[offset] != 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen hdr = (const void *)t->pre_hdr_change;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (hdr->next_uid > next_uid)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen next_uid = hdr->next_uid;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen return next_uid;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int _mail_index_transaction_commit(struct mail_index_transaction *t,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t *log_file_seq_r,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uoff_t *log_file_offset_r)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen int ret;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(t->first_new_seq >
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_view_get_messages_count(t->view));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (t->cache_trans_ctx != NULL) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_cache_transaction_commit(t->cache_trans_ctx);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen t->cache_trans_ctx = NULL;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (array_is_created(&t->appends)) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen mail_index_transaction_sort_appends(t);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen mail_index_update_day_headers(t);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen }
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (mail_index_transaction_convert_to_uids(t) < 0)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen ret = -1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen else {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ret = mail_transaction_log_append(t, log_file_seq_r,
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen log_file_offset_r);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_transaction_unref(&t);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return ret;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen}
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenstatic void _mail_index_transaction_rollback(struct mail_index_transaction *t)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (t->cache_trans_ctx != NULL) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_cache_transaction_rollback(t->cache_trans_ctx);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen t->cache_trans_ctx = NULL;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_transaction_unref(&t);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenint mail_index_transaction_commit(struct mail_index_transaction **_t,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen uint32_t *log_file_seq_r,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen uoff_t *log_file_offset_r)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct mail_index_transaction *t = *_t;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen mail_index_transaction_rollback(_t);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return -1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen *_t = NULL;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return t->v.commit(t, log_file_seq_r, log_file_offset_r);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction **_t)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_transaction *t = *_t;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen *_t = NULL;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen t->v.rollback(t);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstruct mail_index_record *
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenmail_index_transaction_lookup(struct mail_index_transaction *t, uint32_t seq)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(seq >= t->first_new_seq && seq <= t->last_new_seq);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return array_idx_modifiable(&t->appends, seq - t->first_new_seq);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenvoid mail_index_append(struct mail_index_transaction *t, uint32_t uid,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t *seq_r)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_record *rec;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen i_assert(!t->no_appends);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen t->log_updates = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!array_is_created(&t->appends))
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_array_init(&t->appends, 32);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* sequence number is visible only inside given view,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen so let it generate it */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (t->last_new_seq != 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *seq_r = ++t->last_new_seq;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen else
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen *seq_r = t->last_new_seq = t->first_new_seq;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen rec = array_append_space(&t->appends);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (uid != 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->uid = uid;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!t->appends_nonsorted &&
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen t->last_new_seq != t->first_new_seq) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen /* if previous record's UID is larger than this one,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen we'll have to sort the appends later */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec = mail_index_transaction_lookup(t, *seq_r - 1);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (rec->uid > uid)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen t->appends_nonsorted = TRUE;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid mail_index_append_assign_uids(struct mail_index_transaction *t,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint32_t first_uid, uint32_t *next_uid_r)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_record *recs;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen unsigned int i, count;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(first_uid != 0);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!array_is_created(&t->appends))
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen recs = array_get_modifiable(&t->appends, &count);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* find the first mail with uid = 0 */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (i = 0; i < count; i++) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (recs[i].uid == 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (; i < count; i++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(recs[i].uid == 0);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen recs[i].uid = first_uid++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *next_uid_r = first_uid;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenvoid mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen t->log_updates = TRUE;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* expunges is a sorted array of {seq1, seq2, ..}, .. */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen seq_range_array_add(&t->expunges, 128, seq);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenstatic bool
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_transaction_update_want_add(struct mail_index_transaction *t,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen const struct mail_transaction_flag_update *u)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen const struct mail_index_record *rec;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen uint32_t seq;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES) == 0)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen for (seq = u->uid1; seq <= u->uid2; seq++) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (mail_index_lookup(t->view, seq, &rec) < 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if ((rec->flags & u->add_flags) != u->add_flags ||
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen (rec->flags & u->remove_flags) != 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return FALSE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenmail_index_insert_flag_update(struct mail_index_transaction *t,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct mail_transaction_flag_update u,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen uint32_t left_idx, uint32_t right_idx)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct mail_transaction_flag_update *updates, tmp_update;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen unsigned int count;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen uint32_t idx, move;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen updates = array_get_modifiable(&t->updates, &count);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(left_idx <= right_idx && right_idx <= count);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen /* find the first update with either overlapping range,
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen or the update which will come after our insert */
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen idx = left_idx;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen while (left_idx < right_idx) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen idx = (left_idx + right_idx) / 2;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (updates[idx].uid2 < u.uid1)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen left_idx = idx+1;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen else if (updates[idx].uid1 > u.uid1)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen right_idx = idx;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen else
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen break;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen }
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (idx < count && updates[idx].uid2 < u.uid1)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen idx++;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen /* overlapping ranges, split/merge them */
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen i_assert(idx == count || updates[idx].uid2 >= u.uid1);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen for (; idx < count && u.uid2 >= updates[idx].uid1; idx++) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (u.uid1 != updates[idx].uid1 &&
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen (updates[idx].add_flags != u.add_flags ||
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (u.uid1 < updates[idx].uid1) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen /* insert new update */
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen tmp_update = u;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen tmp_update.uid2 = updates[idx].uid1 - 1;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen move = 0;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen } else {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* split existing update from beginning */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update = updates[idx];
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen tmp_update.uid2 = u.uid1 - 1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].uid1 = u.uid1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen move = 1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_assert(tmp_update.uid1 <= tmp_update.uid2);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (mail_transaction_update_want_add(t, &tmp_update)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen array_insert(&t->updates, idx, &tmp_update, 1);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen updates = array_get_modifiable(&t->updates,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen &count);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen idx += move;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else if (u.uid1 < updates[idx].uid1) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].uid1 = u.uid1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (u.uid2 < updates[idx].uid2 &&
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen (updates[idx].add_flags != u.add_flags ||
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* split existing update from end */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update = updates[idx];
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen tmp_update.uid2 = u.uid2;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].uid1 = u.uid2 + 1;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_assert(tmp_update.uid1 <= tmp_update.uid2);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen if (mail_transaction_update_want_add(t, &tmp_update))
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen array_insert(&t->updates, idx, &tmp_update, 1);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen updates = array_get_modifiable(&t->updates, &count);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen }
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen updates[idx].add_flags =
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen (updates[idx].add_flags | u.add_flags) &
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen ~u.remove_flags;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].remove_flags =
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen (updates[idx].remove_flags | u.remove_flags) &
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ~u.add_flags;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen u.uid1 = updates[idx].uid2 + 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (updates[idx].add_flags == 0 &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen updates[idx].remove_flags == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we can remove this update completely */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen array_delete(&t->updates, idx, 1);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen updates = array_get_modifiable(&t->updates, &count);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen idx--;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (u.uid1 > u.uid2) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* break here before idx++ so last_update_idx is set
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen correctly */
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
}
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);
if (mail_transaction_update_want_add(t, &u)) {
array_insert(&t->updates, idx, &u, 1);
count++;
}
}
t->last_update_idx = idx == count ? count-1 : 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 first_idx, count;
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)) {
i_array_init(&t->updates, 256);
if (mail_transaction_update_want_add(t, &u))
array_append(&t->updates, &u, 1);
return;
}
last_update = array_get_modifiable(&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) {
if (mail_transaction_update_want_add(t, &u))
array_append(&t->updates, &u, 1);
else if (t->last_update_idx > 0)
t->last_update_idx--;
} else {
i_assert(t->last_update_idx < count);
/* slow path */
if (seq1 > last_update->uid2) {
/* added after this */
first_idx = t->last_update_idx + 1;
} else {
/* added before this or on top of this */
first_idx = 0;
count = t->last_update_idx + 1;
}
mail_index_insert_flag_update(t, u, first_idx, count);
}
}
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_ext_updates = TRUE;
if (!array_is_created(&t->ext_resizes))
i_array_init(&t->ext_resizes, 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);
mail_index_ext_set_reset_id(t, ext_id, reset_id);
if (!array_is_created(&t->ext_resets))
i_array_init(&t->ext_resets, ext_id + 2);
array_idx_set(&t->ext_resets, ext_id, &reset_id);
t->log_ext_updates = TRUE;
}
static bool
mail_index_transaction_has_ext_changes(struct mail_index_transaction *t)
{
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);
for (i = 0; i < count; i++) {
if (array_is_created(&array[i]))
return TRUE;
}
}
if (array_is_created(&t->ext_hdr_updates)) {
struct mail_index_transaction_ext_hdr_update *const *hdr;
hdr = array_get(&t->ext_hdr_updates, &count);
for (i = 0; i < count; i++) {
if (hdr[i] != NULL)
return TRUE;
}
}
if (array_is_created(&t->ext_resets)) {
const uint32_t *ids;
ids = array_get(&t->ext_resets, &count);
for (i = 0; i < count; i++) {
if (ids[i] != 0)
return TRUE;
}
}
if (array_is_created(&t->ext_resizes)) {
const struct mail_transaction_ext_intro *resizes;
resizes = array_get(&t->ext_resizes, &count);
for (i = 0; i < count; i++) {
if (resizes[i].name_size > 0)
return TRUE;
}
}
return FALSE;
}
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);
}
if (array_is_created(&t->ext_hdr_updates) &&
ext_id < array_count(&t->ext_hdr_updates)) {
/* if extension headers have been updated, clear them */
struct mail_index_transaction_ext_hdr_update **hdr;
hdr = array_idx_modifiable(&t->ext_hdr_updates, ext_id);
if (*hdr != NULL)
i_free_and_null(*hdr);
}
if (array_is_created(&t->ext_resets) &&
ext_id < array_count(&t->ext_resets)) {
/* clear resets */
array_idx_clear(&t->ext_resets, ext_id);
}
if (array_is_created(&t->ext_resizes) &&
ext_id < array_count(&t->ext_resizes)) {
/* clear resizes */
array_idx_clear(&t->ext_resizes, ext_id);
}
if (!array_is_created(&t->ext_reset_ids))
i_array_init(&t->ext_reset_ids, ext_id + 2);
array_idx_set(&t->ext_reset_ids, ext_id, &reset_id);
t->log_ext_updates = mail_index_transaction_has_ext_changes(t);
}
void mail_index_update_header_ext(struct mail_index_transaction *t,
uint32_t ext_id, size_t offset,
const void *data, size_t size)
{
struct mail_index_transaction_ext_hdr_update *hdr, **pos;
hdr = i_malloc(sizeof(*hdr) + size);
hdr->ext_id = ext_id;
hdr->offset = offset;
hdr->size = size;
memcpy(hdr + 1, data, size);
if (!array_is_created(&t->ext_hdr_updates))
i_array_init(&t->ext_hdr_updates, ext_id + 2);
pos = array_idx_modifiable(&t->ext_hdr_updates, ext_id);
if (*pos != NULL) {
i_panic("mail_index_update_header_ext() doesn't currently "
"support multiple updates to the same ext header");
}
*pos = hdr;
t->log_ext_updates = TRUE;
}
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_TYPE(seq_array) *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_ext_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))
i_array_init(&t->ext_rec_updates, ext_id + 2);
array = array_idx_modifiable(&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_TYPE(keyword_indexes)
*keyword_indexes)
{
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_idx(keyword_indexes, 0),
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 *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];
i_array_init(&t->keyword_updates, 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_modifiable(&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_modifiable(&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)) {
u = array_get_modifiable(&t->keyword_updates,
&ku_count);
for (i = 0; i < ku_count; i++) {
seq_range_array_remove(&u[i].add_seq, seq);
if (seq < t->first_new_seq) {
seq_range_array_remove(
&u[i].remove_seq, seq);
}
}
}
/* Add the wanted keyword back */
for (i = 0; i < keywords->count; i++) {
u = array_idx_modifiable(&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;
}
void mail_index_reset(struct mail_index_transaction *t)
{
mail_index_transaction_reset(t);
t->reset = TRUE;
}
struct mail_index_transaction_vfuncs trans_vfuncs = {
_mail_index_transaction_commit,
_mail_index_transaction_rollback
};
struct mail_index_transaction *
mail_index_transaction_begin(struct mail_index_view *view,
enum mail_index_transaction_flags flags)
{
struct mail_index_transaction *t;
/* don't allow syncing view while there's ongoing transactions */
mail_index_view_transaction_ref(view);
mail_index_view_ref(view);
t = i_new(struct mail_index_transaction, 1);
t->refcount = 1;
t->v = trans_vfuncs;
t->view = view;
t->flags = flags;
t->sync_transaction = view->index_sync_view;
if (view->syncing) {
/* transaction view cannot work if new records are being added
in two places. make sure it doesn't happen. */
t->no_appends = TRUE;
t->first_new_seq = (uint32_t)-1;
} else {
t->first_new_seq =
mail_index_view_get_messages_count(t->view) + 1;
}
i_array_init(&t->module_contexts,
I_MIN(5, mail_index_module_register.id));
if (hook_mail_index_transaction_created != NULL)
hook_mail_index_transaction_created(t);
return t;
}