mail-cache-transaction.c revision 2ca4cb08680aebb1474d762738cf436871f095fb
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-set-size.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "read-full.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-cache-private.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "mail-index-transaction-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen#include <stddef.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_cache_transaction_ctx {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_view *view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_transaction *trans;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t update_header_offsets[MAIL_CACHE_HEADERS_COUNT];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int next_unused_header_lowwater;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_t *cache_data, *cache_data_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t prev_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t prev_pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_t *reservations;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t reserved_space_offset, reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t last_grow_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t first_seq, last_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen enum mail_cache_field fields;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int changes:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const unsigned char *null4[] = { 0, 0, 0, 0 };
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstruct mail_cache_transaction_ctx *
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_get_transaction(struct mail_cache_view *view,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_index_transaction *t)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_transaction_ctx *ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (t->cache_trans_ctx != NULL)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return t->cache_trans_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct mail_cache_transaction_ctx, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cache = view->cache;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->view = view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->trans = t;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cache_data =
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_create_dynamic(system_pool, 32768, (size_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cache_data_seq =
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_create_dynamic(system_pool, 256, (size_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reservations =
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_create_dynamic(system_pool, 256, (size_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen t->cache_trans_ctx = ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(ctx->cache_data);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_free(ctx->cache_data_seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_free(ctx->reservations);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct stat st;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uoff_t new_fsize, grow_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* grow the file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize = cache->hdr_copy.used_file_size + size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (grow_size < 16384)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen grow_size = 16384;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize += grow_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize &= ~1023;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (fstat(cache->fd, &st) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((uoff_t)st.st_size < new_fsize) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (file_set_size(cache->fd, new_fsize) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header *hole_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t offset, prev_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = hdr->hole_offset; prev_offset = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen while (offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pread_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_corrupted(cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "Invalid magic in hole header");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (hole.size >= size)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen break;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = hole.next_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (prev_offset == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->hole_offset = hole.next_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, &hole.next_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(hole.next_offset), prev_offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->deleted_space -= hole.size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole_r->next_offset = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole_r->size = hole.size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->reservations, &ctx->reserved_space_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(ctx->reserved_space_offset));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->reservations, &ctx->reserved_space,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(ctx->reserved_space));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size, int commit)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t *buf;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_unlink_hole(cache, size, &hole)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* found a large enough hole. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space_offset = hole.next_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space = hole.size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_add_reservation(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* mail_cache_unlink_hole() could have noticed corruption */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((uoff_t)hdr->used_file_size + size > (uint32_t)-1) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_set_error(cache->index, "Cache file too large: %s",
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!commit) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = (size + ctx->last_grow_size) * 2;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((uoff_t)hdr->used_file_size + size > (uint32_t)-1)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = (uint32_t)-1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->last_grow_size = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_grow_file(ctx->cache, size) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space_offset + ctx->reserved_space ==
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can simply grow it */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space = size - ctx->reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* grow reservation. it's probably the last one in the buffer,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen but it's not guarateed because we might have used holes
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen as well */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf = buffer_get_modifyable_data(ctx->reservations, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size /= sizeof(uint32_t);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(size >= 2);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen do {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size -= 2;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (buf[size] == ctx->reserved_space_offset) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf[size+1] = ctx->reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen break;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } while (size >= 2);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space_offset = hdr->used_file_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_add_reservation(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->used_file_size = ctx->reserved_space_offset + ctx->reserved_space;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_hole_header hole;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset + size == cache->hdr_copy.used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can just set used_file_size back */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.used_file_size = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else if (size >= MAIL_CACHE_MIN_HOLE_SIZE) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* set it up as a hole */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.next_offset = cache->hdr_copy.hole_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.size = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.magic = MAIL_CACHE_HOLE_HEADER_MAGIC;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, &hole, sizeof(hole), offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.deleted_space += size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.hole_offset = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int locked = ctx->cache->locked;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_lock(ctx->cache) <= 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_free_space(ctx->cache, ctx->reserved_space_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_unlock(ctx->cache);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic uint32_t
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t min_size, size_t max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t *available_space_r, int commit)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int locked = ctx->cache->locked;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (min_size > ctx->reserved_space) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_lock(ctx->cache) <= 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = mail_cache_transaction_reserve_more(ctx, max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!locked)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_unlock(ctx->cache);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ret < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = max_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size = I_MIN(max_size, ctx->reserved_space);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = ctx->reserved_space_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space_offset += size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->reserved_space -= size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (available_space_r != NULL)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *available_space_r = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (size == max_size && commit) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* final commit - see if we can free the rest of the
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reserved space */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free_space(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mail_cache_record *rec, *tmp_rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const uint32_t *seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t write_offset, old_offset, rec_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size, max_size, seq_idx, seq_limit, seq_count;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int commit;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit = ctx->prev_seq == 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (commit) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* committing, remove the last dummy record */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_set_used_size(ctx->cache_data, ctx->prev_pos);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = buffer_get_data(ctx->cache_data, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(ctx->prev_pos <= size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq = buffer_get_data(ctx->cache_data_seq, &seq_count);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_count /= sizeof(*seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (seq_idx = 0, rec_offset = 0; rec_offset < ctx->prev_pos;) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen max_size = ctx->prev_pos - rec_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset = mail_cache_transaction_get_space(ctx, rec->size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &max_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen commit);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (write_offset == 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* nothing to write / error */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ctx->prev_pos == 0 ? 0 : -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (max_size < ctx->prev_pos) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* see how much we can really write there */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen tmp_rec = rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (size = 0; size + tmp_rec->size <= max_size; ) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_limit++;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size += tmp_rec->size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen tmp_rec = CONST_PTR_OFFSET(tmp_rec,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen tmp_rec->size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen max_size = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen seq_limit = seq_count;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* write it to file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, rec, max_size, write_offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* write the cache_offsets to index file. records' prev_offset
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen is updated to point to old cache record when index is being
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen synced. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (; seq_idx < seq_limit; seq_idx++) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_update_cache(ctx->trans, seq[seq_idx],
2ca4cb08680aebb1474d762738cf436871f095fbTimo Sirainen cache->hdr->file_seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset, &old_offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (old_offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we added records for this message multiple
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen times in this same uncommitted transaction.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen only the new one will be written to
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen transaction log, we need to do the linking
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ourself here. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_link(cache, old_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen write_offset += rec->size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec_offset += rec->size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = CONST_PTR_OFFSET(rec, rec->size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* drop the written data from buffer */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_copy(ctx->cache_data, 0,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cache_data, ctx->prev_pos, (size_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_set_used_size(ctx->cache_data, size - ctx->prev_pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_set_used_size(ctx->cache_data_seq, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_switch_seq(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_record *rec, new_rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen void *data;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* fix record size */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen data = buffer_get_modifyable_data(ctx->cache_data, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = PTR_OFFSET(data, ctx->prev_pos);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec->size = size - ctx->prev_pos;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->cache_data_seq, &ctx->prev_seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(ctx->prev_seq));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_pos = size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen memset(&new_rec, 0, sizeof(new_rec));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->cache_data, &new_rec, sizeof(new_rec));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_seq = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->changes = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen int i, ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!ctx->changes) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free(ctx);
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen return 0;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen }
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_lock(cache) <= 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_rollback(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_switch_seq(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* make sure everything's written before updating offsets */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (fdatasync(cache->fd) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ret == 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = ctx->update_header_offsets[i];
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.header_offsets[i] =
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_uint32_to_offset(offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_unlock(cache);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->next_unused_header_lowwater == MAIL_CACHE_HEADERS_COUNT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* they're all used - compress the cache to get more */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->need_compress = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const uint32_t *buf;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free_space(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf = buffer_get_data(ctx->reservations, &size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(size % sizeof(uint32_t)*2 == 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size /= sizeof(*buf);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (size > 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* free flushed data as well. do it from end to beginning so
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen we have a better chance of updating used_file_size instead
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen of adding holes */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen do {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size -= 2;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_free_space(ctx->cache, buf[size],
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf[size+1]);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } while (size > 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure we don't cache the headers */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < ctx->next_unused_header_lowwater; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t offset = cache->hdr->header_offsets[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_cache_offset_to_uint32(offset) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->split_offsets[i] = 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const char *write_header_string(const char *const headers[],
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *size_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *buffer;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen 512, (size_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*headers != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (buffer_get_used_size(buffer) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buffer, "\n", 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buffer, *headers, strlen(*headers));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen headers++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buffer, null4, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size = buffer_get_used_size(buffer);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((size & 3) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buffer, null4, 4 - (size & 3));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size += 4 - (size & 3);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *size_r = size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return buffer_get_data(buffer, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int idx, const char *const headers[])
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache *cache = ctx->cache;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t offset, size, total_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *header_str, *prev_str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(*headers != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(idx >= ctx->next_unused_header_lowwater);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(mail_cache_offset_to_uint32(cache->hdr->
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen header_offsets[idx]) == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_push();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen header_str = write_header_string(headers, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (idx != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen prev_str = mail_cache_get_header_fields_str(cache, idx-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (prev_str == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_pop();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(strcmp(header_str, prev_str) != 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen total_size = size + sizeof(uint32_t);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = mail_cache_transaction_get_space(ctx, total_size, total_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen NULL, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, &size, sizeof(size), offset) < 0 ||
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen pwrite_full(cache->fd, header_str, size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset + sizeof(uint32_t)) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen offset = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->update_header_offsets[idx] = offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->changes = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* update cached headers */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->split_offsets[idx] = cache->hdr->header_offsets[idx];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->split_headers[idx] =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_split_header(cache, header_str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure get_header_fields() still works for this header
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while the transaction isn't yet committed. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->next_unused_header_lowwater = idx + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_pop();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return offset > 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic size_t
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_get_insert_pos(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen enum mail_cache_field field)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mail_cache_record *cache_rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const void *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t data_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen data = buffer_get_data(ctx->cache_data, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache_rec = CONST_PTR_OFFSET(data, ctx->prev_pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen pos = ctx->prev_pos + sizeof(*cache_rec);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((field & mask) != 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if ((cache_rec->fields & mask) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data_size = mail_cache_field_sizes[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen memcpy(&data_size, CONST_PTR_OFFSET(data, pos),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(data_size));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen pos += sizeof(data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen pos += (data_size + 3) & ~3;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen enum mail_cache_field field,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const void *data, size_t data_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_record *cache_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned char *buf;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen size_t full_size, pos;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t data_size32;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen unsigned int field_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data_size > 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data_size < (uint32_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen data_size32 = (uint32_t)data_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((field & MAIL_CACHE_FIXED_MASK) != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen field_idx = mail_cache_field_index(field);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(mail_cache_field_sizes[field_idx] == data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if ((field & MAIL_CACHE_STRING_MASK) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(((char *) data)[data_size-1] == '\0');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->prev_seq != seq) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_transaction_switch_seq(ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->prev_seq = seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* remember roughly what we have modified, so cache lookups can
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen look into transactions to see changes. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (seq < ctx->first_seq || ctx->first_seq == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->first_seq = seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (seq > ctx->last_seq)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->last_seq = seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->fields |= field;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen full_size = (data_size + 3) & ~3;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((field & MAIL_CACHE_FIXED_MASK) == 0)
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen full_size += sizeof(data_size32);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (buffer_get_used_size(ctx->cache_data) + full_size >
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_get_size(ctx->cache_data)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* time to flush our buffer */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_transaction_flush(ctx) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* fields must be ordered. find where to insert it. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen pos = mail_cache_transaction_get_insert_pos(ctx, field);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_copy(ctx->cache_data, pos + full_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cache_data, pos, (size_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache_rec = buffer_get_space_unsafe(ctx->cache_data, ctx->prev_pos,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(*cache_rec));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache_rec->fields |= field;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buf = buffer_get_space_unsafe(ctx->cache_data, pos, full_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((field & MAIL_CACHE_FIXED_MASK) == 0) {
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen memcpy(buf, &data_size32, sizeof(data_size32));
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen buf += sizeof(data_size32);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(buf, data, data_size); buf += data_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((data_size & 3) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(buf, 0, 4 - (data_size & 3));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_update_record_flags(struct mail_cache_view *view, uint32_t seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen enum mail_cache_record_flag flags)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t new_offset)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (new_offset + sizeof(struct mail_cache_record) >
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_corrupted(cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "Cache record offset %u points outside file",
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_offset += offsetof(struct mail_cache_record, prev_offset);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pwrite_full(cache->fd, &old_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(old_offset), new_offset) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.continued_record_count++;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_delete(struct mail_cache *cache, uint32_t offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_record *cache_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(cache->locked);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache_rec = mail_cache_get_record(cache, offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cache_rec == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we'll only update the deleted_space in header. we can't really
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do any actual deleting as other processes might still be using
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the data. also it's actually useful as some index views are still
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen able to ask cached data from messages that have already been
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen expunged. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.deleted_space += cache_rec->size;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen cache_rec =
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen mail_cache_get_record(cache, cache_rec->prev_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } while (cache_rec != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_modified = TRUE;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen return 0;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen}