mail-index-transaction.c revision ba665db60cf64cbe6e3ac67822de72101ec6fd36
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "buffer.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "mail-index-view-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-log.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "mail-cache-private.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "mail-index-transaction-private.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <stddef.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <stdlib.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenstruct mail_index_transaction *
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_index_transaction_begin(struct mail_index_view *view,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen int hide, int external)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index_transaction *t;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* don't allow syncing view while there's ongoing transactions */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_view_transaction_ref(view);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_view_ref(view);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t = i_new(struct mail_index_transaction, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->refcount = 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->view = view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->hide_transaction = hide;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->external = external;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (view->syncing) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* transaction view cannot work if new records are being added
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen in two places. make sure it doesn't happen. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->no_appends = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return t;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen}
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainenstatic void mail_keyword_transaction_free(struct mail_keyword_transaction *kt)
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen{
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen struct mail_keyword_transaction **p;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (p = &kt->keywords->kt; *p != NULL; p = &(*p)->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*p == kt) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *p = kt->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*p == NULL) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* no transactions left, free mail_keywords */
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen i_assert(kt->keywords->kt == NULL);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(kt->keywords);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (kt->messages != NULL)
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen buffer_free(kt->messages);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen i_free(kt);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen}
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t **recs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t i, size;
ec1e30ecc38f0deddaf655413cf02d5972ddbc70Timo Sirainen
ec1e30ecc38f0deddaf655413cf02d5972ddbc70Timo Sirainen if (t->ext_rec_updates != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen recs = buffer_get_modifyable_data(t->ext_rec_updates, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size /= sizeof(*recs);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen for (i = 0; i < size; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (recs[i] != NULL)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen buffer_free(recs[i]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(t->ext_rec_updates);
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->keyword_updates != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_keyword_transaction **kt;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kt = buffer_get_modifyable_data(t->keyword_updates, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size /= sizeof(*kt);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < size; i++)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_keyword_transaction_free(kt[i]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(t->keyword_updates);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (t->appends != NULL)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen buffer_free(t->appends);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->expunges != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(t->expunges);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->updates != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(t->updates);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->ext_resizes != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(t->ext_resizes);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->ext_resets != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(t->ext_resets);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_view_transaction_unref(t->view);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_view_close(t->view);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(t);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen{
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (--t->refcount == 0)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen mail_index_transaction_free(t);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen}
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenstatic void
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenmail_index_buffer_convert_to_uids(struct mail_index_transaction *t,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen buffer_t *buf, size_t record_size, int range)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen{
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct mail_index_view *view = t->view;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen const struct mail_index_record *rec;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen unsigned char *data;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen size_t size, i;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen uint32_t *seq;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen int j;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (buf == NULL)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* @UNSAFE */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen data = buffer_get_modifyable_data(buf, &size);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen for (i = 0; i < size; i += record_size) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen seq = (uint32_t *)&data[i];
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
bef8712387812fc5d9496b9958935c6d0c418777Timo Sirainen for (j = 0; j <= range; j++, seq++) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (*seq >= t->first_new_seq) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen rec = mail_index_transaction_lookup(t, *seq);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen *seq = rec->uid;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen } else {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_assert(*seq <= view->map->records_count);
bef8712387812fc5d9496b9958935c6d0c418777Timo Sirainen *seq = MAIL_INDEX_MAP_IDX(view->map,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen *seq - 1)->uid;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_assert(*seq != 0);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen}
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenstatic int
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index *index = t->view->index;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen const struct mail_index_ext *extensions;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen buffer_t **updates;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen size_t i, size;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_view_lock(t->view) < 0)
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (t->ext_rec_updates != NULL) {
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen extensions = buffer_get_data(index->extensions, NULL);
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen updates = buffer_get_modifyable_data(t->ext_rec_updates, &size);
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen size /= sizeof(*updates);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (i = 0; i < size; i++) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (updates[i] == NULL)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen continue;
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen mail_index_buffer_convert_to_uids(t, updates[i],
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen sizeof(uint32_t) + extensions[i].record_size,
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen FALSE);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (t->keyword_updates != NULL) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_keyword_transaction **kt;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kt = buffer_get_modifyable_data(t->keyword_updates, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size /= sizeof(*kt);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < size; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (kt[i]->messages == NULL)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen mail_index_buffer_convert_to_uids(t, kt[i]->messages,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(uint32_t) * 2, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen mail_index_buffer_convert_to_uids(t, t->expunges,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_transaction_expunge), TRUE);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen mail_index_buffer_convert_to_uids(t, t->updates,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_transaction_flag_update), TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_transaction_commit(struct mail_index_transaction *t,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *log_file_seq_r,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen uoff_t *log_file_offset_r)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_transaction_rollback(t);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return -1;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
5529671faac3c5672a948be93091056736c7afffTimo Sirainen
5529671faac3c5672a948be93091056736c7afffTimo Sirainen if (t->cache_trans_ctx != NULL) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen mail_cache_transaction_commit(t->cache_trans_ctx);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen t->cache_trans_ctx = NULL;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (mail_index_transaction_convert_to_uids(t) < 0)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen ret = -1;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_transaction_log_append(t, log_file_seq_r,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen log_file_offset_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen mail_index_transaction_unref(t);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return ret;
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen}
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction *t)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen{
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen if (t->cache_trans_ctx != NULL) {
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen mail_cache_transaction_rollback(t->cache_trans_ctx);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen t->cache_trans_ctx = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_transaction_unref(t);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_index_record *
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_index_transaction_lookup(struct mail_index_transaction *t, uint32_t seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen size_t pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(seq >= t->first_new_seq && seq <= t->last_new_seq);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos = (seq - t->first_new_seq) * sizeof(struct mail_index_record);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return buffer_get_space_unsafe(t->appends, pos,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_index_record));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_append(struct mail_index_transaction *t, uint32_t uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *seq_r)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen{
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct mail_index_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(!t->no_appends);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen t->log_updates = TRUE;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->appends == NULL)
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen t->appends = buffer_create_dynamic(default_pool, 4096);
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* sequence number is visible only inside given view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so let it generate it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->last_new_seq != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *seq_r = ++t->last_new_seq;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen else
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen *seq_r = t->last_new_seq = t->first_new_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen rec = buffer_append_space_unsafe(t->appends, sizeof(*rec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(rec, 0, sizeof(*rec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec->uid = uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_append_assign_uids(struct mail_index_transaction *t,
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen uint32_t first_uid, uint32_t *next_uid_r)
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen{
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen struct mail_index_record *rec, *end;
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen size_t size;
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->appends == NULL)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen return;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = buffer_get_modifyable_data(t->appends, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end = PTR_OFFSET(rec, size);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen /* find the first mail with uid = 0 */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; rec != end; rec++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rec->uid == 0)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; rec != end; rec++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(rec->uid == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec->uid = first_uid++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen *next_uid_r = first_uid;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct seq_range {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq1, seq2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mail_index_update_seq_range_buffer(buffer_t *buffer, uint32_t seq)
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct seq_range *data, value;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int idx, left_idx, right_idx;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen size_t size;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen value.seq1 = value.seq2 = seq;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen data = buffer_get_modifyable_data(buffer, &size);
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen size /= sizeof(*data);
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen i_assert(size > 0);
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen /* quick checks */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[size-1].seq2 == seq-1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* grow last range */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data[size-1].seq2 = seq;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[size-1].seq2 < seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buffer, &value, sizeof(value));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[0].seq1 == seq+1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* grow down first range */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data[0].seq1 = seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[0].seq1 > seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_insert(buffer, 0, &value, sizeof(value));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* somewhere in the middle, array is sorted so find it with
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen binary search */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen idx = 0; left_idx = 0; right_idx = size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (left_idx < right_idx) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen idx = (left_idx + right_idx) / 2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[idx].seq1 <= seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[idx].seq2 >= seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* it's already expunged */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen left_idx = idx+1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen right_idx = idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[idx].seq2 < seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen idx++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* idx == size couldn't happen because we already handle it above */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(idx < size && data[idx].seq1 >= seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data[idx].seq1 > seq || data[idx].seq2 < seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[idx].seq1 == seq+1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data[idx].seq1 = seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (idx > 0 && data[idx-1].seq2 == seq-1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* merge */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data[idx-1].seq2 = data[idx].seq2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_delete(buffer, idx * sizeof(*data),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(*data));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else if (data[idx].seq2 == seq-1) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert(idx+1 < size); /* already handled above */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data[idx].seq2 = seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[idx+1].seq1 == seq+1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* merge */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data[idx+1].seq1 = data[idx].seq1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_delete(buffer, idx * sizeof(*data),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(*data));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen buffer_insert(buffer, idx * sizeof(*data),
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen &value, sizeof(value));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenvoid mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen t->log_updates = TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* expunges is a sorted array of {seq1, seq2, ..}, .. */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (t->expunges == NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen t->expunges = buffer_create_dynamic(default_pool, 1024);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_append(t->expunges, &seq, sizeof(seq));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_append(t->expunges, &seq, sizeof(seq));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_index_update_seq_range_buffer(t->expunges, seq);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenstatic void
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenmail_index_insert_flag_update(struct mail_index_transaction *t,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct mail_transaction_flag_update u,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen uint32_t left_idx, uint32_t right_idx)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct mail_transaction_flag_update *updates, tmp_update;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen size_t size;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen uint32_t idx, move;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen updates = buffer_get_modifyable_data(t->updates, &size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen size /= sizeof(*updates);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(left_idx <= right_idx && right_idx <= size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* find the first update with either overlapping range,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen or the update which will come after our insert */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen idx = 0;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen while (left_idx < right_idx) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen idx = (left_idx + right_idx) / 2;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (updates[idx].uid2 < u.uid1)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen left_idx = idx+1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen else if (updates[idx].uid1 > u.uid1)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen right_idx = idx;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen else
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (idx < size && updates[idx].uid2 < u.uid1)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen idx++;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* overlapping ranges, split/merge them */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (; idx < size && u.uid2 >= updates[idx].uid1; idx++) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (u.uid1 != updates[idx].uid1 &&
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen (updates[idx].add_flags != u.add_flags ||
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (u.uid1 < updates[idx].uid1) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* insert new update */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update = u;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update.uid2 = updates[idx].uid1 - 1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen move = 0;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* split existing update from beginning */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update = updates[idx];
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update.uid2 = u.uid1 - 1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].uid1 = u.uid1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen move = 1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(tmp_update.uid1 <= tmp_update.uid2);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_insert(t->updates, idx * sizeof(tmp_update),
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen &tmp_update, sizeof(tmp_update));
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates = buffer_get_modifyable_data(t->updates, NULL);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen size++; idx += move;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else if (u.uid1 < updates[idx].uid1) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].uid1 = u.uid1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (u.uid2 < updates[idx].uid2 &&
5a07b37a9df398b5189c14872a600384208ab74bTimo 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];
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen tmp_update.uid2 = u.uid2;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].uid1 = u.uid2 + 1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(tmp_update.uid1 <= tmp_update.uid2);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen buffer_insert(t->updates, idx * sizeof(tmp_update),
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen &tmp_update, sizeof(tmp_update));
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates = buffer_get_modifyable_data(t->updates, NULL);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen size++;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].add_flags =
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen (updates[idx].add_flags | u.add_flags) &
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen ~u.remove_flags;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].remove_flags =
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen (updates[idx].remove_flags | u.remove_flags) &
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ~u.add_flags;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.uid1 = updates[idx].uid2 + 1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (u.uid1 > u.uid2) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* break here before idx++ so last_update_idx is set
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen correctly */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(idx <= size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (u.uid1 <= u.uid2) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(idx == size || updates[idx].uid1 > u.uid2);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffer_insert(t->updates, idx * sizeof(u), &u, sizeof(u));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen t->last_update_idx = idx;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void mail_index_record_modify_flags(struct mail_index_record *rec,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen enum modify_type modify_type,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen enum mail_flags flags)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen switch (modify_type) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen case MODIFY_REPLACE:
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen rec->flags = flags;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen break;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen case MODIFY_ADD:
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen rec->flags |= flags;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen break;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen case MODIFY_REMOVE:
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen rec->flags &= ~flags;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen break;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenvoid mail_index_update_flags_range(struct mail_index_transaction *t,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen uint32_t seq1, uint32_t seq2,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen enum modify_type modify_type,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen enum mail_flags flags)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index_record *rec;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_transaction_flag_update u, *last_update;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen size_t size;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen t->log_updates = TRUE;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (seq2 >= t->first_new_seq) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* updates for appended messages, modify them directly */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen uint32_t seq;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (seq = I_MAX(t->first_new_seq, seq1); seq <= seq2; seq++) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen rec = mail_index_transaction_lookup(t, seq);
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen mail_index_record_modify_flags(rec, modify_type, flags);
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen }
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen if (seq1 >= t->first_new_seq)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* range contains also existing messages. update them next. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen seq2 = t->first_new_seq - 1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(seq1 <= seq2 && seq1 > 0);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(seq2 <= mail_index_view_get_messages_count(t->view));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen memset(&u, 0, sizeof(u));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.uid1 = seq1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.uid2 = seq2;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen switch (modify_type) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen case MODIFY_REPLACE:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.add_flags = flags;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.remove_flags = ~flags & MAIL_INDEX_FLAGS_MASK;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen case MODIFY_ADD:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.add_flags = flags;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen case MODIFY_REMOVE:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.remove_flags = flags;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (t->updates == NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen t->updates = buffer_create_dynamic(default_pool, 4096);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffer_append(t->updates, &u, sizeof(u));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen last_update = buffer_get_modifyable_data(t->updates, &size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen size /= sizeof(*last_update);
if (t->last_update_idx < size) {
/* 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 == size ||
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 == size) {
buffer_append(t->updates, &u, sizeof(u));
return;
}
/* slow path */
if (seq1 > last_update->uid2) {
/* added after this */
mail_index_insert_flag_update(t, u, t->last_update_idx + 1,
size);
} else {
/* added before this or on top of this */
mail_index_insert_flag_update(t, u, 0, t->last_update_idx);
}
}
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);
}
int mail_index_seq_buffer_lookup(buffer_t *buffer, uint32_t seq,
size_t record_size, size_t *pos_r)
{
unsigned int idx, left_idx, right_idx;
void *data;
uint32_t full_record_size, *seq_p;
size_t size;
full_record_size = record_size + sizeof(seq);
data = buffer_get_modifyable_data(buffer, &size);
/* we're probably appending it, check */
if (size == 0)
idx = 0;
else if (*((uint32_t *)PTR_OFFSET(data, size-full_record_size)) < seq)
idx = size / full_record_size;
else {
idx = 0; left_idx = 0; right_idx = size / full_record_size;
while (left_idx < right_idx) {
idx = (left_idx + right_idx) / 2;
seq_p = PTR_OFFSET(data, idx * full_record_size);
if (*seq_p < seq)
left_idx = idx+1;
else if (*seq_p > seq)
right_idx = idx;
else {
*pos_r = idx * full_record_size;
return TRUE;
}
}
}
*pos_r = idx * full_record_size;
return FALSE;
}
static int mail_index_update_seq_buffer(buffer_t **buffer, uint32_t seq,
const void *record, size_t record_size,
void *old_record)
{
void *p;
size_t pos;
if (*buffer == NULL) {
*buffer = buffer_create_dynamic(default_pool, 1024);
buffer_append(*buffer, &seq, sizeof(seq));
buffer_append(*buffer, record, record_size);
return FALSE;
}
if (mail_index_seq_buffer_lookup(*buffer, seq, record_size, &pos)) {
/* already there, update */
p = buffer_get_space_unsafe(*buffer, pos + sizeof(seq),
record_size);
if (old_record != NULL)
memcpy(old_record, p, record_size);
memcpy(p, record, record_size);
return TRUE;
} else {
/* insert */
buffer_copy(*buffer, pos + sizeof(seq) + record_size,
*buffer, pos, (size_t)-1);
buffer_write(*buffer, pos, &seq, sizeof(seq));
buffer_write(*buffer, pos + sizeof(seq), record, record_size);
return FALSE;
}
}
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size)
{
i_assert(offset < sizeof(t->hdr_change));
i_assert(size <= sizeof(t->hdr_change) - offset);
t->hdr_changed = TRUE;
t->log_updates = TRUE;
memcpy(t->hdr_change + offset, data, size);
for (; size > 0; size--)
t->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;
const struct mail_index_ext *ext;
memset(&intro, 0, sizeof(intro));
if (!mail_index_map_get_ext_idx(t->view->map, ext_id, &intro.ext_id)) {
intro.ext_id = (uint32_t)-1;
ext = t->view->index->extensions->data;
ext += ext_id;
} else {
ext = t->view->map->extensions->data;
ext += ext_id;
}
/* allow only header size changes if something was already written */
i_assert(t->ext_rec_updates == NULL ||
(ext->record_size == record_size &&
ext->record_align == record_align));
t->log_updates = TRUE;
if (t->ext_resizes == NULL)
t->ext_resizes = buffer_create_dynamic(default_pool, 128);
intro.hdr_size = hdr_size;
intro.record_size = record_size;
intro.record_align = record_align;
intro.name_size = 1;
buffer_write(t->ext_resizes, ext_id * sizeof(intro),
&intro, sizeof(intro));
}
void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
uint32_t reset_id)
{
size_t pos;
i_assert(reset_id != 0);
t->log_updates = TRUE;
if (t->ext_rec_updates != NULL &&
ext_id < t->ext_rec_updates->used / sizeof(buffer_t *)) {
buffer_t *const *buf = t->ext_rec_updates->data;
buf += ext_id;
if (*buf != NULL)
buffer_set_used_size(*buf, 0);
}
pos = ext_id * sizeof(uint32_t);
if (t->ext_resets == NULL) {
t->ext_resets = buffer_create_dynamic(default_pool,
pos + sizeof(uint32_t));
}
buffer_write(t->ext_resets, pos, &reset_id, sizeof(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_ext *ext;
const struct mail_transaction_ext_intro *intro;
buffer_t **buf;
uint16_t record_size;
size_t size;
i_assert(seq > 0 &&
(seq <= mail_index_view_get_messages_count(t->view) ||
seq <= t->last_new_seq));
i_assert(ext_id < index->extensions->used / sizeof(*ext));
t->log_updates = TRUE;
if (t->ext_resizes == NULL) {
intro = NULL;
size = 0;
} else {
intro = buffer_get_data(t->ext_resizes, &size);
}
if (ext_id < size / sizeof(*intro) && intro[ext_id].name_size != 0) {
/* resized record */
record_size = intro[ext_id].record_size;
} else {
ext = index->extensions->data;
record_size = ext[ext_id].record_size;
}
if (t->ext_rec_updates == NULL)
t->ext_rec_updates = buffer_create_dynamic(default_pool, 128);
buf = buffer_get_space_unsafe(t->ext_rec_updates,
ext_id * sizeof(buffer_t *),
sizeof(buffer_t *));
/* @UNSAFE */
if (!mail_index_update_seq_buffer(buf, seq, data, record_size,
old_data_r)) {
if (old_data_r != NULL)
memset(old_data_r, 0, record_size);
}
}
static struct mail_keyword_transaction *
mail_keyword_transaction_new(struct mail_index_transaction *t,
struct mail_keywords *keywords)
{
struct mail_keyword_transaction *kt;
if (t->keyword_updates == NULL)
t->keyword_updates = buffer_create_dynamic(default_pool, 512);
kt = i_new(struct mail_keyword_transaction, 1);
kt->transaction = t;
kt->keywords = keywords;
kt->next = keywords->kt;
keywords->kt = kt;
buffer_append(t->keyword_updates, &kt, sizeof(kt));
return kt;
}
static struct mail_keywords *
mail_index_keywords_build(struct mail_index *index,
const char *const keywords[], unsigned int count)
{
struct mail_keywords k;
const char **missing_keywords, *keyword;
buffer_t *keyword_buf;
unsigned int i, j, bitmask_offset, missing_count = 0;
size_t size;
uint8_t *b;
if (count == 0)
return i_new(struct mail_keywords, 1);
/* @UNSAFE */
t_push();
missing_keywords = t_new(const char *, count + 1);
memset(&k, 0, sizeof(k));
/* keywords are sorted in index. look up the existing ones and add
new ones. build a bitmap pointing to them. keywords are never
removed from index's keyword list. */
bitmask_offset = sizeof(k) - sizeof(k.bitmask);
keyword_buf = buffer_create_dynamic(default_pool, bitmask_offset +
(count + 7) / 8 + 8);
for (i = 0; i < count; i++) {
for (j = 0; index->keywords[j] != NULL; j++) {
if (strcasecmp(keywords[i], index->keywords[j]) == 0)
break;
}
if (index->keywords[j] != NULL) {
if (keyword_buf->used == 0) {
/* first one */
k.start = j;
} else if (j < k.start) {
buffer_copy(keyword_buf,
bitmask_offset + k.start - j,
keyword_buf, bitmask_offset,
(size_t)-1);
k.start = j;
}
b = buffer_get_space_unsafe(keyword_buf,
bitmask_offset +
(j - k.start) / 8, 1);
*b |= 1 << ((j - k.start) % 8);
k.end = j;
k.count++;
} else {
/* arrays are sorted, can't match anymore */
missing_keywords[missing_count++] = keywords[i];
}
}
if (missing_count > 0) {
/* add missing keywords. first drop the trailing NULL. */
size = index->keywords_buf->used - sizeof(const char *);
buffer_set_used_size(index->keywords_buf, size);
j = size / sizeof(const char *);
for (; *missing_keywords != NULL; missing_keywords++, j++) {
keyword = p_strdup(index->keywords_pool,
*missing_keywords);
buffer_append(index->keywords_buf,
&keyword, sizeof(keyword));
b = buffer_get_space_unsafe(keyword_buf,
bitmask_offset +
(j - k.start) / 8, 1);
*b |= 1 << ((j - k.start) % 8);
k.end = j;
k.count++;
}
buffer_append_zero(index->keywords_buf, sizeof(const char *));
index->keywords = index->keywords_buf->data;
}
buffer_write(keyword_buf, 0, &k, bitmask_offset);
t_pop();
return buffer_free_without_data(keyword_buf);
}
struct mail_keywords *
mail_index_keywords_create(struct mail_index_transaction *t,
const char *const keywords[])
{
struct mail_keywords *k;
const char *const null_keywords[] = { NULL };
if (keywords == NULL)
keywords = null_keywords;
k = mail_index_keywords_build(t->view->index, keywords,
strarray_length(keywords));
(void)mail_keyword_transaction_new(t, k);
return k;
}
void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
struct mail_keywords *keywords)
{
struct mail_keyword_transaction *kt;
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->kt->transaction->view->index == t->view->index);
for (kt = keywords->kt; kt != NULL; kt = kt->next) {
if (kt->transaction == t &&
(kt->modify_type == modify_type || kt->messages == NULL))
break;
}
if (kt == NULL)
kt = mail_keyword_transaction_new(t, keywords);
if (kt->messages == NULL) {
kt->messages = buffer_create_dynamic(default_pool, 32);
kt->modify_type = modify_type;
buffer_append(kt->messages, &seq, sizeof(seq));
buffer_append(kt->messages, &seq, sizeof(seq));
} else {
mail_index_update_seq_range_buffer(kt->messages, seq);
}
t->log_updates = TRUE;
}