mail-cache-transaction.c revision 0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny/* Copyright (C) 2003-2004 Timo Sirainen */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include "lib.h"
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include "buffer.h"
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include "byteorder.h"
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include "file-set-size.h"
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include "mmap-util.h"
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include "mail-cache-private.h"
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#include <sys/stat.h>
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny#if 0
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystruct mail_cache_transaction_ctx {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache *cache;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache_view *view;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_index_transaction *trans;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int next_unused_header_lowwater;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache_record cache_rec;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_t *cache_data;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t first_seq, last_seq, prev_seq;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny enum mail_cache_field prev_fields;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_t *cache_marks;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny};
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic const unsigned char *null4[] = { 0, 0, 0, 0 };
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_transaction_begin(struct mail_cache_view *view, int nonblock,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_index_transaction *t,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache_transaction_ctx **ctx_r)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache_transaction_ctx *ctx;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny int ret;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(view->cache->trans_ctx == NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ret = mail_cache_lock(view->cache, nonblock);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ret <= 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return ret;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx = i_new(struct mail_cache_transaction_ctx, 1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache = view->cache;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->view = view;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->trans = t;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache_data = buffer_create_dynamic(system_pool, 8192, (size_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny view->cache->trans_ctx = ctx;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny *ctx_r = ctx;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_transaction_end(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny int ret = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(ctx->cache->trans_ctx != NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny (void)mail_cache_transaction_rollback(ctx);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_cache_unlock(ctx->cache) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ret = -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache->trans_ctx = NULL;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->cache_marks != NULL)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_free(ctx->cache_marks);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_free(ctx->cache_data);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_free(ctx);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return ret;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic void mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->next_unused_header_lowwater = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->first_seq = ctx->last_seq = ctx->prev_seq = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->prev_fields = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->cache_marks != NULL)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_set_used_size(ctx->cache_marks, 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_set_used_size(ctx->cache_data, 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic void mark_update(buffer_t **buf, uint32_t offset, uint32_t data)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (*buf == NULL)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny *buf = buffer_create_dynamic(system_pool, 1024, (size_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(*buf, &offset, sizeof(offset));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(*buf, &data, sizeof(data));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int write_mark_updates(struct mail_cache *cache)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const uint32_t *data, *end;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size_t size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny data = buffer_get_data(cache->trans_ctx->cache_marks, &size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny end = data + size/sizeof(uint32_t);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny while (data < end) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (pwrite(cache->fd, data+1, sizeof(*data), data[0]) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_set_syscall_error(cache, "pwrite()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny data += 2;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int commit_all_changes(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache *cache = ctx->cache;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t cont;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* write everything to disk */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (msync(cache->mmap_base, cache->mmap_length, MS_SYNC) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_set_syscall_error(cache, "msync()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (fdatasync(cache->fd) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_set_syscall_error(cache, "fdatasync()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->cache_marks == NULL ||
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_get_used_size(ctx->cache_marks) == 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* now that we're sure it's written, set on all the used-bits */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (write_mark_updates(cache) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* update continued records count */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cont = nbo_to_uint32(cache->hdr->continued_record_count);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cont += buffer_get_used_size(ctx->cache_marks) /
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny (sizeof(uint32_t) * 2);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (cont * 100 / cache->index->hdr->messages_count >=
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny COMPRESS_CONTINUED_PERCENTAGE &&
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->used_file_size >= COMPRESS_MIN_SIZE) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* too many continued rows, compress */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny //FIXME:cache->index->set_flags |= MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->hdr->continued_record_count = uint32_to_nbo(cont);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_cache_grow(struct mail_cache *cache, uint32_t size)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct stat st;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uoff_t grow_size, new_fsize;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny new_fsize = cache->used_file_size + size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (grow_size < 16384)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny grow_size = 16384;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny new_fsize += grow_size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny new_fsize &= ~1023;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (fstat(cache->fd, &st) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_set_syscall_error(cache, "fstat()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (cache->used_file_size + size <= (uoff_t)st.st_size) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* no need to grow, just update mmap */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mmap_update(cache, 0, 0) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(cache->mmap_length >= (uoff_t)st.st_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (file_set_size(cache->fd, (off_t)new_fsize) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_set_syscall_error(cache, "file_set_size()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return mmap_update(cache, 0, 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t size)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* NOTE: must be done within transaction or rollback would break it */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert((size & 3) == 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny offset = ctx->cache->used_file_size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (offset >= 0x40000000) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_set_error(ctx->cache->index,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny "Cache file too large: %s",
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache->filepath);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (offset + size > ctx->cache->mmap_length) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_cache_grow(ctx->cache, size) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache->used_file_size += size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache *cache = ctx->cache;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache_record *cache_rec, *next;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const struct mail_index_record *rec;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t write_offset, update_offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const void *buf;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size_t size, buf_size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buf = buffer_get_data(ctx->cache_data, &buf_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size = sizeof(*cache_rec) + buf_size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache_rec.size = uint32_to_nbo(size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny write_offset = mail_cache_append_space(ctx, size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (write_offset == 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny // FIXME: check cache_offset in transaction
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_index_lookup_latest(ctx->view->view, ctx->prev_seq, &rec) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache_rec = mail_cache_get_record(cache, rec->cache_offset);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (cache_rec == NULL) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* first cache record - update offset in index file */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_update_cache(ctx->trans, ctx->prev_seq,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny write_offset);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny } else {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* find the last cache record */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny while ((next = mail_cache_get_next_record(cache,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache_rec)) != NULL)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache_rec = next;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* mark next_offset to be updated later */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny update_offset = (char *) &cache_rec->next_offset -
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny (char *) cache->mmap_base;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mark_update(&ctx->cache_marks, update_offset,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_uint32_to_offset(write_offset));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->prev_seq = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->prev_fields = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy((char *) cache->mmap_base + write_offset,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny &ctx->cache_rec, sizeof(ctx->cache_rec));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy((char *) cache->mmap_base + write_offset +
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny sizeof(ctx->cache_rec), buf, buf_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* reset the write context */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_set_used_size(ctx->cache_data, 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny int ret = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->prev_seq != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_cache_write(ctx) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache->hdr->used_file_size =
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_to_nbo(ctx->cache->used_file_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (commit_all_changes(ctx) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ret = -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->next_unused_header_lowwater == MAIL_CACHE_HEADERS_COUNT) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* they're all used - compress the cache to get more */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* FIXME: ctx->cache->index->set_flags |=
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;*/
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_transaction_flush(ctx);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return ret;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache *cache = ctx->cache;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int i;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* no need to actually modify the file - we just didn't update
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny used_file_size */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->used_file_size = nbo_to_uint32(cache->hdr->used_file_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* make sure we don't cache the headers */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny for (i = 0; i < ctx->next_unused_header_lowwater; i++) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t offset = cache->hdr->header_offsets[i];
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_cache_offset_to_uint32(offset) == 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->split_offsets[i] = 1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_transaction_flush(ctx);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic const char *write_header_string(const char *const headers[],
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t *size_r)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_t *buffer;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size_t size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer = buffer_create_dynamic(pool_datastack_create(),
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny 512, (size_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny while (*headers != NULL) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (buffer_get_used_size(buffer) != 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(buffer, "\n", 1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(buffer, *headers, strlen(*headers));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny headers++;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(buffer, null4, 1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size = buffer_get_used_size(buffer);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((size & 3) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(buffer, null4, 4 - (size & 3));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size += 4 - (size & 3);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny *size_r = size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return buffer_get_data(buffer, NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int idx, const char *const headers[])
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct mail_cache *cache = ctx->cache;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t offset, update_offset, size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const char *header_str, *prev_str;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(*headers != NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(idx >= ctx->next_unused_header_lowwater);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(mail_cache_offset_to_uint32(cache->hdr->
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny header_offsets[idx]) == 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny t_push();
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny header_str = write_header_string(headers, &size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (idx != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny prev_str = mail_cache_get_header_fields_str(cache, idx-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (prev_str == NULL) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny t_pop();
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return FALSE;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(strcmp(header_str, prev_str) != 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny offset = mail_cache_append_space(ctx, size + sizeof(uint32_t));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (offset != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy((char *) cache->mmap_base + offset + sizeof(uint32_t),
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny header_str, size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size = uint32_to_nbo(size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy((char *) cache->mmap_base + offset,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny &size, sizeof(uint32_t));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* update cached headers */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->split_offsets[idx] = cache->hdr->header_offsets[idx];
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->split_headers[idx] =
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_split_header(cache, header_str);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* mark used-bit to be updated later. not really needed for
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny read-safety, but if transaction get rolled back we can't let
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny this point to invalid location. */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny update_offset = (char *) &cache->hdr->header_offsets[idx] -
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny (char *) cache->mmap_base;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mark_update(&ctx->cache_marks, update_offset,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_cache_uint32_to_offset(offset));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* make sure get_header_fields() still works for this header
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny while the transaction isn't yet committed. */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->next_unused_header_lowwater = idx + 1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny t_pop();
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return offset > 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic size_t get_insert_offset(struct mail_cache_transaction_ctx *ctx,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny enum mail_cache_field field)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const unsigned char *buf;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int mask;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t data_size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size_t offset = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny int i;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buf = buffer_get_data(ctx->cache_data, NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((field & mask) != 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((ctx->cache_rec.fields & mask) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny data_size = mail_cache_field_sizes[i];
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny else {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy(&data_size, buf + offset,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny sizeof(data_size));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny data_size = nbo_to_uint32(data_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny offset += sizeof(data_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny offset += (data_size + 3) & ~3;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_unreached();
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int get_field_num(enum mail_cache_field field)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int mask;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny int i;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((field & mask) != 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return i;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny}
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny enum mail_cache_field field,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const void *data, size_t data_size)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny uint32_t nb_data_size;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size_t full_size, offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned char *buf;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny int field_num;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(data_size > 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(data_size < (uint32_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny nb_data_size = uint32_to_nbo((uint32_t)data_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((field & MAIL_CACHE_FIXED_MASK) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny field_num = get_field_num(field);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(field_num != -1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(mail_cache_field_sizes[field_num] == data_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny } else if ((field & MAIL_CACHE_STRING_MASK) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(((char *) data)[data_size-1] == '\0');
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->prev_seq != seq && ctx->prev_seq != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_cache_write(ctx) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return -1;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny }
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->prev_seq = seq;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert((ctx->cache_rec.fields & field) == 0);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny full_size = (data_size + 3) & ~3;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((field & MAIL_CACHE_FIXED_MASK) == 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny full_size += sizeof(nb_data_size);
/* fields must be ordered. find where to insert it. */
if (field > ctx->cache_rec.fields)
buf = buffer_append_space_unsafe(ctx->cache_data, full_size);
else {
offset = get_insert_offset(ctx, field);
buffer_copy(ctx->cache_data, offset + full_size,
ctx->cache_data, offset, (size_t)-1);
buf = buffer_get_space_unsafe(ctx->cache_data,
offset, full_size);
}
ctx->cache_rec.fields |= field;
/* @UNSAFE */
if ((field & MAIL_CACHE_FIXED_MASK) == 0) {
memcpy(buf, &nb_data_size, sizeof(nb_data_size));
buf += sizeof(nb_data_size);
}
memcpy(buf, data, data_size); buf += data_size;
if ((data_size & 3) != 0)
memset(buf, 0, 4 - (data_size & 3));
/* remember the transaction uid range */
if (seq < ctx->first_seq || ctx->first_seq == 0)
ctx->first_seq = seq;
if (seq > ctx->last_seq)
ctx->last_seq = seq;
ctx->prev_fields |= field;
return 0;
}
int mail_cache_delete(struct mail_cache_transaction_ctx *ctx, uint32_t seq)
{
struct mail_cache *cache = ctx->cache;
struct mail_cache_record *cache_rec;
uint32_t deleted_space;
uoff_t max_del_space;
cache_rec = mail_cache_lookup(ctx->view, seq, 0);
if (cache_rec == NULL)
return 0;
/* we'll only update the deleted_space in header. we can't really
do any actual deleting as other processes might still be using
the data. also it's actually useful as some index views are still
able to ask cached data from messages that have already been
expunged. */
deleted_space = nbo_to_uint32(cache->hdr->deleted_space);
do {
deleted_space -= nbo_to_uint32(cache_rec->size);
cache_rec = mail_cache_get_next_record(cache, cache_rec);
} while (cache_rec != NULL);
/* see if we've reached the max. deleted space in file */
max_del_space = cache->used_file_size / 100 * COMPRESS_PERCENTAGE;
if (deleted_space >= max_del_space &&
cache->used_file_size >= COMPRESS_MIN_SIZE) {
//FIXME:cache->index->set_flags |= MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
}
cache->hdr->deleted_space = uint32_to_nbo(deleted_space);
return 0;
}
int
mail_cache_transaction_autocommit(struct mail_cache_view *view,
uint32_t seq, enum mail_cache_field fields)
{
struct mail_cache *cache = view->cache;
if (cache->trans_ctx != NULL &&
cache->trans_ctx->first_seq <= seq &&
cache->trans_ctx->last_seq >= seq &&
(cache->trans_ctx->prev_seq != seq || fields == 0 ||
(cache->trans_ctx->prev_fields & fields) != 0)) {
/* write non-index changes */
if (cache->trans_ctx->prev_seq == seq) {
if (mail_cache_write(cache->trans_ctx) < 0)
return -1;
}
if (mail_cache_transaction_commit(cache->trans_ctx) < 0)
return -1;
}
return 0;
}
#else
#endif