Mercurial > dovecot > original-hg > dovecot-1.2
changeset 7909:bf9c51edbc66 HEAD
Added non-optimized support for SEARCH INTHREAD.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 20 Jun 2008 05:37:30 +0300 |
parents | 1e69c84a1e5a |
children | c1bbdc2b262e |
files | src/lib-storage/index/index-search.c src/lib-storage/mail-search-build.c src/lib-storage/mail-search.c src/lib-storage/mail-search.h |
diffstat | 4 files changed, 240 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/index-search.c Fri Jun 20 05:35:05 2008 +0300 +++ b/src/lib-storage/index/index-search.c Fri Jun 20 05:37:30 2008 +0300 @@ -34,6 +34,7 @@ uint32_t seq1, seq2; struct mail *mail; struct index_mail *imail; + struct mail_thread_context *thread_ctx; const char *error; @@ -77,6 +78,7 @@ ctx->have_seqsets = TRUE; break; case SEARCH_UIDSET: + case SEARCH_INTHREAD: case SEARCH_FLAGS: case SEARCH_KEYWORDS: case SEARCH_MODSEQ: @@ -140,6 +142,7 @@ switch (arg->type) { case SEARCH_UIDSET: + case SEARCH_INTHREAD: return seq_range_exists(&arg->value.seqset, rec->uid); case SEARCH_FLAGS: /* recent flag shouldn't be set, but indexes from v1.0.x @@ -858,6 +861,96 @@ } } +static int search_build_subthread(struct mail_thread_iterate_context *iter, + ARRAY_TYPE(seq_range) *uids) +{ + struct mail_thread_iterate_context *child_iter; + const struct mail_thread_child_node *node; + int ret = 0; + + while ((node = mail_thread_iterate_next(iter, &child_iter)) != NULL) { + if (child_iter != NULL) { + if (search_build_subthread(child_iter, uids) < 0) + ret = -1; + } + seq_range_array_add(uids, 0, node->uid); + } + if (mail_thread_iterate_deinit(&iter) < 0) + ret = -1; + return ret; +} + +static int search_build_inthread_result(struct index_search_context *ctx, + struct mail_search_arg *arg) +{ + struct mail_thread_iterate_context *iter, *child_iter; + const struct mail_thread_child_node *node; + const ARRAY_TYPE(seq_range) *search_uids; + ARRAY_TYPE(seq_range) thread_uids; + int ret; + + p_array_init(&arg->value.seqset, ctx->mail_ctx.args->pool, 64); + if (mailbox_search_result_build(ctx->mail_ctx.transaction, + arg->value.search_args, + MAILBOX_SEARCH_RESULT_FLAG_UPDATE | + MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC, + &arg->value.search_result) < 0) + return -1; + if (ctx->thread_ctx == NULL) { + /* failed earlier */ + return -1; + } + + search_uids = mailbox_search_result_get(arg->value.search_result); + if (array_count(search_uids) == 0) { + /* search found nothing - no threads can match */ + return 0; + } + + t_array_init(&thread_uids, 128); + iter = mail_thread_iterate_init(ctx->thread_ctx, + arg->value.thread_type, FALSE); + while ((node = mail_thread_iterate_next(iter, &child_iter)) != NULL) { + seq_range_array_add(&thread_uids, 0, node->uid); + if (child_iter != NULL) { + if (search_build_subthread(child_iter, + &thread_uids) < 0) + ret = -1; + } + if (seq_range_array_have_common(&thread_uids, search_uids)) { + /* yes, we want this thread */ + seq_range_array_merge(&arg->value.seqset, &thread_uids); + } + array_clear(&thread_uids); + } + if (mail_thread_iterate_deinit(&iter) < 0) + ret = -1; + return ret; +} + +static int search_build_inthreads(struct index_search_context *ctx, + struct mail_search_arg *arg) +{ + int ret = 0; + + for (; arg != NULL; arg = arg->next) { + switch (arg->type) { + case SEARCH_OR: + case SEARCH_SUB: + if (search_build_inthreads(ctx, arg->value.subargs) < 0) + ret = -1; + break; + case SEARCH_INTHREAD: + if (search_build_inthread_result(ctx, arg) < 0) + ret = -1; + break; + default: + break; + } + } + return ret; +} + struct mail_search_context * index_storage_search_init(struct mailbox_transaction_context *_t, struct mail_search_args *args, @@ -879,6 +972,13 @@ sizeof(void *), 5); mail_search_args_reset(ctx->mail_ctx.args->args, TRUE); + if (args->have_inthreads) { + if (mail_thread_init(_t->box, FALSE, NULL, + &ctx->thread_ctx) < 0) + ctx->failed = TRUE; + if (search_build_inthreads(ctx, args->args) < 0) + ctx->failed = TRUE; + } search_get_seqset(ctx, args->args); (void)mail_search_args_foreach(args->args, search_init_arg, ctx); @@ -917,6 +1017,8 @@ if (ctx->mail_ctx.sort_program != NULL) index_sort_program_deinit(&ctx->mail_ctx.sort_program); + if (ctx->thread_ctx != NULL) + mail_thread_deinit(&ctx->thread_ctx); array_free(&ctx->mail_ctx.results); array_free(&ctx->mail_ctx.module_contexts); i_free(ctx); @@ -1001,6 +1103,7 @@ case SEARCH_FLAGS: case SEARCH_KEYWORDS: case SEARCH_MODSEQ: + case SEARCH_INTHREAD: break; case SEARCH_ALL: case SEARCH_UIDSET:
--- a/src/lib-storage/mail-search-build.c Fri Jun 20 05:35:05 2008 +0300 +++ b/src/lib-storage/mail-search-build.c Fri Jun 20 05:37:30 2008 +0300 @@ -374,6 +374,31 @@ return ARG_NEW_HEADER(SEARCH_HEADER, key); } break; + case 'I': + if (strcmp(str, "INTHREAD") == 0) { + /* <algorithm> <search key> */ + enum mail_thread_type thread_type; + const char *str; + + if ((*args)->type != IMAP_ARG_ATOM) { + data->error = "Invalid parameter for INTHREAD"; + return FALSE; + } + + str = IMAP_ARG_STR_NONULL(*args); + if (!mail_thread_type_parse(str, &thread_type)) { + data->error = "Unknown thread algorithm"; + return FALSE; + } + *args += 1; + + *next_sarg = search_arg_new(data->pool, + SEARCH_INTHREAD); + (*next_sarg)->value.thread_type = thread_type; + subargs = &(*next_sarg)->value.subargs; + return search_arg_build(data, args, subargs); + } + break; case 'K': if (strcmp(str, "KEYWORD") == 0) { return ARG_NEW_STR(SEARCH_KEYWORDS);
--- a/src/lib-storage/mail-search.c Fri Jun 20 05:35:05 2008 +0300 +++ b/src/lib-storage/mail-search.c Fri Jun 20 05:37:30 2008 +0300 @@ -61,6 +61,7 @@ bool change_uidsets, const ARRAY_TYPE(seq_range) *search_saved_uidset) { + struct mail_search_args *thread_args; const char *keywords[2]; for (; arg != NULL; arg = arg->next) { @@ -85,6 +86,23 @@ keywords); break; + case SEARCH_INTHREAD: + thread_args = arg->value.search_args; + if (thread_args == NULL) { + arg->value.search_args = thread_args = + p_new(args->pool, + struct mail_search_args, 1); + thread_args->pool = args->pool; + thread_args->args = arg->value.subargs; + thread_args->charset = args->charset; + thread_args->simplified = TRUE; + /* simplification should have unnested all + inthreads, so we'll assume that + have_inthreads=FALSE */ + } + thread_args->refcount++; + thread_args->box = args->box; + /* fall through */ case SEARCH_SUB: case SEARCH_OR: mail_search_args_init_sub(args, arg->value.subargs, @@ -124,6 +142,16 @@ break; mailbox_keywords_free(args->box, &arg->value.keywords); break; + case SEARCH_INTHREAD: + i_assert(arg->value.search_args->refcount > 0); + arg->value.search_args->refcount--; + arg->value.search_args->box = NULL; + if (args->refcount == 0 && + arg->value.search_result != NULL) { + mailbox_search_result_free( + &arg->value.search_result); + } + /* fall through */ case SEARCH_SUB: case SEARCH_OR: mail_search_args_deinit_sub(args, arg->value.subargs); @@ -164,6 +192,7 @@ break; case SEARCH_SUB: case SEARCH_OR: + case SEARCH_INTHREAD: mail_search_args_seq2uid_sub(args, arg->value.subargs, uids); break; @@ -445,9 +474,11 @@ continue; } - if (args->type == SEARCH_SUB || args->type == SEARCH_OR) { + if (args->type == SEARCH_SUB || + args->type == SEARCH_OR || + args->type == SEARCH_INTHREAD) { mail_search_args_simplify_sub(args->value.subargs, - args->type == SEARCH_SUB); + args->type != SEARCH_OR); } /* merge all flags arguments */ @@ -507,8 +538,80 @@ } } +static bool +mail_search_args_unnest_inthreads(struct mail_search_args *args, + struct mail_search_arg **argp, + bool parent_inthreads, bool parent_and) +{ + struct mail_search_arg *arg, *thread_arg, *or_arg; + bool child_inthreads = FALSE, non_inthreads = FALSE; + + for (arg = *argp; arg != NULL; arg = arg->next) { + switch (arg->type) { + case SEARCH_SUB: + case SEARCH_OR: + if (!mail_search_args_unnest_inthreads(args, + &arg->value.subargs, parent_inthreads, + arg->type != SEARCH_OR)) { + arg->result = 1; + child_inthreads = TRUE; + } else { + arg->result = 0; + non_inthreads = TRUE; + } + break; + case SEARCH_INTHREAD: + if (mail_search_args_unnest_inthreads(args, + &arg->value.subargs, TRUE, TRUE)) { + /* children converted to SEARCH_INTHREADs */ + arg->type = SEARCH_SUB; + } + args->have_inthreads = TRUE; + arg->result = 1; + child_inthreads = TRUE; + break; + default: + arg->result = 0; + non_inthreads = TRUE; + break; + } + } + + if (!parent_inthreads || !child_inthreads || !non_inthreads) + return FALSE; + + /* put all non-INTHREADs under a single INTHREAD */ + thread_arg = p_new(args->pool, struct mail_search_arg, 1); + thread_arg->type = SEARCH_INTHREAD; + + while (*argp != NULL) { + arg = *argp; + argp = &(*argp)->next; + + if (arg->result == 0) { + /* not an INTHREAD or a SUB/OR with only INTHREADs */ + arg->next = thread_arg->value.subargs; + thread_arg->value.subargs = arg; + } + } + if (!parent_and) { + /* We want to OR the args */ + or_arg = p_new(args->pool, struct mail_search_arg, 1); + or_arg->type = SEARCH_OR; + or_arg->value.subargs = thread_arg->value.subargs; + thread_arg->value.subargs = or_arg; + } + return TRUE; +} + void mail_search_args_simplify(struct mail_search_args *args) { args->simplified = TRUE; + mail_search_args_simplify_sub(args->args, TRUE); + if (mail_search_args_unnest_inthreads(args, &args->args, + FALSE, TRUE)) { + /* we may have added some extra SUBs that could be dropped */ + mail_search_args_simplify_sub(args->args, TRUE); + } }
--- a/src/lib-storage/mail-search.h Fri Jun 20 05:35:05 2008 +0300 +++ b/src/lib-storage/mail-search.h Fri Jun 20 05:37:30 2008 +0300 @@ -3,6 +3,7 @@ #include "seq-range-array.h" #include "mail-types.h" +#include "mail-thread.h" enum mail_search_arg_type { SEARCH_OR, @@ -41,7 +42,8 @@ SEARCH_TEXT_FAST, /* extensions */ - SEARCH_MODSEQ + SEARCH_MODSEQ, + SEARCH_INTHREAD }; enum mail_search_arg_flag { @@ -72,9 +74,12 @@ time_t time; uoff_t size; enum mail_flags flags; + enum mail_search_arg_flag search_flags; + enum mail_thread_type thread_type; struct mail_keywords *keywords; struct mail_search_modseq *modseq; - enum mail_search_arg_flag search_flags; + struct mail_search_args *search_args; + struct mail_search_result *search_result; } value; void *context;