dovecot-1.2: Added non-optimized support for SEARCH INTHREAD.
dovecot at dovecot.org
dovecot at dovecot.org
Fri Jun 20 05:37:41 EEST 2008
details: http://hg.dovecot.org/dovecot-1.2/rev/bf9c51edbc66
changeset: 7909:bf9c51edbc66
user: Timo Sirainen <tss at iki.fi>
date: Fri Jun 20 05:37:30 2008 +0300
description:
Added non-optimized support for SEARCH INTHREAD.
diffstat:
4 files changed, 241 insertions(+), 5 deletions(-)
src/lib-storage/index/index-search.c | 103 ++++++++++++++++++++++++++++++++
src/lib-storage/mail-search-build.c | 25 +++++++
src/lib-storage/mail-search.c | 109 +++++++++++++++++++++++++++++++++-
src/lib-storage/mail-search.h | 9 ++
diffs (truncated from 381 to 300 lines):
diff -r 1e69c84a1e5a -r bf9c51edbc66 src/lib-storage/index/index-search.c
--- 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 @@ struct index_search_context {
uint32_t seq1, seq2;
struct mail *mail;
struct index_mail *imail;
+ struct mail_thread_context *thread_ctx;
const char *error;
@@ -77,6 +78,7 @@ static void search_init_arg(struct mail_
ctx->have_seqsets = TRUE;
break;
case SEARCH_UIDSET:
+ case SEARCH_INTHREAD:
case SEARCH_FLAGS:
case SEARCH_KEYWORDS:
case SEARCH_MODSEQ:
@@ -140,6 +142,7 @@ static int search_arg_match_index(struct
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 void search_get_seqset(struct ind
}
}
+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 @@ index_storage_search_init(struct mailbox
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 @@ int index_storage_search_deinit(struct m
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 @@ static bool search_arg_is_static(struct
case SEARCH_FLAGS:
case SEARCH_KEYWORDS:
case SEARCH_MODSEQ:
+ case SEARCH_INTHREAD:
break;
case SEARCH_ALL:
case SEARCH_UIDSET:
diff -r 1e69c84a1e5a -r bf9c51edbc66 src/lib-storage/mail-search-build.c
--- 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 @@ static bool search_arg_build(struct sear
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);
diff -r 1e69c84a1e5a -r bf9c51edbc66 src/lib-storage/mail-search.c
--- 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 @@ mail_search_args_init_sub(struct mail_se
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 @@ mail_search_args_init_sub(struct mail_se
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 @@ static void mail_search_args_deinit_sub(
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 @@ static void mail_search_args_seq2uid_sub
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 @@ mail_search_args_simplify_sub(struct mai
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 @@ mail_search_args_simplify_sub(struct mai
}
}
+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;
More information about the dovecot-cvs
mailing list