fts-storage.c revision 96308127e006bb3b1108093bcf4cc1fd9481cb7a
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct timeval search_start_time, last_notify;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen union mailbox_transaction_module_context module_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_storage_module,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_mail_module, &mail_module_register);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void fts_mailbox_close(struct mailbox *box)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic int fts_build_mail_flush_headers(struct fts_storage_build_context *ctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fts_backend_build_more(ctx->build, ctx->uid, str_data(ctx->headers),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic bool fts_build_want_index_part(const struct message_block *block)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* we'll index only text/xxx and message/rfc822 parts for now */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void fts_build_mail_header(struct fts_storage_build_context *ctx,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct message_header_line *hdr = block->hdr;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* hdr->full_value is always set because we get the block from
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen message_decoder */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_append_n(ctx->headers, hdr->middle, hdr->middle_len);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen str_append_n(ctx->headers, hdr->full_value, hdr->full_value_len);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int fts_build_mail(struct fts_storage_build_context *ctx, uint32_t uid)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen parser = message_parser_init(pool_datastack_create(), input,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen decoder = message_decoder_init(MESSAGE_DECODER_FLAG_DTCASE);
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen ret = message_parser_parse_next_block(parser, &raw_block);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (raw_block.hdr == NULL && raw_block.size != 0 &&
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen /* skipping this body */
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen if (!message_decoder_decode_next_block(decoder, &raw_block,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* end of headers */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fts_backend_build_more(ctx->build, ctx->uid,
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen if (message_parser_deinit(&parser, &parts) < 0)
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen mail_set_cache_corrupted(ctx->mail, MAIL_FETCH_MESSAGE_PARTS);
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen /* Index all headers at the end. This is required for Squat,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen because it can handle only incremental UIDs. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fts_build_init_seq(struct fts_search_context *fctx,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen uint32_t seq1, uint32_t seq2, uint32_t last_uid)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fctx->best_arg->type == SEARCH_HEADER_COMPRESS_LWSP) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* we're not updating the index just for header lookups */
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (fts_backend_build_init(backend, &last_uid_locked, &build) < 0)
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen if (last_uid != last_uid_locked && last_uid_locked != (uint32_t)-1) {
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen /* changed, need to get again the sequences */
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen mailbox_get_seq_range(t->box, last_uid+1, (uint32_t)-1,
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen /* no new messages */
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen mail_search_build_add_seqset(search_args, seq1, seq2);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx = i_new(struct fts_storage_build_context, 1);
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen ctx->search_ctx = mailbox_search_init(t, search_args, NULL);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic struct fts_backend *
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenfts_mailbox_get_backend(struct fts_search_context *fctx,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (fctx->build_backend == fctx->fbox->backend_fast)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(fctx->build_backend == fctx->fbox->backend_substr);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic int fts_build_init_trans(struct fts_search_context *fctx,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen backend = fts_mailbox_get_backend(fctx, t->box);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (fts_backend_get_last_uid(backend, &last_uid) < 0)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mailbox_get_seq_range(t->box, last_uid+1, (uint32_t)-1, &seq1, &seq2);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* no new messages */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ret = fts_build_init_seq(fctx, backend, t, seq1, seq2, last_uid);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenfts_build_init_box(struct fts_search_context *fctx, struct mailbox *box,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mailbox_get_seq_range(box, last_uid + 1, (uint32_t)-1, &seq1, &seq2);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen fctx->virtual_ctx.trans = mailbox_transaction_begin(box, 0);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return fts_build_init_seq(fctx, backend, fctx->virtual_ctx.trans,
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainenstatic int mailbox_name_cmp(const struct fts_orig_mailboxes *box1,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen vname1 = mail_namespace_get_vname(box1->ns, tmp1, box1->name);
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainen vname2 = mail_namespace_get_vname(box2->ns, tmp2, box2->name);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenfts_backend_uid_map_mailbox_cmp(const struct fts_backend_uid_map *map1,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainenstatic int fts_build_init_virtual_next(struct fts_search_context *fctx)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen unsigned int boxi, uidi, box_count, last_uid_count;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen (void)mailbox_transaction_commit(&fctx->virtual_ctx.trans);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen boxes = array_get(&vctx->orig_mailboxes, &box_count);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen last_uids = array_get(&vctx->last_uids, &last_uid_count);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen while (vret == 0 && boxi < box_count && uidi < last_uid_count) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen vname = mail_namespace_get_vname(boxes[boxi].ns, tmp,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* match. check also that uidvalidity matches. */
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen mailbox_get_status(boxes[boxi].box, STATUS_UIDVALIDITY,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen if (status.uidvalidity != last_uids[uidi].uidvalidity) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen } else if (ret > 0) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* not part of this virtual mailbox */
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* no messages indexed in the mailbox */
71da447014454c84828d9dface77219875554d7dTimo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic const char *
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenfts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mail_namespace *ns = mailbox_get_namespace(box);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (*name == '\0' && ns != mailbox_get_namespace(box) &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* ugly workaround to allow selecting INBOX from a Maildir/
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen when it's not in the inbox=yes namespace. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return "INBOX";
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int fts_build_init_virtual(struct fts_search_context *fctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen unsigned int i, box_count;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_get_virtual_backend_boxes(fctx->t->box, &mailboxes, TRUE);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen boxes = array_get_modifiable(&mailboxes, &box_count);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vctx->pool = pool_alloconly_create("fts virtual build", 1024);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen p_array_init(&vctx->orig_mailboxes, vctx->pool, box_count);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen for (i = 0; i < box_count; i++) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen orig_box.name = fts_box_get_root(boxes[i], &orig_box.ns);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen array_append(&vctx->orig_mailboxes, &orig_box, 1);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen orig_boxes = array_get(&vctx->orig_mailboxes, &box_count);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* empty virtual mailbox */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* virtual mailbox is built from only a single mailbox
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (currently). check that directly. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_transaction_begin(orig_boxes[0].box, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = fts_build_init_trans(fctx, fctx->virtual_ctx.trans);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* virtual mailbox is built from multiple mailboxes. figure out which
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ones need updating. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen p_array_init(&vctx->last_uids, vctx->pool, 64);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fts_backend_get_all_last_uids(fctx->build_backend, vctx->pool,
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen array_sort(&vctx->orig_mailboxes, mailbox_name_cmp);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen array_sort(&vctx->last_uids, fts_backend_uid_map_mailbox_cmp);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int fts_build_init(struct fts_search_context *fctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_get_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (status.messages == fctx->fbox->last_messages_count &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* no new messages since last check */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* index was up-to-date */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen fctx->fbox->last_messages_count = status.messages;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int fts_build_deinit(struct fts_storage_build_context **_ctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct fts_storage_build_context *ctx = *_ctx;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox *box = ctx->mail->transaction->box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fts_backend_build_deinit(&ctx->build) < 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_get_status(box, STATUS_MESSAGES | STATUS_UIDNEXT,
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen if (ioloop_time - ctx->search_start_time.tv_sec >=
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen /* we notified at least once */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void fts_build_notify(struct fts_storage_build_context *ctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox *box = ctx->mail->transaction->box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* set the search time in here, in case a plugin
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen already spent some time indexing the mailbox */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else if (box->storage->callbacks.notify_ok != NULL) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen range = array_idx(&ctx->search_args->args->value.seqset, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen percentage = (ctx->mail->seq - range->seq1) * 100.0 /
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen secs = (msecs / (percentage / 100.0) - msecs) / 1000;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen text = t_strdup_printf("Indexed %d%% of the mailbox, "
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstatic int fts_build_more(struct fts_storage_build_context *ctx)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen unsigned int count = 0;
T_BEGIN {
} T_END;
if (ret < 0)
return TRUE;
return FALSE;
return TRUE;
return TRUE;
static struct mail_search_context *
fctx->t = t;
return ctx;
return ctx;
int ret;
if (ret == 0) {
if (ret > 0) {
case SEARCH_TEXT:
case SEARCH_BODY:
case SEARCH_BODY_FAST:
case SEARCH_TEXT_FAST:
&def_count);
&maybe_count);
return FALSE;
if (use_maybe)
if (!use_maybe) {
return ret;
return TRUE;
return TRUE;
return TRUE;
return FALSE;
const char **value_r)
static struct mail *
return _mail;
const char *const *tmp;
FTS_BACKEND_FLAG_SUBSTRING_LOOKUPS) != 0) {
*tmp);
*tmp);
static struct mailbox_transaction_context *
struct mailbox_transaction_context *t;
bool committed)
int ret;
return ret;
const char *env;