mail-transaction-log.c revision 98fb9437058e007980df344e55c592105e7cf6df
/* Copyright (C) 2003-2004 Timo Sirainen */
#include "lib.h"
#include "buffer.h"
#include "file-lock.h"
#include "file-dotlock.h"
#include "read-full.h"
#include "write-full.h"
#include "mmap-util.h"
#include "mail-index-private.h"
#include "mail-index-view-private.h"
#include "mail-transaction-log-private.h"
#include "mail-transaction-util.h"
#include "mail-index-transaction-private.h"
#include <stddef.h>
/* this lock should never exist for a long time.. */
#define LOG_DOTLOCK_TIMEOUT 30
#define LOG_DOTLOCK_STALE_TIMEOUT 0
#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 120
struct mail_transaction_add_ctx {
struct mail_transaction_log *log;
struct mail_index_view *view;
};
static struct mail_transaction_log_file *
const char *path);
static int
int lock_type);
void
const char *fmt, ...)
{
}
t_push();
"Corrupted transaction log file %s: %s",
t_pop();
}
{
struct mail_transaction_log_file *file;
unsigned int lock_id;
int ret;
if (mail_transaction_log_lock_head(log) < 0)
return -1;
if (ret == 0) {
if (ret <= 0)
ret = -1;
/* broken - fix it by creating a new log file */
}
}
return ret;
}
struct mail_transaction_log *
{
struct mail_transaction_log *log;
const char *path;
return NULL;
}
/* head log file isn't same as head index file -
shouldn't happen except in race conditions. lock them and
check again - FIXME: missing error handling.
FIXME: index->hdr check crashes if we created the log */
}
return log;
}
{
}
static int
int lock_type)
{
int ret;
if (ret < 0) {
return -1;
}
if (ret == 0) {
"Dotlock was lost for transaction log file %s",
return -1;
}
return 0;
}
if (ret > 0) {
return 0;
}
if (ret < 0) {
"file_lock_dotlock()");
return -1;
}
"Timeout while waiting for release of "
"dotlock for transaction log file %s",
return -1;
}
static int
int lock_type)
{
int ret;
} else {
}
if (ret > 0) {
return 0;
}
if (ret < 0) {
"file_wait_lock()");
return -1;
}
"Timeout while waiting for release of "
"%s fcntl() lock for transaction log file %s",
return -1;
}
static void
{
}
}
static int
{
int ret;
else {
return -1;
}
if (ret < 0) {
// FIXME: handle ESTALE
return -1;
}
if (ret == 0) {
"unexpected end of file while reading header");
return 0;
}
/* corrupted */
"Transaction log file %s: marked corrupted",
return 0;
}
/* either index was just recreated, or transaction has wrong
indexid. we don't know here which one is the case, so we'll
just fail. If index->indexid == 0, we're rebuilding it and
we just want to lock the transaction log. */
"Transaction log file %s: invalid indexid",
return 0;
}
return 0;
}
"used_size (%u) < old_size (%u)",
return 0;
}
return 1;
}
const char *path,
{
struct mail_transaction_log_header hdr;
unsigned int lock_id;
if (fd == -1) {
"file_dotlock_open()");
return -1;
}
/* log creation is locked now - see if someone already created it */
if (fd2 != -1) {
"fstat()");
/* same file, still broken */
} else {
return fd2;
}
fd2 = -1;
if (ret < 0)
return -1;
return -1;
}
return -1;
}
if (ret > 0) {
/* update log_file_* fields in header */
struct mail_index_header idx_hdr;
ret = -1;
}
if (ret <= 0) {
return -1;
}
} else {
/* creating new index file */
}
return -1;
}
if (fd2 < 0) {
return -1;
}
return -1;
/* success */
return fd2;
}
static struct mail_transaction_log_file *
{
struct mail_transaction_log_file **p;
struct mail_transaction_log_file *file;
int ret;
return NULL;
}
if (ret == 0) {
/* corrupted header */
"stat()");
fd = -1;
ret = -1;
}
if (fd != -1) {
}
}
if (ret <= 0) {
return NULL;
}
;
*p = file;
return file;
}
static struct mail_transaction_log_file *
const char *path)
{
int fd;
if (fd == -1) {
"open()");
return NULL;
}
if (fd == -1)
return NULL;
}
}
{
struct mail_transaction_log_file **p;
if ((*p)->refcount != 0)
p = &(*p)->next;
else {
*p = (*p)->next;
}
}
}
{
struct mail_transaction_log_file *file;
int fd;
"fstat()");
return -1;
}
if (fd == -1)
return 0;
return -1;
}
return 0;
}
{
struct mail_transaction_log_file *file;
const char *path;
int ret;
return -1;
}
/* same file */
return ret <= 0 ? -1 : 0;
}
return -1;
}
return 0;
}
struct mail_transaction_log_file **file_r)
{
struct mail_transaction_log_file *file;
if (mail_transaction_log_refresh(log) < 0)
return -1;
}
return 1;
}
}
return 0;
}
static int
{
void *data;
int ret;
/* we have to insert missing data to beginning of buffer */
/* log file was deleted in NFS server, fail silently */
ret = 0;
}
if (ret <= 0)
return ret;
}
size = 0;
} else {
/* caller should have checked this.. */
return 1;
}
}
if (size == 0)
return 1;
/* log file was deleted in NFS server, fail silently */
ret = 0;
}
return ret;
}
{
/* corrupted */
return 0;
}
/* with mmap_no_write we could alternatively just write to log with
msync() rather than pwrite(). that'd cause slightly more disk I/O,
so rather use more memory. */
/* see if we already have it */
return 1;
}
"fstat()");
return -1;
}
/* we've seen the whole file.. do we have all of it mapped? */
return 1;
}
}
"munmap()");
}
}
return -1;
return -1;
}
return -1;
}
if (!use_mmap) {
if (ret <= 0) {
/* make sure we don't leave ourself in
inconsistent state */
}
file->buffer_size = 0;
} else {
}
return ret;
}
"mmap()");
return -1;
}
return 1;
}
{
struct mail_transaction_log_file *file;
int ret = 0;
/* we want to get the head file locked. this is a bit racy,
since by the time we have it locked a new log file may have been
created.
creating new log file requires locking the head file, so if we
can lock it and don't see another file, we can be sure no-one is
creating a new log at the moment */
for (;;) {
return -1;
}
/* success */
break;
}
return -1;
}
if (ret < 0)
break;
/* try again */
}
return ret;
}
{
struct mail_transaction_log_view *sync_view;
const struct mail_transaction_header *hdr;
const void *data;
int ret;
}
}
return ret;
}
static void
{
// FIXME: make sure this function works correctly
unsigned char *data;
return;
return;
expunges_before = 0;
exp++;
}
/* this sequence was expunged */
if (!two)
continue;
/* we point to next non-expunged message */
}
if (expunges_before != 0) {
if (uids) {
&seq[2]);
}
seq[0] -= expunges_before;
}
if (two) {
exp2++;
}
/* whole range is expunged */
continue;
}
if (count != 0) {
if (uids) {
(void)mail_index_lookup_uid(view,
seq[1],
&seq[3]);
}
}
}
dest_idx += record_size;
}
}
static int
struct mail_index_transaction *t)
{
return 0;
/* all sequences are currently relative to given view. we have to
find out all the expunges since then, even the ones that aren't
yet synchronized to index file. */
return -1;
}
sizeof(struct mail_transaction_flag_update),
sizeof(struct mail_transaction_cache_update),
sizeof(struct mail_transaction_expunge),
return 0;
}
static int
{
struct mail_transaction_header hdr;
const void *data;
if (size == 0)
return 0;
} else {
/* write only the header */
size = 0;
}
if (type == MAIL_TRANSACTION_EXPUNGE)
if (external)
return -1;
if (size != 0) {
return -1;
}
return 0;
}
int mail_transaction_log_append(struct mail_index_transaction *t,
{
struct mail_transaction_log *log;
struct mail_transaction_log_file *file;
int ret;
/* nothing to append */
return 0;
}
} else {
if (mail_transaction_log_lock_head(log) < 0)
return -1;
}
if (mail_transaction_log_fix_sequences(log, t) < 0) {
return -1;
}
ret = 0;
}
}
}
}
if (ret == 0) {
/* rewrite used_size */
}
t->hide_transaction) {
}
if (ret < 0) {
"pwrite()");
/* we don't know how much of it got written,
it may be corrupted now.. */
"fsync()");
ret = -1;
}
return ret;
}
{
if (mail_transaction_log_lock_head(log) < 0)
return -1;
return 0;
}
{
}
{
}