mail-cache-transaction.c revision 0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny/* Copyright (C) 2003-2004 Timo Sirainen */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic const unsigned char *null4[] = { 0, 0, 0, 0 };
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_transaction_begin(struct mail_cache_view *view, int nonblock,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx = i_new(struct mail_cache_transaction_ctx, 1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->cache_data = buffer_create_dynamic(system_pool, 8192, (size_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_transaction_end(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic void mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny ctx->first_seq = ctx->last_seq = ctx->prev_seq = 0;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic void mark_update(buffer_t **buf, uint32_t offset, uint32_t data)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny *buf = buffer_create_dynamic(system_pool, 1024, (size_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int write_mark_updates(struct mail_cache *cache)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny data = buffer_get_data(cache->trans_ctx->cache_marks, &size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (pwrite(cache->fd, data+1, sizeof(*data), data[0]) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int commit_all_changes(struct mail_cache_transaction_ctx *ctx)
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, "fdatasync()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* now that we're sure it's written, set on all the used-bits */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* update continued records count */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cont = nbo_to_uint32(cache->hdr->continued_record_count);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (cont * 100 / cache->index->hdr->messages_count >=
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* too many continued rows, compress */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny //FIXME:cache->index->set_flags |= MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->hdr->continued_record_count = uint32_to_nbo(cont);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_cache_grow(struct mail_cache *cache, uint32_t size)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (cache->used_file_size + size <= (uoff_t)st.st_size) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* no need to grow, just update mmap */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(cache->mmap_length >= (uoff_t)st.st_size);
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 Zelenystatic uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* NOTE: must be done within transaction or rollback would break it */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny "Cache file too large: %s",
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const void *buf;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buf = buffer_get_data(ctx->cache_data, &buf_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny write_offset = mail_cache_append_space(ctx, size);
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 cache_rec = mail_cache_get_record(cache, rec->cache_offset);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* first cache record - update offset in index file */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_update_cache(ctx->trans, ctx->prev_seq,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* find the last cache record */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* mark next_offset to be updated later */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny update_offset = (char *) &cache_rec->next_offset -
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy((char *) cache->mmap_base + write_offset +
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* reset the write context */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
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 Zelenyvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int i;
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 /* make sure we don't cache the headers */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny for (i = 0; i < ctx->next_unused_header_lowwater; i++) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic const char *write_header_string(const char *const headers[],
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer = buffer_create_dynamic(pool_datastack_create(),
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(buffer, *headers, strlen(*headers));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(idx >= ctx->next_unused_header_lowwater);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(mail_cache_offset_to_uint32(cache->hdr->
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny header_str = write_header_string(headers, &size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny prev_str = mail_cache_get_header_fields_str(cache, idx-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny offset = mail_cache_append_space(ctx, size + sizeof(uint32_t));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy((char *) cache->mmap_base + offset + sizeof(uint32_t),
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* update cached headers */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny cache->split_offsets[idx] = cache->hdr->header_offsets[idx];
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 /* make sure get_header_fields() still works for this header
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny while the transaction isn't yet committed. */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic size_t get_insert_offset(struct mail_cache_transaction_ctx *ctx,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const unsigned char *buf;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int mask;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int get_field_num(enum mail_cache_field field)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned int mask;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny unsigned char *buf;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny nb_data_size = uint32_to_nbo((uint32_t)data_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny i_assert(mail_cache_field_sizes[field_num] == data_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny } else if ((field & MAIL_CACHE_STRING_MASK) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ctx->prev_seq != seq && ctx->prev_seq != 0) {