fts-storage.c revision ff01c351d308504551048039304725d578978c2e
/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "str.h"
#include "istream.h"
#include "message-parser.h"
#include "message-decoder.h"
#include "mail-namespace.h"
#include "mail-search-build.h"
#include "mail-storage-private.h"
#include "fts-api-private.h"
#include "fts-storage.h"
#include "fts-plugin.h"
#include <stdlib.h>
#define FTS_CONTEXT(obj) \
#define FTS_MAIL_CONTEXT(obj) \
#define FTS_SEARCH_NONBLOCK_COUNT 50
#define FTS_BUILD_NOTIFY_INTERVAL_SECS 10
struct fts_mail {
union mail_module_context module_ctx;
char score[30];
};
struct fts_storage_build_context {
struct mail_search_context *search_ctx;
struct mail_search_args *search_args;
struct fts_backend_build_context *build;
};
struct fts_transaction_context {
struct fts_storage_build_context *build_ctx;
unsigned int free_mail:1;
unsigned int expunges:1;
};
{
int ret;
return ret;
}
{
return 0;
return -1;
return 0;
}
{
MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0;
}
const struct message_block *block)
{
/* hdr->full_value is always set because we get the block from
message_decoder */
if (!hdr->no_newline)
}
{
struct message_parser_ctx *parser;
struct message_decoder_context *decoder;
int ret;
return -1;
0);
for (;;) {
if (ret < 0) {
if (input->stream_errno == 0)
ret = 0;
break;
}
/* skipping this body */
continue;
}
&block))
continue;
/* end of headers */
} else {
FALSE) < 0) {
ret = -1;
break;
}
}
}
if (ret == 0) {
/* Index all headers at the end. This is required for Squat,
because it can handle only incremental UIDs. */
}
return ret;
}
struct fts_backend *backend,
struct mailbox_transaction_context *t,
{
struct mail_search_args *search_args;
struct fts_storage_build_context *ctx;
struct fts_backend_build_context *build;
/* we're not updating the index just for header lookups */
return 0;
}
return -1;
/* changed, need to get again the sequences */
if (seq1 == 0) {
/* no new messages */
(void)fts_backend_build_deinit(&build);
return 0;
}
}
return 1;
}
static struct fts_backend *
{
return fbox->backend_fast;
else {
return fbox->backend_substr;
}
}
struct mailbox_transaction_context *t)
{
struct fts_backend *backend;
int ret;
return -1;
if (seq1 == 0) {
/* no new messages */
return 0;
}
return ret < 0 ? -1 : 0;
}
static int
{
struct fts_backend *backend;
if (seq1 == 0)
return 0;
}
{
int ret;
T_BEGIN {
} T_END;
return ret;
}
{
}
{
struct mailbox_status status;
const struct fts_orig_mailboxes *boxes;
const struct fts_backend_uid_map *last_uids;
const char *vname;
return 0;
if (ret == 0) {
/* match. check also that uidvalidity matches. */
&status);
uidi++;
continue;
}
boxi++;
uidi++;
} else if (ret > 0) {
/* not part of this virtual mailbox */
uidi++;
} else {
/* no messages indexed in the mailbox */
boxi++;
}
}
boxi++;
}
return vret;
}
static const char *
{
/* ugly workaround to allow selecting INBOX from a Maildir/
when it's not in the inbox=yes namespace. */
return "INBOX";
}
return name;
}
{
struct fts_backend_uid_map *last_uids;
struct fts_orig_mailboxes *orig_boxes;
struct fts_orig_mailboxes orig_box;
unsigned int i, box_count, last_uid_count;
int ret;
for (i = 0; i < box_count; i++) {
}
if (box_count <= 0) {
if (box_count == 0) {
/* empty virtual mailbox */
return 0;
}
/* virtual mailbox is built from only a single mailbox
(currently). check that directly. */
return ret;
}
/* virtual mailbox is built from multiple mailboxes. figure out which
ones need updating. */
return -1;
}
return ret < 0 ? -1 : 0;
}
{
struct mailbox_status status;
int ret;
&status);
/* no new messages since last check */
return 0;
}
else
/* index was up-to-date */
}
return ret;
}
{
struct mailbox_status status;
int ret = 0;
ret = -1;
ret = -1;
if (ret == 0) {
&status);
}
/* we notified at least once */
}
return ret;
}
{
float percentage;
/* set the search time in here, in case a plugin
already spent some time indexing the mailbox */
T_BEGIN {
const char *text;
"ETA %d:%02d", (int)percentage,
} T_END;
}
}
{
unsigned int count = 0;
int ret;
T_BEGIN {
} T_END;
if (ret < 0)
return -1;
if (++count == FTS_SEARCH_NONBLOCK_COUNT)
return 0;
}
return 1;
}
struct fts_search_context *fctx)
{
}
ctx->progress_cur = 0;
}
struct fts_search_context *fctx)
{
return TRUE;
}
/* this process is already building the indexes */
return FALSE;
}
if (fts_build_init(fctx) < 0) {
return TRUE;
}
/* the index was up to date */
} else {
/* hide "searching" notifications */
}
return TRUE;
}
static struct mail_search_context *
struct mail_search_args *args,
const enum mail_sort_type *sort_program)
{
struct mail_search_context *ctx;
struct fts_search_context *fctx;
fctx->t = t;
return ctx;
return ctx;
}
{
int ret;
if (!fctx->build_initialized) {
/* we're still waiting for this process (but another command)
to finish building the indexes */
*tryagain_r = TRUE;
return 0;
}
}
/* this command is still building the indexes */
if (ret == 0) {
*tryagain_r = TRUE;
return 0;
}
/* finished / error */
ret = -1;
if (ret > 0) {
if (fts_build_init_virtual_next(fctx) == 0) {
/* all finished */
}
}
}
/* if we're here, the indexes are either built or they're not used */
}
static void
{
struct mail_search_arg *arg;
case SEARCH_TEXT:
case SEARCH_BODY:
/* we're marking only fast args */
break;
}
case SEARCH_BODY_FAST:
case SEARCH_TEXT_FAST:
break;
default:
break;
}
}
}
{
struct mailbox_status status;
}
{
unsigned int def_count, maybe_count;
/* fts_search_lookup() was called successfully */
for (;;) {
&def_count);
&maybe_count);
/* if we're ahead of current positions, skip them */
fctx->definite_idx++;
/* look for the non-indexed mails */
return FALSE;
return search_nonindexed(ctx);
}
} else {
}
if (use_maybe)
else
/* current sequence is already larger than where
range begins, so use the current sequence. */
} else {
}
/* ctx->seq points to previous sequence we want */
break;
}
if (!use_maybe) {
/* we have definite results, update args */
}
/* this is a virtual mailbox and we're searching headers.
some mailboxes had more messages indexed than others.
to avoid duplicates or jumping around, ignore the rest of
the search results and just go through the messages in
order. */
return search_nonindexed(ctx);
}
return ret;
}
static bool
{
return TRUE;
/* virtual mailbox searches don't return sequences sorted.
just check if the suggested sequence exists. */
return TRUE;
}
return TRUE;
}
return FALSE;
}
{
/* the search was cancelled */
}
}
{
}
{
}
const char **value_r)
{
const struct fts_score_map *scores;
unsigned int count;
else {
}
return 0;
}
}
static struct mail *
fts_mail_alloc(struct mailbox_transaction_context *t,
struct mailbox_header_lookup_ctx *wanted_headers)
{
struct mail_private *mail;
}
return _mail;
}
{
struct fts_backend *backend;
const char *const *tmp;
continue;
FTS_BACKEND_FLAG_SUBSTRING_LOOKUPS) != 0) {
i_fatal("fts: duplicate substring backend: %s",
*tmp);
}
} else {
i_fatal("fts: duplicate fast backend: %s",
*tmp);
}
}
}
i_info("fts: No backends enabled by the fts setting");
}
static struct mailbox_transaction_context *
{
struct mailbox_transaction_context *t;
struct fts_transaction_context *ft;
/* the backend creation is delayed until the first transaction is
started. at that point the mailbox has been synced at least once. */
if (!fbox->backend_set) {
}
return t;
}
static void
{
}
static void
bool committed)
{
}
}
}
static void fts_transaction_rollback(struct mailbox_transaction_context *t)
{
}
}
static int fts_transaction_commit(struct mailbox_transaction_context *t,
{
int ret;
}
return ret;
}
{
struct fts_mailbox *fbox;
}
{
const char *env;
if (fts_next_hook_mailbox_opened != NULL)
}