Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-index/mail-cache-compress.c @ 2339:406692edc12d HEAD
Cache fixes. Decisions are saved again.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 20 Jul 2004 19:50:56 +0300 |
parents | 7d02e2a7672d |
children | fed6d07bd8ee |
line wrap: on
line source
/* Copyright (C) 2003-2004 Timo Sirainen */ #include "lib.h" #include "buffer.h" #include "ostream.h" #include "file-set-size.h" #include "mail-cache-private.h" static unsigned char null4[4] = { 0, 0, 0, 0 }; struct mail_cache_copy_context { int new_msg; buffer_t *buffer, *field_seen; uint8_t field_seen_value; }; static int mail_cache_compress_callback(struct mail_cache_view *view, uint32_t file_field, const void *data, size_t data_size, void *context) { struct mail_cache_copy_context *ctx = context; enum mail_cache_decision_type dec; unsigned int field; uint8_t *field_seen; uint32_t size32; field_seen = buffer_get_space_unsafe(ctx->field_seen, file_field, 1); if (*field_seen == ctx->field_seen_value) { /* duplicate */ return 1; } *field_seen = ctx->field_seen_value; field = view->cache->file_field_map[file_field]; dec = view->cache->fields[field].field.decision & ~MAIL_CACHE_DECISION_FORCED; if (ctx->new_msg) { if (dec == MAIL_CACHE_DECISION_NO) return 1; } else { if (dec != MAIL_CACHE_DECISION_YES) return 1; } buffer_append(ctx->buffer, &file_field, sizeof(file_field)); if (view->cache->fields[field].field.field_size == (unsigned int)-1) { size32 = (uint32_t)data_size; buffer_append(ctx->buffer, &size32, sizeof(size32)); } buffer_append(ctx->buffer, data, data_size); if ((data_size & 3) != 0) buffer_append(ctx->buffer, null4, 4 - (data_size & 3)); return 1; } static int mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd) { struct mail_cache_copy_context ctx; struct mail_cache_view *cache_view; struct mail_index_transaction *t; const struct mail_index_header *idx_hdr; struct mail_cache_header hdr; struct mail_cache_record cache_rec; struct ostream *output; buffer_t *buffer; uint32_t message_count, seq, first_new_seq, old_offset; uoff_t offset; /* get sequence of first message which doesn't need it's temp fields removed. */ if (mail_index_get_header(view, &idx_hdr) < 0) return -1; if (idx_hdr->day_first_uid[7] == 0) { first_new_seq = 1; message_count = mail_index_view_get_message_count(view); } else { if (mail_index_lookup_uid_range(view, idx_hdr->day_first_uid[7], (uint32_t)-1, &first_new_seq, &message_count) < 0) return -1; if (first_new_seq == 0) first_new_seq = message_count+1; } cache_view = mail_cache_view_open(cache, view); t = mail_index_transaction_begin(view, FALSE); output = o_stream_create_file(fd, default_pool, 0, FALSE); memset(&hdr, 0, sizeof(hdr)); hdr.version = MAIL_CACHE_VERSION; hdr.indexid = idx_hdr->indexid; hdr.file_seq = idx_hdr->cache_file_seq + 1; o_stream_send(output, &hdr, sizeof(hdr)); if (cache->fields_count != 0) { hdr.field_header_offset = mail_cache_uint32_to_offset(output->offset); t_push(); buffer = buffer_create_dynamic(pool_datastack_create(), 256, (size_t)-1); mail_cache_header_fields_get(cache, buffer); o_stream_send(output, buffer_get_data(buffer, NULL), buffer_get_used_size(buffer)); t_pop(); } memset(&ctx, 0, sizeof(ctx)); ctx.buffer = buffer_create_dynamic(default_pool, 4096, (size_t)-1); ctx.field_seen = buffer_create_dynamic(default_pool, 64, (size_t)-1); ctx.field_seen_value = 0; mail_index_reset_cache(t, hdr.file_seq); for (seq = 1; seq <= message_count; seq++) { ctx.new_msg = seq >= first_new_seq; buffer_set_used_size(ctx.buffer, 0); if (++ctx.field_seen_value == 0) { memset(buffer_get_modifyable_data(ctx.field_seen, NULL), 0, buffer_get_size(ctx.field_seen)); ctx.field_seen_value++; } memset(&cache_rec, 0, sizeof(cache_rec)); buffer_append(ctx.buffer, &cache_rec, sizeof(cache_rec)); (void)mail_cache_foreach(cache_view, seq, mail_cache_compress_callback, &ctx); cache_rec.size = buffer_get_used_size(ctx.buffer); if (cache_rec.size == sizeof(cache_rec)) continue; mail_index_update_cache(t, seq, hdr.file_seq, output->offset, &old_offset); buffer_write(ctx.buffer, 0, &cache_rec, sizeof(cache_rec)); o_stream_send(output, buffer_get_data(ctx.buffer, NULL), cache_rec.size); } hdr.used_file_size = output->offset; buffer_free(ctx.buffer); o_stream_seek(output, 0); o_stream_send(output, &hdr, sizeof(hdr)); mail_cache_view_close(cache_view); if (o_stream_flush(output) < 0) { errno = output->stream_errno; mail_cache_set_syscall_error(cache, "o_stream_flush()"); (void)mail_index_transaction_rollback(t); o_stream_unref(output); return -1; } if (hdr.used_file_size < MAIL_CACHE_INITIAL_SIZE) { /* grow the file some more. doesn't matter if it fails */ (void)file_set_size(fd, MAIL_CACHE_INITIAL_SIZE); } o_stream_unref(output); if (fdatasync(fd) < 0) { mail_cache_set_syscall_error(cache, "fdatasync()"); (void)mail_index_transaction_rollback(t); return -1; } return mail_index_transaction_commit(t, &seq, &offset); } int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view) { int fd, ret, locked; if ((ret = mail_cache_lock(cache)) < 0) return -1; locked = ret > 0; /* get the latest info on fields */ if (mail_cache_header_fields_read(cache) < 0) { if (locked) mail_cache_unlock(cache); return -1; } #ifdef DEBUG i_warning("Compressing cache file %s", cache->filepath); #endif fd = file_dotlock_open(cache->filepath, NULL, NULL, MAIL_CACHE_LOCK_TIMEOUT, MAIL_CACHE_LOCK_CHANGE_TIMEOUT, MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL); if (fd == -1) { mail_cache_set_syscall_error(cache, "file_dotlock_open()"); if (locked) mail_cache_unlock(cache); return -1; } // FIXME: check that cache file wasn't just recreated ret = 0; if (mail_cache_copy(cache, view, fd) < 0) { (void)file_dotlock_delete(cache->filepath, NULL, fd); ret = -1; } else { if (file_dotlock_replace(cache->filepath, NULL, -1, FALSE) < 0) { mail_cache_set_syscall_error(cache, "file_dotlock_replace()"); (void)close(fd); ret = -1; } else { mail_cache_file_close(cache); cache->fd = fd; if (mail_cache_map(cache, 0, 0) < 0) ret = -1; else if (mail_cache_header_fields_read(cache) < 0) ret = -1; } } if (locked) mail_cache_unlock(cache); if (ret == 0) cache->need_compress = FALSE; return ret; } int mail_cache_need_compress(struct mail_cache *cache) { return cache->need_compress; }