mail-index-view-sync.c revision 1103e7320af882c2c649841612b99b4502cb82a2
/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "buffer.h"
#include "mail-index-view-private.h"
#include "mail-index-sync-private.h"
#include "mail-index-modseq.h"
#include "mail-transaction-log.h"
struct mail_index_view_sync_ctx {
struct mail_index_view *view;
struct mail_index_sync_map_ctx sync_map_ctx;
/* After syncing view, map is replaced with sync_new_map. */
struct mail_index_map *sync_new_map;
unsigned int finish_min_msg_count;
const struct mail_transaction_header *hdr;
const void *data;
unsigned int failed:1;
unsigned int sync_map_update:1;
unsigned int skipped_expunges:1;
unsigned int last_read:1;
unsigned int hidden:1;
};
static int
{
/* Note that all the sequences are actually still UIDs at this point */
unsigned int first, i, dest_count;
/* @UNSAFE */
if (dest_count == 0) {
return 0;
}
/* src[] must be sorted. */
return -1;
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;
}
}
return 0;
}
static int
bool *reset_r)
{
int ret;
for (;;) {
/* the view begins from the first non-synced transaction */
reset_r);
if (ret <= 0) {
if (ret < 0)
return -1;
/* FIXME: use the new index to get needed
changes */
"Transaction log got desynced for index %s",
return -1;
}
if (!*reset_r || sync_expunges)
break;
/* we can't do this. sync only up to reset. */
&end_seq, &end_offset);
/* we have only this reset log */
break;
}
}
return 0;
}
static int
unsigned int *expunge_count_r)
{
const struct mail_transaction_header *hdr;
const void *data;
unsigned int count, expunge_count = 0;
int ret;
/* 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 */
continue;
/* this is simply a request for expunge */
continue;
}
"Corrupted expunge record");
ret = -1;
break;
}
}
if (ret < 0) {
return -1;
}
/* convert UIDs to sequences */
count--;
else {
dest++;
}
}
return 0;
}
{
return TRUE;
}
return FALSE;
}
{
const struct mail_transaction_header *hdr;
const void *data;
bool have_expunges = FALSE;
int ret;
continue;
/* this is simply a request for expunge */
continue;
}
/* we have an expunge. see if it still exists. */
break;
}
}
/* handle failures as having expunges (which is safer).
we'll probably fail later. */
return ret < 0 || have_expunges;
}
{
bool reset;
/* replace the view's map */
/* update log positions */
return -1;
return 0;
}
struct mail_index_view_sync_ctx *
{
struct mail_index_view_sync_ctx *ctx;
struct mail_index_map *map;
unsigned int expunge_count = 0;
/* Syncing the view invalidates all previous looked up records.
Unreference the mappings this view keeps because of them. */
if ((flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) != 0) {
/* just get this view synced - don't return anything */
if (mail_index_view_sync_init_fix(ctx) < 0)
return ctx;
}
if (mail_index_view_is_inconsistent(view)) {
return ctx;
}
return ctx;
}
if (sync_expunges) {
/* get list of all expunges first */
&expunge_count) < 0) {
return ctx;
}
have_expunges = expunge_count > 0;
} else {
}
"%s reset, view is now inconsistent",
}
if (!have_expunges) {
/* no expunges, we can just replace the map */
"Index %s lost messages without expunging "
ctx->finish_min_msg_count = 0;
}
} else {
/* expunges seen. create a private map which we update.
if we're syncing expunges the map will finally be replaced
with the head map to remove the expunged messages. */
} else {
}
if (sync_expunges) {
}
}
#ifdef DEBUG
#endif
return ctx;
}
static bool
{
const struct mail_index_view_log_sync_area *syncs;
unsigned int i, count;
return FALSE;
for (i = 0; i < count; i++) {
return TRUE;
}
return FALSE;
}
static bool
const struct mail_transaction_header *hdr)
{
if (!ctx->skipped_expunges) {
}
return FALSE;
}
/* already synced */
return FALSE;
}
}
view->log_file_head_offset)) {
/* already synced */
return FALSE;
}
return TRUE;
}
static int
{
const struct mail_transaction_header *hdr;
int ret;
bool synced_to_map;
do {
/* Get the next transaction from log. */
if (ret <= 0) {
if (ret < 0)
return -1;
return 0;
}
/* skip records we've already synced */
/* If we started from a map that we didn't create ourself,
some of the transactions may already be synced. at the end
of this view sync we'll update file_seq=0 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). */
} T_END;
if (ret < 0)
return -1;
}
return 1;
}
static bool
struct mail_index_view_sync_rec *rec)
{
case MAIL_TRANSACTION_FLAG_UPDATE: {
const struct mail_transaction_flag_update *update =
/* data contains mail_transaction_flag_update[] */
for (;;) {
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:
return FALSE;
}
return TRUE;
}
struct mail_index_view_sync_rec *sync_rec)
{
int ret;
do {
if (ret <= 0) {
if (ret < 0)
return FALSE;
}
ctx->data_offset = 0;
}
return TRUE;
}
{
}
static void
{
const struct mail_index_view_log_sync_area *syncs;
unsigned int i, count;
return;
/* Clean up to view's tail */
for (i = 0; i < count; i++) {
if ((syncs[i].log_file_offset +
break;
}
if (i > 0)
}
bool *delayed_expunges_r)
{
/* we didn't sync everything */
ret = -1;
}
}
if (!ctx->skipped_expunges) {
}
if (ctx->sync_map_update) {
/* log offsets have no meaning in views. make sure they're not
tried to be used wrong by setting them to zero. */
}
#ifdef DEBUG
#endif
/* set log view to empty range so unneeded memory gets freed */
return ret;
}
unsigned int length)
{
struct mail_index_view_log_sync_area *area;
}