static void fts_transaction_rollback(struct mailbox_transaction_context *t) { struct fts_mailbox *fbox = FTS_CONTEXT(t->box); (void)fts_transaction_end(t); fbox->module_ctx.super.transaction_rollback(t); }
static bool fts_mailbox_build_continue(struct mail_search_context *ctx) { struct fts_search_context *fctx = FTS_CONTEXT(ctx); int ret; ret = fts_indexer_more(fctx->indexer_ctx); if (ret == 0) return FALSE; /* indexing finished */ ctx->progress_hidden = FALSE; if (fts_indexer_deinit(&fctx->indexer_ctx) < 0) ret = -1; if (ret > 0) fts_search_lookup(fctx); if (ret < 0) { /* if indexing timed out, it probably means that the mailbox is still being indexed, but it's a large mailbox and it takes a while. in this situation we'll simply abort the search. if indexing failed for any other reason, just fallback to searching the slow way. */ fctx->indexing_timed_out = mailbox_get_last_mail_error(fctx->box) == MAIL_ERROR_INUSE; } return TRUE; }
static int fts_mail_get_special(struct mail *_mail, enum mail_fetch_field field, const char **value_r) { struct mail_private *mail = (struct mail_private *)_mail; struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail); struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction); const struct fts_score_map *scores; if (field != MAIL_FETCH_SEARCH_RELEVANCY || ft->scores == NULL) scores = NULL; else { scores = array_bsearch(&ft->scores->score_map, &_mail->uid, fts_score_cmp); } if (scores != NULL) { i_assert(scores->uid == _mail->uid); (void)i_snprintf(fmail->score, sizeof(fmail->score), "%f", scores->score); *value_r = fmail->score; return 0; } return fmail->module_ctx.super.get_special(_mail, field, value_r); }
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 mailbox_transaction_context * fts_transaction_begin(struct mailbox *box, enum mailbox_transaction_flags flags) { struct fts_mailbox *fbox = FTS_CONTEXT(box); struct mailbox_transaction_context *t; struct fts_transaction_context *ft; ft = i_new(struct fts_transaction_context, 1); t = fbox->module_ctx.super.transaction_begin(box, flags); MODULE_CONTEXT_SET(t, fts_storage_module, ft); return t; }
static void fts_mail_precache(struct mail *_mail) { struct mail_private *mail = (struct mail_private *)_mail; struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail); struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction); fmail->module_ctx.super.precache(_mail); if (fmail->virtual_mail) { if (ft->highest_virtual_uid < _mail->uid) ft->highest_virtual_uid = _mail->uid; } else T_BEGIN { fts_mail_index(_mail); } T_END; }
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; }
void fts_mail_allocated(struct mail *_mail) { struct mail_private *mail = (struct mail_private *)_mail; struct mail_vfuncs *v = mail->vlast; struct fts_mailbox *fbox = FTS_CONTEXT(_mail->box); struct fts_mail *fmail; if (fbox == NULL) return; fmail = p_new(mail->pool, struct fts_mail, 1); fmail->module_ctx.super = *v; mail->vlast = &fmail->module_ctx.super; fmail->virtual_mail = _mail->box->virtual_vfuncs != NULL; v->get_special = fts_mail_get_special; v->precache = fts_mail_precache; MODULE_CONTEXT_SET(mail, fts_mail_module, fmail); }
static int fts_mailbox_get_status(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status_r) { struct fts_mailbox *fbox = FTS_CONTEXT(box); uint32_t seq; if (fbox->module_ctx.super.get_status(box, items, status_r) < 0) return -1; if ((items & STATUS_LAST_CACHED_SEQ) != 0) { if (fts_mailbox_get_last_cached_seq(box, &seq) < 0) return -1; /* use whichever is smaller */ if (status_r->last_cached_seq > seq) status_r->last_cached_seq = seq; } 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; } }
static void fts_search_apply_results_level(struct mail_search_context *ctx, struct mail_search_arg *args, unsigned int *idx) { struct fts_search_context *fctx = FTS_CONTEXT(ctx); const struct fts_search_level *level; level = array_idx(&fctx->levels, *idx); if (array_is_created(&level->definite_seqs) && seq_range_exists(&level->definite_seqs, ctx->seq)) fts_search_deserialize_add_matches(args, level->args_matches); else if (!array_is_created(&level->maybe_seqs) || !seq_range_exists(&level->maybe_seqs, ctx->seq)) fts_search_deserialize_add_nonmatches(args, level->args_matches); for (; args != NULL; args = args->next) { if (args->type != SEARCH_OR && args->type != SEARCH_SUB) continue; *idx += 1; fts_search_apply_results_level(ctx, args->value.subargs, idx); } }