Mercurial > dovecot > core-2.2
view src/lib-storage/index/index-status.c @ 14133:ba770cba5598
Updated copyright notices to include year 2012.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 12 Feb 2012 18:55:28 +0200 |
parents | 3830d5a57fd4 |
children | 1222b7e38bf3 |
line wrap: on
line source
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "mail-cache.h" #include "mail-search-build.h" #include "index-storage.h" #include "mail-index-modseq.h" static void get_last_cached_seq(struct mailbox *box, uint32_t *last_cached_seq_r) { const struct mail_index_header *hdr; struct mail_cache_view *cache_view; uint32_t seq; *last_cached_seq_r = 0; if (!mail_cache_exists(box->cache)) return; cache_view = mail_cache_view_open(box->cache, box->view); hdr = mail_index_get_header(box->view); for (seq = hdr->messages_count; seq > 0; seq--) { if (mail_cache_field_exists_any(cache_view, seq)) { *last_cached_seq_r = seq; break; } } mail_cache_view_close(&cache_view); } int index_storage_get_status(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status_r) { const struct mail_index_header *hdr; memset(status_r, 0, sizeof(struct mailbox_status)); if (!box->opened) { if (mailbox_open(box) < 0) return -1; if (mailbox_sync(box, 0) < 0) return -1; } /* we can get most of the status items without any trouble */ hdr = mail_index_get_header(box->view); status_r->messages = hdr->messages_count; if ((items & STATUS_RECENT) != 0) { /* make sure recent count is set, in case syncing hasn't been done yet */ index_sync_update_recent_count(box); status_r->recent = index_mailbox_get_recent_count(box); i_assert(status_r->recent <= status_r->messages); } status_r->unseen = hdr->messages_count - hdr->seen_messages_count; status_r->uidvalidity = hdr->uid_validity; status_r->uidnext = hdr->next_uid; status_r->first_recent_uid = hdr->first_recent_uid; status_r->nonpermanent_modseqs = mail_index_is_in_memory(box->index); if ((items & STATUS_HIGHESTMODSEQ) != 0) { status_r->highest_modseq = mail_index_modseq_get_highest(box->view); if (status_r->highest_modseq == 0) { /* modseqs not enabled yet, but we can't return 0 */ status_r->highest_modseq = 1; } } if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) { mail_index_lookup_first(box->view, 0, MAIL_SEEN, &status_r->first_unseen_seq); } if ((items & STATUS_LAST_CACHED_SEQ) != 0) get_last_cached_seq(box, &status_r->last_cached_seq); if ((items & STATUS_KEYWORDS) != 0) status_r->keywords = mail_index_get_keywords(box->index); if ((items & STATUS_PERMANENT_FLAGS) != 0) { if (!mailbox_is_readonly(box)) { status_r->permanent_flags = MAIL_FLAGS_NONRECENT; status_r->permanent_keywords = TRUE; status_r->allow_new_keywords = !box->disallow_new_keywords; } } return 0; } static void get_metadata_cache_fields(struct mailbox *box, struct mailbox_metadata *metadata_r) { const struct mail_cache_field *fields; enum mail_cache_decision_type dec; ARRAY_TYPE(mailbox_cache_field) *cache_fields; struct mailbox_cache_field *cf; unsigned int i, count; fields = mail_cache_register_get_list(box->cache, pool_datastack_create(), &count); cache_fields = t_new(ARRAY_TYPE(mailbox_cache_field), 1); t_array_init(cache_fields, count); for (i = 0; i < count; i++) { dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED; if (dec != MAIL_CACHE_DECISION_NO) { cf = array_append_space(cache_fields); cf->name = fields[i].name; cf->decision = fields[i].decision; cf->last_used = fields[i].last_used; } } metadata_r->cache_fields = cache_fields; } static void get_metadata_precache_fields(struct mailbox *box, struct mailbox_metadata *metadata_r) { const struct mail_cache_field *fields; unsigned int i, count; enum mail_fetch_field cache = 0; fields = mail_cache_register_get_list(box->cache, pool_datastack_create(), &count); for (i = 0; i < count; i++) { const char *name = fields[i].name; if (strncmp(name, "hdr.", 4) == 0 || strcmp(name, "date.sent") == 0 || strcmp(name, "imap.envelope") == 0) cache |= MAIL_FETCH_STREAM_HEADER; else if (strcmp(name, "mime.parts") == 0 || strcmp(name, "imap.body") == 0 || strcmp(name, "imap.bodystructure") == 0) cache |= MAIL_FETCH_STREAM_BODY; else if (strcmp(name, "date.received") == 0) cache |= MAIL_FETCH_RECEIVED_DATE; else if (strcmp(name, "date.save") == 0) cache |= MAIL_FETCH_SAVE_DATE; else if (strcmp(name, "size.virtual") == 0) cache |= MAIL_FETCH_VIRTUAL_SIZE; else if (strcmp(name, "size.physical") == 0) cache |= MAIL_FETCH_PHYSICAL_SIZE; else if (strcmp(name, "pop3.uidl") == 0) cache |= MAIL_FETCH_UIDL_BACKEND; else if (strcmp(name, "guid") == 0) cache |= MAIL_FETCH_GUID; else if (strcmp(name, "flags") == 0) { /* just ignore for now at least.. */ } else if (box->storage->set->mail_debug) i_debug("Ignoring unknown cache field: %s", name); } metadata_r->precache_fields = cache; } static int virtual_size_add_new(struct mailbox *box, struct index_vsize_header *vsize_hdr) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); const struct mail_index_header *hdr; struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; struct mail_search_args *search_args; struct mail *mail; uint32_t seq1, seq2; uoff_t vsize; int ret = 0; hdr = mail_index_get_header(box->view); if (vsize_hdr->highest_uid == 0) seq2 = 0; else if (!mail_index_lookup_seq_range(box->view, 1, vsize_hdr->highest_uid, &seq1, &seq2)) seq2 = 0; if (vsize_hdr->message_count != seq2) { if (vsize_hdr->message_count < seq2) { mail_storage_set_critical(box->storage, "vsize-hdr has invalid message-count (%u < %u)", vsize_hdr->message_count, seq2); } else { /* some messages have been expunged, rescan */ } memset(vsize_hdr, 0, sizeof(*vsize_hdr)); seq2 = 0; } search_args = mail_search_build_init(); mail_search_build_add_seqset(search_args, seq2 + 1, hdr->messages_count); trans = mailbox_transaction_begin(box, 0); search_ctx = mailbox_search_init(trans, search_args, NULL, MAIL_FETCH_VIRTUAL_SIZE, NULL); while (mailbox_search_next(search_ctx, &mail)) { if (mail_get_virtual_size(mail, &vsize) < 0) { if (mail->expunged) continue; ret = -1; break; } vsize_hdr->vsize += vsize; vsize_hdr->highest_uid = mail->uid; vsize_hdr->message_count++; } if (mailbox_search_deinit(&search_ctx) < 0) ret = -1; if (ret == 0) { /* success, cache all */ vsize_hdr->highest_uid = hdr->next_uid - 1; } else { /* search failed, cache only up to highest seen uid */ } mail_index_update_header_ext(trans->itrans, ibox->vsize_hdr_ext_id, 0, vsize_hdr, sizeof(*vsize_hdr)); (void)mailbox_transaction_commit(&trans); return ret; } static int get_metadata_virtual_size(struct mailbox *box, struct mailbox_metadata *metadata_r) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); struct index_vsize_header vsize_hdr; struct mailbox_status status; const void *data; size_t size; int ret; mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, &status); mail_index_get_header_ext(box->view, ibox->vsize_hdr_ext_id, &data, &size); if (size == sizeof(vsize_hdr)) memcpy(&vsize_hdr, data, sizeof(vsize_hdr)); else { if (size != 0) { mail_storage_set_critical(box->storage, "vsize-hdr has invalid size: %"PRIuSIZE_T, size); } memset(&vsize_hdr, 0, sizeof(vsize_hdr)); } if (vsize_hdr.highest_uid + 1 == status.uidnext && vsize_hdr.message_count == status.messages) { /* up to date */ metadata_r->virtual_size = vsize_hdr.vsize; return 0; } if (vsize_hdr.highest_uid >= status.uidnext) { mail_storage_set_critical(box->storage, "vsize-hdr has invalid highest-uid (%u >= %u)", vsize_hdr.highest_uid, status.uidnext); memset(&vsize_hdr, 0, sizeof(vsize_hdr)); } ret = virtual_size_add_new(box, &vsize_hdr); metadata_r->virtual_size = vsize_hdr.vsize; return ret; } int index_mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, struct mailbox_metadata *metadata_r) { if (!box->opened) { if (mailbox_open(box) < 0) return -1; } if ((items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) { if (get_metadata_virtual_size(box, metadata_r) < 0) return -1; } if ((items & MAILBOX_METADATA_CACHE_FIELDS) != 0) get_metadata_cache_fields(box, metadata_r); if ((items & MAILBOX_METADATA_PRECACHE_FIELDS) != 0) get_metadata_precache_fields(box, metadata_r); return 0; }