]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Moved the main functionality from "doveadm index" to MAILBOX_SYNC_FLAG_PRECACHE
authorTimo Sirainen <tss@iki.fi>
Tue, 14 Jun 2011 13:59:57 +0000 (16:59 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 14 Jun 2011 13:59:57 +0000 (16:59 +0300)
This also allows plugins to hook into the sync and implement their own
precaching easily. fts indexing is now done this way rather than kludging.

src/doveadm/doveadm-mail-index.c
src/lib-storage/index/index-sync.c
src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage.h
src/plugins/fts/fts-storage.c

index 1ff0757fe1ff78bcb4b202cec9b1e1f6e31e4209..e1d0e054888d170e5f6733d8bcc386d09ae156ba 100644 (file)
 #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);
-
-       ret = mailbox_search_deinit(&ctx);
-       if (mailbox_transaction_commit(&t) < 0)
-               ret = -1;
-       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);
@@ -172,19 +18,13 @@ cmd_index_box(const struct mailbox_info *info)
                            MAILBOX_FLAG_KEEP_RECENT |
                            MAILBOX_FLAG_IGNORE_ACLS);
 
-       if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
+       if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ |
+                        MAILBOX_SYNC_FLAG_PRECACHE) < 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;
@@ -203,16 +43,6 @@ cmd_index_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user)
        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) {
index c376bf8fad794461db6b0585476c8f2253872749..214bcc90faadd847b45d75391f3d9a455bcd8945 100644 (file)
@@ -6,6 +6,17 @@
 #include "array.h"
 #include "index-sync-private.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
+};
+
 enum mail_index_sync_flags index_storage_get_sync_flags(struct mailbox *box)
 {
        enum mail_index_sync_flags sync_flags = 0;
@@ -177,6 +188,7 @@ index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
 
        ctx = i_new(struct index_mailbox_sync_context, 1);
        ctx->ctx.box = box;
+       ctx->ctx.flags = flags;
 
        if (failed) {
                ctx->failed = TRUE;
@@ -324,6 +336,121 @@ index_mailbox_expunge_unseen_recent(struct index_mailbox_sync_context *ctx)
 #endif
 }
 
+static enum cache_mask
+cache_fields_get(const struct mailbox_status *status, bool debug)
+{
+       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 (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 (box->storage->set->mail_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 (box->storage->set->mail_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 index_sync_precache(struct mailbox *box)
+{
+       struct mailbox_status status;
+       enum cache_mask cache;
+
+       mailbox_get_status(box, STATUS_MESSAGES | STATUS_CACHE_FIELDS, &status);
+
+       cache = cache_fields_get(&status, box->storage->set->mail_debug);
+       return cache_add(box, &status, cache);
+}
+
 int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
                              struct mailbox_sync_status *status_r)
 {
@@ -380,6 +507,11 @@ int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
                array_free(&ctx->hidden_updates);
        if (array_is_created(&ctx->all_flag_update_uids))
                array_free(&ctx->all_flag_update_uids);
+
+       if ((_ctx->flags & MAILBOX_SYNC_FLAG_PRECACHE) != 0 && ret == 0) {
+               if (index_sync_precache(_ctx->box) < 0)
+                       ret = -1;
+       }
        i_free(ctx);
        return ret;
 }
index 8ca43ed8e32fd371d12f4bf94a5c9abadbbdde5b..6d27cf142b8a76297b10572b414d5a2f08ece8f5 100644 (file)
@@ -451,6 +451,7 @@ struct mail_save_context {
 
 struct mailbox_sync_context {
        struct mailbox *box;
+       enum mailbox_sync_flags flags;
 };
 
 struct mailbox_header_lookup_ctx {
index 7feaaffd0fa0d125ad2baecda974136814d25d1d..b2cc0565f767579f719bd964f9f5f481eae0859f 100644 (file)
@@ -159,7 +159,9 @@ enum mailbox_sync_flags {
           flag for plugins. */
        MAILBOX_SYNC_FLAG_EXPUNGE               = 0x80,
        /* Force doing a full resync of indexes. */
-       MAILBOX_SYNC_FLAG_FORCE_RESYNC          = 0x100
+       MAILBOX_SYNC_FLAG_FORCE_RESYNC          = 0x100,
+       /* Add all missing data to cache and fts index ("doveadm index") */
+       MAILBOX_SYNC_FLAG_PRECACHE              = 0x200
 };
 
 enum mailbox_sync_type {
index 3aa9fbc5066281fcc0cf9182e9523d687191e50d..09214e8167f91adca1aa16407179ef7482c01e73 100644 (file)
@@ -710,30 +710,16 @@ fts_mailbox_search_init(struct mailbox_transaction_context *t,
        return ctx;
 }
 
-static bool
-fts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
-                                struct mail *mail, bool *tryagain_r)
+static int fts_mailbox_search_build_more(struct mail_search_context *ctx)
 {
-       struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
        struct fts_search_context *fctx = FTS_CONTEXT(ctx);
-       int ret;
-
-       if (!fctx->build_initialized) {
-               /* we're still waiting for this process (but another command)
-                  to finish building the indexes */
-               if (!fts_try_build_init(ctx, fctx)) {
-                       *tryagain_r = TRUE;
-                       return FALSE;
-               }
-       }
+       int ret = 1;
 
        while (fctx->build_ctx != NULL) {
                /* this command is still building the indexes */
                ret = fts_build_more(fctx->build_ctx);
-               if (ret == 0) {
-                       *tryagain_r = TRUE;
-                       return FALSE;
-               }
+               if (ret == 0)
+                       return 0;
 
                /* finished / error */
                ctx->progress_hidden = FALSE;
@@ -746,6 +732,29 @@ fts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
                        }
                }
        }
+       return ret;
+}
+
+static bool
+fts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
+                                struct mail *mail, bool *tryagain_r)
+{
+       struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
+       struct fts_search_context *fctx = FTS_CONTEXT(ctx);
+
+       if (!fctx->build_initialized) {
+               /* we're still waiting for this process (but another command)
+                  to finish building the indexes */
+               if (!fts_try_build_init(ctx, fctx)) {
+                       *tryagain_r = TRUE;
+                       return FALSE;
+               }
+       }
+
+       if (fts_mailbox_search_build_more(ctx) == 0) {
+               *tryagain_r = TRUE;
+               return FALSE;
+       }
 
        /* if we're here, the indexes are either built or they're not used */
        return fbox->module_ctx.super.
@@ -1110,6 +1119,50 @@ fts_transaction_commit(struct mailbox_transaction_context *t,
        return ret;
 }
 
+static int fts_update(struct mailbox *box)
+{
+       struct mailbox_transaction_context *t;
+       struct mail_search_args *search_args;
+       struct mail_search_arg *arg;
+       struct mail_search_context *ctx;
+       struct fts_search_context *fctx;
+       int ret = 0;
+
+       t = mailbox_transaction_begin(box, 0);
+       search_args = mail_search_build_init();
+       search_args->charset = "UTF-8";
+       mail_search_build_add_all(search_args);
+       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);
+
+       fctx = FTS_CONTEXT(ctx);
+       if (fctx->build_initialized) {
+               while ((ret = fts_mailbox_search_build_more(ctx)) == 0) ;
+       }
+       (void)mailbox_search_deinit(&ctx);
+       (void)mailbox_transaction_commit(&t);
+
+       return ret < 0 ? -1 : 0;
+}
+
+static int fts_sync_deinit(struct mailbox_sync_context *ctx,
+                          struct mailbox_sync_status *status_r)
+{
+       struct mailbox *box = ctx->box;
+       struct fts_mailbox *fbox = FTS_CONTEXT(box);
+       bool precache;
+
+       precache = (ctx->flags & MAILBOX_SYNC_FLAG_PRECACHE) != 0;
+       if (fbox->module_ctx.super.sync_deinit(ctx, status_r) < 0)
+               return -1;
+       ctx = NULL;
+
+       return !precache ? 0 : fts_update(box);
+}
+
 static void fts_mailbox_init(struct mailbox *box, const char *env)
 {
        struct mailbox_vfuncs *v = box->vlast;
@@ -1131,6 +1184,7 @@ static void fts_mailbox_init(struct mailbox *box, const char *env)
        v->transaction_begin = fts_transaction_begin;
        v->transaction_rollback = fts_transaction_rollback;
        v->transaction_commit = fts_transaction_commit;
+       v->sync_deinit = fts_sync_deinit;
 
        MODULE_CONTEXT_SET(box, fts_storage_module, fbox);
 }