mail-cache-transaction.c revision f501ad38c51cf1d8f4f84313922c785e6ae6e81f
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen#include "ioloop.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "file-cache.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
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen#define MAIL_CACHE_WRITE_BUFFER 32768
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainenstruct mail_cache_reservation {
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen uint32_t offset;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen uint32_t size;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen};
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo 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
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen buffer_t *cache_data;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ARRAY_DEFINE(cache_data_seq, uint32_t);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t prev_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t prev_pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ARRAY_DEFINE(reservations, struct mail_cache_reservation);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t reserved_space_offset, reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t last_grow_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen unsigned int tried_compression:1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int changes:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
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;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&ctx->reservations, 32);
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen i_assert(view->transaction == NULL);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen view->transaction = ctx;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen view->trans_view = mail_index_transaction_open_updated_view(t);
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{
1a5fcc972dbadfe7959011b8ad422707e2dfc19fTimo Sirainen ctx->cache_file_seq = MAIL_CACHE_IS_UNUSABLE(ctx->cache) ? 0 :
1a5fcc972dbadfe7959011b8ad422707e2dfc19fTimo Sirainen ctx->cache->hdr->file_seq;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen mail_index_ext_set_reset_id(ctx->trans, ctx->cache->ext_id,
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen ctx->cache_file_seq);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen if (ctx->cache_data != NULL)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen buffer_set_used_size(ctx->cache_data, 0);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen if (array_is_created(&ctx->cache_data_seq))
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen array_clear(&ctx->cache_data_seq);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->prev_seq = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->prev_pos = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen array_clear(&ctx->reservations);
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
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainenstatic void
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainenmail_cache_transaction_free(struct mail_cache_transaction_ctx **_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen struct mail_cache_transaction_ctx *ctx = *_ctx;
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen *_ctx = NULL;
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen ctx->trans->cache_trans_ctx = NULL;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->view->transaction = NULL;
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen mail_index_view_close(&ctx->view->trans_view);
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen if (ctx->cache_data != NULL)
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&ctx->cache_data);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen if (array_is_created(&ctx->cache_data_seq))
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen array_free(&ctx->cache_data_seq);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen array_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
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen if (ctx->cache_file_seq == 0) {
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen if (!ctx->cache->opened)
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen (void)mail_cache_open_and_verify(ctx->cache);
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen if (!MAIL_CACHE_IS_UNUSABLE(ctx->cache)) {
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen i_assert(ctx->cache_data == NULL ||
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen ctx->cache_data->used == 0);
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen }
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen }
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen if ((ret = mail_cache_lock(ctx->cache, FALSE)) <= 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
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
6ef7e31619edfaa17ed044b45861d106a86191efTimo 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;
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen prev_offset = offset;
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 {
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, &hole.next_offset,
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen sizeof(hole.next_offset), prev_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->deleted_space -= hole.size;
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen cache->hdr_modified = TRUE;
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
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainenmail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx,
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen uint32_t offset, uint32_t size)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen struct mail_cache_reservation res;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen ctx->reserved_space_offset = offset;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen ctx->reserved_space = size;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen res.offset = offset;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen res.size = size;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen array_append(&ctx->reservations, &res, 1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainenstatic void
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainenmail_cache_transaction_partial_commit(struct mail_cache_transaction_ctx *ctx,
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen uint32_t offset, uint32_t size)
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen{
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen struct mail_cache_reservation *res;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen unsigned int i, count;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (offset + size == ctx->cache->hdr_copy.used_file_size &&
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen offset + size == ctx->reserved_space_offset) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen i_assert(ctx->reserved_space == 0);
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen ctx->reserved_space_offset = 0;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
1f6653c23f792401623734d783ede1653ba65436Timo Sirainen res = array_get_modifiable(&ctx->reservations, &count);
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen for (i = 0; i < count; i++) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (res[i].offset == offset) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (res[i].size == size) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen array_delete(&ctx->reservations, i, 1);
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen } else {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen i_assert(res[i].size > size);
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen res[i].offset += size;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen res[i].size -= size;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen break;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen}
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen size_t block_size, bool 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;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen struct mail_cache_reservation *reservations;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen unsigned int count;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_unlink_hole(cache, block_size, &hole)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* found a large enough hole. */
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen mail_cache_transaction_add_reservation(ctx, hole.next_offset,
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen hole.size);
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
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if ((uint32_t)-1 - hdr->used_file_size < block_size) {
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
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (!commit && block_size < MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen /* allocate some more space than we need */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen size_t new_block_size = (block_size + ctx->last_grow_size) * 2;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (new_block_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen new_block_size = MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if ((uint32_t)-1 - hdr->used_file_size >= new_block_size) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen block_size = new_block_size;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->last_grow_size = new_block_size;
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_grow_file(ctx->cache, block_size) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space_offset + ctx->reserved_space ==
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen hdr->used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can simply grow it */
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 */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen reservations = array_get_modifiable(&ctx->reservations, &count);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen do {
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen i_assert(count > 0);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen count--;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen } while (reservations[count].offset +
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations[count].size != hdr->used_file_size);
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations[count].size += block_size;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen ctx->reserved_space += block_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen mail_cache_transaction_add_reservation(ctx, hdr->used_file_size,
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen block_size);
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
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen return;
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo 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
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, &hole, sizeof(hole), offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
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
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool locked = ctx->cache->locked;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space == 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return 0;
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);
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen ctx->reserved_space_offset = 0;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen ctx->reserved_space = 0;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (!locked) {
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_unlock(ctx->cache) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return -1;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen }
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t min_size, size_t max_size,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen uint32_t *offset_r, size_t *available_space_r,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool commit)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool locked = ctx->cache->locked;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen uint32_t cache_file_seq;
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) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* not enough preallocated space in transaction, get more */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen cache_file_seq = ctx->cache_file_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if ((ret = mail_cache_transaction_lock(ctx)) <= 0)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return ret;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = mail_cache_transaction_reserve_more(ctx, max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit);
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (!locked) {
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_unlock(ctx->cache) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return -1;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ret < 0)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return -1;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (cache_file_seq != ctx->cache_file_seq) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* cache file reopened - need to abort */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = max_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = I_MIN(max_size, ctx->reserved_space);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen *offset_r = 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 */
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_transaction_free_space(ctx) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen i_assert(size >= min_size);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainenstatic int
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenmail_cache_transaction_update_index(struct mail_cache_transaction_ctx *ctx,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct mail_cache_record *rec,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const uint32_t *seq, uint32_t *seq_idx,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen uint32_t seq_limit, uint32_t write_offset,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen uint32_t *size_r)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct mail_cache *cache = ctx->cache;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen uint32_t i, old_offset, orig_write_offset;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* write the cache_offsets to index file. records' prev_offset
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen is updated to point to old cache record when index is being
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen synced. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen orig_write_offset = write_offset;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen for (i = *seq_idx; i < seq_limit; i++) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_index_update_ext(ctx->trans, seq[i], cache->ext_id,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen &write_offset, &old_offset);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (old_offset != 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* we added records for this message multiple
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen times in this same uncommitted transaction.
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen only the new one will be written to
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen transaction log, we need to do the linking
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ourself here. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (old_offset > write_offset) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (mail_cache_link_unlocked(cache, old_offset,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen write_offset) < 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return -1;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen } else {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* if we're combining multiple transactions,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen make sure the one with the smallest offset
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen is written into index. this is required for
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen non-file-mmaped cache to work properly. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_index_update_ext(ctx->trans, seq[i],
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen cache->ext_id,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen &old_offset, NULL);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (mail_cache_link_unlocked(cache,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen write_offset,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen old_offset) < 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return -1;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen write_offset += rec->size;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen rec = CONST_PTR_OFFSET(rec, rec->size);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen *seq_idx = i;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen *size_r = write_offset - orig_write_offset;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return 0;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo 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;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen uint32_t write_offset, write_size, rec_pos, seq_idx, seq_limit;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen size_t size, max_size;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen unsigned int seq_count;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int ret;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool 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
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen seq = array_get(&ctx->cache_data_seq, &seq_count);
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
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ret = mail_cache_transaction_get_space(ctx, rec->size,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen max_size, &write_offset,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen &max_size, commit);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (ret <= 0) {
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen /* error / couldn't lock / cache file reopened */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return ret;
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);
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, rec, max_size, write_offset) < 0)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return -1;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_transaction_update_index(ctx, rec, seq,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen &seq_idx, seq_limit,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen write_offset,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen &write_size) < 0)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return -1;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen rec_pos += write_size;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen rec = CONST_PTR_OFFSET(rec, write_size);
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
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen array_clear(&ctx->cache_data_seq);
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen return 1;
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 */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen data = buffer_get_modifiable_data(ctx->cache_data, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = PTR_OFFSET(data, ctx->prev_pos);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec->size = size - ctx->prev_pos;
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen i_assert(rec->size > sizeof(*rec));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen array_append(&ctx->cache_data_seq, &ctx->prev_seq, 1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_pos = size;
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen } else if (ctx->cache_data == NULL) {
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen ctx->cache_data =
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen buffer_create_dynamic(default_pool,
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen MAIL_CACHE_WRITE_BUFFER);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&ctx->cache_data_seq, 64);
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
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainenint mail_cache_transaction_commit(struct mail_cache_transaction_ctx **_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen struct mail_cache_transaction_ctx *ctx = *_ctx;
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)) {
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen mail_cache_transaction_free(_ctx);
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen return 0;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen }
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0) {
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo 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
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen /* Here would be a good place to do fdatasync() to make sure
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen everything is written before offsets are updated to index.
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen However it slows down I/O unneededly and we're pretty good at
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen catching and fixing cache corruption, so we no longer do it. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_unlock(cache) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen ret = -1;
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen mail_cache_transaction_free(_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainenvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx **_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen struct mail_cache_transaction_ctx *ctx = *_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen const struct mail_cache_reservation *reservations;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen unsigned int count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen if ((ctx->reserved_space > 0 || array_count(&ctx->reservations) > 0) &&
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen !MAIL_CACHE_IS_UNUSABLE(cache)) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (mail_cache_transaction_lock(ctx) > 0) {
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations = array_get(&ctx->reservations, &count);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen /* free flushed data as well. do it from end to
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen beginning so we have a better chance of
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen updating used_file_size instead of adding
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen holes */
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen while (count > 0) {
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen count--;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen mail_cache_free_space(ctx->cache,
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations[count].offset,
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations[count].size);
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen }
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen (void)mail_cache_unlock(cache);
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen mail_cache_transaction_free(_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstatic int
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenmail_cache_header_fields_write(struct mail_cache_transaction_ctx *ctx,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen const buffer_t *buffer)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct mail_cache *cache = ctx->cache;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen size_t size = buffer->used;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen uint32_t offset, hdr_offset;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (mail_cache_transaction_get_space(ctx, size, size,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen &offset, NULL, TRUE) <= 0)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (mail_cache_write(cache, buffer->data, size, offset) < 0)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (!cache->index->fsync_disable) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (fdatasync(cache->fd) < 0) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (mail_cache_header_fields_get_next_offset(cache, &hdr_offset) < 0)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* if we rollback the transaction, we must not overwrite this
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen area because it's already committed after updating the
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen header offset */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_cache_transaction_partial_commit(ctx, offset, size);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* after it's guaranteed to be in disk, update header offset */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen offset = mail_index_uint32_to_offset(offset);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (mail_cache_write(cache, &offset, sizeof(offset), hdr_offset) < 0)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (hdr_offset == offsetof(struct mail_cache_header,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen field_header_offset)) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* we're adding the first field. hdr_copy needs to be kept
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen in sync so unlocking won't overwrite it. */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen cache->hdr_copy.field_header_offset = hdr_offset;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen cache->hdr_ro_copy.field_header_offset = hdr_offset;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainenstatic int mail_cache_header_add_field(struct mail_cache_transaction_ctx *ctx,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen unsigned int field_idx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache *cache = ctx->cache;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen unsigned int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *buffer;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen /* we want to avoid adding all the fields one by one to the cache file,
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen so just add all of them at once in here. the unused ones get dropped
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen later when compressing. */
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen for (i = 0; i < cache->fields_count; i++)
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen cache->fields[i].used = TRUE;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen if ((ret = mail_cache_transaction_lock(ctx)) <= 0) {
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen /* create the cache file if it doesn't exist yet */
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen if (ctx->tried_compression)
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return -1;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen ctx->tried_compression = TRUE;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen if (mail_cache_compress(cache, ctx->trans) < 0)
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return -1;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen /* if we compressed the cache, the field should be there now.
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen it's however possible that someone else just compressed it
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen and we only reopened the cache file. */
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen if (cache->field_file_map[field_idx] != (uint32_t)-1)
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen return 0;
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen /* need to add it */
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen if ((ret = mail_cache_transaction_lock(ctx)) <= 0)
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen return -1;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen }
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) {
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen (void)mail_cache_unlock(cache);
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen return -1;
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen }
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (cache->field_file_map[field_idx] != (uint32_t)-1) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen /* it was already added */
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_unlock(cache) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return -1;
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen return 0;
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen }
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_push();
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_header_fields_get(cache, buffer);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen ret = mail_cache_header_fields_write(ctx, buffer);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen t_pop();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (ret == 0) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* we wrote all the headers, so there are no pending changes */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen cache->field_header_write_pending = FALSE;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen ret = mail_cache_header_fields_read(cache);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (ret == 0 && cache->field_file_map[field_idx] == (uint32_t)-1) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_index_set_error(cache->index,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen "Cache file %s: Newly added field got "
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen "lost unexpectedly", cache->filepath);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_unlock(cache) < 0)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen ret = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen unsigned int field_idx, 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
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen i_assert(field_idx < ctx->cache->fields_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data_size < (uint32_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen if (ctx->cache->fields[field_idx].field.decision ==
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen if (ctx->cache_file_seq == 0) {
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen if (!ctx->cache->opened)
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen (void)mail_cache_open_and_verify(ctx->cache);
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen
b387ee112301fef59d16ab3b120e3821cd0c70dfTimo Sirainen if (!MAIL_CACHE_IS_UNUSABLE(ctx->cache))
b387ee112301fef59d16ab3b120e3821cd0c70dfTimo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen }
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen file_field = ctx->cache->field_file_map[field_idx];
17118d434fcd48b0f0211bdac2747276f0b05223Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(ctx->cache) || file_field == (uint32_t)-1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we'll have to add this field to headers */
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen if (mail_cache_header_add_field(ctx, field_idx) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen if (ctx->cache_file_seq == 0)
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen file_field = ctx->cache->field_file_map[field_idx];
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(file_field != (uint32_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
17118d434fcd48b0f0211bdac2747276f0b05223Timo Sirainen i_assert(ctx->cache_file_seq != 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen mail_cache_decision_add(ctx->view, seq, field_idx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen fixed_size = ctx->cache->fields[field_idx].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
988f9ad3b5e973c12453a780effc477031107648Timo Sirainen /* remember that this value exists, in case we try to look it up */
988f9ad3b5e973c12453a780effc477031107648Timo Sirainen buffer_write(ctx->view->cached_exists_buf, field_idx,
988f9ad3b5e973c12453a780effc477031107648Timo Sirainen &ctx->view->cached_exists_value, 1);
988f9ad3b5e973c12453a780effc477031107648Timo 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
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen if (ctx->cache_data->used + full_size >
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen buffer_get_size(ctx->cache_data) && ctx->prev_pos > 0) {
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen /* time to flush our buffer. if flushing fails because the
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen cache file had been compressed and was reopened, return
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen without adding the cached data since cache_data buffer
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen doesn't contain the cache_rec anymore. */
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen if (mail_cache_transaction_flush(ctx) <= 0) {
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen /* make sure the transaction is reset, so we don't
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen constantly try to flush for each call to this
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen function */
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen mail_cache_transaction_reset(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen }
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)
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen buffer_append_zero(ctx->cache_data, 4 - (data_size & 3));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainenbool mail_cache_field_want_add(struct mail_cache_transaction_ctx *ctx,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen uint32_t seq, unsigned int field_idx)
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen{
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen enum mail_cache_decision_type decision;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen
65b73edef55f8d1a4e343fdc47c2a3f9d4554db3Timo Sirainen if (!ctx->cache->opened)
65b73edef55f8d1a4e343fdc47c2a3f9d4554db3Timo Sirainen (void)mail_cache_open_and_verify(ctx->cache);
65b73edef55f8d1a4e343fdc47c2a3f9d4554db3Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen decision = mail_cache_field_get_decision(ctx->view->cache, field_idx);
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen if ((decision & ~MAIL_CACHE_DECISION_FORCED) == MAIL_CACHE_DECISION_NO)
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen return FALSE;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen return mail_cache_field_exists(ctx->view, seq, field_idx) == 0;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen}
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainenbool mail_cache_field_can_add(struct mail_cache_transaction_ctx *ctx,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen uint32_t seq, unsigned int field_idx)
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen{
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen enum mail_cache_decision_type decision;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen
65b73edef55f8d1a4e343fdc47c2a3f9d4554db3Timo Sirainen if (!ctx->cache->opened)
65b73edef55f8d1a4e343fdc47c2a3f9d4554db3Timo Sirainen (void)mail_cache_open_and_verify(ctx->cache);
65b73edef55f8d1a4e343fdc47c2a3f9d4554db3Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen decision = mail_cache_field_get_decision(ctx->view->cache, field_idx);
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen if (decision == (MAIL_CACHE_DECISION_FORCED | MAIL_CACHE_DECISION_NO))
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen return FALSE;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen return mail_cache_field_exists(ctx->view, seq, field_idx) == 0;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen}
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo 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);
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen return mail_cache_write(cache, &old_offset, sizeof(old_offset),
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen new_offset);
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{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen const struct mail_cache_record *rec;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen ARRAY_TYPE(uint32_t) looping_offsets;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo 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. */
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen t_push();
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen t_array_init(&looping_offsets, 8);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen array_append(&looping_offsets, &offset, 1);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen while (mail_cache_get_record(cache, offset, &rec) == 0) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen cache->hdr_copy.deleted_space += rec->size;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen offset = rec->prev_offset;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (offset == 0) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* successfully got to the end of the list */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen ret = 0;
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen break;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (mail_cache_track_loops(&looping_offsets, offset)) {
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen mail_cache_set_corrupted(cache,
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen "record list is circular");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen break;
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen }
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen }
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen t_pop();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return ret;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen}