Mercurial > dovecot > core-2.2
changeset 1844:4c2678dd65f1 HEAD
Some optimizations to messageset handling in search.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 26 Oct 2003 21:41:09 +0200 |
parents | 03f4b7b2641d |
children | bd8b6ed35327 |
files | src/lib-storage/index/index-messageset.c src/lib-storage/index/index-messageset.h src/lib-storage/index/index-search.c src/lib-storage/mail-search.c src/lib-storage/mail-search.h |
diffstat | 5 files changed, 145 insertions(+), 63 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/index-messageset.c Sun Oct 26 21:39:58 2003 +0200 +++ b/src/lib-storage/index/index-messageset.c Sun Oct 26 21:41:09 2003 +0200 @@ -17,6 +17,7 @@ struct messageset_mail mail; unsigned int messages_count; unsigned int num1, num2; + unsigned int min_uid, max_uid; const char *messageset, *p; int uidset, skip_expunged; @@ -44,6 +45,9 @@ ctx->uidset = uidset; ctx->skip_expunged = skip_expunged; + ctx->min_uid = 1; + ctx->max_uid = (unsigned int)-1; + /* Reset index errors, we rely on it to check for failures */ index_reset_error(ctx->index); @@ -67,6 +71,13 @@ return ctx; } +void index_messageset_limit_range(struct messageset_context *ctx, + unsigned int min_uid, unsigned int max_uid) +{ + ctx->min_uid = min_uid; + ctx->max_uid = max_uid; +} + int index_messageset_deinit(struct messageset_context *ctx) { int ret = ctx->ret; @@ -220,6 +231,14 @@ ctx->num2 = temp; } } + i_assert(ctx->num1 <= ctx->num2); + + if (ctx->num1 < ctx->min_uid) + ctx->num1 = ctx->min_uid; + if (ctx->num2 > ctx->max_uid) + ctx->num2 = ctx->max_uid; + if (ctx->num1 > ctx->num2) + return 1; /* get list of expunged messages in our range. */ ctx->expunges = mail_modifylog_uid_get_expunges(ctx->index->modifylog, @@ -269,13 +288,24 @@ /* get the first non-expunged message. note that if all messages were expunged in the range, this points outside wanted range. */ ctx->mail.idx_seq = ctx->num1 - expunges_before; + ctx->mail.client_seq = ctx->num1; ctx->mail.rec = ctx->index->lookup(ctx->index, ctx->mail.idx_seq); + while (ctx->mail.rec != NULL && ctx->mail.rec->uid < ctx->min_uid) { + ctx->mail.idx_seq++; + ctx->mail.client_seq++; + ctx->mail.rec = ctx->index->next(ctx->index, ctx->mail.rec); + } + + if (ctx->mail.rec != NULL && ctx->mail.rec->uid > ctx->max_uid) { + ctx->mail.rec = NULL; + return 1; + } + if (ctx->mail.rec == NULL) { return ctx->index->get_last_error(ctx->index) == MAIL_INDEX_ERROR_NONE ? 1 : -1; } - ctx->mail.client_seq = ctx->num1; return 0; }
--- a/src/lib-storage/index/index-messageset.h Sun Oct 26 21:39:58 2003 +0200 +++ b/src/lib-storage/index/index-messageset.h Sun Oct 26 21:41:09 2003 +0200 @@ -19,6 +19,9 @@ index_messageset_init_range(struct index_mailbox *ibox, unsigned int num1, unsigned int num2, int uidset); +void index_messageset_limit_range(struct messageset_context *ctx, + unsigned int min_uid, unsigned int max_uid); + /* Returns 1 if all were found, 0 if some messages were expunged, -1 if internal error occured or -2 if messageset was invalid. */ int index_messageset_deinit(struct messageset_context *ctx);
--- a/src/lib-storage/index/index-search.c Sun Oct 26 21:39:58 2003 +0200 +++ b/src/lib-storage/index/index-search.c Sun Oct 26 21:41:09 2003 +0200 @@ -611,21 +611,32 @@ return TRUE; } -static int search_get_sequid(struct index_mailbox *ibox, - const struct mail_search_arg *args, - unsigned int *first_seq, unsigned int *last_seq, - unsigned int *first_uid, unsigned int *last_uid) +struct search_msgset_context { + struct index_mailbox *ibox; + + unsigned int first_seq, last_seq; + unsigned int first_uid, last_uid; + + struct mail_search_arg *msgset_arg; + unsigned int msgset_arg_count; +}; + +static int search_parse_msgset_args(struct search_msgset_context *ctx, + struct mail_search_arg *args) { + struct index_mailbox *ibox = ctx->ibox; + for (; args != NULL; args = args->next) { /* FIXME: we don't check if OR condition can limit the range. It's a bit tricky and unlikely to affect performance much. */ if (args->type == SEARCH_SUB) { - if (!search_get_sequid(ibox, args->value.subargs, - first_seq, last_seq, - first_uid, last_uid)) + if (!search_parse_msgset_args(ctx, args->value.subargs)) return FALSE; } else if (args->type == SEARCH_SET) { - if (!seq_update(args->value.str, first_seq, last_seq, + ctx->msgset_arg = args; + ctx->msgset_arg_count++; + if (!seq_update(args->value.str, + &ctx->first_seq, &ctx->last_seq, ibox->synced_messages_count)) { mail_storage_set_syntax_error(ibox->box.storage, "Invalid messageset: %s", @@ -633,7 +644,10 @@ return FALSE; } } else if (args->type == SEARCH_UID) { - if (!seq_update(args->value.str, first_uid, last_uid, + ctx->msgset_arg = args; + ctx->msgset_arg_count++; + if (!seq_update(args->value.str, + &ctx->first_uid, &ctx->last_uid, ibox->index->header->next_uid-1)) { mail_storage_set_syntax_error(ibox->box.storage, "Invalid messageset: %s", @@ -642,8 +656,9 @@ } } else if (args->type == SEARCH_ALL) { /* go through everything */ - *first_seq = 1; - *last_seq = ibox->synced_messages_count; + ctx->first_seq = 1; + ctx->last_seq = ibox->synced_messages_count; + ctx->msgset_arg_count++; return TRUE; } } @@ -652,7 +667,7 @@ } static int search_limit_by_flags(struct index_mailbox *ibox, - const struct mail_search_arg *args, + struct mail_search_arg *args, unsigned int *first_uid, unsigned int *last_uid) { @@ -666,15 +681,19 @@ if (!args->not && hdr->seen_messages_count == 0) return FALSE; - /* UNSEEN with all seen? */ - if (args->not && - hdr->seen_messages_count == hdr->messages_count) - return FALSE; + if (hdr->seen_messages_count == hdr->messages_count) { + /* UNSEEN with all seen? */ + if (args->not) + return FALSE; - /* UNSEEN with lowwater limiting */ - uid = hdr->first_unseen_uid_lowwater; - if (args->not && *first_uid < uid) - *first_uid = uid; + /* SEEN with all seen */ + args->match_always = TRUE; + } else { + /* UNSEEN with lowwater limiting */ + uid = hdr->first_unseen_uid_lowwater; + if (args->not && *first_uid < uid) + *first_uid = uid; + } } if (args->type == SEARCH_DELETED) { @@ -682,15 +701,20 @@ if (!args->not && hdr->deleted_messages_count == 0) return FALSE; - /* UNDELETED with all deleted? */ - if (args->not && - hdr->deleted_messages_count == hdr->messages_count) - return FALSE; + if (hdr->deleted_messages_count == + hdr->messages_count) { + /* UNDELETED with all deleted? */ + if (args->not) + return FALSE; - /* DELETED with lowwater limiting */ - uid = hdr->first_deleted_uid_lowwater; - if (!args->not && *first_uid < uid) - *first_uid = uid; + /* DELETED with all deleted */ + args->match_always = TRUE; + } else { + /* DELETED with lowwater limiting */ + uid = hdr->first_deleted_uid_lowwater; + if (!args->not && *first_uid < uid) + *first_uid = uid; + } } if (args->type == SEARCH_RECENT) { @@ -728,53 +752,67 @@ return TRUE; } -static int search_get_uid_range(struct index_mailbox *ibox, - const struct mail_search_arg *args, - unsigned int *first_uid, unsigned int *last_uid) +static int search_get_msgset(struct index_mailbox *ibox, + struct mail_search_arg *args, + struct messageset_context **msgset_r) { - unsigned int first_seq, last_seq, uid; + struct search_msgset_context ctx; + unsigned int uid; - *first_uid = *last_uid = 0; - first_seq = last_seq = 0; + memset(&ctx, 0, sizeof(ctx)); + ctx.ibox = ibox; - if (!search_get_sequid(ibox, args, &first_seq, &last_seq, - first_uid, last_uid)) + if (!search_parse_msgset_args(&ctx, args)) return -1; /* seq_update() should make sure that these can't happen */ - i_assert(first_seq <= last_seq); - i_assert(*first_uid <= *last_uid); + i_assert(ctx.first_seq <= ctx.last_seq); + i_assert(ctx.first_uid <= ctx.last_uid); - if (first_seq > 1) { - if (!client_seq_to_uid(ibox, first_seq, &uid)) + if (ctx.first_seq > 1) { + if (!client_seq_to_uid(ibox, ctx.first_seq, &uid)) return -1; if (uid == 0) return 0; - if (*first_uid == 0 || uid < *first_uid) - *first_uid = uid; + if (ctx.first_uid == 0 || uid < ctx.first_uid) + ctx.first_uid = uid; } - if (last_seq > 1 && last_seq != ibox->synced_messages_count) { - if (!client_seq_to_uid(ibox, last_seq, &uid)) + if (ctx.last_seq > 1 && ctx.last_seq != ibox->synced_messages_count) { + if (!client_seq_to_uid(ibox, ctx.last_seq, &uid)) return -1; if (uid == 0) return 0; - if (*last_uid == 0 || uid > *last_uid) - *last_uid = uid; + if (ctx.last_uid == 0 || uid > ctx.last_uid) + ctx.last_uid = uid; } - if (*first_uid == 0) - *first_uid = 1; - if (*last_uid == 0 || last_seq == ibox->synced_messages_count) - *last_uid = ibox->index->header->next_uid-1; + if (ctx.first_uid == 0) + ctx.first_uid = 1; + if (ctx.last_uid == 0 || ctx.last_seq == ibox->synced_messages_count) + ctx.last_uid = ibox->index->header->next_uid-1; /* UNSEEN and DELETED in root search level may limit the range */ - if (!search_limit_by_flags(ibox, args, first_uid, last_uid)) + if (!search_limit_by_flags(ibox, args, &ctx.first_uid, &ctx.last_uid)) return 0; - i_assert(*first_uid <= *last_uid); + i_assert(ctx.first_uid <= ctx.last_uid); + + if (ctx.msgset_arg != NULL && ctx.msgset_arg_count == 1) { + /* one messageset argument, we can use it */ + *msgset_r = index_messageset_init(ibox, + ctx.msgset_arg->value.str, + ctx.msgset_arg->type == SEARCH_UID, TRUE); + /* we might be able to limit it some more */ + index_messageset_limit_range(*msgset_r, + ctx.first_uid, ctx.last_uid); + ctx.msgset_arg->match_always = TRUE; + } else { + *msgset_r = index_messageset_init_range(ibox, ctx.first_uid, + ctx.last_uid, TRUE); + } return 1; } @@ -795,7 +833,6 @@ { struct index_mailbox *ibox = (struct index_mailbox *) box; struct mail_search_context *ctx; - unsigned int first_uid, last_uid; if (sort_program != NULL && *sort_program != MAIL_SORT_END) { i_error("BUG: index_storage_search_init(): " @@ -817,8 +854,10 @@ if (ibox->synced_messages_count == 0) return ctx; + mail_search_args_reset(ctx->args, TRUE); + /* see if we can limit the records we look at */ - switch (search_get_uid_range(ibox, args, &first_uid, &last_uid)) { + switch (search_get_msgset(ibox, args, &ctx->msgset_ctx)) { case -1: /* error */ ctx->failed = TRUE; @@ -828,8 +867,6 @@ return ctx; } - ctx->msgset_ctx = - index_messageset_init_range(ibox, first_uid, last_uid, TRUE); return ctx; } @@ -870,7 +907,7 @@ int ret; /* check the index matches first */ - mail_search_args_reset(ctx->args); + mail_search_args_reset(ctx->args, FALSE); ret = mail_search_args_foreach(ctx->args, search_index_arg, ctx); if (ret >= 0) return ret > 0;
--- a/src/lib-storage/mail-search.c Sun Oct 26 21:39:58 2003 +0200 +++ b/src/lib-storage/mail-search.c Sun Oct 26 21:41:09 2003 +0200 @@ -4,12 +4,22 @@ #include "buffer.h" #include "mail-search.h" -void mail_search_args_reset(struct mail_search_arg *args) +void mail_search_args_reset(struct mail_search_arg *args, int full_reset) { while (args != NULL) { if (args->type == SEARCH_OR || args->type == SEARCH_SUB) - mail_search_args_reset(args->value.subargs); - args->result = -1; + mail_search_args_reset(args->value.subargs, full_reset); + + if (!args->match_always) + args->result = -1; + else { + if (!full_reset) + args->result = 1; + else { + args->match_always = FALSE; + args->result = -1; + } + } args = args->next; }
--- a/src/lib-storage/mail-search.h Sun Oct 26 21:39:58 2003 +0200 +++ b/src/lib-storage/mail-search.h Sun Oct 26 21:41:09 2003 +0200 @@ -52,6 +52,7 @@ void *context; const char *hdr_field_name; /* for SEARCH_HEADER* */ unsigned int not:1; + unsigned int match_always:1; /* result = 1 always */ int result; /* -1 = unknown, 0 = unmatched, 1 = matched */ }; @@ -65,8 +66,9 @@ typedef void (*mail_search_foreach_callback_t)(struct mail_search_arg *arg, void *context); -/* Reset the results in search arguments */ -void mail_search_args_reset(struct mail_search_arg *args); +/* Reset the results in search arguments. match_always is reset only if + full_reset is TRUE. */ +void mail_search_args_reset(struct mail_search_arg *args, int full_reset); /* goes through arguments in list that don't have a result yet. Returns 1 = search matched, 0 = search unmatched, -1 = don't know yet */