mail-index-sync.c revision a8c5a86d183db25a57bf193c06b41e092ec2e151
/* Copyright (c) 2003-2014 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "mail-index-view-private.h"
#include "mail-index-sync-private.h"
#include "mail-index-transaction-private.h"
#include "mail-transaction-log-private.h"
#include "mail-cache.h"
#include <stdio.h>
#include <stdlib.h>
struct mail_index_sync_ctx {
struct mail_index *index;
struct mail_index_view *view;
enum mail_index_sync_flags flags;
const struct mail_transaction_header *hdr;
const void *data;
};
{
for (i = 0; i < size; i++) {
}
}
{
for (i = 0; i < size; i++) {
e[i].guid_128);
}
}
{
for (i = 0; i < size; i++) {
if (u[i].add_flags != 0) {
u[i].add_flags);
}
if (u[i].remove_flags != 0) {
u[i].remove_flags);
}
}
}
{
const char *keyword_names[2];
struct mail_keywords *keywords;
uidset_offset = sizeof(*u) + u->name_size;
if ((uidset_offset % 4) != 0)
for (i = 0; i < size; i += 2) {
/* FIXME: mail_index_update_keywords_range() */
u->modify_type, keywords);
}
}
}
{
struct mail_keywords *keywords;
for (i = 0; i < size; i++) {
}
}
}
{
case MAIL_TRANSACTION_EXPUNGE:
break;
break;
break;
break;
break;
default:
return FALSE;
}
return TRUE;
}
{
struct mail_transaction_flag_update update;
const struct mail_index_record *rec;
continue;
}
}
static void
{
}
static int
{
struct mail_index_sync_list *synclist;
const struct mail_index_transaction_keyword_update *keyword_updates;
unsigned int i, keyword_count;
int ret;
/* show dirty flags as flag updates */
}
/* read all transactions from log into a transaction in memory.
skip the external ones, they're already synced to mailbox and
included in our view */
continue;
T_BEGIN {
} T_END;
}
/* create an array containing all expunge, flag and keyword update
arrays so we can easily go through all of the changes. */
}
}
for (i = 0; i < keyword_count; i++) {
(const void *)&keyword_updates[i].add_seq;
synclist->keyword_idx = i;
}
(const void *)&keyword_updates[i].remove_seq;
synclist->keyword_idx = i;
}
}
return ret;
}
static bool
{
if ((flags & MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES) == 0)
return TRUE;
/* sync only if there's something to do */
(flags & MAIL_INDEX_SYNC_FLAG_DROP_RECENT) != 0)
return TRUE;
(flags & MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY) != 0)
return TRUE;
/* we want to sync up to transaction log's head */
}
return TRUE;
if (index->need_recreate)
return TRUE;
/* already synced */
}
static int
{
bool reset;
int ret;
if (ret < 0)
return -1;
if (ret == 0) {
/* either corrupted or the file was deleted for
some reason. either way, we can't go forward */
"Unexpected transaction log desync with index %s",
return 0;
}
return 1;
}
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
enum mail_index_sync_flags flags)
{
int ret;
(flags & MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES) != 0);
return ret;
}
static int
enum mail_index_sync_flags flags,
{
const struct mail_index_header *hdr;
int ret;
/* if we require changes, don't lock transaction log yet. first check
if there's anything to sync. */
if ((flags & MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES) == 0) {
return -1;
}
/* The view must contain what we expect the mailbox to look like
currently. That allows the backend to update external flag
changes (etc.) if the view doesn't match the mailbox.
We'll update the view to contain everything that exist in the
transaction log except for expunges. They're synced in
mail_index_sync_commit(). */
if (ret == 0) {
if (locked)
return -1;
}
/* let's try again */
if (locked)
return -1;
}
}
if (locked)
return 0;
}
if (index->index_deleted &&
(flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) == 0) {
/* index is already deleted. we can't sync. */
if (locked)
return -1;
}
if (!locked) {
/* it looks like we have something to sync. lock the file and
check again. */
}
/* broken sync positions. fix them. */
"broken sync positions in index file %s",
}
return 1;
}
static int
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
{
const struct mail_index_header *hdr;
struct mail_index_sync_ctx *ctx;
struct mail_index_view *sync_view;
int ret;
/* index is corrupted and need to be reopened */
return -1;
}
if (ret <= 0)
return ret;
/* set before any rollbacks are called */
/* we wish to see all the changes from last mailbox sync position to
the end of the transaction log */
if (ret < 0) {
return -1;
}
if (ret == 0) {
/* if a log file is missing, there's nothing we can do except
to skip over it. fix the problem with fsck and try again. */
return 0;
}
/* we need to have all the transactions sorted to optimize
caller's mailbox access patterns */
if (mail_index_sync_read_and_sort(ctx) < 0) {
return -1;
}
/* create the transaction after the view has been updated with
external transactions and marked as sync view */
(flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) != 0;
return 1;
}
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
enum mail_index_sync_flags flags)
{
bool retry;
int ret;
if (retry) {
}
return ret;
}
{
}
enum mail_index_sync_flags flags)
{
const struct mail_transaction_header *hdr;
const void *data;
bool reset;
int ret;
(flags & MAIL_INDEX_SYNC_FLAG_DROP_RECENT) != 0)
return TRUE;
(flags & MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY) != 0)
return TRUE;
/* let the actual syncing handle the error */
return TRUE;
}
continue;
/* extension record updates aren't exactly needed
to be synced, but cache syncing relies on tail
offsets being updated. */
case MAIL_TRANSACTION_EXPUNGE:
return TRUE;
default:
break;
}
}
return ret < 0;
}
enum mail_index_sync_flags flags)
{
struct mail_index_view *view;
bool ret;
return ret;
}
{
}
static void
const struct mail_transaction_expunge_guid *exp)
{
}
static void
const struct mail_index_flag_update *update)
{
}
static void
struct mail_index_sync_list *sync_list)
{
}
struct mail_index_sync_rec *sync_rec)
{
struct mail_index_sync_list *sync_list;
/* FIXME: replace with a priority queue so we don't have to go
through the whole list constantly. and remember to make sure that
keyword resets are sent before adds! */
/* FIXME: pretty ugly to do this for expunges, which isn't even a
seq_range. */
for (i = 0; i < count; i++) {
continue;
/* use this one. */
break;
}
next_i = i;
}
}
if (i == count) {
/* nothing left in sync_list */
return FALSE;
}
i = next_i;
}
(const struct mail_transaction_expunge_guid *)uid_range);
(const struct mail_index_flag_update *)uid_range);
} else {
&sync_list[i]);
}
return TRUE;
}
{
const struct mail_index_sync_list *sync_list;
return TRUE;
}
return FALSE;
}
{
}
{
struct mail_index_sync_list *sync_list;
}
{
}
static void
{
/* didn't sync everything */
} else {
/* synced everything, but we might also have committed new
transactions. include them also here. */
}
/* If tail offset has changed, make sure it gets written to
transaction log. */
}
{
/* we recently just rotated the log and rewrote index */
return FALSE;
}
if (log_diff > MAIL_INDEX_MAX_WRITE_BYTES ||
return TRUE;
if (index->need_recreate)
return TRUE;
return FALSE;
}
{
int ret = 0;
if (delete_index) {
/* finish this sync by marking the index deleted */
}
/* if cache compression fails, we don't really care.
the cache offsets are updated only if the compression was
successful. */
}
offsetof(struct mail_index_header,
}
}
return -1;
}
if (delete_index)
else if (index_undeleted) {
}
/* refresh the mapping with newly committed external transactions
and the synced expunges. sync using file handler here so that the
expunge handlers get called. */
ret = -1;
if (ret == 0 &&
}
return ret;
}
{
}
{
}
{
const unsigned int *keyword_indexes;
unsigned int i, count;
for (i = 0; i < count; i++) {
if (keyword_indexes[i] == idx)
return FALSE;
}
return TRUE;
for (i = 0; i < count; i++) {
if (keyword_indexes[i] == idx) {
return TRUE;
}
}
return FALSE;
default:
i_unreached();
return FALSE;
}
}
const char *fmt, ...)
{
/* make sure we don't get to this same error again by updating the
dovecot.index */
/* be silent */
return;
}
T_BEGIN {
"Log synchronization error at "
} T_END;
}