Mercurial > dovecot > original-hg > dovecot-1.2
changeset 6903:a8d3513b54c5 HEAD
Added missing files.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 03 Dec 2007 10:23:06 +0200 |
parents | cff5428c3c4d |
children | 275d22eb25ba |
files | src/plugins/fts/fts-search.c src/plugins/fts/fts-storage.h |
diffstat | 2 files changed, 233 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/fts/fts-search.c Mon Dec 03 10:23:06 2007 +0200 @@ -0,0 +1,195 @@ +/* Copyright (c) 2006-2007 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "seq-range-array.h" +#include "mail-search.h" +#include "mail-storage-private.h" +#include "fts-api-private.h" +#include "fts-storage.h" + +static void +uid_range_to_seqs(struct mailbox *box, const ARRAY_TYPE(seq_range) *uid_range, + ARRAY_TYPE(seq_range) *seq_range) +{ + const struct seq_range *range; + struct seq_range new_range; + unsigned int i, count; + + range = array_get(uid_range, &count); + i_array_init(seq_range, count); + for (i = 0; i < count; i++) { + mailbox_get_uids(box, range[i].seq1, range[i].seq2, + &new_range.seq1, &new_range.seq2); + if (new_range.seq1 != 0) + array_append(seq_range, &new_range, 1); + } +} + +static void fts_uid_results_to_seq(struct fts_search_context *fctx) +{ + ARRAY_TYPE(seq_range) uid_range; + + uid_range = fctx->definite_seqs; + i_array_init(&fctx->definite_seqs, array_count(&uid_range)); + uid_range_to_seqs(fctx->t->box, &uid_range, &fctx->definite_seqs); + array_free(&uid_range); + + uid_range = fctx->maybe_seqs; + i_array_init(&fctx->maybe_seqs, array_count(&uid_range)); + uid_range_to_seqs(fctx->t->box, &uid_range, &fctx->maybe_seqs); + array_free(&uid_range); +} + +static int fts_search_lookup_arg(struct fts_search_context *fctx, + struct mail_search_arg *arg, bool filter) +{ + struct fts_backend *backend; + enum fts_lookup_flags flags = 0; + const char *key; + + switch (arg->type) { + case SEARCH_HEADER: + /* we can filter out messages that don't have the header, + but we can't trust definite results list. */ + flags = FTS_LOOKUP_FLAG_HEADER; + backend = fctx->fbox->backend_substr; + key = arg->value.str; + if (*key == '\0') { + /* we're only checking the existence + of the header. */ + key = arg->hdr_field_name; + } + break; + case SEARCH_TEXT: + case SEARCH_TEXT_FAST: + flags = FTS_LOOKUP_FLAG_HEADER; + case SEARCH_BODY: + case SEARCH_BODY_FAST: + flags |= FTS_LOOKUP_FLAG_BODY; + key = arg->value.str; + backend = fctx->fbox->backend_fast != NULL && + (arg->type == SEARCH_TEXT_FAST || + arg->type == SEARCH_BODY_FAST) ? + fctx->fbox->backend_fast : fctx->fbox->backend_substr; + break; + default: + /* can't filter this */ + i_assert(filter); + return 0; + } + if (arg->not) + flags |= FTS_LOOKUP_FLAG_INVERT; + + if (!backend->locked) { + if (fts_backend_lock(backend) <= 0) + return -1; + } + + if (!filter) { + return fts_backend_lookup(backend, key, flags, + &fctx->definite_seqs, + &fctx->maybe_seqs); + } else { + return fts_backend_filter(backend, key, flags, + &fctx->definite_seqs, + &fctx->maybe_seqs); + } +} + +void fts_search_lookup(struct fts_search_context *fctx) +{ + struct mail_search_arg *arg; + int ret; + + if (fctx->best_arg == NULL) + return; + + i_array_init(&fctx->definite_seqs, 64); + i_array_init(&fctx->maybe_seqs, 64); + + /* start filtering with the best arg */ + ret = fts_search_lookup_arg(fctx, fctx->best_arg, FALSE); + /* filter the rest */ + for (arg = fctx->args; arg != NULL && ret == 0; arg = arg->next) { + if (arg != fctx->best_arg) + ret = fts_search_lookup_arg(fctx, arg, TRUE); + } + + if (fctx->fbox->backend_fast != NULL && + fctx->fbox->backend_fast->locked) + fts_backend_unlock(fctx->fbox->backend_fast); + if (fctx->fbox->backend_substr != NULL && + fctx->fbox->backend_substr->locked) + fts_backend_unlock(fctx->fbox->backend_substr); + + if (ret == 0) { + fctx->seqs_set = TRUE; + fts_uid_results_to_seq(fctx); + } +} + +static bool arg_is_better(const struct mail_search_arg *new_arg, + const struct mail_search_arg *old_arg) +{ + if (old_arg == NULL) + return TRUE; + if (new_arg == NULL) + return FALSE; + + /* avoid NOTs */ + if (old_arg->not && !new_arg->not) + return TRUE; + if (!old_arg->not && new_arg->not) + return FALSE; + + /* prefer not to use headers. they have a larger possibility of + having lots of identical strings */ + if (old_arg->type == SEARCH_HEADER) + return TRUE; + else if (new_arg->type == SEARCH_HEADER) + return FALSE; + + return strlen(new_arg->value.str) > strlen(old_arg->value.str); +} + +static void +fts_search_args_find_best(struct mail_search_arg *args, + struct mail_search_arg **best_fast_arg, + struct mail_search_arg **best_substr_arg) +{ + for (; args != NULL; args = args->next) { + switch (args->type) { + case SEARCH_BODY_FAST: + case SEARCH_TEXT_FAST: + if (arg_is_better(args, *best_fast_arg)) + *best_fast_arg = args; + break; + case SEARCH_BODY: + case SEARCH_TEXT: + case SEARCH_HEADER: + if (arg_is_better(args, *best_substr_arg)) + *best_substr_arg = args; + break; + default: + break; + } + } +} + +void fts_search_analyze(struct fts_search_context *fctx) +{ + struct mail_search_arg *best_fast_arg = NULL, *best_substr_arg = NULL; + + fts_search_args_find_best(fctx->args, &best_fast_arg, &best_substr_arg); + + if (best_fast_arg != NULL && fctx->fbox->backend_fast != NULL) { + /* use fast backend whenever possible */ + fctx->best_arg = best_fast_arg; + fctx->build_backend = fctx->fbox->backend_fast; + } else if (best_fast_arg != NULL || best_substr_arg != NULL) { + fctx->build_backend = fctx->fbox->backend_substr; + fctx->best_arg = arg_is_better(best_substr_arg, best_fast_arg) ? + best_substr_arg : best_fast_arg; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/fts/fts-storage.h Mon Dec 03 10:23:06 2007 +0200 @@ -0,0 +1,38 @@ +#ifndef FTS_STORAGE_H +#define FTS_STORAGE_H + +struct fts_mailbox { + union mailbox_module_context module_ctx; + struct fts_backend *backend_substr; + struct fts_backend *backend_fast; + + const char *env; + unsigned int backend_set:1; +}; + +struct fts_search_context { + union mail_search_module_context module_ctx; + + struct fts_mailbox *fbox; + struct mailbox_transaction_context *t; + struct mail_search_arg *args; + struct mail_search_arg *best_arg; + + ARRAY_TYPE(seq_range) definite_seqs, maybe_seqs; + unsigned int definite_idx, maybe_idx; + uint32_t first_nonindexed_seq; + + struct fts_backend *build_backend; + struct fts_storage_build_context *build_ctx; + + unsigned int build_initialized:1; + unsigned int seqs_set:1; +}; + +/* Figure out if we want to use full text search indexes and update + backends in fctx accordingly. */ +void fts_search_analyze(struct fts_search_context *fctx); +/* Perform the actual index lookup and update definite_uids and maybe_uids. */ +void fts_search_lookup(struct fts_search_context *fctx); + +#endif