fts-storage.c revision fd14806f879f6cd4f023750e0c4cac27a7f94fbb
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct fts_backend_update_context *sync_update_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen union mailbox_transaction_module_context module_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_storage_module,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_mail_module, &mail_module_register);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_mailbox_list_module,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void fts_scores_unref(struct fts_scores **_scores)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic bool fts_try_build_init(struct mail_search_context *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* this process is already building the indexes */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen switch (fts_build_init(fctx->backend, ctx->transaction->box, FALSE,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* the index was up to date */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* hide "searching" notifications while building index */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic bool fts_want_build_args(const struct mail_search_arg *args)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* we want to update index only when searching from message body.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen it's not worth the wait for searching only from headers, which
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen could be in cache file already */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenfts_mailbox_search_init(struct mailbox_transaction_context *t,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(t);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(t->box->list);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx = fbox->module_ctx.super.search_init(t, args, sort_program,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (!fts_backend_can_lookup(flist->backend, args->args))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen fctx->result_pool = pool_alloconly_create("fts results", 1024*32);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen fctx->orig_matches = buffer_create_dynamic(default_pool, 64);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen MODULE_CONTEXT_SET(ctx, fts_storage_module, fctx);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen strcmp(t->box->storage->name, VIRTUAL_STORAGE_NAME) == 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* transaction contains the last search's scores. they can be
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen queried later with mail_get_special() */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic bool fts_mailbox_build_continue(struct mail_search_context *ctx)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* we're still waiting for this process (but another command)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen to finish building the indexes */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* this command is still building the indexes */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenfts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen search_next_nonblock(ctx, mail_r, tryagain_r);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenfts_search_apply_results_level(struct mail_search_context *ctx,
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen struct mail_search_arg *args, unsigned int *idx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (array_is_created(&level->definite_seqs) &&
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen seq_range_exists(&level->definite_seqs, ctx->seq))
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen fts_search_deserialize_add_matches(args, level->args_matches);
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen else if (!array_is_created(&level->maybe_seqs) ||
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen !seq_range_exists(&level->maybe_seqs, ctx->seq))
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen fts_search_deserialize_add_nonmatches(args, level->args_matches);
9c7e765845357342923e16351181091028e5930fTimo Sirainen if (args->type != SEARCH_OR && args->type != SEARCH_SUB)
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen fts_search_apply_results_level(ctx, args->value.subargs, idx);
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainenstatic bool fts_mailbox_search_next_update_seq(struct mail_search_context *ctx)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen unsigned int idx;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (fctx == NULL || !fctx->fts_lookup_success) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* fts lookup not done for this search */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return fbox->module_ctx.super.search_next_update_seq(ctx);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* restore original [non]matches */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen fts_search_deserialize(ctx->args->args, fctx->orig_matches);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (!fbox->module_ctx.super.search_next_update_seq(ctx))
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* we've not indexed this far */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* apply [non]matches based on the FTS lookup results */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fts_search_apply_results_level(ctx, ctx->args->args, &idx);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int fts_mailbox_search_deinit(struct mail_search_context *ctx)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* the search was cancelled */
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen return fbox->module_ctx.super.search_deinit(ctx);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic int fts_score_cmp(const uint32_t *uid, const struct fts_score_map *score)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic int fts_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen const char **value_r)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen if (field != MAIL_FETCH_SEARCH_RELEVANCY || ft->scores == NULL)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen scores = array_bsearch(&ft->scores->score_map, &_mail->uid,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_snprintf(fmail->score, sizeof(fmail->score),
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return fmail->module_ctx.super.get_special(_mail, field, value_r);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(_mail->box);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen fmail = p_new(mail->pool, struct fts_mail, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MODULE_CONTEXT_SET(mail, fts_mail_module, fmail);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ft = i_new(struct fts_transaction_context, 1);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen t = fbox->module_ctx.super.transaction_begin(box, flags);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen MODULE_CONTEXT_SET(t, fts_storage_module, ft);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainenstatic void fts_transaction_rollback(struct mailbox_transaction_context *t)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(t);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen fbox->module_ctx.super.transaction_rollback(t);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainenfts_transaction_commit(struct mailbox_transaction_context *t,
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen struct mail_transaction_commit_changes *changes_r)
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(t);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return fbox->module_ctx.super.transaction_commit(t, changes_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic void fts_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list);
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen if (fbox->module_ctx.super.sync_notify != NULL)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen fbox->module_ctx.super.sync_notify(box, uid, sync_type);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (uid == 0 && fbox->sync_update_ctx != NULL) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* this sync is finished */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen (void)fts_backend_update_deinit(&fbox->sync_update_ctx);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen fbox->sync_update_ctx = fts_backend_update_init(flist->backend);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen fts_backend_update_set_mailbox(fbox->sync_update_ctx, box);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen fts_backend_update_expunge(fbox->sync_update_ctx, uid);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ret = fts_build_init(flist->backend, box,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_debug("%s: FTS index is up to date", box->vname);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_debug("%s: Updating FTS index", box->vname);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen while ((ret = fts_build_more(build_ctx)) == 0) ;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int fts_sync_deinit(struct mailbox_sync_context *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen precache = (ctx->flags & MAILBOX_SYNC_FLAG_PRECACHE) != 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (fbox->module_ctx.super.sync_deinit(ctx, status_r) < 0)
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen "FTS index update for mailbox %s failed",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid fts_mailbox_allocated(struct mailbox *box)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list);
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen fbox = p_new(box->pool, struct fts_mailbox, 1);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen v->search_next_nonblock = fts_mailbox_search_next_nonblock;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen v->search_next_update_seq = fts_mailbox_search_next_update_seq;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen v->transaction_rollback = fts_transaction_rollback;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen v->transaction_commit = fts_transaction_commit;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen MODULE_CONTEXT_SET(box, fts_storage_module, fbox);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainenstatic void fts_mailbox_list_deinit(struct mailbox_list *list)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(list);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenvoid fts_mailbox_list_created(struct mailbox_list *list)
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen name = mail_user_plugin_getenv(list->ns->user, "fts");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_debug("fts: No fts setting - plugin disabled");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_debug("fts: Indexes disabled for namespace '%s'",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fts_backend_init(name, list->ns, &error, &backend) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fts: Failed to initialize backend '%s': %s",
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen flist = p_new(list->pool, struct fts_mailbox_list, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MODULE_CONTEXT_SET(list, fts_mailbox_list_module, flist);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstruct fts_backend *fts_mailbox_backend(struct mailbox *box)