virtual-search.c revision 03010dbaa74ec70f062994dfe3cd39bedc99a28b
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (c) 2008-2013 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen#include "lib.h"
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-search.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "index-search-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "virtual-storage.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <stdlib.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenenum virtual_search_state {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen VIRTUAL_SEARCH_STATE_BUILD,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen VIRTUAL_SEARCH_STATE_RETURN,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen VIRTUAL_SEARCH_STATE_SORT,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen VIRTUAL_SEARCH_STATE_SORT_DONE
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct virtual_search_record {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t mailbox_id;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t real_uid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t virtual_seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct virtual_search_context {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen union mail_search_module_context module_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ARRAY_TYPE(seq_range) result;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct seq_range_iter result_iter;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ARRAY(struct virtual_search_record) records;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen enum virtual_search_state search_state;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen unsigned int next_result_n;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int next_record_idx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int virtual_search_record_cmp(const struct virtual_search_record *r1,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const struct virtual_search_record *r2)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (r1->mailbox_id < r2->mailbox_id)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (r1->mailbox_id > r2->mailbox_id)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (r1->real_uid < r2->real_uid)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (r1->real_uid > r2->real_uid)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int mail_search_get_result(struct mail_search_context *ctx)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const struct mail_search_arg *arg;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen int ret = 1;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen for (arg = ctx->args->args; arg != NULL; arg = arg->next) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (arg->result < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen if (arg->result == 0)
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen ret = 0;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen }
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void virtual_search_get_records(struct mail_search_context *ctx,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct virtual_search_context *vctx)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct virtual_mailbox *mbox =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (struct virtual_mailbox *)ctx->transaction->box;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen const struct virtual_mail_index_record *vrec;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct virtual_search_record srec;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const void *data;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen int result;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memset(&srec, 0, sizeof(srec));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen while (index_storage_search_next_update_seq(ctx)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen result = mail_search_get_result(ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(result != 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (result > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* full match, no need to check this any further */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen seq_range_array_add(&vctx->result, ctx->seq);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* possible match, save and check later */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mail_index_lookup_ext(mbox->box.view, ctx->seq,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mbox->virtual_ext_id,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen &data, NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen vrec = data;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen srec.mailbox_id = vrec->mailbox_id;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen srec.real_uid = vrec->real_uid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen srec.virtual_seq = ctx->seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_append(&vctx->records, &srec, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_search_args_reset(ctx->args->args, FALSE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_sort(&vctx->records, virtual_search_record_cmp);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->progress_max = array_count(&vctx->records);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct mail_search_context *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvirtual_search_init(struct mailbox_transaction_context *t,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_search_args *args,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const enum mail_sort_type *sort_program,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen enum mail_fetch_field wanted_fields,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_search_context *ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct virtual_search_context *vctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx = index_storage_search_init(t, args, sort_program,
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen wanted_fields, wanted_headers);
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen vctx = i_new(struct virtual_search_context, 1);
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_BUILD;
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen i_array_init(&vctx->result, 64);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_array_init(&vctx->records, 64);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen MODULE_CONTEXT_SET(ctx, virtual_storage_module, vctx);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen virtual_search_get_records(ctx, vctx);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen seq_range_array_iter_init(&vctx->result_iter, &vctx->result);
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen return ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint virtual_search_deinit(struct mail_search_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct virtual_search_context *vctx = VIRTUAL_CONTEXT(ctx);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen array_free(&vctx->result);
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen array_free(&vctx->records);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_free(vctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return index_storage_search_deinit(ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool virtual_search_next_nonblock(struct mail_search_context *ctx,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct mail **mail_r, bool *tryagain_r)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct virtual_search_context *vctx = VIRTUAL_CONTEXT(ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct index_search_context *ictx = (struct index_search_context *)ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen uint32_t seq;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen switch (vctx->search_state) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case VIRTUAL_SEARCH_STATE_BUILD:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->sort_program == NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_SORT;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_RETURN;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return virtual_search_next_nonblock(ctx, mail_r, tryagain_r);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case VIRTUAL_SEARCH_STATE_RETURN:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return index_storage_search_next_nonblock(ctx, mail_r, tryagain_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen case VIRTUAL_SEARCH_STATE_SORT:
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen /* the messages won't be returned sorted, so we'll have to
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen do it ourself */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen while (index_storage_search_next_nonblock(ctx, mail_r, tryagain_r))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen seq_range_array_add(&vctx->result, (*mail_r)->seq);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (*tryagain_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen vctx->next_result_n = 0;
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_SORT_DONE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* fall through */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen case VIRTUAL_SEARCH_STATE_SORT_DONE:
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen *tryagain_r = FALSE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (!seq_range_array_iter_nth(&vctx->result_iter,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen vctx->next_result_n, &seq))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen vctx->next_result_n++;
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen *mail_r = index_search_get_mail(ictx);
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen i_assert(*mail_r != NULL);
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen mail_set_seq(*mail_r, seq);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_unreached();
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void search_args_set_full_match(struct mail_search_arg *args)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (; args != NULL; args = args->next)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen args->result = 1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenbool virtual_search_next_update_seq(struct mail_search_context *ctx)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct virtual_search_context *vctx = VIRTUAL_CONTEXT(ctx);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const struct virtual_search_record *recs;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int count;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen recs = array_get(&vctx->records, &count);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (vctx->next_record_idx < count) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* go through potential results first */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->seq = recs[vctx->next_record_idx++].virtual_seq - 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!index_storage_search_next_update_seq(ctx))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_unreached();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->progress_cur = vctx->next_record_idx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ctx->sort_program != NULL &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen seq_range_array_iter_nth(&vctx->result_iter,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen vctx->next_result_n, &ctx->seq)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* this is known to match fully */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen search_args_set_full_match(ctx->args->args);
6449bd276af37b3e0b81a9c47ecd01f39a2cba53Timo Sirainen vctx->next_result_n++;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}