/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "buffer.h"
#include "file-dotlock.h"
#include "nfs-workarounds.h"
#include "mmap-util.h"
#include "mail-index-private.h"
#include "mail-transaction-log-private.h"
#include <stddef.h>
#include <stdio.h>
static void
struct mail_transaction_log_file *file)
{
}
struct mail_transaction_log *
{
return log;
}
{
return;
if (log2_rotate_time == 0) {
else {
return;
}
}
ioloop_time - (time_t)log2_rotate_time >= (time_t)log->index->optimization_set.log.log2_max_age_secs &&
}
/* Write this as part of the next sync's transaction. We're
here because we're already opening a sync lock, so it'll
always happen. It's also required especially with mdbox map
index, which doesn't like changes done outside syncing. */
}
}
{
const char *reason;
int ret;
/* these settings aren't available at alloc() time, so we need to
set them here: */
return 0;
/* leave the file for _create() */
return ret;
}
return 1;
}
{
return 0;
}
/* remember what file we tried to open. if someone else created
a new file, use it instead of recreating it */
}
return -1;
}
return 1;
}
{
}
{
}
{
/* we couldn't read dovecot.index and we don't have the first
.log file, so just start from scratch */
}
else {
return 0;
}
}
{
"indexid changed: %u -> %u",
}
}
}
}
{
/* remove only files from the beginning. this way if a view has
referenced an old file, it can still find the new files even if
there aren't any references to it currently. */
break;
}
/* sanity check: we shouldn't have locked refcount=0 files */
}
}
{
if (file->need_rotate)
return TRUE;
/* upgrade immediately to a new log file format */
return TRUE;
}
/* file is too large, definitely rotate */
return TRUE;
}
/* file is still too small */
return FALSE;
}
/* rotate if the timestamp is old enough */
}
{
int ret;
if (reset) {
}
} else {
/* we're locked, we shouldn't need to worry about ESTALE
problems in here. */
return -1;
}
return -1;
}
if (ret == 0) {
"Transaction log %s was recreated while we had it locked - "
"locking is broken (lock_method=%s)", path,
return -1;
}
}
else {
/* the newly created log file is already locked */
"rotating while syncing");
}
return 0;
}
static int
const char **reason_r)
{
*reason_r = "Log is in memory";
return 0;
}
"stat()");
return -1;
}
/* We shouldn't lose dovecot.index.log unless the mailbox was
deleted or renamed. Just fail this and let the mailbox
opening code figure out whether to create a new log file
or not. Anything else can cause unwanted behavior (e.g.
mailbox deletion not fully finishing due to .nfs* files and
an IDLEing IMAP process creating the index back here). */
*reason_r = "Trasnaction log lost while it was open";
return -1;
/* NFS: log files get rotated to .log.2 files instead
of being unlinked, so we don't bother checking if
the existing file has already been unlinked here
(in which case inodes could match but point to
different files) */
*reason_r = "Log inode is unchanged";
return 0;
}
return -1;
}
*reason_r = "Log reopened";
return 0;
}
{
}
{
}
struct mail_transaction_log_file **file_r,
const char **reason_r)
{
const char *reason;
int ret;
/* see if the .log file has been recreated */
/* transaction log is locked. there's no way a newer
file exists. */
*reason_r = "Log is locked - newer log can't exist";
return 0;
}
return -1;
}
"Requested newer log than exists: %s", reason);
return 0;
}
/* try again, this time flush attribute cache */
"Log refresh with NFS flush failed: %s", reason);
return -1;
}
"Requested newer log than exists - "
"still after NFS flush: %s", reason);
return 0;
}
}
}
return 1;
}
/* Fail here mainly to avoid unnecessarily trying to
open .log.2 that most likely doesn't even exist. */
*reason_r = "Log was reset after requested file_seq";
return 0;
}
}
*reason_r = "Logs are only in memory";
return 0;
}
/* see if we have it in log.2 file */
return ret;
}
/* but is it what we expected? */
return 0;
}
return 1;
}
const char *lock_reason)
{
const char *reason;
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 (;;) {
if (mail_transaction_log_file_lock(file) < 0)
return -1;
"trying to lock head for %s", lock_reason));
}
/* success */
break;
}
"trying to lock head for %s", lock_reason));
}
if (ret < 0)
break;
/* try again */
}
i_warning("Locking transaction log file %s took %ld seconds (%s)",
}
return ret;
}
const char *lock_reason,
{
const char *reason;
if (!log->log_2_unlink_checked) {
/* we need to check once in a while if .log.2 should be deleted
to avoid wasting space on such old files. but we also don't
want to waste time on checking it when the same mailbox
gets opened over and over again rapidly (e.g. pop3). so
do this only when there have actually been some changes
to mailbox (i.e. when it's being locked here) */
}
return -1;
/* update sync_offset */
"Failed to map transaction log %s at "
"%s - map failed", lock_reason));
return -1;
}
return 0;
}
const char *lock_reason)
{
}
{
}
{
}
}
{
}
{
"unlink()");
return -1;
}
return 0;
}
struct dotlock_settings *set_r)
{
}