fts-storage.c revision af3f857bb3166ed99595e11a9d18e5b5cc670e1a
/* Copyright (c) 2006-2008 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 10
#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_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;
}
{
struct fts_backend_uid_map *last_uids;
unsigned int box_count, last_uid_count;
int ret;
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. */
mailbox_transaction_begin(boxes[0], 0);
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;
}
{
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 */
}
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;
(void)fts_try_build_init(fctx);
return ctx;
}
{
int ret;
if (!fctx->build_initialized) {
/* we're still waiting for this process (but another command)
to finish building the indexes */
if (!fts_try_build_init(fctx)) {
*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:
case SEARCH_BODY_FAST:
case SEARCH_TEXT_FAST:
break;
default:
break;
}
}
}
{
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 fts_mailbox_search_next_update_seq(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 fts_mailbox_search_next_update_seq(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)
}