mail-cache-transaction.c revision 0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-set-size.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "read-full.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-cache-private.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "mail-index-transaction-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen#include <stddef.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_cache_transaction_ctx {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_view *view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_transaction *trans;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen uint32_t cache_file_seq;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_t *cache_data, *cache_data_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t prev_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t prev_pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_t *reservations;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t reserved_space_offset, reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t last_grow_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int changes:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const unsigned char *null4[] = { 0, 0, 0, 0 };
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen uint32_t old_offset, uint32_t new_offset);
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstruct mail_cache_transaction_ctx *
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_get_transaction(struct mail_cache_view *view,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_index_transaction *t)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_transaction_ctx *ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (t->cache_trans_ctx != NULL)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return t->cache_trans_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct mail_cache_transaction_ctx, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cache = view->cache;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->view = view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->trans = t;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reservations =
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_create_dynamic(system_pool, 256, (size_t)-1);
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen if (!MAIL_CACHE_IS_UNUSABLE(ctx->cache))
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen i_assert(view->transaction == NULL);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen view->transaction = ctx;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen t->cache_trans_ctx = ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstatic void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen{
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (ctx->cache_data)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen buffer_set_used_size(ctx->cache_data, 0);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (ctx->cache_data_seq)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen buffer_set_used_size(ctx->cache_data_seq, 0);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->prev_seq = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->prev_pos = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen buffer_set_used_size(ctx->reservations, 0);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->reserved_space_offset = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->reserved_space = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->last_grow_size = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->changes = FALSE;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen}
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->view->transaction = NULL;
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen if (ctx->cache_data != NULL)
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen buffer_free(ctx->cache_data);
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen if (ctx->cache_data_seq != NULL)
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen buffer_free(ctx->cache_data_seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_free(ctx->reservations);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstatic int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen{
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen int ret;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if ((ret = mail_cache_lock(ctx->cache)) <= 0)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen return ret;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen mail_cache_transaction_reset(ctx);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen return 1;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen}
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct stat st;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uoff_t new_fsize, grow_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* grow the file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize = cache->hdr_copy.used_file_size + size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (grow_size < 16384)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen grow_size = 16384;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize += grow_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize &= ~1023;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (fstat(cache->fd, &st) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((uoff_t)st.st_size < new_fsize) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (file_set_size(cache->fd, new_fsize) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header *hole_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t offset, prev_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = hdr->hole_offset; prev_offset = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen while (offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pread_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_corrupted(cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "Invalid magic in hole header");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (hole.size >= size)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen break;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = hole.next_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (prev_offset == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->hole_offset = hole.next_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, &hole.next_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(hole.next_offset), prev_offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->deleted_space -= hole.size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole_r->next_offset = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole_r->size = hole.size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->reservations, &ctx->reserved_space_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(ctx->reserved_space_offset));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->reservations, &ctx->reserved_space,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(ctx->reserved_space));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size, int commit)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t *buf;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_unlink_hole(cache, size, &hole)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* found a large enough hole. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space_offset = hole.next_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space = hole.size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_add_reservation(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* mail_cache_unlink_hole() could have noticed corruption */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((uoff_t)hdr->used_file_size + size > (uint32_t)-1) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_set_error(cache->index, "Cache file too large: %s",
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!commit) {
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen /* allocate some more space than we need */
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen size_t new_size = (size + ctx->last_grow_size) * 2;
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen if ((uoff_t)hdr->used_file_size + new_size > (uint32_t)-1)
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen new_size = (uint32_t)-1;
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen if (new_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen new_size = size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE ?
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen size : MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen }
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen ctx->last_grow_size = new_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_grow_file(ctx->cache, size) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space_offset + ctx->reserved_space ==
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can simply grow it */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space = size - ctx->reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* grow reservation. it's probably the last one in the buffer,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen but it's not guarateed because we might have used holes
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen as well */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf = buffer_get_modifyable_data(ctx->reservations, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size /= sizeof(uint32_t);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(size >= 2);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen do {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size -= 2;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (buf[size] == ctx->reserved_space_offset) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf[size+1] = ctx->reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen break;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } while (size >= 2);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space_offset = hdr->used_file_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_add_reservation(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->used_file_size = ctx->reserved_space_offset + ctx->reserved_space;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset + size == cache->hdr_copy.used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can just set used_file_size back */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.used_file_size = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else if (size >= MAIL_CACHE_MIN_HOLE_SIZE) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* set it up as a hole */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.next_offset = cache->hdr_copy.hole_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.size = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.magic = MAIL_CACHE_HOLE_HEADER_MAGIC;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, &hole, sizeof(hole), offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.deleted_space += size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.hole_offset = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int locked = ctx->cache->locked;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen /* check again - locking might have reopened the cache file */
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen if (ctx->reserved_space != 0) {
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen i_assert(ctx->cache_file_seq == ctx->cache->hdr->file_seq);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen mail_cache_free_space(ctx->cache, ctx->reserved_space_offset,
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen ctx->reserved_space);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_unlock(ctx->cache);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic uint32_t
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t min_size, size_t max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t *available_space_r, int commit)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int locked = ctx->cache->locked;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert((min_size & 3) == 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert((max_size & 3) == 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (min_size > ctx->reserved_space) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = mail_cache_transaction_reserve_more(ctx, max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_unlock(ctx->cache);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ret < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = max_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = I_MIN(max_size, ctx->reserved_space);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = ctx->reserved_space_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space_offset += size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space -= size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (available_space_r != NULL)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *available_space_r = size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert((size & 3) == 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (size == max_size && commit) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* final commit - see if we can free the rest of the
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reserved space */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free_space(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mail_cache_record *rec, *tmp_rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const uint32_t *seq;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen uint32_t write_offset, old_offset, rec_pos, cache_file_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size, max_size, seq_idx, seq_limit, seq_count;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int commit;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen return -1;
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit = ctx->prev_seq == 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (commit) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* committing, remove the last dummy record */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_set_used_size(ctx->cache_data, ctx->prev_pos);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq) {
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen /* cache file reopened - need to abort */
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen mail_cache_transaction_reset(ctx);
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen return 0;
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen }
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = buffer_get_data(ctx->cache_data, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(ctx->prev_pos <= size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq = buffer_get_data(ctx->cache_data_seq, &seq_count);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_count /= sizeof(*seq);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen seq_limit = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen for (seq_idx = 0, rec_pos = 0; rec_pos < ctx->prev_pos;) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen max_size = ctx->prev_pos - rec_pos;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen cache_file_seq = ctx->cache_file_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset = mail_cache_transaction_get_space(ctx, rec->size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen if (cache_file_seq != ctx->cache_file_seq) {
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen /* cache file reopened - need to abort */
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen return 0;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen }
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (write_offset == 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* nothing to write / error */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ctx->prev_pos == 0 ? 0 : -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (rec_pos + max_size < ctx->prev_pos) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* see how much we can really write there */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen tmp_rec = rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (size = 0; size + tmp_rec->size <= max_size; ) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_limit++;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size += tmp_rec->size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen tmp_rec = CONST_PTR_OFFSET(tmp_rec,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen tmp_rec->size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen max_size = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_limit = seq_count;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* write it to file */
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen i_assert(ctx->cache_file_seq == cache->hdr->file_seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, rec, max_size, write_offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* write the cache_offsets to index file. records' prev_offset
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen is updated to point to old cache record when index is being
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen synced. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (; seq_idx < seq_limit; seq_idx++) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_update_cache(ctx->trans, seq[seq_idx],
2ca4cb08680aebb1474d762738cf436871f095fbTimo Sirainen cache->hdr->file_seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset, &old_offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (old_offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we added records for this message multiple
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen times in this same uncommitted transaction.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen only the new one will be written to
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen transaction log, we need to do the linking
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ourself here. */
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen if (mail_cache_link_unlocked(cache, old_offset,
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen write_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset += rec->size;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen rec_pos += rec->size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = CONST_PTR_OFFSET(rec, rec->size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* drop the written data from buffer */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_copy(ctx->cache_data, 0,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cache_data, ctx->prev_pos, (size_t)-1);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_set_used_size(ctx->cache_data,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_get_used_size(ctx->cache_data) -
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->prev_pos);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->prev_pos = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_set_used_size(ctx->cache_data_seq, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_switch_seq(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_record *rec, new_rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen void *data;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* fix record size */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen data = buffer_get_modifyable_data(ctx->cache_data, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = PTR_OFFSET(data, ctx->prev_pos);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec->size = size - ctx->prev_pos;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen i_assert(rec->size != 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->cache_data_seq, &ctx->prev_seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(ctx->prev_seq));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_pos = size;
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen } else if (ctx->cache_data == NULL) {
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen ctx->cache_data =
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen buffer_create_dynamic(system_pool, 32768, (size_t)-1);
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen ctx->cache_data_seq =
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen buffer_create_dynamic(system_pool, 256, (size_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen memset(&new_rec, 0, sizeof(new_rec));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->cache_data, &new_rec, sizeof(new_rec));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_seq = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->changes = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache *cache = ctx->cache;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen if (!ctx->changes || MAIL_CACHE_IS_UNUSABLE(cache)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free(ctx);
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen return 0;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen }
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_rollback(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_switch_seq(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* make sure everything's written before updating offsets */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (fdatasync(cache->fd) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_unlock(cache);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const uint32_t *buf;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen if ((ctx->reserved_space > 0 || ctx->reservations->used > 0) &&
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen !MAIL_CACHE_IS_UNUSABLE(cache)) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) > 0) {
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen mail_cache_transaction_free_space(ctx);
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen buf = buffer_get_data(ctx->reservations, &size);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen i_assert(size % sizeof(uint32_t)*2 == 0);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen size /= sizeof(*buf);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen if (size > 0) {
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen /* free flushed data as well. do it from end to
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen beginning so we have a better chance of
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen updating used_file_size instead of adding
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen holes */
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen do {
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen size -= 2;
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen mail_cache_free_space(ctx->cache,
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen buf[size],
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen buf[size+1]);
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen } while (size > 0);
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen }
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen mail_cache_unlock(cache);
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainenstatic int mail_cache_header_add_field(struct mail_cache_transaction_ctx *ctx,
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen unsigned int field)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache *cache = ctx->cache;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *buffer;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const void *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t offset, hdr_offset;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen /* re-read header to make sure we don't lose any fields. */
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (mail_cache_header_fields_read(cache) < 0) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen mail_cache_unlock(cache);
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen return -1;
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen }
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (ctx->cache->field_file_map[field] != (uint32_t)-1) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen /* it was already added */
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen mail_cache_unlock(cache);
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen return 0;
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen }
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_push();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen 256, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_header_fields_get(cache, buffer);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data = buffer_get_data(buffer, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen offset = mail_cache_transaction_get_space(ctx, size, size, &size, TRUE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (offset == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen else if (pwrite_full(cache->fd, data, size, offset) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else if (fdatasync(cache->fd) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else if (mail_cache_header_fields_get_next_offset(cache,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen &hdr_offset) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* after it's guaranteed to be in disk, update header offset */
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen offset = mail_index_uint32_to_offset(offset);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (pwrite_full(cache->fd, &offset, sizeof(offset),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hdr_offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we'll need to fix mappings. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_header_fields_read(cache) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_unlock(cache);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field, const void *data, size_t data_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t file_field, data_size32;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int fixed_size;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen size_t full_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(field < ctx->cache->fields_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data_size < (uint32_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (ctx->cache->fields[field].field.decision ==
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file_field = ctx->cache->field_file_map[field];
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file_field == (uint32_t)-1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we'll have to add this field to headers */
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (mail_cache_header_add_field(ctx, field) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file_field = ctx->cache->field_file_map[field];
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(file_field != (uint32_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen mail_cache_decision_add(ctx->view, seq, field);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen fixed_size = ctx->cache->fields[field].field.field_size;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen i_assert(fixed_size == (unsigned int)-1 || fixed_size == data_size);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen data_size32 = (uint32_t)data_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != seq) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_switch_seq(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_seq = seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* remember roughly what we have modified, so cache lookups can
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen look into transactions to see changes. */
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen if (seq < ctx->view->trans_seq1 || ctx->view->trans_seq1 == 0)
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen ctx->view->trans_seq1 = seq;
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen if (seq > ctx->view->trans_seq2)
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen ctx->view->trans_seq2 = seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen full_size = (data_size + 3) & ~3;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (fixed_size == (unsigned int)-1)
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen full_size += sizeof(data_size32);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (buffer_get_used_size(ctx->cache_data) + full_size >
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_get_size(ctx->cache_data)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* time to flush our buffer */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(ctx->cache_data, &file_field, sizeof(file_field));
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (fixed_size == (unsigned int)-1) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->cache_data, &data_size32,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen sizeof(data_size32));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->cache_data, data, data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((data_size & 3) != 0)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->cache_data, null4, 4 - (data_size & 3));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainenint mail_cache_transaction_lookup(struct mail_cache_transaction_ctx *ctx,
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen uint32_t seq, uint32_t *offset_r)
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen{
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen return mail_index_update_cache_lookup(ctx->trans, seq, offset_r);
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen}
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen uint32_t old_offset, uint32_t new_offset)
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen{
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen new_offset += offsetof(struct mail_cache_record, prev_offset);
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen if (pwrite_full(cache->fd, &old_offset,
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen sizeof(old_offset), new_offset) < 0) {
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen return -1;
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen }
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen return 0;
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen}
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t new_offset)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen return -1;
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (new_offset + sizeof(struct mail_cache_record) >
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_corrupted(cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "Cache record offset %u points outside file",
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen if (mail_cache_link_unlocked(cache, old_offset, new_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.continued_record_count++;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_delete(struct mail_cache *cache, uint32_t offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_record *cache_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache_rec = mail_cache_get_record(cache, offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cache_rec == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we'll only update the deleted_space in header. we can't really
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do any actual deleting as other processes might still be using
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the data. also it's actually useful as some index views are still
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen able to ask cached data from messages that have already been
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen expunged. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.deleted_space += cache_rec->size;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen cache_rec =
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen mail_cache_get_record(cache, cache_rec->prev_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } while (cache_rec != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen return 0;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen}