mail-cache-transaction.c revision 4b058f90f9e8a2c6b2eed275de4eb8cc5195a71d
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"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-cache-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-transaction-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainenstruct mail_cache_transaction_ctx {
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen struct mail_cache *cache;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen struct mail_cache_view *view;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen struct mail_index_transaction *trans;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen uint32_t cache_file_seq;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen buffer_t *cache_data, *cache_data_seq;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen uint32_t prev_seq;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen size_t prev_pos;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen buffer_t *reservations;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen uint32_t reserved_space_offset, reserved_space;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen uint32_t last_grow_size;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen unsigned int changes:1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen};
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t old_offset, uint32_t new_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstruct mail_cache_transaction_ctx *
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainenmail_cache_get_transaction(struct mail_cache_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_transaction *t)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_transaction_ctx *ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->cache_trans_ctx != NULL)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return t->cache_trans_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen ctx = i_new(struct mail_cache_transaction_ctx, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cache = view->cache;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ctx->view = view;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen ctx->trans = t;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ctx->reservations = buffer_create_dynamic(system_pool, 256);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!MAIL_CACHE_IS_UNUSABLE(ctx->cache))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen i_assert(view->transaction == NULL);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen view->transaction = ctx;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen t->cache_trans_ctx = ctx;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return ctx;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen}
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainenstatic void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen{
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (ctx->cache_data)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen buffer_set_used_size(ctx->cache_data, 0);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (ctx->cache_data_seq)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen buffer_set_used_size(ctx->cache_data_seq, 0);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ctx->prev_seq = 0;
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ctx->prev_pos = 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen buffer_set_used_size(ctx->reservations, 0);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx->reserved_space_offset = 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ctx->reserved_space = 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ctx->last_grow_size = 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ctx->changes = FALSE;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen{
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ctx->view->transaction = NULL;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (ctx->cache_data != NULL)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen buffer_free(ctx->cache_data);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (ctx->cache_data_seq != NULL)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen buffer_free(ctx->cache_data_seq);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen buffer_free(ctx->reservations);
445f9e31c6c3aa6c0a72be8565da8f6e594d24fbTimo Sirainen i_free(ctx);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen int ret;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if ((ret = mail_cache_lock(ctx->cache)) <= 0)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return ret;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_cache_transaction_reset(ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct stat st;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uoff_t new_fsize, grow_size;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_assert(cache->locked);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* grow the file */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen new_fsize = cache->hdr_copy.used_file_size + size;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (grow_size < 16384)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen grow_size = 16384;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen new_fsize += grow_size;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen new_fsize &= ~1023;
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen if (fstat(cache->fd, &st) < 0) {
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if ((uoff_t)st.st_size < new_fsize) {
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (file_set_size(cache->fd, new_fsize) < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen return 0;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen}
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstatic int mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail_cache_hole_header *hole_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen struct mail_cache_hole_header hole;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen uint32_t offset, prev_offset;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen i_assert(cache->locked);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen offset = hdr->hole_offset; prev_offset = 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen while (offset != 0) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_cache_set_syscall_error(cache, "pread_full()");
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return FALSE;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen }
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen mail_cache_set_corrupted(cache,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "Invalid magic in hole header");
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (hole.size >= size)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen break;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen offset = hole.next_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (offset == 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (prev_offset == 0)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen hdr->hole_offset = hole.next_offset;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen else {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (pwrite_full(cache->fd, &hole.next_offset,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen sizeof(hole.next_offset), prev_offset) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return FALSE;
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen hdr->deleted_space -= hole.size;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen hole_r->next_offset = offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen hole_r->size = hole.size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx)
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen buffer_append(ctx->reservations, &ctx->reserved_space_offset,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sizeof(ctx->reserved_space_offset));
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen buffer_append(ctx->reservations, &ctx->reserved_space,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sizeof(ctx->reserved_space));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen size_t size, int commit)
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen{
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen struct mail_cache *cache = ctx->cache;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen struct mail_cache_hole_header hole;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen uint32_t *buf;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen i_assert(cache->locked);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (mail_cache_unlink_hole(cache, size, &hole)) {
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen /* found a large enough hole. */
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen ctx->reserved_space_offset = hole.next_offset;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen ctx->reserved_space = hole.size;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mail_cache_transaction_add_reservation(ctx);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen return 0;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen /* mail_cache_unlink_hole() could have noticed corruption */
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen return -1;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if ((uoff_t)hdr->used_file_size + size > (uint32_t)-1) {
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mail_index_set_error(cache->index, "Cache file too large: %s",
43d504fb5b23e14878e9777cdebff9c623f0b52cTimo Sirainen cache->filepath);
43d504fb5b23e14878e9777cdebff9c623f0b52cTimo Sirainen return -1;
43d504fb5b23e14878e9777cdebff9c623f0b52cTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (!commit) {
43d504fb5b23e14878e9777cdebff9c623f0b52cTimo Sirainen /* allocate some more space than we need */
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen size_t new_size = (size + ctx->last_grow_size) * 2;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if ((uoff_t)hdr->used_file_size + new_size > (uint32_t)-1)
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen new_size = (uint32_t)-1;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (new_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen new_size = size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE ?
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen size : MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen ctx->last_grow_size = new_size;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_cache_grow_file(ctx->cache, size) < 0)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (ctx->reserved_space_offset + ctx->reserved_space ==
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hdr->used_file_size) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* we can simply grow it */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen ctx->reserved_space = size - ctx->reserved_space;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen /* grow reservation. it's probably the last one in the buffer,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen but it's not guarateed because we might have used holes
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen as well */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buf = buffer_get_modifyable_data(ctx->reservations, &size);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen size /= sizeof(uint32_t);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen i_assert(size >= 2);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen do {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen size -= 2;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (buf[size] == ctx->reserved_space_offset) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buf[size+1] = ctx->reserved_space;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } while (size >= 2);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->reserved_space_offset = hdr->used_file_size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->reserved_space = size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_cache_transaction_add_reservation(ctx);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen cache->hdr_modified = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hdr->used_file_size = ctx->reserved_space_offset + ctx->reserved_space;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenmail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_cache_hole_header hole;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(cache->locked);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen if (offset + size == cache->hdr_copy.used_file_size) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* we can just set used_file_size back */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen cache->hdr_modified = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen cache->hdr_copy.used_file_size = offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else if (size >= MAIL_CACHE_MIN_HOLE_SIZE) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* set it up as a hole */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen hole.next_offset = cache->hdr_copy.hole_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen hole.size = size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen hole.magic = MAIL_CACHE_HOLE_HEADER_MAGIC;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (pwrite_full(cache->fd, &hole, sizeof(hole), offset) < 0) {
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen return;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen cache->hdr_copy.deleted_space += size;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen cache->hdr_copy.hole_offset = offset;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen cache->hdr_modified = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int locked = ctx->cache->locked;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ctx->reserved_space == 0)
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen return;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!locked) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen return;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen /* check again - locking might have reopened the cache file */
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen if (ctx->reserved_space != 0) {
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen i_assert(ctx->cache_file_seq == ctx->cache->hdr->file_seq);
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen mail_cache_free_space(ctx->cache, ctx->reserved_space_offset,
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen ctx->reserved_space);
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen if (!locked)
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen mail_cache_unlock(ctx->cache);
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen}
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen
484efa22e65c509f787dbbc892351146c726c257Timo Sirainenstatic uint32_t
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainenmail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen size_t min_size, size_t max_size,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen size_t *available_space_r, int commit)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int locked = ctx->cache->locked;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen uint32_t offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen size_t size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int ret;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen i_assert((min_size & 3) == 0);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen i_assert((max_size & 3) == 0);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (min_size > ctx->reserved_space) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (!locked) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return 0;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen ret = mail_cache_transaction_reserve_more(ctx, max_size,
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen commit);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (!locked)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_cache_unlock(ctx->cache);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (ret < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 0;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen size = max_size;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen } else {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen size = I_MIN(max_size, ctx->reserved_space);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen offset = ctx->reserved_space_offset;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx->reserved_space_offset += size;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen ctx->reserved_space -= size;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (available_space_r != NULL)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen *available_space_r = size;
f0f9c8e94abac18f8acd91b9e724c4c32863723aTimo Sirainen i_assert((size & 3) == 0);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (size == max_size && commit) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* final commit - see if we can free the rest of the
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen reserved space */
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_cache_transaction_free_space(ctx);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return offset;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic int
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenmail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail_cache *cache = ctx->cache;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct mail_cache_record *rec, *tmp_rec;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen const uint32_t *seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t write_offset, old_offset, rec_pos, cache_file_seq;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen size_t size, max_size, seq_idx, seq_limit, seq_count;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int commit;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen return -1;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen commit = ctx->prev_seq == 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (commit) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* committing, remove the last dummy record */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen buffer_set_used_size(ctx->cache_data, ctx->prev_pos);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq) {
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen /* cache file reopened - need to abort */
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_cache_transaction_reset(ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
8af07808ba203f8709e2ff9eaf2291e1c4a4d53dTimo Sirainen rec = buffer_get_data(ctx->cache_data, &size);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_assert(ctx->prev_pos <= size);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen seq = buffer_get_data(ctx->cache_data_seq, &seq_count);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen seq_count /= sizeof(*seq);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen seq_limit = 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (seq_idx = 0, rec_pos = 0; rec_pos < ctx->prev_pos;) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen max_size = ctx->prev_pos - rec_pos;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen cache_file_seq = ctx->cache_file_seq;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen write_offset = mail_cache_transaction_get_space(ctx, rec->size,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen max_size,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen &max_size,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen commit);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (cache_file_seq != ctx->cache_file_seq) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* cache file reopened - need to abort */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (write_offset == 0) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* nothing to write / error */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen return ctx->prev_pos == 0 ? 0 : -1;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (rec_pos + max_size < ctx->prev_pos) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* see how much we can really write there */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen tmp_rec = rec;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen for (size = 0; size + tmp_rec->size <= max_size; ) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen seq_limit++;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen size += tmp_rec->size;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen tmp_rec = CONST_PTR_OFFSET(tmp_rec,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen tmp_rec->size);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen max_size = size;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen } else {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen seq_limit = seq_count;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* write it to file */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen i_assert(ctx->cache_file_seq == cache->hdr->file_seq);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (pwrite_full(cache->fd, rec, max_size, write_offset) < 0) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* write the cache_offsets to index file. records' prev_offset
33d63688ed8b26dc333e3c2edbfb2fe6e412604dTimo Sirainen is updated to point to old cache record when index is being
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen synced. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen for (; seq_idx < seq_limit; seq_idx++) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mail_index_update_cache(ctx->trans, seq[seq_idx],
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen cache->hdr->file_seq,
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen write_offset, &old_offset);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen if (old_offset != 0) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen /* we added records for this message multiple
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen times in this same uncommitted transaction.
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen only the new one will be written to
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen transaction log, we need to do the linking
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ourself here. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_cache_link_unlocked(cache, old_offset,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen write_offset) < 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen write_offset += rec->size;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen rec_pos += rec->size;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen rec = CONST_PTR_OFFSET(rec, rec->size);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen /* drop the written data from buffer */
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen buffer_copy(ctx->cache_data, 0,
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen ctx->cache_data, ctx->prev_pos, (size_t)-1);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buffer_set_used_size(ctx->cache_data,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen buffer_get_used_size(ctx->cache_data) -
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->prev_pos);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->prev_pos = 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buffer_set_used_size(ctx->cache_data_seq, 0);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenmail_cache_transaction_switch_seq(struct mail_cache_transaction_ctx *ctx)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_cache_record *rec, new_rec;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen void *data;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen size_t size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (ctx->prev_seq != 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* fix record size */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen data = buffer_get_modifyable_data(ctx->cache_data, &size);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen rec = PTR_OFFSET(data, ctx->prev_pos);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen rec->size = size - ctx->prev_pos;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(rec->size != 0);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen buffer_append(ctx->cache_data_seq, &ctx->prev_seq,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen sizeof(ctx->prev_seq));
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen ctx->prev_pos = size;
844adc2ea94a10ef81d1ceac9a87b877c20de623Timo Sirainen } else if (ctx->cache_data == NULL) {
844adc2ea94a10ef81d1ceac9a87b877c20de623Timo Sirainen ctx->cache_data = buffer_create_dynamic(system_pool, 32768);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen ctx->cache_data_seq = buffer_create_dynamic(system_pool, 256);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen memset(&new_rec, 0, sizeof(new_rec));
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen buffer_append(ctx->cache_data, &new_rec, sizeof(new_rec));
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen ctx->prev_seq = 0;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen ctx->changes = TRUE;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen}
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainenint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen{
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen struct mail_cache *cache = ctx->cache;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen int ret = 0;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (!ctx->changes || MAIL_CACHE_IS_UNUSABLE(cache)) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_cache_transaction_free(ctx);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen return 0;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_cache_transaction_rollback(ctx);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return -1;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (ctx->prev_seq != 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mail_cache_transaction_switch_seq(ctx);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen ret = -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* make sure everything's written before updating offsets */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (fdatasync(cache->fd) < 0) {
bb26f09873c18f342cd1ab2d0ee0b9018e6546d9Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
bb26f09873c18f342cd1ab2d0ee0b9018e6546d9Timo Sirainen ret = -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_cache_unlock(cache);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_cache_transaction_free(ctx);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen return ret;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen}
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail_cache *cache = ctx->cache;
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen const uint32_t *buf;
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen size_t size;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((ctx->reserved_space > 0 || ctx->reservations->used > 0) &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen !MAIL_CACHE_IS_UNUSABLE(cache)) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mail_cache_transaction_lock(ctx) > 0) {
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen mail_cache_transaction_free_space(ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen buf = buffer_get_data(ctx->reservations, &size);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(size % sizeof(uint32_t)*2 == 0);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen size /= sizeof(*buf);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (size > 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* free flushed data as well. do it from end to
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen beginning so we have a better chance of
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen updating used_file_size instead of adding
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen holes */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen do {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen size -= 2;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_cache_free_space(ctx->cache,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buf[size],
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buf[size+1]);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen } while (size > 0);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_cache_unlock(cache);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_cache_transaction_free(ctx);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen}
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic int mail_cache_header_add_field(struct mail_cache_transaction_ctx *ctx,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen unsigned int field)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen struct mail_cache *cache = ctx->cache;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buffer_t *buffer;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen const void *data;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen size_t size;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uint32_t offset, hdr_offset;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen int ret = 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* re-read header to make sure we don't lose any fields. */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (mail_cache_header_fields_read(cache) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_cache_unlock(cache);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ctx->cache->field_file_map[field] != (uint32_t)-1) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* it was already added */
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen mail_cache_unlock(cache);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen t_push();
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_cache_header_fields_get(cache, buffer);
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen data = buffer_get_data(buffer, &size);
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen offset = mail_cache_transaction_get_space(ctx, size, size, &size, TRUE);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (offset == 0)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen else if (pwrite_full(cache->fd, data, size, offset) < 0) {
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen ret = -1;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen } else if (fdatasync(cache->fd) < 0) {
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen ret = -1;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen } else if (mail_cache_header_fields_get_next_offset(cache,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen &hdr_offset) < 0)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen else {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* after it's guaranteed to be in disk, update header offset */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen offset = mail_index_uint32_to_offset(offset);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (pwrite_full(cache->fd, &offset, sizeof(offset),
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen hdr_offset) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen /* we'll need to fix mappings. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (mail_cache_header_fields_read(cache) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen t_pop();
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_cache_unlock(cache);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return ret;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenvoid mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen unsigned int field, const void *data, size_t data_size)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t file_field, data_size32;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen unsigned int fixed_size;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen size_t full_size;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen i_assert(field < ctx->cache->fields_count);
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen i_assert(data_size < (uint32_t)-1);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (ctx->cache->fields[field].field.decision ==
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED))
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return;
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen file_field = ctx->cache->field_file_map[field];
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (file_field == (uint32_t)-1) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* we'll have to add this field to headers */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (mail_cache_header_add_field(ctx, field) < 0)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen file_field = ctx->cache->field_file_map[field];
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen i_assert(file_field != (uint32_t)-1);
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen }
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen mail_cache_decision_add(ctx->view, seq, field);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen fixed_size = ctx->cache->fields[field].field.field_size;
ab3c1eab9ca13916358a9e8b12df8212fefb7dbfTimo Sirainen i_assert(fixed_size == (unsigned int)-1 || fixed_size == data_size);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen data_size32 = (uint32_t)data_size;
3021a062b16ff0138408be6107d6bcd0ced280b9Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (ctx->prev_seq != seq) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_cache_transaction_switch_seq(ctx);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ctx->prev_seq = seq;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen /* remember roughly what we have modified, so cache lookups can
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen look into transactions to see changes. */
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (seq < ctx->view->trans_seq1 || ctx->view->trans_seq1 == 0)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ctx->view->trans_seq1 = seq;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (seq > ctx->view->trans_seq2)
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen ctx->view->trans_seq2 = seq;
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen }
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen full_size = (data_size + 3) & ~3;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fixed_size == (unsigned int)-1)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen full_size += sizeof(data_size32);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (buffer_get_used_size(ctx->cache_data) + full_size >
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen buffer_get_size(ctx->cache_data)) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* time to flush our buffer */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return;
1276e0340fe29495b6694dc7508f070cf6fca1cfTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen buffer_append(ctx->cache_data, &file_field, sizeof(file_field));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (fixed_size == (unsigned int)-1) {
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen buffer_append(ctx->cache_data, &data_size32,
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen sizeof(data_size32));
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen buffer_append(ctx->cache_data, data, data_size);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((data_size & 3) != 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen buffer_append(ctx->cache_data, null4, 4 - (data_size & 3));
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenint mail_cache_transaction_lookup(struct mail_cache_transaction_ctx *ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t seq, uint32_t *offset_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return mail_index_update_cache_lookup(ctx->trans, seq, offset_r);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t old_offset, uint32_t new_offset)
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen{
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen new_offset += offsetof(struct mail_cache_record, prev_offset);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (pwrite_full(cache->fd, &old_offset,
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen sizeof(old_offset), new_offset) < 0) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen return -1;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenint mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t new_offset)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen i_assert(cache->locked);
60d3fa9883237e896a8704275b6116fa46f7ffdaTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
659fe5d24825b160cae512538088020d97a60239Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (new_offset + sizeof(struct mail_cache_record) >
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen cache->hdr_copy.used_file_size) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_cache_set_corrupted(cache,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "Cache record offset %u points outside file",
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen new_offset);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (mail_cache_link_unlocked(cache, old_offset, new_offset) < 0)
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen return -1;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen cache->hdr_copy.continued_record_count++;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen cache->hdr_modified = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainenint mail_cache_delete(struct mail_cache *cache, uint32_t offset)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen{
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct mail_cache_record *cache_rec;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen i_assert(cache->locked);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen cache_rec = mail_cache_get_record(cache, offset);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (cache_rec == NULL)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* we'll only update the deleted_space in header. we can't really
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen do any actual deleting as other processes might still be using
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen the data. also it's actually useful as some index views are still
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen able to ask cached data from messages that have already been
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen expunged. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen do {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen cache->hdr_copy.deleted_space += cache_rec->size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen cache_rec =
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_cache_get_record(cache, cache_rec->prev_offset);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } while (cache_rec != NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen cache->hdr_modified = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen}
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen