mail-cache-transaction.c revision cfbf891f065b18602703ed6fa2af1a541d4d0b04
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi ARRAY_DEFINE(reservations, struct mail_cache_reservation);
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi uint32_t reserved_space_offset, reserved_space;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumistatic int mail_cache_link_unlocked(struct mail_cache *cache,
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumimail_cache_get_transaction(struct mail_cache_view *view,
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi ctx = i_new(struct mail_cache_transaction_ctx, 1);
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi view->trans_view = mail_index_transaction_open_updated_view(t);
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumistatic void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx)
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi ctx->cache_file_seq = MAIL_CACHE_IS_UNUSABLE(ctx->cache) ? 0 :
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi mail_index_ext_set_reset_id(ctx->trans, ctx->cache->ext_id,
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumimail_cache_transaction_free(struct mail_cache_transaction_ctx **_ctx)
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi struct mail_cache_transaction_ctx *ctx = *_ctx;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi mail_index_view_close(&ctx->view->trans_view);
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumistatic int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx)
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi (void)mail_cache_open_and_verify(ctx->cache);
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi ctx->cache_file_seq = ctx->cache->hdr->file_seq;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi if ((ret = mail_cache_lock(ctx->cache, FALSE)) <= 0)
5fd9f759c1575525ef5f8d31b6c4a2ae89e0e12fKATOH Yasufumi if (ctx->cache_file_seq != ctx->cache->hdr->file_seq)
dc421f3aac1f0e516c763dd156629a8ed2a7b4caKATOH Yasufumistatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi /* grow the file */
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi new_fsize = cache->hdr_copy.used_file_size + size;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi mail_cache_set_syscall_error(cache, "fstat()");
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi if (file_set_size(cache->fd, new_fsize) < 0) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi mail_cache_set_syscall_error(cache, "file_set_size()");
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumistatic bool mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi struct mail_cache_header *hdr = &cache->hdr_copy;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi while (offset != 0) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi mail_cache_set_syscall_error(cache, "pread_full()");
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi "Invalid magic in hole header");
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if (mail_cache_write(cache, &hole.next_offset,
9111aa793259eb1de897af6add5bf0400e962f9fKATOH Yasufumimail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx,
800648d24ad2791bc656e47f3a048c01fbe27587KATOH Yasufumimail_cache_transaction_partial_commit(struct mail_cache_transaction_ctx *ctx,
800648d24ad2791bc656e47f3a048c01fbe27587KATOH Yasufumi unsigned int i, count;
800648d24ad2791bc656e47f3a048c01fbe27587KATOH Yasufumi if (offset + size == ctx->cache->hdr_copy.used_file_size &&
800648d24ad2791bc656e47f3a048c01fbe27587KATOH Yasufumi offset + size == ctx->reserved_space_offset) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi res = array_get_modifiable(&ctx->reservations, &count);
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi for (i = 0; i < count; i++) {
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumimail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi struct mail_cache_header *hdr = &cache->hdr_copy;
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi unsigned int count;
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if (mail_cache_unlink_hole(cache, block_size, &hole)) {
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi /* found a large enough hole. */
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi mail_cache_transaction_add_reservation(ctx, hole.next_offset,
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi /* mail_cache_unlink_hole() could have noticed corruption */
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if ((uint32_t)-1 - hdr->used_file_size < block_size) {
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi mail_index_set_error(cache->index, "Cache file too large: %s",
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if (!commit && block_size < MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi /* allocate some more space than we need */
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi size_t new_block_size = (block_size + ctx->last_grow_size) * 2;
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if (new_block_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE)
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi new_block_size = MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if ((uint32_t)-1 - hdr->used_file_size >= new_block_size) {
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if (mail_cache_grow_file(ctx->cache, block_size) < 0)
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi if (ctx->reserved_space_offset + ctx->reserved_space ==
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi /* we can simply grow it */
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi /* grow reservation. it's probably the last one in the buffer,
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi but it's not guarateed because we might have used holes
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi reservations = array_get_modifiable(&ctx->reservations, &count);
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi reservations[count].size != hdr->used_file_size);
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi mail_cache_transaction_add_reservation(ctx, hdr->used_file_size,
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumi hdr->used_file_size = ctx->reserved_space_offset + ctx->reserved_space;
f57517ef962c4b499d229fcf502b43fbd8a54fbeKATOH Yasufumimail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi if (offset + size == cache->hdr_copy.used_file_size) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi /* we can just set used_file_size back */
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi } else if (size >= MAIL_CACHE_MIN_HOLE_SIZE) {
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi /* set it up as a hole */
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi hole.next_offset = cache->hdr_copy.hole_offset;
28f2ab26ea78e929253e38c6e87bb0e3c05112f2KATOH Yasufumi if (mail_cache_write(cache, &hole, sizeof(hole), offset) < 0)
if (!locked) {
if (!locked) {
bool commit)
int ret;
if (!locked) {
return ret;
commit);
if (!locked) {
if (ret < 0)
if (old_offset != 0) {
write_offset) < 0)
old_offset) < 0)
*seq_idx = i;
unsigned int seq_count;
int ret;
bool commit;
if (commit) {
seq_limit = 0;
if (ret <= 0) {
return ret;
seq_limit++;
&write_size) < 0)
void *data;
int ret = 0;
return ret;
unsigned int count;
while (count > 0) {
count--;
unsigned int field_idx)
int ret;
t_push();
t_pop();
if (ret == 0) {
return ret;
unsigned int fixed_size;
sizeof(data_size32));
return FALSE;
return FALSE;
t_push();
if (offset == 0) {
ret = 0;
t_pop();
return ret;