mail-transaction-log-file.c revision e0f4fbf127b192667c62af7875c4f2ca294b6c7a
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen/* Copyright (c) 2003-2017 Dovecot authors, see the included COPYING file */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file,
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainenlog_file_set_syscall_error(struct mail_transaction_log_file *file,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainenmail_transaction_log_mark_corrupted(struct mail_transaction_log_file *file)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen unsigned int offset =
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen offsetof(struct mail_transaction_log_header, indexid);
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file) ||
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen /* indexid=0 marks the log file as corrupted. we opened the file with
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen O_APPEND, and now we need to drop it for pwrite() to work (at least
720692523ece4a549f7c589508d5693ee310f6b3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (fcntl(file->fd, F_SETFL, flags & ~O_APPEND) < 0) {
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen const char *fmt, ...)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen "Corrupted transaction log file %s seq %u: %s "
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen t_strdup_vprintf(fmt, va), file->sync_offset);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenvoid mail_transaction_log_file_free(struct mail_transaction_log_file **_file)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen struct mail_transaction_log_file *file = *_file;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0)
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainenmail_transaction_log_file_skip_to_head(struct mail_transaction_log_file *file)
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen const struct mail_index_modseq_header *modseq_hdr;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (map == NULL || file->hdr.file_seq != map->hdr.log_file_seq ||
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen /* we can get a valid log offset from index file. initialize
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen sync_offset from it so we don't have to read the whole log
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen file from beginning. */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen modseq_hdr = mail_index_map_get_modseq_header(map);
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen "%s: log_file_head_offset too small",
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen } else if (modseq_hdr == NULL && file->hdr.initial_modseq == 0) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen /* modseqs not used yet */
20a3870db4f78717574ee94bca1512994391b2abTimo Sirainen /* highest_modseq not synced, start from beginning */
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen } else if (modseq_hdr->log_offset > head_offset) {
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen "%s: modseq_hdr.log_offset too large",
20a3870db4f78717574ee94bca1512994391b2abTimo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen /* start from where we last stopped tracking modseqs */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen file->sync_highest_modseq = modseq_hdr->highest_modseq;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen if (file->hdr.file_seq == log->index->map->hdr.log_file_seq) {
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen file->saved_tail_sync_offset = file->saved_tail_offset;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen if (file->saved_tail_offset > file->max_tail_offset)
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen file->max_tail_offset = file->saved_tail_offset;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen /* insert it to correct position */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
a912d084eb8024ce35462c9fd2d50b86b13d8d33Timo Sirainen i_assert((*p)->hdr.file_seq < file->hdr.file_seq);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen /* if we read any unfinished data, make sure the buffer gets
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen truncated. */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen (void)mail_transaction_log_file_sync(file, &retry);
#if !WORDS_BIGENDIAN
MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0)
struct mail_transaction_log_file *
return NULL;
return file;
int ret;
if (ret > 0) {
if (ret < 0) {
int ret;
if (ret < 0) {
if (ret == 0) {
unsigned int lock_timeout_secs;
int ret;
if (ret > 0) {
if (ret < 0) {
const char *lock_reason)
unsigned int lock_time;
static ssize_t
void *dest;
yet (hdr.size=0), the buffer must be truncated later */
pos = 0;
if (ret > 0)
int ret;
ret = 0;
return ret;
bool ignore_estale)
struct mail_transaction_log_file *f;
int ret;
if (ret < 0) {
const unsigned int hdr_version =
#if !WORDS_BIGENDIAN
return mail_transaction_log_file_fail_dupe(f);
bool ignore_estale)
return TRUE;
return FALSE;
unsigned int hdr_offset;
const char *path2;
if (reset)
FALSE) > 0 &&
if (reset) {
if (ret < 0)
if (rename_existing) {
DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) <= 0) {
bool reset)
if (ret < 0) {
return ret;
const char **reason_r)
bool ignore_estale;
int ret;
if (ret > 0) {
if (ret == 0) {
i == MAIL_INDEX_ESTALE_RETRY_COUNT) {
const unsigned int offset_pos =
sizeof(tail_offset));
if (*cur_modseq != 0) {
const unsigned int modseq_ext_len =
modseq_ext_len) == 0) {
case MAIL_TRANSACTION_APPEND:
case MAIL_TRANSACTION_MODSEQ_UPDATE: {
static struct modseq_cache *
if (idx > 0) {
static struct modseq_cache *
return NULL;
best = i;
return NULL;
static struct modseq_cache *
return NULL;
best = i;
return NULL;
int ret;
if (ret <= 0) {
if (ret < 0)
int ret;
if (ret <= 0) {
if (ret < 0)
unsigned int trans_size)
int ret;
if (ret != 0)
case MAIL_TRANSACTION_BOUNDARY: {
bool *retry_r)
const void *data;
int ret;
if (trans_size == 0) {
if (ret < 0)
void *data;
if (ret > 0) {
if (ret == 0) {
void *data;
if (ret > 0)
if (ret < 0) {
return TRUE;
return TRUE;
return FALSE;
bool retry;
int ret;
if (ret <= 0)
return ret;
return ret;
MADV_SEQUENTIAL) < 0)
bool retry;
int ret;
!retry)
return ret;
FALSE);
} while (retry);
return ret;
int ret;
end_offset) == 0)
if (ret <= 0)
return ret;
*file)