mail-cache-transaction.c revision 6a669919418a1c7469f9faf55d11b3c723f72cff
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen#include "array.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-cache.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "file-set-size.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "write-full.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "mail-cache-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-transaction-private.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MAIL_CACHE_WRITE_BUFFER 32768
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainenstruct mail_cache_reservation {
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen uint32_t offset;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen uint32_t size;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen};
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo 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
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t cache_file_seq;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
956f7778e413d3184d69e7b96e4a6b3cd5570bcdTimo Sirainen buffer_t *cache_data;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ARRAY_DEFINE(cache_data_seq, uint32_t);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen uint32_t prev_seq;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen size_t prev_pos;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ARRAY_DEFINE(reservations, struct mail_cache_reservation);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t reserved_space_offset, reserved_space;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen uint32_t last_grow_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int changes:1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen};
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo SirainenARRAY_DEFINE_TYPE(uint32_t, uint32_t);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen uint32_t old_offset, uint32_t new_offset);
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainenstruct mail_cache_transaction_ctx *
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_get_transaction(struct mail_cache_view *view,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_index_transaction *t)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_transaction_ctx *ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (t->cache_trans_ctx != NULL)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return t->cache_trans_ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo 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;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_array_init(&ctx->reservations, 32);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen i_assert(view->transaction == NULL);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen view->transaction = ctx;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen view->trans_view = mail_index_transaction_open_updated_view(t);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen t->cache_trans_ctx = ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen{
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
1a5fcc972dbadfe7959011b8ad422707e2dfc19fTimo Sirainen
1a5fcc972dbadfe7959011b8ad422707e2dfc19fTimo Sirainen if (ctx->cache_data)
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen buffer_set_used_size(ctx->cache_data, 0);
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen if (array_is_created(&ctx->cache_data_seq))
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen array_clear(&ctx->cache_data_seq);
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen ctx->prev_seq = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->prev_pos = 0;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo 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;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->changes = FALSE;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen}
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstatic void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen{
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->view->transaction = NULL;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen if (ctx->cache_data != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(ctx->cache_data);
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen if (array_is_created(&ctx->cache_data_seq))
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen array_free(&ctx->cache_data_seq);
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen array_free(&ctx->reservations);
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen i_free(ctx);
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen}
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainenstatic int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen{
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen int ret;
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen if (ctx->cache_file_seq == 0) {
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen if (!ctx->cache->opened)
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen (void)mail_cache_open_and_verify(ctx->cache);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen if (!MAIL_CACHE_IS_UNUSABLE(ctx->cache))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if ((ret = mail_cache_lock(ctx->cache)) <= 0)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen return ret;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq)
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen mail_cache_transaction_reset(ctx);
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen return 1;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen}
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainenstatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen{
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen struct stat st;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen uoff_t new_fsize, grow_size;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen i_assert(cache->locked);
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen /* grow the file */
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen new_fsize = cache->hdr_copy.used_file_size + size;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen if (grow_size < 16384)
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen grow_size = 16384;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen new_fsize += grow_size;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen new_fsize &= ~1023;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen if (fstat(cache->fd, &st) < 0) {
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen return -1;
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen }
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if ((uoff_t)st.st_size < new_fsize) {
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (file_set_size(cache->fd, new_fsize) < 0) {
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen return -1;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen }
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen }
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen return 0;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen}
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainenstatic bool mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_hole_header *hole_r)
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen{
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_hole_header hole;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen uint32_t offset, prev_offset;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen i_assert(cache->locked);
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen offset = hdr->hole_offset; prev_offset = 0;
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen while (offset != 0) {
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen mail_cache_set_syscall_error(cache, "pread_full()");
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen return FALSE;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen }
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen mail_cache_set_corrupted(cache,
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen "Invalid magic in hole header");
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen return FALSE;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen }
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (hole.size >= size)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen break;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen prev_offset = offset;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen offset = hole.next_offset;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen }
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (offset == 0)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen return FALSE;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (prev_offset == 0)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen hdr->hole_offset = hole.next_offset;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen else {
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if (mail_cache_write(cache, &hole.next_offset,
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen sizeof(hole.next_offset), prev_offset) < 0)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen return FALSE;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen }
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen hdr->deleted_space -= hole.size;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen cache->hdr_modified = TRUE;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen hole_r->next_offset = offset;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen hole_r->size = hole.size;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen return TRUE;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen}
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainenstatic void
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenmail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx,
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen uint32_t offset, uint32_t size)
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen{
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_reservation res;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen ctx->reserved_space_offset = offset;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen ctx->reserved_space = size;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen res.offset = offset;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen res.size = size;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen array_append(&ctx->reservations, &res, 1);
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen}
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainenstatic int
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainenmail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen size_t block_size, bool commit)
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen{
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache *cache = ctx->cache;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_hole_header hole;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen struct mail_cache_reservation *reservations;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen unsigned int count;
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen i_assert(cache->locked);
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen if (mail_cache_unlink_hole(cache, block_size, &hole)) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen /* found a large enough hole. */
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen mail_cache_transaction_add_reservation(ctx, hole.next_offset,
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen hole.size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* mail_cache_unlink_hole() could have noticed corruption */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo 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);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!commit && block_size < MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* allocate some more space than we need */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t new_block_size = (block_size + ctx->last_grow_size) * 2;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (new_block_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_block_size = MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((uint32_t)-1 - hdr->used_file_size >= new_block_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen block_size = new_block_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->last_grow_size = new_block_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_grow_file(ctx->cache, block_size) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (ctx->reserved_space_offset + ctx->reserved_space ==
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen hdr->used_file_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen as well */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reservations = array_get_modifiable(&ctx->reservations, &count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen do {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(count > 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen count--;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } while (reservations[count].offset +
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reservations[count].size != hdr->used_file_size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reservations[count].size += block_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space += block_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_add_reservation(ctx, hdr->used_file_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo 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;
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen return 0;
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen return;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset + size == cache->hdr_copy.used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can just set used_file_size back */
faef57a36800fe952a5794328467f846d5480ae6Timo 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;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hole.size = size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hole.magic = MAIL_CACHE_HOLE_HEADER_MAGIC;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen if (mail_cache_write(cache, &hole, sizeof(hole), offset) < 0)
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen return;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen cache->hdr_copy.deleted_space += size;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen cache->hdr_copy.hole_offset = offset;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen cache->hdr_modified = TRUE;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen }
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen}
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainenstatic int
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainenmail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen bool locked = ctx->cache->locked;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (ctx->reserved_space == 0)
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen return 0;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (!locked) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen return 0;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen /* check again - locking might have reopened the cache file */
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (ctx->reserved_space != 0) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen i_assert(ctx->cache_file_seq == ctx->cache->hdr->file_seq);
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen mail_cache_free_space(ctx->cache, ctx->reserved_space_offset,
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen ctx->reserved_space);
1f6653c23f792401623734d783ede1653ba65436Timo Sirainen ctx->reserved_space_offset = 0;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen ctx->reserved_space = 0;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (!locked) {
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen if (mail_cache_unlock(ctx->cache) < 0)
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen return -1;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen }
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen return 0;
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen}
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainenstatic int
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainenmail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen size_t min_size, size_t max_size,
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen uint32_t *offset_r, size_t *available_space_r,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen bool commit)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool locked = ctx->cache->locked;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t cache_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int ret;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen i_assert((min_size & 3) == 0);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen i_assert((max_size & 3) == 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (min_size > ctx->reserved_space) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* not enough preallocated space in transaction, get more */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen cache_file_seq = ctx->cache_file_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen if ((ret = mail_cache_transaction_lock(ctx)) <= 0)
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen return ret;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = mail_cache_transaction_reserve_more(ctx, max_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen commit);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_unlock(ctx->cache) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (ret < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cache_file_seq != ctx->cache_file_seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* cache file reopened - need to abort */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen size = max_size;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen } else {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen size = I_MIN(max_size, ctx->reserved_space);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen *offset_r = ctx->reserved_space_offset;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->reserved_space_offset += size;
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen ctx->reserved_space -= size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (available_space_r != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *available_space_r = size;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen i_assert((size & 3) == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (size == max_size && commit) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* final commit - see if we can free the rest of the
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen reserved space */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_free_space(ctx) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(size >= min_size);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen return 1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainenstatic int
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainenmail_cache_transaction_update_index(struct mail_cache_transaction_ctx *ctx,
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen const struct mail_cache_record *rec,
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen const uint32_t *seq, uint32_t *seq_idx,
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen uint32_t seq_limit, uint32_t write_offset,
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen uint32_t *size_r)
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache *cache = ctx->cache;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen uint32_t i, old_offset, orig_write_offset;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* write the cache_offsets to index file. records' prev_offset
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen is updated to point to old cache record when index is being
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen synced. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen orig_write_offset = write_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = *seq_idx; i < seq_limit; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_ext(ctx->trans, seq[i], cache->ext_id,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &write_offset, &old_offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (old_offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we added records for this message multiple
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen times in this same uncommitted transaction.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen only the new one will be written to
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen transaction log, we need to do the linking
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ourself here. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (old_offset > write_offset) {
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen if (mail_cache_link_unlocked(cache, old_offset,
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen write_offset) < 0)
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* if we're combining multiple transactions,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen make sure the one with the smallest offset
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen is written into index. this is required for
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen non-file-mmaped cache to work properly. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_update_ext(ctx->trans, seq[i],
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->ext_id,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &old_offset, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_link_unlocked(cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset,
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen old_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset += rec->size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = CONST_PTR_OFFSET(rec, rec->size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen *seq_idx = i;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *size_r = write_offset - orig_write_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainenmail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache *cache = ctx->cache;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen const struct mail_cache_record *rec, *tmp_rec;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen const uint32_t *seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t write_offset, write_size, rec_pos, seq_idx, seq_limit;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size, max_size;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen unsigned int seq_count;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen int ret;
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen bool commit;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen return -1;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen commit = ctx->prev_seq == 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (commit) {
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen /* committing, remove the last dummy record */
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen buffer_set_used_size(ctx->cache_data, ctx->prev_pos);
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen }
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (ctx->cache_file_seq == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = mail_cache_transaction_lock(ctx)) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* cache file reopened - need to abort */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen mail_cache_transaction_reset(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = buffer_get_data(ctx->cache_data, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(ctx->prev_pos <= size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen seq = array_get(&ctx->cache_data_seq, &seq_count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen seq_limit = 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (seq_idx = 0, rec_pos = 0; rec_pos < ctx->prev_pos;) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen max_size = ctx->prev_pos - rec_pos;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = mail_cache_transaction_get_space(ctx, rec->size,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen max_size, &write_offset,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen &max_size, commit);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ret <= 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* error / couldn't lock / cache file reopened */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ret;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen }
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (rec_pos + max_size < ctx->prev_pos) {
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen /* see how much we can really write there */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tmp_rec = rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (size = 0; size + tmp_rec->size <= max_size; ) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen seq_limit++;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen size += tmp_rec->size;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen tmp_rec = CONST_PTR_OFFSET(tmp_rec,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen tmp_rec->size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen max_size = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_limit = seq_count;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* write it to file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(ctx->cache_file_seq == cache->hdr->file_seq);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_write(cache, rec, max_size, write_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_update_index(ctx, rec, seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &seq_idx, seq_limit,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen write_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &write_size) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec_pos += write_size;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen rec = CONST_PTR_OFFSET(rec, write_size);
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* drop the written data from buffer */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen buffer_copy(ctx->cache_data, 0,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->cache_data, ctx->prev_pos, (size_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_set_used_size(ctx->cache_data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_get_used_size(ctx->cache_data) -
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->prev_pos);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ctx->prev_pos = 0;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen array_clear(&ctx->cache_data_seq);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return 1;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenstatic void
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenmail_cache_transaction_switch_seq(struct mail_cache_transaction_ctx *ctx)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct mail_cache_record *rec, new_rec;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen void *data;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen size_t size;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ctx->prev_seq != 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* fix record size */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen data = buffer_get_modifiable_data(ctx->cache_data, &size);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen rec = PTR_OFFSET(data, ctx->prev_pos);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen rec->size = size - ctx->prev_pos;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_assert(rec->size > sizeof(*rec));
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen array_append(&ctx->cache_data_seq, &ctx->prev_seq, 1);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ctx->prev_pos = size;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen } else if (ctx->cache_data == NULL) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ctx->cache_data =
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen buffer_create_dynamic(default_pool,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen MAIL_CACHE_WRITE_BUFFER);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_array_init(&ctx->cache_data_seq, 64);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen memset(&new_rec, 0, sizeof(new_rec));
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen buffer_append(ctx->cache_data, &new_rec, sizeof(new_rec));
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ctx->prev_seq = 0;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ctx->changes = TRUE;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct mail_cache *cache = ctx->cache;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen int ret = 0;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (!ctx->changes || MAIL_CACHE_IS_UNUSABLE(cache)) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_cache_transaction_free(ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return 0;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_transaction_lock(ctx) <= 0) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen mail_cache_transaction_rollback(ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return -1;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_transaction_switch_seq(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = -1;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen /* Here would be a good place to do fdatasync() to make sure
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen everything is written before offsets are updated to index.
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen However it slows down I/O unneededly and we're pretty good at
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen catching and fixing cache corruption, so we no longer do it. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen if (mail_cache_unlock(cache) < 0)
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen ret = -1;
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen mail_cache_transaction_free(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ret;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen const struct mail_cache_reservation *reservations;
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen unsigned int count;
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen if ((ctx->reserved_space > 0 || array_count(&ctx->reservations) > 0) &&
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen !MAIL_CACHE_IS_UNUSABLE(cache)) {
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen if (mail_cache_transaction_lock(ctx) > 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reservations = array_get(&ctx->reservations, &count);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* free flushed data as well. do it from end to
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen beginning so we have a better chance of
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen updating used_file_size instead of adding
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen holes */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen while (count > 0) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen count--;
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen mail_cache_free_space(ctx->cache,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen reservations[count].offset,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen reservations[count].size);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen (void)mail_cache_unlock(cache);
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_transaction_free(ctx);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_header_add_field(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int field)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_t *buffer;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const void *data;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t offset, hdr_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int ret = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_lock(ctx) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen /* re-read header to make sure we don't lose any fields. */
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_header_fields_read(cache) < 0) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen (void)mail_cache_unlock(cache);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return -1;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (ctx->cache->field_file_map[field] != (uint32_t)-1) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* it was already added */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_unlock(cache) < 0)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return -1;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return 0;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen t_push();
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_header_fields_get(cache, buffer);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen data = buffer_get_data(buffer, &size);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (mail_cache_transaction_get_space(ctx, size, size,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen &offset, NULL, TRUE) <= 0)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (mail_cache_write(cache, data, size, offset) < 0)
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen ret = -1;
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen else if (!cache->index->fsync_disable && fdatasync(cache->fd) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else if (mail_cache_header_fields_get_next_offset(cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &hdr_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* after it's guaranteed to be in disk, update header offset */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = mail_index_uint32_to_offset(offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_write(cache, &offset, sizeof(offset),
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = -1;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we'll need to fix mappings. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_header_fields_read(cache) < 0)
6a669919418a1c7469f9faf55d11b3c723f72cffTimo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
eee852da15c907d2aa20bce58fbfcaae04b558d5Timo Sirainen }
eee852da15c907d2aa20bce58fbfcaae04b558d5Timo Sirainen t_pop();
eee852da15c907d2aa20bce58fbfcaae04b558d5Timo Sirainen
eee852da15c907d2aa20bce58fbfcaae04b558d5Timo Sirainen if (mail_cache_unlock(cache) < 0)
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen ret = -1;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen return ret;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainenvoid mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen unsigned int field, const void *data, size_t data_size)
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen{
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen uint32_t file_field, data_size32;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int fixed_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t full_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(field < ctx->cache->fields_count);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(data_size < (uint32_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->cache->fields[field].field.decision ==
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED))
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file_field = ctx->cache->field_file_map[field];
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen if (file_field == (uint32_t)-1) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we'll have to add this field to headers */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_header_add_field(ctx, field) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen file_field = ctx->cache->field_file_map[field];
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen i_assert(file_field != (uint32_t)-1);
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen }
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen mail_cache_decision_add(ctx->view, seq, field);
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen fixed_size = ctx->cache->fields[field].field.field_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(fixed_size == (unsigned int)-1 || fixed_size == data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen data_size32 = (uint32_t)data_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != seq) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_switch_seq(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_seq = seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen /* remember roughly what we have modified, so cache lookups can
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen look into transactions to see changes. */
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen if (seq < ctx->view->trans_seq1 || ctx->view->trans_seq1 == 0)
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen ctx->view->trans_seq1 = seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (seq > ctx->view->trans_seq2)
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen ctx->view->trans_seq2 = seq;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen }
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen full_size = (data_size + 3) & ~3;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fixed_size == (unsigned int)-1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen full_size += sizeof(data_size32);
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->cache_data->used + full_size >
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen buffer_get_size(ctx->cache_data) && ctx->prev_pos > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* time to flush our buffer. if flushing fails because the
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen cache file had been compressed and was reopened, return
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen without adding the cached data since cache_data buffer
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen doesn't contain the cache_rec anymore. */
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen if (mail_cache_transaction_flush(ctx) <= 0) {
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen /* make sure the transaction is reset, so we don't
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen constantly try to flush for each call to this
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen function */
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen mail_cache_transaction_reset(ctx);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen return;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen }
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen }
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen buffer_append(ctx->cache_data, &file_field, sizeof(file_field));
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen if (fixed_size == (unsigned int)-1) {
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen buffer_append(ctx->cache_data, &data_size32,
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen sizeof(data_size32));
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen }
31854ec69857e384882bcade5cf0c5dea8abf230Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen buffer_append(ctx->cache_data, data, data_size);
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen if ((data_size & 3) != 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append_zero(ctx->cache_data, 4 - (data_size & 3));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool mail_cache_field_want_add(struct mail_cache_transaction_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq, unsigned int field)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen enum mail_cache_decision_type decision;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen decision = mail_cache_field_get_decision(ctx->view->cache, field);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if ((decision & ~MAIL_CACHE_DECISION_FORCED) == MAIL_CACHE_DECISION_NO)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return FALSE;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return mail_cache_field_exists(ctx->view, seq, field) == 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenbool mail_cache_field_can_add(struct mail_cache_transaction_ctx *ctx,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen uint32_t seq, unsigned int field)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen enum mail_cache_decision_type decision;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
959a66f100887ce0acf442a397cfaec89570436aTimo Sirainen decision = mail_cache_field_get_decision(ctx->view->cache, field);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (decision == (MAIL_CACHE_DECISION_FORCED | MAIL_CACHE_DECISION_NO))
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return FALSE;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return mail_cache_field_exists(ctx->view, seq, field) == 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen uint32_t old_offset, uint32_t new_offset)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen new_offset += offsetof(struct mail_cache_record, prev_offset);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return mail_cache_write(cache, &old_offset, sizeof(old_offset),
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen new_offset);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenint mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen uint32_t new_offset)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen i_assert(cache->locked);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (new_offset + sizeof(struct mail_cache_record) >
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen cache->hdr_copy.used_file_size) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_cache_set_corrupted(cache,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen "Cache record offset %u points outside file",
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen new_offset);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen if (mail_cache_link_unlocked(cache, old_offset, new_offset) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen cache->hdr_copy.continued_record_count++;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen cache->hdr_modified = TRUE;
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen return 0;
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen}
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainenstatic bool find_offset(ARRAY_TYPE(uint32_t) *array, uint32_t offset)
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen{
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen const uint32_t *offsets;
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen unsigned int i, count;
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen offsets = array_get(array, &count);
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen for (i = 0; i < count; i++) {
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen if (offsets[i] == offset)
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen return TRUE;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen }
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return FALSE;
3157004d1281d5c203f739fa2e83f7a8488de92dTimo Sirainen}
3157004d1281d5c203f739fa2e83f7a8488de92dTimo Sirainen
3157004d1281d5c203f739fa2e83f7a8488de92dTimo Sirainenint mail_cache_delete(struct mail_cache *cache, uint32_t offset)
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen{
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen const struct mail_cache_record *cache_rec;
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen ARRAY_TYPE(uint32_t) tmp_offsets;
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen i_assert(cache->locked);
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen if (mail_cache_get_record(cache, offset, &cache_rec) < 0)
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen return -1;
ac90bc1130bc014e41c47a1eb81dc1a3d1108115Timo Sirainen if (cache_rec == NULL)
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen /* we'll only update the deleted_space in header. we can't really
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen do any actual deleting as other processes might still be using
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen the data. also it's actually useful as some index views are still
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen able to ask cached data from messages that have already been
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen expunged. */
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen t_push();
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen t_array_init(&tmp_offsets, 8);
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen array_append(&tmp_offsets, &offset, 1);
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen for (;;) {
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen cache->hdr_copy.deleted_space += cache_rec->size;
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (mail_cache_get_record(cache, cache_rec->prev_offset,
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen &cache_rec) < 0) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen t_pop();
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (cache_rec == NULL)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen break;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (find_offset(&tmp_offsets, cache_rec->prev_offset)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen "record list is circular");
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen t_pop();
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen array_append(&tmp_offsets, &cache_rec->prev_offset, 1);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen t_pop();
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen cache->hdr_modified = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen