void fts_mailbox_allocated(struct mailbox *box) { struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list); struct mailbox_vfuncs *v = box->vlast; struct fts_mailbox *fbox; if (flist == NULL) return; fbox = p_new(box->pool, struct fts_mailbox, 1); fbox->module_ctx.super = *v; box->vlast = &fbox->module_ctx.super; v->get_status = fts_mailbox_get_status; v->search_init = fts_mailbox_search_init; v->search_next_nonblock = fts_mailbox_search_next_nonblock; v->search_next_update_seq = fts_mailbox_search_next_update_seq; v->search_deinit = fts_mailbox_search_deinit; v->transaction_begin = fts_transaction_begin; v->transaction_rollback = fts_transaction_rollback; v->transaction_commit = fts_transaction_commit; v->sync_notify = fts_mailbox_sync_notify; v->sync_deinit = fts_sync_deinit; v->save_finish = fts_save_finish; v->copy = fts_copy; MODULE_CONTEXT_SET(box, fts_storage_module, fbox); }
static void fts_mailbox_list_deinit(struct mailbox_list *list) { struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(list); fts_backend_deinit(&flist->backend); flist->module_ctx.super.deinit(list); }
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); struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list); bool optimize; int ret = 0; optimize = (ctx->flags & (MAILBOX_SYNC_FLAG_FORCE_RESYNC | MAILBOX_SYNC_FLAG_OPTIMIZE)) != 0; if (fbox->module_ctx.super.sync_deinit(ctx, status_r) < 0) return -1; ctx = NULL; if (optimize) { if (fts_backend_optimize(flist->backend) < 0) { mail_storage_set_critical(box->storage, "FTS optimize for mailbox %s failed", box->vname); ret = -1; } } return ret; }
static void fts_mailbox_sync_notify(struct mailbox *box, uint32_t uid, enum mailbox_sync_type sync_type) { struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list); struct fts_mailbox *fbox = FTS_CONTEXT(box); if (fbox->module_ctx.super.sync_notify != NULL) fbox->module_ctx.super.sync_notify(box, uid, sync_type); if (sync_type != MAILBOX_SYNC_TYPE_EXPUNGE) { if (uid == 0 && fbox->sync_update_ctx != NULL) { /* this sync is finished */ (void)fts_backend_update_deinit(&fbox->sync_update_ctx); } return; } if (fbox->sync_update_ctx == NULL) { if (fts_backend_is_updating(flist->backend)) { /* FIXME: maildir workaround - we could get here because we're building an index, which doesn't find some mail and starts syncing the mailbox.. */ return; } fbox->sync_update_ctx = fts_backend_update_init(flist->backend); fts_backend_update_set_mailbox(fbox->sync_update_ctx, box); } fts_backend_update_expunge(fbox->sync_update_ctx, uid); }
static int fts_transaction_end(struct mailbox_transaction_context *t, const char **error_r) { struct fts_transaction_context *ft = FTS_CONTEXT(t); struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(t->box->list); int ret = ft->failed ? -1 : 0; if (ft->failed) *error_r = "transaction context"; if (ft->precached) { i_assert(flist->update_ctx_refcount > 0); if (--flist->update_ctx_refcount == 0) { if (fts_backend_update_deinit(&flist->update_ctx) < 0) { ret = -1; *error_r = "backend deinit"; } } } else if (ft->highest_virtual_uid > 0) { if (fts_index_set_last_uid(t->box, ft->highest_virtual_uid) < 0) { ret = -1; *error_r = "index last uid setting"; } } if (ft->scores != NULL) fts_scores_unref(&ft->scores); i_free(ft); return ret; }
static struct mail_search_context * fts_mailbox_search_init(struct mailbox_transaction_context *t, struct mail_search_args *args, const enum mail_sort_type *sort_program, enum mail_fetch_field wanted_fields, struct mailbox_header_lookup_ctx *wanted_headers) { struct fts_transaction_context *ft = FTS_CONTEXT(t); struct fts_mailbox *fbox = FTS_CONTEXT(t->box); struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(t->box->list); struct mail_search_context *ctx; struct fts_search_context *fctx; ctx = fbox->module_ctx.super.search_init(t, args, sort_program, wanted_fields, wanted_headers); if (!fts_backend_can_lookup(flist->backend, args->args)) return ctx; fctx = i_new(struct fts_search_context, 1); fctx->box = t->box; fctx->backend = flist->backend; fctx->t = t; fctx->args = args; fctx->result_pool = pool_alloconly_create("fts results", 1024*64); fctx->orig_matches = buffer_create_dynamic(default_pool, 64); fctx->virtual_mailbox = strcmp(t->box->storage->name, VIRTUAL_STORAGE_NAME) == 0; fctx->enforced = mail_user_plugin_getenv(t->box->storage->user, "fts_enforced") != NULL; i_array_init(&fctx->levels, 8); fctx->scores = i_new(struct fts_scores, 1); fctx->scores->refcount = 1; i_array_init(&fctx->scores->score_map, 64); MODULE_CONTEXT_SET(ctx, fts_storage_module, fctx); /* FIXME: we'll assume that all the args are fuzzy. not good, but would require much more work to fix it. */ if (!fts_args_have_fuzzy(args->args) && mail_user_plugin_getenv(t->box->storage->user, "fts_no_autofuzzy") != NULL) fctx->flags |= FTS_LOOKUP_FLAG_NO_AUTO_FUZZY; /* transaction contains the last search's scores. they can be queried later with mail_get_special() */ if (ft->scores != NULL) fts_scores_unref(&ft->scores); ft->scores = fctx->scores; ft->scores->refcount++; if (fctx->enforced || fts_want_build_args(args->args)) fts_try_build_init(ctx, fctx); else fts_search_lookup(fctx); return ctx; }
static int fts_mail_precache_init(struct mail *_mail) { struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction); struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(_mail->box->list); uint32_t last_seq; if (fts_mailbox_get_last_cached_seq(_mail->box, &last_seq) < 0) return -1; ft->precached = TRUE; ft->next_index_seq = last_seq + 1; if (flist->update_ctx == NULL) flist->update_ctx = fts_backend_update_init(flist->backend); flist->update_ctx_refcount++; return 0; }
static int fts_mailbox_get_last_cached_seq(struct mailbox *box, uint32_t *seq_r) { struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list); uint32_t seq1, seq2, last_uid; if (fts_backend_get_last_uid(flist->backend, box, &last_uid) < 0) { mail_storage_set_internal_error(box->storage); return -1; } if (last_uid == 0) *seq_r = 0; else { mailbox_get_seq_range(box, 1, last_uid, &seq1, &seq2); *seq_r = seq2; } return 0; }
static void fts_mail_index(struct mail *_mail) { struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction); struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(_mail->box->list); if (ft->failed) return; if (!ft->precached) { if (fts_mail_precache_init(_mail) < 0) { ft->failed = TRUE; return; } } if (ft->next_index_seq < _mail->seq) { /* most likely a virtual mailbox. we'll first need to index all mails up to the current one. */ fts_backend_update_set_mailbox(flist->update_ctx, _mail->box); if (fts_mail_precache_range(_mail->transaction, flist->update_ctx, ft->next_index_seq, _mail->seq-1) < 0) { ft->failed = TRUE; return; } } if (ft->next_index_seq == _mail->seq) { fts_backend_update_set_mailbox(flist->update_ctx, _mail->box); if (fts_build_mail(flist->update_ctx, _mail) < 0) { mail_storage_set_internal_error(_mail->box->storage); ft->failed = TRUE; } ft->next_index_seq = _mail->seq + 1; } }
struct fts_backend *fts_list_backend(struct mailbox_list *list) { struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(list); return flist == NULL ? NULL : flist->backend; }
struct fts_backend *fts_mailbox_backend(struct mailbox *box) { struct fts_mailbox_list *flist = FTS_LIST_CONTEXT(box->list); return flist->backend; }