virtual-sync.c revision 4df58367179abb17eafde40a1c47f3adb2dcd1f2
/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "bsearch-insert-pos.h"
#include "ioloop.h"
#include "str.h"
#include "mail-index-modseq.h"
#include "mail-search-build.h"
#include "mailbox-search-result-private.h"
#include "index-search-result.h"
#include "virtual-storage.h"
#include <stdlib.h>
struct virtual_add_record {
struct virtual_mail_index_record rec;
};
struct virtual_sync_mail {
struct virtual_mail_index_record vrec;
};
struct virtual_sync_context {
struct virtual_mailbox *mbox;
struct mail_index_sync_ctx *index_sync_ctx;
struct mail_index *index;
struct mail_index_view *sync_view;
struct mail_index_transaction *trans;
const char *const *kw_all;
/* messages expunged within this sync */
enum mailbox_sync_flags flags;
unsigned int ext_header_changed:1;
unsigned int ext_header_rewrite:1;
unsigned int expunge_removed:1;
unsigned int retry:1;
};
{
}
struct virtual_backend_box *bbox,
{
enum mail_flags flags;
const char *const *kw_names;
struct mail_keywords *keywords;
i_panic("UID lost unexpectedly");
/* copy flags */
/* copy keywords */
}
{
return -1;
return 1;
return -1;
return 1;
/* broken */
return 0;
}
static void
{
struct mailbox_transaction_context *trans;
}
}
static void
{
struct mailbox_transaction_context *trans;
(void)mailbox_transaction_commit(&trans);
}
}
{
return -1;
return 1;
return 0;
}
{
const struct virtual_mail_index_header *ext_hdr;
const struct mail_index_header *hdr;
const struct virtual_mail_index_mailbox_record *mailboxes;
const void *ext_data;
bool ret;
/* fully refreshed */
return TRUE;
}
ext_name_offset = 0;
ext_mailbox_count = 0;
} else {
ext_name_offset = sizeof(*ext_hdr) +
if (ext_name_offset >= ext_size ||
i_error("virtual %s: Broken mailbox_count header",
ext_mailbox_count = 0;
} else {
}
}
/* update mailbox backends */
prev_mailbox_id = 0;
for (i = 0; i < ext_mailbox_count; i++) {
i_error("virtual %s: Broken mailbox id",
break;
}
i_error("virtual %s: Broken mailbox name_len",
break;
}
i_error("virtual %s: Broken mailbox list",
break;
}
T_BEGIN {
const unsigned char *nameptr;
const char *name;
} T_END;
/* mailbox no longer exists */
} else {
bbox->sync_mailbox_idx = i;
}
}
} else {
}
/* assign new mailbox IDs if any are missing */
for (i = 0; i < count; i++) {
if (bboxes[i]->mailbox_id == 0) {
}
}
/* sort the backend mailboxes by mailbox_id. */
return ret;
}
{
struct virtual_mail_index_header ext_hdr;
struct virtual_backend_box **bboxes;
const void *ext_data;
mailbox_pos = sizeof(ext_hdr);
for (i = 0; i < count; i++) {
i_assert(i == 0 ||
bboxes[i]->sync_mailbox_idx = i;
mailbox_pos += sizeof(mailbox);
}
sizeof(struct virtual_mail_index_record),
sizeof(uint32_t));
}
}
{
struct virtual_mail_index_header ext_hdr;
if (!ctx->ext_header_changed)
return;
/* we changed something - update the change counter in header */
}
const struct mail_index_sync_rec *sync_rec)
{
struct virtual_backend_box *bbox;
const struct virtual_mail_index_record *vrec;
const void *data;
enum mail_flags flags;
struct mail_keywords *keywords;
enum modify_type modify_type;
const char *kw_names[2];
bool expunged;
/* don't care */
return;
break;
}
/* already expunged, nothing to do. */
return;
}
continue;
i_panic("UID lost unexpectedly");
break;
if (flags != 0) {
MODIFY_ADD, flags);
}
if (flags != 0) {
}
break;
kw_names);
break;
kw_names);
keywords);
break;
i_unreached();
}
}
}
{
struct mail_index_sync_rec sync_rec;
}
{
const struct mail_index_header *hdr;
if (hdr->uid_validity != 0)
else
/* mark the newly seen messages as recent */
}
if (ctx->ext_header_rewrite) {
/* entire mailbox list needs to be rewritten */
} else {
/* update only changed parts in the header */
}
}
{
struct mailbox_transaction_context *trans;
struct mail_search_context *search_ctx;
struct virtual_backend_uidmap uidmap;
int ret;
/* save the result and keep it updated */
/* add the found UIDs to uidmap. virtual_uid gets assigned later. */
}
(void)mailbox_transaction_commit(&trans);
return ret;
}
{
return -1;
return 1;
return 0;
}
static void
struct virtual_backend_box *bbox,
struct mail_search_result *result)
{
const struct virtual_mail_index_record *vrec;
const void *data;
unsigned int uid_count;
bool expunged;
/* add the currently existing UIDs to uidmap. */
}
}
/* the uidmap must be sorted by real_uids */
}
static void
{
unsigned int i, count;
for (i = 0; i < count; i++) {
}
}
}
struct virtual_backend_box *bbox)
{
const enum mailbox_search_result_flags result_flags =
struct mail_search_result *result;
/* build the initial search result from the existing UIDs */
/* changes done from now on must update the sync queue */
/* get list of changed messages */
&seq, &old_msg_count))
old_msg_count = 0;
}
return -1;
}
return 0;
}
{
}
static void
struct virtual_backend_box *bbox,
{
struct virtual_backend_uidmap *uidmap;
if (uid_count == 0)
return;
/* everything in removed_uids should exist in bbox->uids */
/* find the first uidmap record to be removed */
sizeof(*uidmap),
i_unreached();
/* remove the unwanted messages */
}
&vseq))
i_unreached();
}
}
}
static void
struct virtual_backend_box *bbox,
{
struct virtual_backend_uidmap *uidmap;
struct virtual_add_record rec;
if (uid_count == 0)
return;
/* none of added_uids should exist in bbox->uids. find the position
of the first inserted index. */
/* fast path: usually messages are appended */
sizeof(*uidmap),
&dest))
i_unreached();
/* make space for all added UIDs. */
for (i = 0; i < uid_count; i++) {
}
}
}
}
struct virtual_backend_box *bbox)
{
&removed_uids, &added_uids);
/* if any of the pending removes came back, we don't want to expunge
them anymore. also since they already exist, remove them from
added_uids. */
&temp_uids);
}
}
if (!ctx->expunge_removed) {
/* delay removing messages that don't match the search
criteria, but don't delay removing expunged messages */
&ctx->sync_expunges);
&ctx->sync_expunges);
}
&removed_uids);
/* remove all current and old */
&removed_uids);
} else {
}
}
const struct mailbox_sync_rec *sync_rec,
unsigned int *idx1_r,
unsigned int *idx2_r)
{
const struct virtual_backend_uidmap *uidmap;
return FALSE;
return TRUE;
}
struct virtual_backend_box *bbox,
enum mailbox_sync_flags sync_flags)
{
struct mailbox_sync_context *sync_ctx;
const struct virtual_backend_uidmap *uidmap;
struct mailbox_sync_rec sync_rec;
if (ctx->expunge_removed) {
/* no need to keep track of expunges */
break;
}
break;
case MAILBOX_SYNC_TYPE_FLAGS:
break;
i_unreached();
}
break;
case MAILBOX_SYNC_TYPE_MODSEQ:
break;
}
}
}
struct virtual_backend_box *bbox)
{
const unsigned int uidval_pos =
struct mailbox_status status;
unsigned int mailbox_offset;
return;
/* mailbox changed - update extension header */
if (!ctx->ext_header_rewrite) {
/* we'll rewrite the entire header later */
return;
}
mailbox_offset = sizeof(struct virtual_mail_index_header) +
sizeof(mailbox) - uidval_pos);
}
struct virtual_backend_box *bbox)
{
enum mailbox_sync_flags sync_flags;
struct mailbox_status status;
int ret;
/* if we already did some changes to index, commit them before
syncing starts. */
/* we use modseqs for speeding up initial search result build.
make sure the backend has them enabled. */
/* first sync in this process */
&status) < 0)
return -1;
/* UID validity changed since last sync (or this is
the first sync), do a full search */
} else {
/* build the initial search using the saved modseq.
we can't directly update the search result because
uidmap isn't finished for all messages yet, so
mark the sync to be retried. */
}
} else {
/* sync using the existing search result */
} T_END;
}
return ret;
}
{
struct virtual_sync_mail *vmails;
struct virtual_add_record add_rec;
const struct virtual_mail_index_record *vrec;
const void *data;
bool expunged;
unsigned int j = 0, uidmap_count = 0;
/* sort the messages in current view by their backend mailbox and
real UID */
}
/* create real mailbox uid -> virtual uid mapping and expunge
messages no longer matching the search rule */
for (i = 0; i < messages; i++) {
/* add the rest of the newly seen messages */
for (; j < uidmap_count; j++) {
}
vrec->mailbox_id);
/* the entire mailbox is lost */
continue;
}
&uidmap_count);
j = 0;
}
/* if virtual record doesn't exist in uidmap, it's expunged */
for (; j < uidmap_count; j++) {
break;
/* newly seen message */
}
else {
/* exists - update uidmap and flags */
/* if ctx->retry is set, we're just opening the virtual
mailbox and using a continued search using modseq.
some messages in uidmap may already be expunged, so
we can't go looking at the real messages yet.
after retrying the sync we'll get back here and
really do it. */
}
}
}
/* if there are any mailboxes we didn't yet sync, add new messages in
them */
for (i = 0; i < count; i++) {
continue;
for (j = 0; j < uidmap_count; j++) {
}
}
}
{
return -1;
return 1;
/* if they're in same mailbox, we can order them correctly by the UID.
if they're in different mailboxes, ordering by UID doesn't really
help but it doesn't really harm either. */
return -1;
return 1;
/* two messages in different mailboxes have the same received date
and UID. */
return 0;
}
{
struct virtual_backend_box *bbox;
struct virtual_add_record *adds;
const struct virtual_mail_index_record *vrec;
unsigned int i, count;
/* get all messages' received dates */
vrec->mailbox_id);
}
i_unreached();
&adds[i].received_date) < 0) {
/* probably expunged already, just add it somewhere */
adds[i].received_date = 0;
}
}
}
{
struct virtual_add_record *adds;
struct virtual_backend_box *bbox;
struct virtual_backend_uidmap *uidmap;
const struct virtual_mail_index_record *vrec;
if (count == 0)
return;
/* all messages are from a single mailbox. add them in
the same order. */
} else {
/* sort new messages by received date to get the add order */
}
vrec->mailbox_id);
}
}
/* assign UIDs to new messages */
/* update virtual UIDs in uidmap */
vrec->mailbox_id);
}
sizeof(*uidmap),
&idx))
i_unreached();
}
}
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
for (i = 0; i < count; i++) {
/* backend failed, copy the error */
return -1;
}
}
/* initial sync: assign virtual UIDs to existing messages and
sync all flags */
}
return 0;
}
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
for (i = 0; i < count; i++)
}
{
if (success) {
ret = -1;
}
} else {
}
return ret;
}
enum mailbox_sync_flags flags)
{
struct virtual_sync_context *ctx;
int ret;
/* Removed messages are expunged when
a) EXPUNGE is used
b) Mailbox is being opened (FIX_INCONSISTENT is set) */
if (ret <= 0) {
if (ret < 0)
return ret;
}
if (!virtual_sync_ext_header_read(ctx))
/* apply changes from virtual index to backend mailboxes */
/* update list of UIDs in backend mailboxes */
}
if (ret < 0)
}
struct mailbox_sync_context *
{
int ret = 0;
}