mail-cache-transaction.c revision e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbe
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi/* Copyright (C) 2003-2004 Timo Sirainen */
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi array_t ARRAY_DEFINE(cache_data_seq, uint32_t);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi uint32_t reserved_space_offset, reserved_space;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumistatic int mail_cache_link_unlocked(struct mail_cache *cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumimail_cache_get_transaction(struct mail_cache_view *view,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi ctx = i_new(struct mail_cache_transaction_ctx, 1);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi ctx->reservations = buffer_create_dynamic(system_pool, 256);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi ctx->cache_file_seq = ctx->cache->hdr->file_seq;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi view->trans_view = mail_index_transaction_open_updated_view(t);
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumistatic void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx)
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi ctx->cache_file_seq = ctx->cache->hdr->file_seq;
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumistatic void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumistatic int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx)
99282c429a23a2ffa699ca149bb7f9cd5705646aKATOH Yasufumi if ((ret = mail_cache_lock(ctx->cache)) <= 0)
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumi if (ctx->cache_file_seq != ctx->cache->hdr->file_seq)
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumistatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
e8ea311657f82b91710dfcb8bca656bd5b94c66cKATOH Yasufumi /* grow the file */
e8ea311657f82b91710dfcb8bca656bd5b94c66cKATOH Yasufumi new_fsize = cache->hdr_copy.used_file_size + size;
e8ea311657f82b91710dfcb8bca656bd5b94c66cKATOH Yasufumi grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi mail_cache_set_syscall_error(cache, "fstat()");
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi if (file_set_size(cache->fd, new_fsize) < 0) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi mail_cache_set_syscall_error(cache, "file_set_size()");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumistatic int mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi struct mail_cache_header *hdr = &cache->hdr_copy;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi while (offset != 0) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi mail_cache_set_syscall_error(cache, "pread_full()");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi "Invalid magic in hole header");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (pwrite_full(cache->fd, &hole.next_offset,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi sizeof(hole.next_offset), prev_offset) < 0) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi mail_cache_set_syscall_error(cache, "pwrite_full()");
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumimail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi buffer_append(ctx->reservations, &offset, sizeof(offset));
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi buffer_append(ctx->reservations, &size, sizeof(size));
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumimail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi struct mail_cache_header *hdr = &cache->hdr_copy;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (mail_cache_unlink_hole(cache, block_size, &hole)) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi /* found a large enough hole. */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_transaction_add_reservation(ctx, hole.next_offset,
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi /* mail_cache_unlink_hole() could have noticed corruption */
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi if ((uint32_t)-1 - hdr->used_file_size < block_size) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi mail_index_set_error(cache->index, "Cache file too large: %s",
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi if (!commit && block_size < MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi /* allocate some more space than we need */
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi size_t new_block_size = (block_size + ctx->last_grow_size) * 2;
f7f1ba77b76e4d4dc18638cfdc859c3dc1750a9eStéphane Graber if (new_block_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi new_block_size = MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if ((uint32_t)-1 - hdr->used_file_size >= new_block_size) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (mail_cache_grow_file(ctx->cache, block_size) < 0)
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi if (ctx->reserved_space_offset + ctx->reserved_space ==
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi /* we can simply grow it */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* grow reservation. it's probably the last one in the buffer,
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumi but it's not guarateed because we might have used holes
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumi buf = buffer_get_modifyable_data(ctx->reservations, &size);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi } while (buf[size] + buf[size+1] != hdr->used_file_size);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_transaction_add_reservation(ctx, hdr->used_file_size,
48e49f08c0f0d33d75e42cd1f6bf446f740fff8aKATOH Yasufumi hdr->used_file_size = ctx->reserved_space_offset + ctx->reserved_space;
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumimail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi if (offset + size == cache->hdr_copy.used_file_size) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* we can just set used_file_size back */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi } else if (size >= MAIL_CACHE_MIN_HOLE_SIZE) {
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi /* set it up as a hole */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi hole.next_offset = cache->hdr_copy.hole_offset;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (pwrite_full(cache->fd, &hole, sizeof(hole), offset) < 0) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_syscall_error(cache, "pwrite_full()");
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumimail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi /* check again - locking might have reopened the cache file */
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi i_assert(ctx->cache_file_seq == ctx->cache->hdr->file_seq);
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi mail_cache_free_space(ctx->cache, ctx->reserved_space_offset,
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumimail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
9a97d4e4bdf331bb2c2b8ed14bcefa53358c288fKATOH Yasufumi uint32_t *offset_r, size_t *available_space_r,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* not enough preallocated space in transaction, get more */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if ((ret = mail_cache_transaction_lock(ctx)) <= 0)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi ret = mail_cache_transaction_reserve_more(ctx, max_size,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* cache file reopened - need to abort */
if (old_offset != 0) {
write_offset) < 0)
old_offset) < 0)
*seq_idx = i;
unsigned int seq_count;
if (commit) {
seq_limit = 0;
if (ret <= 0) {
return ret;
seq_limit++;
&write_size) < 0)
void *data;
int ret = 0;
return ret;
if (size > 0) {
} while (size > 0);
unsigned int field)
const void *data;
int ret = 0;
t_push();
&hdr_offset) < 0)
hdr_offset) < 0) {
t_pop();
return ret;
unsigned int fixed_size;
sizeof(data_size32));
&cache_rec) < 0)