Mercurial > dovecot > core-2.2
changeset 12996:840e27a52e51
doveadm: Added "index" command to add unindexed messages into index/cache/fts.
The caching adds only the fields that were previously added to the mailbox's
caching decisions, so it won't do anything useful for mailboxes that user's
client hasn't accessed yet.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 05 May 2011 18:13:55 +0200 |
parents | e9918fd289f3 |
children | 622d42376fe0 |
files | src/doveadm/Makefile.am src/doveadm/doveadm-mail-index.c src/doveadm/doveadm-mail.c src/doveadm/doveadm-mail.h |
diffstat | 4 files changed, 250 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/doveadm/Makefile.am Thu May 05 17:49:45 2011 +0200 +++ b/src/doveadm/Makefile.am Thu May 05 18:13:55 2011 +0200 @@ -63,6 +63,7 @@ doveadm-mail-expunge.c \ doveadm-mail-fetch.c \ doveadm-mail-import.c \ + doveadm-mail-index.c \ doveadm-mail-iter.c \ doveadm-mail-mailbox.c \ doveadm-mail-mailbox-status.c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-mail-index.c Thu May 05 18:13:55 2011 +0200 @@ -0,0 +1,247 @@ +/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-namespace.h" +#include "mail-storage.h" +#include "mail-search-build.h" +#include "doveadm-mail.h" + +enum cache_mask { + CACHE_HDR = 0x01, + CACHE_BODY = 0x02, + CACHE_RECEIVED_DATE = 0x04, + CACHE_SAVE_DATE = 0x08, + CACHE_VIRTUAL_SIZE = 0x10, + CACHE_PHYSICAL_SIZE = 0x20, + CACHE_POP3_UIDL = 0x40, + CACHE_GUID = 0x80 +}; + +static bool fts_is_enabled = FALSE; + +static enum cache_mask cache_fields_get(const struct mailbox_status *status) +{ + const char *const *cache_fields; + unsigned int i, count; + enum cache_mask cache = 0; + + cache_fields = array_get(status->cache_fields, &count); + for (i = 0; i < count; i++) { + if (strncmp(cache_fields[i], "hdr.", 4) == 0 || + strcmp(cache_fields[i], "date.sent") == 0 || + strcmp(cache_fields[i], "imap.envelope") == 0) + cache |= CACHE_HDR; + else if (strcmp(cache_fields[i], "mime.parts") == 0 || + strcmp(cache_fields[i], "imap.body") == 0 || + strcmp(cache_fields[i], "imap.bodystructure") == 0) + cache |= CACHE_BODY; + else if (strcmp(cache_fields[i], "date.received") == 0) + cache |= CACHE_RECEIVED_DATE; + else if (strcmp(cache_fields[i], "date.save") == 0) + cache |= CACHE_SAVE_DATE; + else if (strcmp(cache_fields[i], "size.virtual") == 0) + cache |= CACHE_VIRTUAL_SIZE; + else if (strcmp(cache_fields[i], "size.physical") == 0) + cache |= CACHE_PHYSICAL_SIZE; + else if (strcmp(cache_fields[i], "pop3.uidl") == 0) + cache |= CACHE_POP3_UIDL; + else if (strcmp(cache_fields[i], "guid") == 0) + cache |= CACHE_GUID; + else if (doveadm_debug) { + i_debug("Ignoring unknown cache field: %s", + cache_fields[i]); + } + } + return cache; +} + +static int cache_add(struct mailbox *box, const struct mailbox_status *status, + enum cache_mask cache) +{ + struct mailbox_transaction_context *trans; + struct mail *mail; + uint32_t seq; + time_t date; + uoff_t size; + const char *str; + + if (doveadm_debug) { + i_debug("%s: Nothing in mailbox cache, skipping", + mailbox_get_vname(box)); + return 0; + } + + /* find the first message we need to index */ + trans = mailbox_transaction_begin(box, 0); + mail = mail_alloc(trans, 0, NULL); + for (seq = status->messages; seq > 0; seq--) { + mail_set_seq(mail, seq); + if (mail_is_cached(mail)) + break; + } + seq++; + + if (doveadm_debug) { + if (seq > status->messages) { + i_debug("%s: Cache is already up to date", + mailbox_get_vname(box)); + } else { + i_debug("%s: Caching mails seq=%u..%u cache=0x%x", + mailbox_get_vname(box), + seq, status->messages, cache); + } + } + + for (; seq <= status->messages; seq++) { + mail_set_seq(mail, seq); + + if ((cache & (CACHE_HDR | CACHE_BODY)) != 0) + mail_parse(mail, (cache & CACHE_BODY) != 0); + if ((cache & CACHE_RECEIVED_DATE) != 0) + (void)mail_get_received_date(mail, &date); + if ((cache & CACHE_SAVE_DATE) != 0) + (void)mail_get_save_date(mail, &date); + if ((cache & CACHE_VIRTUAL_SIZE) != 0) + (void)mail_get_virtual_size(mail, &size); + if ((cache & CACHE_PHYSICAL_SIZE) != 0) + (void)mail_get_physical_size(mail, &size); + if ((cache & CACHE_POP3_UIDL) != 0) { + (void)mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, + &str); + } + if ((cache & CACHE_GUID) != 0) + (void)mail_get_special(mail, MAIL_FETCH_GUID, &str); + } + mail_free(&mail); + if (mailbox_transaction_commit(&trans) < 0) { + i_error("Commiting mailbox %s failed: %s", + mailbox_get_vname(box), + mail_storage_get_last_error(mailbox_get_storage(box), NULL)); + return -1; + } + return 0; +} + +static int fts_update(struct mailbox *box, const struct mailbox_status *status) +{ + struct mailbox_transaction_context *t; + struct mail_search_args *search_args; + struct mail_search_arg *arg; + struct mail_search_context *ctx; + struct mail *mail; + int ret; + + if (!fts_is_enabled) + return 0; + + /* a bit kludgy way to trigger the full text search update: + search for a string in the last message */ + t = mailbox_transaction_begin(box, 0); + search_args = mail_search_build_init(); + search_args->charset = "UTF-8"; + mail_search_build_add_seqset(search_args, + status->messages, status->messages); + arg = mail_search_build_add(search_args, SEARCH_BODY_FAST); + arg->value.str = "xyzzy"; + + ctx = mailbox_search_init(t, search_args, NULL); + mail_search_args_unref(&search_args); + + mail = mail_alloc(t, 0, NULL); + while (mailbox_search_next(ctx, mail)) { + } + mail_free(&mail); + + if (mailbox_search_deinit(&ctx) < 0) + ret = -1; + (void)mailbox_transaction_commit(&t); + return ret; +} + +static int +cmd_index_box(const struct mailbox_info *info) +{ + struct mailbox *box; + struct mailbox_status status; + const char *storage_name; + enum cache_mask cache; + int ret = 0; + + storage_name = mail_namespace_get_storage_name(info->ns, info->name); + box = mailbox_alloc(info->ns->list, storage_name, + MAILBOX_FLAG_KEEP_RECENT | + MAILBOX_FLAG_IGNORE_ACLS); + + if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { + i_error("Syncing mailbox %s failed: %s", info->name, + mail_storage_get_last_error(mailbox_get_storage(box), NULL)); + mailbox_free(&box); + return -1; + } + mailbox_get_status(box, STATUS_MESSAGES | STATUS_CACHE_FIELDS, &status); + + cache = cache_fields_get(&status); + ret = cache_add(box, &status, cache); + + if (fts_update(box, &status) < 0) + ret = -1; + + mailbox_free(&box); + return ret; +} + +static void +cmd_index_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user) +{ + const enum mailbox_list_iter_flags iter_flags = + MAILBOX_LIST_ITER_RAW_LIST | + MAILBOX_LIST_ITER_NO_AUTO_INBOX | + MAILBOX_LIST_ITER_RETURN_NO_FLAGS | + MAILBOX_LIST_ITER_STAR_WITHIN_NS; + const enum namespace_type ns_mask = + NAMESPACE_PRIVATE | NAMESPACE_SHARED | NAMESPACE_PUBLIC; + struct mailbox_list_iterate_context *iter; + const struct mailbox_info *info; + + if (mail_user_plugin_getenv(user, "fts") != NULL) T_BEGIN { + const char *const *plugins; + + plugins = t_strsplit(user->set->mail_plugins, " "); + for (; *plugins != NULL; plugins++) { + if (strncmp(*plugins, "fts", 3) == 0) + fts_is_enabled = TRUE; + } + } T_END; + + iter = mailbox_list_iter_init_namespaces(user->namespaces, ctx->args, + ns_mask, iter_flags); + while ((info = mailbox_list_iter_next(iter)) != NULL) { + if ((info->flags & (MAILBOX_NOSELECT | + MAILBOX_NONEXISTENT)) == 0) T_BEGIN { + (void)cmd_index_box(info); + } T_END; + } + if (mailbox_list_iter_deinit(&iter) < 0) + i_error("Listing mailboxes failed"); +} + +static void cmd_index_init(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED, + const char *const args[]) +{ + if (args[0] == NULL) + doveadm_mail_help_name("index"); +} + +static struct doveadm_mail_cmd_context *cmd_index_alloc(void) +{ + struct doveadm_mail_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context); + ctx->v.init = cmd_index_init; + ctx->v.run = cmd_index_run; + return ctx; +} + +struct doveadm_mail_cmd cmd_index = { + cmd_index_alloc, "index", "<mailbox>" +};
--- a/src/doveadm/doveadm-mail.c Thu May 05 17:49:45 2011 +0200 +++ b/src/doveadm/doveadm-mail.c Thu May 05 18:13:55 2011 +0200 @@ -565,6 +565,7 @@ &cmd_search, &cmd_fetch, &cmd_import, + &cmd_index, &cmd_altmove, &cmd_move, &cmd_mailbox_list,
--- a/src/doveadm/doveadm-mail.h Thu May 05 17:49:45 2011 +0200 +++ b/src/doveadm/doveadm-mail.h Thu May 05 18:13:55 2011 +0200 @@ -108,6 +108,7 @@ struct doveadm_mail_cmd cmd_search; struct doveadm_mail_cmd cmd_fetch; struct doveadm_mail_cmd cmd_import; +struct doveadm_mail_cmd cmd_index; struct doveadm_mail_cmd cmd_altmove; struct doveadm_mail_cmd cmd_move; struct doveadm_mail_cmd cmd_mailbox_list;