mail-index-transaction-export.c revision fad068d459cc7b04fedade4e0bb343be62e6d310
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger#include "lib.h"
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger#include "array.h"
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger#include "mail-index-private.h"
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger#include "mail-index-modseq.h"
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger#include "mail-transaction-log-private.h"
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger#include "mail-index-transaction-private.h"
802014878b7383de536e4fa0ceced1bce3217eadDaniel Couto Vale
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornbergerstruct mail_index_export_context {
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger struct mail_index_transaction *trans;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger struct mail_transaction_log_append_ctx *append_ctx;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger};
492757fbefce7e6aee4a7515983a44d19a542ccchardik
7daf1bcad83f7bcb6f4e1076f925664bbd2d4f36hardikstatic void
492757fbefce7e6aee4a7515983a44d19a542ccchardiklog_append_buffer(struct mail_index_export_context *ctx,
7daf1bcad83f7bcb6f4e1076f925664bbd2d4f36hardik const buffer_t *buf, enum mail_transaction_type type)
ea882c814a23a8acf059ae9e0e49e7a35ddba148hardik{
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger mail_transaction_log_append_add(ctx->append_ctx, type,
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger buf->data, buf->used);
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger}
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornbergerstatic const buffer_t *
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornbergerlog_get_hdr_update_buffer(struct mail_index_transaction *t, bool prepend)
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger{
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger buffer_t *buf;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger const unsigned char *data, *mask;
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa struct mail_transaction_header_update u;
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa uint16_t offset;
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa int state = 0;
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa memset(&u, 0, sizeof(u));
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa data = prepend ? t->pre_hdr_change : t->post_hdr_change;
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa mask = prepend ? t->pre_hdr_mask : t->post_hdr_mask;
54e3222dbd97122749ba5bac2a10d9d6ba1a2283Eugen Kuksa
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa buf = buffer_create_dynamic(pool_datastack_create(), 256);
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa for (offset = 0; offset <= sizeof(t->pre_hdr_change); offset++) {
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa if (offset < sizeof(t->pre_hdr_change) && mask[offset]) {
d6cf50ae9519bdb5252081061b3d6a7e0ccde20bEugen Kuksa if (state == 0) {
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger u.offset = offset;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger state++;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger }
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger } else {
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger if (state > 0) {
7e1eade6e5b88f9a1efa7d3cef366d973ddc1ee4Eugen Kuksa u.size = offset - u.offset;
7e1eade6e5b88f9a1efa7d3cef366d973ddc1ee4Eugen Kuksa buffer_append(buf, &u, sizeof(u));
7e1eade6e5b88f9a1efa7d3cef366d973ddc1ee4Eugen Kuksa buffer_append(buf, data + u.offset, u.size);
7e1eade6e5b88f9a1efa7d3cef366d973ddc1ee4Eugen Kuksa state = 0;
cf6b6be762502d02736a68d9c94fa3cc9977e474Tim Reddehase }
cf6b6be762502d02736a68d9c94fa3cc9977e474Tim Reddehase }
cf6b6be762502d02736a68d9c94fa3cc9977e474Tim Reddehase }
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger return buf;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger}
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornbergerstatic void log_append_ext_intro(struct mail_index_export_context *ctx,
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger uint32_t ext_id, uint32_t reset_id)
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger{
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger struct mail_index_transaction *t = ctx->trans;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger const struct mail_index_registered_ext *rext;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger struct mail_transaction_ext_intro *intro, *resizes;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger buffer_t *buf;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger uint32_t idx;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger unsigned int count;
736e78aff9e67436c35d4835c24fca667f3cadf3Julian Kornberger
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller i_assert(ext_id != (uint32_t)-1);
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa if (t->reset ||
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa !mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) {
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa /* new extension */
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa idx = (uint32_t)-1;
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa }
583cfb88a9eb83c4e7691eb3dbd66247b643229fEugen Kuksa
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa rext = array_idx(&t->view->index->extensions, ext_id);
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa if (!array_is_created(&t->ext_resizes)) {
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa resizes = NULL;
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa count = 0;
250e5c1ec05ffb6d1b933f913c3c65934b206957Eugen Kuksa } else {
250e5c1ec05ffb6d1b933f913c3c65934b206957Eugen Kuksa resizes = array_get_modifiable(&t->ext_resizes, &count);
2f0eba71c311b096362f3603d17addad30213c4dEugen Kuksa }
e5b8591fc3e19ccd4a33757ebcabff27b4ca01ceEugen Kuksa
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa buf = buffer_create_dynamic(pool_datastack_create(), 128);
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa if (ext_id < count && resizes[ext_id].name_size != 0) {
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa /* we're resizing the extension. use the resize struct. */
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa intro = &resizes[ext_id];
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa i_assert(intro->ext_id == idx);
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa intro->name_size = idx != (uint32_t)-1 ? 0 :
815d84cbac89ad1cb14135028f3fea1d1d44a75fEugen Kuksa strlen(rext->name);
b27c7f227c8516589a2bd127c0f74338cf56f0b2Julian Kornberger buffer_append(buf, intro, sizeof(*intro));
b27c7f227c8516589a2bd127c0f74338cf56f0b2Julian Kornberger } else {
402d5f74ba78451acf2ccda16b41398535028a3bEugen Kuksa /* generate a new intro structure */
cf5a6d3745ac43a950c2315b07a1713bae300a97Tim Reddehase intro = buffer_append_space_unsafe(buf, sizeof(*intro));
cf5a6d3745ac43a950c2315b07a1713bae300a97Tim Reddehase intro->ext_id = idx;
cf5a6d3745ac43a950c2315b07a1713bae300a97Tim Reddehase intro->hdr_size = rext->hdr_size;
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa intro->record_size = rext->record_size;
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa intro->record_align = rext->record_align;
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa intro->flags = MAIL_TRANSACTION_EXT_INTRO_FLAG_NO_SHRINK;
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa intro->name_size = idx != (uint32_t)-1 ? 0 :
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa strlen(rext->name);
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa }
2244a7dffeed06ee129d0c94648c6a47615a7a0aEugen Kuksa if (reset_id != 0) {
b27c7f227c8516589a2bd127c0f74338cf56f0b2Julian Kornberger /* we're going to reset this extension in this transaction */
490da89281b7ee019c87406fb8ce7359aff0932cEugen Kuksa intro->reset_id = reset_id;
490da89281b7ee019c87406fb8ce7359aff0932cEugen Kuksa } else if (idx != (uint32_t)-1) {
490da89281b7ee019c87406fb8ce7359aff0932cEugen Kuksa /* use the existing reset_id */
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller const struct mail_index_ext *map_ext =
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller array_idx(&t->view->index->map->extensions, idx);
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller intro->reset_id = map_ext->reset_id;
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller } else {
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller /* new extension, reset_id defaults to 0 */
555b7fd96768daf9592e7ddbd4217d784b08e451henning mueller }
7b8fe34340b2727bb31fe0be67fdf684e47c3609Tim Reddehase buffer_append(buf, rext->name, intro->name_size);
7b8fe34340b2727bb31fe0be67fdf684e47c3609Tim Reddehase if ((buf->used % 4) != 0)
1cbb38d1d07f559b4a1c012a4833513053716007Daniel Couto Vale buffer_append_zero(buf, 4 - (buf->used % 4));
1cbb38d1d07f559b4a1c012a4833513053716007Daniel Couto Vale
7cd362a86385a020b8c674cf9199771ae3267359henning mueller if (ctx->append_ctx->new_highest_modseq == 0 &&
7cd362a86385a020b8c674cf9199771ae3267359henning mueller strcmp(rext->name, MAIL_INDEX_MODSEQ_EXT_NAME) == 0) {
291d5c781e5ce4a7c15cfb16fa4a800177135b3ehenning mueller /* modseq tracking started */
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski ctx->append_ctx->new_highest_modseq = 1;
2635b9bca67d93aec1bed63d10d5f92fefce06e7Till Mossakowski }
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowski
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski log_append_buffer(ctx, buf, MAIL_TRANSACTION_EXT_INTRO);
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowski}
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowski
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowskistatic void
2635b9bca67d93aec1bed63d10d5f92fefce06e7Till Mossakowskilog_append_ext_hdr_update(struct mail_index_export_context *ctx,
2635b9bca67d93aec1bed63d10d5f92fefce06e7Till Mossakowski const struct mail_index_transaction_ext_hdr_update *hdr)
2635b9bca67d93aec1bed63d10d5f92fefce06e7Till Mossakowski{
2635b9bca67d93aec1bed63d10d5f92fefce06e7Till Mossakowski buffer_t *buf;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski const unsigned char *data, *mask;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski struct mail_transaction_ext_hdr_update u;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski struct mail_transaction_ext_hdr_update32 u32;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski size_t offset;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski bool started = FALSE, use_32 = hdr->alloc_size >= 65536;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski memset(&u, 0, sizeof(u));
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski memset(&u32, 0, sizeof(u32));
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski data = hdr->data;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski mask = hdr->mask;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski buf = buffer_create_dynamic(pool_datastack_create(), 256);
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski for (offset = 0; offset <= hdr->alloc_size; offset++) {
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski if (offset < hdr->alloc_size && mask[offset] != 0) {
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski if (!started) {
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski u32.offset = offset;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski started = TRUE;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski }
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski } else {
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski if (started) {
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski u32.size = offset - u32.offset;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski if (use_32)
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski buffer_append(buf, &u32, sizeof(u32));
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski else {
5ad93833caec560945adbce7b6f1342ef731ae83henning mueller u.offset = u32.offset;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski u.size = u32.size;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski buffer_append(buf, &u, sizeof(u));
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski }
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski buffer_append(buf, data + u32.offset, u32.size);
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowski started = FALSE;
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowski }
0c07cc350bdb8afe9b01b4340b33d89500a43106Till Mossakowski }
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski }
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski if (buf->used % 4 != 0)
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski buffer_append_zero(buf, 4 - buf->used % 4);
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski log_append_buffer(ctx, buf, use_32 ? MAIL_TRANSACTION_EXT_HDR_UPDATE32 :
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski MAIL_TRANSACTION_EXT_HDR_UPDATE);
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski}
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowskistatic void
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowskimail_transaction_log_append_ext_intros(struct mail_index_export_context *ctx)
291d5c781e5ce4a7c15cfb16fa4a800177135b3ehenning mueller{
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski struct mail_index_transaction *t = ctx->trans;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski const struct mail_transaction_ext_intro *resize;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski const struct mail_index_transaction_ext_hdr_update *hdrs;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski struct mail_transaction_ext_reset ext_reset;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski unsigned int resize_count, ext_count = 0;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski unsigned int hdrs_count, reset_id_count, reset_count;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski uint32_t ext_id, reset_id;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski const struct mail_transaction_ext_reset *reset;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski const uint32_t *reset_ids;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski buffer_t reset_buf;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski if (!array_is_created(&t->ext_resizes)) {
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski resize = NULL;
1543bf02d52779c4bc29f75de1de4d14636d0e47Till Mossakowski resize_count = 0;
} else {
resize = array_get(&t->ext_resizes, &resize_count);
if (ext_count < resize_count)
ext_count = resize_count;
}
if (!array_is_created(&t->ext_reset_ids)) {
reset_ids = NULL;
reset_id_count = 0;
} else {
reset_ids = array_get(&t->ext_reset_ids, &reset_id_count);
}
if (!array_is_created(&t->ext_resets)) {
reset = NULL;
reset_count = 0;
} else {
reset = array_get(&t->ext_resets, &reset_count);
if (ext_count < reset_count)
ext_count = reset_count;
}
if (!array_is_created(&t->ext_hdr_updates)) {
hdrs = NULL;
hdrs_count = 0;
} else {
hdrs = array_get(&t->ext_hdr_updates, &hdrs_count);
if (ext_count < hdrs_count)
ext_count = hdrs_count;
}
memset(&ext_reset, 0, sizeof(ext_reset));
buffer_create_data(&reset_buf, &ext_reset, sizeof(ext_reset));
buffer_set_used_size(&reset_buf, sizeof(ext_reset));
for (ext_id = 0; ext_id < ext_count; ext_id++) {
if (ext_id < reset_count)
ext_reset = reset[ext_id];
else
ext_reset.new_reset_id = 0;
if ((ext_id < resize_count && resize[ext_id].name_size) ||
ext_reset.new_reset_id != 0 ||
(ext_id < hdrs_count && hdrs[ext_id].alloc_size > 0)) {
if (ext_reset.new_reset_id != 0) {
/* we're going to reset this extension
immediately after the intro */
reset_id = 0;
} else {
reset_id = ext_id < reset_id_count ?
reset_ids[ext_id] : 0;
}
log_append_ext_intro(ctx, ext_id, reset_id);
}
if (ext_reset.new_reset_id != 0) {
i_assert(ext_id < reset_id_count &&
ext_reset.new_reset_id == reset_ids[ext_id]);
log_append_buffer(ctx, &reset_buf,
MAIL_TRANSACTION_EXT_RESET);
}
if (ext_id < hdrs_count && hdrs[ext_id].alloc_size > 0) {
T_BEGIN {
log_append_ext_hdr_update(ctx, &hdrs[ext_id]);
} T_END;
}
}
}
static void log_append_ext_recs(struct mail_index_export_context *ctx,
const ARRAY_TYPE(seq_array_array) *arr,
enum mail_transaction_type type)
{
struct mail_index_transaction *t = ctx->trans;
const ARRAY_TYPE(seq_array) *updates;
const uint32_t *reset_ids;
unsigned int ext_id, count, reset_id_count;
uint32_t reset_id;
if (!array_is_created(&t->ext_reset_ids)) {
reset_ids = NULL;
reset_id_count = 0;
} else {
reset_ids = array_get_modifiable(&t->ext_reset_ids,
&reset_id_count);
}
updates = array_get(arr, &count);
for (ext_id = 0; ext_id < count; ext_id++) {
if (!array_is_created(&updates[ext_id]))
continue;
reset_id = ext_id < reset_id_count ? reset_ids[ext_id] : 0;
log_append_ext_intro(ctx, ext_id, reset_id);
log_append_buffer(ctx, updates[ext_id].arr.buffer, type);
}
}
static void
log_append_keyword_update(struct mail_index_export_context *ctx,
buffer_t *tmp_buf, enum modify_type modify_type,
const char *keyword, const buffer_t *uid_buffer)
{
struct mail_transaction_keyword_update kt_hdr;
i_assert(uid_buffer->used > 0);
memset(&kt_hdr, 0, sizeof(kt_hdr));
kt_hdr.modify_type = modify_type;
kt_hdr.name_size = strlen(keyword);
buffer_set_used_size(tmp_buf, 0);
buffer_append(tmp_buf, &kt_hdr, sizeof(kt_hdr));
buffer_append(tmp_buf, keyword, kt_hdr.name_size);
if ((tmp_buf->used % 4) != 0)
buffer_append_zero(tmp_buf, 4 - (tmp_buf->used % 4));
buffer_append(tmp_buf, uid_buffer->data, uid_buffer->used);
log_append_buffer(ctx, tmp_buf, MAIL_TRANSACTION_KEYWORD_UPDATE);
}
static enum mail_index_sync_type
log_append_keyword_updates(struct mail_index_export_context *ctx)
{
const struct mail_index_transaction_keyword_update *updates;
const char *const *keywords;
buffer_t *tmp_buf;
enum mail_index_sync_type change_mask = 0;
unsigned int i, count, keywords_count;
tmp_buf = buffer_create_dynamic(pool_datastack_create(), 64);
keywords = array_get_modifiable(&ctx->trans->view->index->keywords,
&keywords_count);
updates = array_get_modifiable(&ctx->trans->keyword_updates, &count);
i_assert(count <= keywords_count);
for (i = 0; i < count; i++) {
if (array_is_created(&updates[i].add_seq) &&
array_count(&updates[i].add_seq) > 0) {
change_mask |= MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD;
log_append_keyword_update(ctx, tmp_buf,
MODIFY_ADD, keywords[i],
updates[i].add_seq.arr.buffer);
}
if (array_is_created(&updates[i].remove_seq) &&
array_count(&updates[i].remove_seq) > 0) {
change_mask |= MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE;
log_append_keyword_update(ctx, tmp_buf,
MODIFY_REMOVE, keywords[i],
updates[i].remove_seq.arr.buffer);
}
}
return change_mask;
}
void mail_index_transaction_export(struct mail_index_transaction *t,
struct mail_transaction_log_append_ctx *append_ctx)
{
static uint8_t null4[4] = { 0, 0, 0, 0 };
enum mail_index_sync_type change_mask = 0;
struct mail_index_export_context ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.trans = t;
ctx.append_ctx = append_ctx;
if (t->index_undeleted) {
i_assert(!t->index_deleted);
mail_transaction_log_append_add(ctx.append_ctx,
MAIL_TRANSACTION_INDEX_UNDELETED, &null4, 4);
}
/* send all extension introductions and resizes before appends
to avoid resize overhead as much as possible */
mail_transaction_log_append_ext_intros(&ctx);
if (t->pre_hdr_changed) {
log_append_buffer(&ctx, log_get_hdr_update_buffer(t, TRUE),
MAIL_TRANSACTION_HEADER_UPDATE);
}
if (array_is_created(&t->appends)) {
change_mask |= MAIL_INDEX_SYNC_TYPE_APPEND;
log_append_buffer(&ctx, t->appends.arr.buffer,
MAIL_TRANSACTION_APPEND);
}
if (array_is_created(&t->updates)) {
change_mask |= MAIL_INDEX_SYNC_TYPE_FLAGS;
log_append_buffer(&ctx, t->updates.arr.buffer,
MAIL_TRANSACTION_FLAG_UPDATE);
}
if (array_is_created(&t->ext_rec_updates)) {
log_append_ext_recs(&ctx, &t->ext_rec_updates,
MAIL_TRANSACTION_EXT_REC_UPDATE);
}
if (array_is_created(&t->ext_rec_atomics)) {
log_append_ext_recs(&ctx, &t->ext_rec_atomics,
MAIL_TRANSACTION_EXT_ATOMIC_INC);
}
/* keyword resets before updates */
if (array_is_created(&t->keyword_resets)) {
change_mask |= MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET;
log_append_buffer(&ctx, t->keyword_resets.arr.buffer,
MAIL_TRANSACTION_KEYWORD_RESET);
}
if (array_is_created(&t->keyword_updates))
change_mask |= log_append_keyword_updates(&ctx);
/* keep modseq updates almost last */
if (array_is_created(&t->modseq_updates)) {
log_append_buffer(&ctx, t->modseq_updates.arr.buffer,
MAIL_TRANSACTION_MODSEQ_UPDATE);
}
if (array_is_created(&t->expunges)) {
/* non-external expunges are only requests, ignore them when
checking fsync_mask */
if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0)
change_mask |= MAIL_INDEX_SYNC_TYPE_EXPUNGE;
log_append_buffer(&ctx, t->expunges.arr.buffer,
MAIL_TRANSACTION_EXPUNGE_GUID);
}
if (t->post_hdr_changed) {
log_append_buffer(&ctx, log_get_hdr_update_buffer(t, FALSE),
MAIL_TRANSACTION_HEADER_UPDATE);
}
if (t->index_deleted) {
i_assert(!t->index_undeleted);
mail_transaction_log_append_add(ctx.append_ctx,
MAIL_TRANSACTION_INDEX_DELETED,
&null4, 4);
}
/* Update the tail offsets only when committing the sync transaction.
Other transactions may not know the latest tail offset and might
end up shrinking it. (Alternatively the shrinking tail offsets could
just be ignored, which would probably work fine too.) */
append_ctx->append_sync_offset = t->sync_transaction;
append_ctx->want_fsync =
(t->view->index->fsync_mask & change_mask) != 0 ||
(t->flags & MAIL_INDEX_TRANSACTION_FLAG_FSYNC) != 0;
}