mail-index-view-sync.c revision 23230b2a3fe09ed29bd1314c7b8b4a0b17ea0ecf
/* Copyright (C) 2003-2004 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "buffer.h"
#include "mail-index-view-private.h"
#include "mail-index-sync-private.h"
#include "mail-transaction-log.h"
#include "mail-transaction-util.h"
struct mail_index_view_sync_ctx {
struct mail_index_view *view;
struct mail_index_sync_map_ctx sync_map_ctx;
const struct mail_transaction_header *hdr;
const void *data;
unsigned int skipped_some:1;
unsigned int last_read:1;
unsigned int sync_map_update:1;
};
static void
{
/* Note that all the sequences are actually still UIDs at this point */
unsigned int first, i, dest_count;
/* @UNSAFE */
if (dest_count == 0) {
return;
}
/* src[] must be sorted. */
for (; i < dest_count; i++) {
break;
}
first = i;
i++;
}
/* continue previous record */
} else if (i == first) {
i++; first++;
} else {
/* use next record */
first++;
}
if (i > first) {
i = first;
}
}
}
{
int ret;
/* the view begins from the first non-synced transaction */
if (ret <= 0) {
if (ret == 0) {
/* FIXME: use the new index to get needed changes */
"Transaction log got desynced for index %s",
}
return -1;
}
return 0;
}
static int
{
const struct mail_transaction_header *hdr;
const void *data;
unsigned int count;
int ret;
return -1;
/* get a list of expunge transactions. there may be some that we have
already synced, but it doesn't matter because they'll get dropped
out when converting to sequences */
}
if (ret < 0) {
return -1;
}
/* convert UIDs to sequences */
count--;
else
dest++;
}
return 0;
}
struct mail_index_map *map)
{
/* Keep message count the same. */
/* Keep the old message flag counts also, although they may be
somewhat stale already. We just don't want them to be more than
our old messages_count. */
/* Keep log position so we know where to continue syncing */
}
#define MAIL_INDEX_VIEW_VISIBLE_FLAGS_MASK \
#define MAIL_TRANSACTION_VISIBLE_SYNC_MASK \
#ifdef DEBUG
{
const struct mail_index_record *rec;
del++;
}
recent++;
}
seen++;
else
}
}
#endif
struct mail_index_view_sync_ctx **ctx_r)
{
struct mail_index_view_sync_ctx *ctx;
struct mail_index_map *map;
/* We must sync flags as long as view is mmap()ed, as the flags may
have already changed under us. */
/* Currently we're not handling correctly expunges + no-appends case */
(sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0);
return -1;
if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0) {
/* get list of all expunges first */
return -1;
}
/* only flags, appends and expunges can be left to be synced later */
/* we want to also get non-visible changes. especially because we use
the returned skipped-flag in mail_transaction_log_view_next() to
tell us if any visible changes were skipped. */
if (array_is_created(&expunges))
return -1;
}
if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0 &&
(sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0) {
/* since we're syncing everything, the counters get fixed */
/* keep the old mapping without expunges until we're
fully synced */
} else {
/* We need a private copy of the map if we don't want to
sync expunges.
If view's map is the head map, it means that it contains
already all the latest changes and there's no need for us
to apply any changes to it. This can only happen if there
hadn't been any expunges. */
/* Using non-head mapping. We have to apply
transactions to it to get latest changes into it. */
/* Unless map was synced at the exact same position as
view, the message flags can't be reliably used to
update flag counters. note that map->hdr may contain
old information if another process updated the
index file since. */
const struct mail_index_header *hdr;
}
/* Copy only the mails that we see currently, since
we're going to append the new ones when we see
their transactions. */
#ifdef DEBUG
}
#endif
}
if (ctx->sync_map_update) {
/* Start the sync using our old view's header.
The old view->hdr may differ from map->hdr if
another view sharing the map with us had synced
itself. */
}
}
/* Syncing the view invalidates all previous looked up records.
Unreference the mappings this view keeps because of them. */
return 0;
}
{
const struct mail_index_view_log_sync_pos *syncs;
unsigned int i, count;
if (!array_is_created(sync_arr))
return FALSE;
for (i = 0; i < count; i++) {
return TRUE;
}
return FALSE;
}
static int
{
int ret;
bool skipped, synced_to_map;
for (;;) {
/* Get the next transaction from log. */
if (skipped) {
/* We skipped some (visible) transactions that were
outside our sync mask. Note that we may get here
even when ret=0. */
}
if (ret <= 0) {
if (ret < 0)
return -1;
return 0;
}
if (!ctx->skipped_some) {
/* We haven't skipped anything while syncing this view.
Update this view's synced log offset. */
}
/* skip everything we've already synced */
continue;
if (ctx->skipped_some) {
/* We've been skipping some transactions, which means
we'll go through these same transactions again
later. Since we're syncing this one, we don't want
to do it again. */
offset);
}
/* if we started from a map that we didn't create ourself,
some of the external transactions may already be synced.
at the end of view sync we'll update the ext_offset in the
header so that this check always becomes FALSE for
subsequent syncs. */
/* Apply transaction to view's mapping if needed (meaning we
didn't just re-map the view to head mapping). */
if (ctx->sync_map_update) {
MAIL_TRANSACTION_EXPUNGE) == 0);
return -1;
}
/* non-visible change that we just wanted to update
to map. */
continue;
}
/* skip changes committed by hidden transactions (eg. in IMAP
store +flags.silent command) */
continue;
break;
}
return 1;
}
#define FLAG_UPDATE_IS_INTERNAL(u) \
((((u)->add_flags | (u)->remove_flags) & \
~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0)
static int
struct mail_index_view_sync_rec *rec)
{
case MAIL_TRANSACTION_APPEND: {
/* data contains the appended records, but we don't care */
break;
}
case MAIL_TRANSACTION_EXPUNGE: {
const struct mail_transaction_expunge *exp =
/* data contains mail_transaction_expunge[] */
break;
}
case MAIL_TRANSACTION_FLAG_UPDATE: {
const struct mail_transaction_flag_update *update =
/* data contains mail_transaction_flag_update[] */
for (;;) {
if (!FLAG_UPDATE_IS_INTERNAL(update))
break;
/* skip internal flag changes */
return 0;
}
break;
}
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
/* data contains mail_transaction_keyword_update header,
the keyword name and an array of { uint32_t uid1, uid2; } */
if (ctx->data_offset == 0) {
/* skip over the header and name */
}
break;
}
case MAIL_TRANSACTION_KEYWORD_RESET: {
const struct mail_transaction_keyword_reset *reset =
/* data contains mail_transaction_keyword_reset[] */
break;
}
default:
i_unreached();
}
return 1;
}
struct mail_index_view_sync_rec *sync_rec)
{
int ret;
do {
if (ret <= 0)
return ret;
ctx->data_offset = 0;
}
return 1;
}
{
}
static void
{
const struct mail_index_view_log_sync_pos *syncs;
unsigned int i, count;
if (!array_is_created(sync_arr))
return;
if (!ctx->skipped_some) {
/* Nothing skipped. Clean it up the quick way. */
return;
}
/* Clean up until view's current syncing position */
for (i = 0; i < count; i++) {
break;
}
if (i > 0)
array_delete(sync_arr, 0, i);
}
{
/* we didn't sync everything */
}
}
if (ctx->sync_map_update) {
}
#ifdef DEBUG
if (!view->broken_counters)
#endif
/* set log view to empty range so unneeded memory gets freed */
}
{
struct mail_index_view_log_sync_pos *pos;
if (!array_is_created(sync_arr))
}
{
}
{
}