mail-transaction-log.c revision d143077bd518de129b8d446fb58e003903e50867
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce/* Copyright (C) 2003-2004 Timo Sirainen */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "lib.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "ioloop.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "buffer.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "file-dotlock.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "read-full.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "write-full.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "mmap-util.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "mail-index-private.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "mail-index-view-private.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "mail-transaction-log-private.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "mail-transaction-util.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include "mail-index-transaction-private.h"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include <stddef.h>
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#include <sys/stat.h>
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#define LOG_PREFETCH 1024
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce/* this lock should never exist for a long time.. */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#define LOG_DOTLOCK_TIMEOUT 30
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce#define LOG_DOTLOCK_STALE_TIMEOUT 0
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 300
8890a30f5d054187fd7d5b50503f82a49cd025f0Lukas Slebodnik
8890a30f5d054187fd7d5b50503f82a49cd025f0Lukas Slebodnik#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestruct mail_transaction_add_ctx {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce struct mail_transaction_log *log;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_index_view *view;
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek buffer_t *appends, *expunges;
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek buffer_t *flag_updates, *cache_updates;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce};
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorcestatic struct mail_transaction_log_file *
7a162ca3ea0bf8ef6b13795a00baa28d17f6131dJakub Hrozekmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
7a162ca3ea0bf8ef6b13795a00baa28d17f6131dJakub Hrozek const char *path);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozekstatic int mail_transaction_log_rotate(struct mail_transaction_log *log,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce int lock_type);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorcestatic int mail_transaction_log_lock_head(struct mail_transaction_log *log);
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidênciovoid
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidênciomail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce const char *fmt, ...)
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce{
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce va_list va;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->hdr.indexid = 0;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (pwrite_full(file->fd, &file->hdr.indexid,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce sizeof(file->hdr.indexid), 0) < 0) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce mail_index_file_set_syscall_error(file->log->index,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->filepath, "pwrite()");
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce va_start(va, fmt);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek t_push();
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_set_error(file->log->index,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "Corrupted transaction log file %s: %s",
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->filepath, t_strdup_vprintf(fmt, va));
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce t_pop();
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce va_end(va);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce}
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorcestatic int
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorcemail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek int ret;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (file->log->dotlock_count > 0)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek ret = 1;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce else {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce ret = file_lock_dotlock(file->filepath, NULL, FALSE,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce LOG_DOTLOCK_TIMEOUT,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek LOG_DOTLOCK_STALE_TIMEOUT,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce NULL, NULL, &file->log->dotlock);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (ret > 0) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->log->dotlock_count++;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->locked = TRUE;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce return 0;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (ret < 0) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce mail_index_file_set_syscall_error(file->log->index,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->filepath,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce "file_lock_dotlock()");
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio return -1;
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio }
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce mail_index_set_error(file->log->index,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce "Timeout while waiting for release of "
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce "dotlock for transaction log file %s",
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->filepath);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->log->index->index_lock_timeout = TRUE;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek}
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekstatic int
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek int ret;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (--file->log->dotlock_count > 0)
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce return 0;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce ret = file_unlock_dotlock(file->filepath, &file->log->dotlock);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (ret < 0) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce mail_index_file_set_syscall_error(file->log->index,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->filepath, "file_unlock_dotlock()");
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (ret == 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_set_error(file->log->index,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce "Dotlock was lost for transaction log file %s",
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->filepath);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce return -1;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce return 0;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce}
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorcestatic int
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcemail_transaction_log_file_lock(struct mail_transaction_log_file *file)
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio{
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio int ret;
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio if (file->locked)
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->log->index->lock_method == MAIL_INDEX_LOCK_DOTLOCK)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return mail_transaction_log_file_dotlock(file);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = mail_index_lock_fd(file->log->index, file->fd, F_WRLCK,
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek MAIL_INDEX_LOCK_SECS);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret > 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->locked = TRUE;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret < 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_file_set_syscall_error(file->log->index,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "mail_index_wait_lock_fd()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_set_error(file->log->index,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Timeout while waiting for release of "
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "fcntl() lock for transaction log file %s",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->filepath);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->log->index->index_lock_timeout = TRUE;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestatic void
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcemail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce int ret;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (!file->locked)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->locked = FALSE;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (file->log->index->lock_method == MAIL_INDEX_LOCK_DOTLOCK) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_transaction_log_file_undotlock(file);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = mail_index_lock_fd(file->log->index, file->fd, F_UNLCK, 0);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret <= 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_file_set_syscall_error(file->log->index,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->filepath,
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio "mail_index_wait_lock_fd()");
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio }
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce#define INDEX_HAS_MISSING_LOGS(index, file) \
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce !(((file)->hdr.file_seq == (index)->hdr->log_file_seq && \
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce (index)->hdr->log_file_offset >= \
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce sizeof(struct mail_transaction_log_header)) || \
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ((file)->hdr.prev_file_seq == (index)->hdr->log_file_seq && \
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce (file)->hdr.prev_file_offset == (index)->hdr->log_file_offset))
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_index *index = log->index;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_transaction_log_file *file;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce unsigned int lock_id;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce int ret;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (mail_transaction_log_lock_head(log) < 0)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file = log->head;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->refcount++;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = mail_index_lock_shared(index, TRUE, &lock_id);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret == 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = mail_index_map(index, FALSE);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret <= 0)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek ret = -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek else if (INDEX_HAS_MISSING_LOGS(index, file)) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek /* broken - fix it by creating a new log file */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = mail_transaction_log_rotate(log, F_UNLCK);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (--file->refcount == 0)
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek mail_transaction_logs_clean(log);
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek else
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek mail_transaction_log_file_unlock(file);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek return ret;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek}
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a8361f37af31a8a9767056bd27c418c947293f56Fabiano Fidênciostruct mail_transaction_log *
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorcemail_transaction_log_open_or_create(struct mail_index *index)
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio{
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio struct mail_transaction_log *log;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek const char *path;
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce log = i_new(struct mail_transaction_log, 1);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce log->index = index;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce path = t_strconcat(log->index->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce MAIL_TRANSACTION_LOG_PREFIX, NULL);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce log->head = mail_transaction_log_file_open_or_create(log, path);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (log->head == NULL) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce i_free(log);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek return NULL;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (index->fd != -1 &&
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce INDEX_HAS_MISSING_LOGS(index, log->head)) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek /* head log file isn't same as head index file -
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek shouldn't happen except in race conditions. lock them and
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek check again - FIXME: missing error handling. */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce (void)mail_transaction_log_check_file_seq(log);
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek }
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return log;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce}
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekvoid mail_transaction_log_close(struct mail_transaction_log *log)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_log_views_close(log);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce log->head->refcount--;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_logs_clean(log);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek log->index->log = NULL;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce i_free(log);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestatic void
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcemail_transaction_log_file_close(struct mail_transaction_log_file *file)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_transaction_log_file_unlock(file);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->buffer != NULL)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce buffer_free(file->buffer);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->mmap_base != NULL) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (munmap(file->mmap_base, file->mmap_size) < 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_file_set_syscall_error(file->log->index,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "munmap()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (close(file->fd) < 0) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce mail_index_file_set_syscall_error(file->log->index,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce file->filepath, "close()");
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce i_free(file->filepath);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce i_free(file);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestatic int
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcemail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce int ret;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio if (ret < 0) {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek // FIXME: handle ESTALE
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio mail_index_file_set_syscall_error(file->log->index,
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio file->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "pread_full()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret == 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_log_file_set_corrupted(file,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "unexpected end of file while reading header");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->hdr.indexid == 0) {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek /* corrupted */
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_set_error(file->log->index,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "Transaction log file %s: marked corrupted",
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->filepath);
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek if (file->hdr.indexid != file->log->index->indexid) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (file->log->index->fd == -1) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* creating index file, silently rebuild
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek transaction log as well */
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* index file was probably just rebuilt and we don't know
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce about it yet */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_set_error(file->log->index,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "Transaction log file %s: invalid indexid (%u != %u)",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->filepath, file->hdr.indexid,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->log->index->indexid);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestatic int
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcemail_transaction_log_file_create2(struct mail_transaction_log *log,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce const char *path, int fd,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce dev_t dev, ino_t ino)
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_index *index = log->index;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_transaction_log_header hdr;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct stat st;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce unsigned int lock_id;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce int fd2, ret;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* log creation is locked now - see if someone already created it */
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek fd2 = open(path, O_RDWR);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (fd2 != -1) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if ((ret = fstat(fd2, &st)) < 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_file_set_syscall_error(index, path,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "fstat()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce } else if (st.st_ino == ino && CMP_DEV_T(st.st_dev, dev)) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* same file, still broken */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce } else {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX,
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio fd);
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio return fd2;
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio }
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio (void)close(fd2);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce fd2 = -1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (ret < 0)
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return -1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce } else if (errno != ENOENT) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce mail_index_file_set_syscall_error(index, path, "open()");
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio return -1;
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio }
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio memset(&hdr, 0, sizeof(hdr));
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio hdr.indexid = index->indexid;
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio if (index->fd != -1) {
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio if (mail_index_lock_shared(index, TRUE, &lock_id) < 0)
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return -1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce hdr.prev_file_seq = index->hdr->log_file_seq;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce hdr.prev_file_offset = index->hdr->log_file_offset;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce }
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce hdr.file_seq = index->hdr->log_file_seq+1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (index->fd != -1)
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce mail_index_unlock(index, lock_id);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (log->head != NULL && hdr.file_seq <= log->head->hdr.file_seq) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce /* make sure the sequence grows */
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce hdr.file_seq = log->head->hdr.file_seq+1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_file_set_syscall_error(index, path,
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio "write_full()");
a8361f37af31a8a9767056bd27c418c947293f56Fabiano Fidêncio return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek fd2 = dup(fd);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (fd2 < 0) {
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio mail_index_file_set_syscall_error(index, path, "dup()");
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return -1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce }
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio if (file_dotlock_replace(path, LOG_NEW_DOTLOCK_SUFFIX, fd, FALSE) <= 0)
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio return -1;
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio
d806427f200dc1ffd44d37724eb40125af5cc8c2Fabiano Fidêncio /* success */
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return fd2;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce}
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidênciostatic int
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidênciomail_transaction_log_file_create(struct mail_transaction_log *log,
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio const char *path, dev_t dev, ino_t ino)
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio{
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio int fd, fd2;
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio /* With dotlocking we might already have path.lock created, so this
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek filename has to be different. */
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio fd = file_dotlock_open(path, NULL, LOG_NEW_DOTLOCK_SUFFIX,
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio LOG_DOTLOCK_TIMEOUT,
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio LOG_DOTLOCK_STALE_TIMEOUT,
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL);
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio if (fd == -1) {
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio mail_index_file_set_syscall_error(log->index, path,
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio "file_dotlock_open()");
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio return -1;
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio }
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio fd2 = mail_transaction_log_file_create2(log, path, fd, dev, ino);
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio if (fd2 < 0) {
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek return -1;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio }
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio return fd2;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio}
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidênciostatic struct mail_transaction_log_file *
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidênciomail_transaction_log_file_fd_open(struct mail_transaction_log *log,
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio const char *path, int fd)
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio{
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio struct mail_transaction_log_file **p;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio struct mail_transaction_log_file *file;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek struct stat st;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio int ret;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio if (fstat(fd, &st) < 0) {
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio mail_index_file_set_syscall_error(log->index, path, "fstat()");
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio (void)close(fd);
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio return NULL;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio }
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file = i_new(struct mail_transaction_log_file, 1);
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->refcount = 1;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek file->log = log;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->filepath = i_strdup(path);
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->fd = fd;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->st_dev = st.st_dev;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->st_ino = st.st_ino;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->last_mtime = st.st_mtime;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio file->sync_offset = sizeof(struct mail_transaction_log_header);
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio ret = mail_transaction_log_file_read_hdr(file);
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio if (ret == 0) {
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio /* corrupted header */
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio fd = mail_transaction_log_file_create(log, path,
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek st.st_dev, st.st_ino);
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio if (fd == -1)
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio ret = -1;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio else if (fstat(fd, &st) < 0) {
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio mail_index_file_set_syscall_error(log->index, path,
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek "fstat()");
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio (void)close(fd);
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio fd = -1;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio ret = -1;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio }
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio if (fd != -1) {
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek (void)close(file->fd);
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio file->fd = fd;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio file->st_dev = st.st_dev;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio file->st_ino = st.st_ino;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio file->last_mtime = st.st_mtime;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio memset(&file->hdr, 0, sizeof(file->hdr));
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio ret = mail_transaction_log_file_read_hdr(file);
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio }
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio }
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (ret <= 0) {
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio mail_transaction_log_file_close(file);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return NULL;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (log->index->map != NULL &&
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->hdr.file_seq == log->index->map->log_file_seq &&
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce log->index->map->log_file_offset != 0) {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek /* we can get a valid log offset from index file. initialize
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek sync_offset from it so we don't have to read the whole log
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file from beginning. */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->sync_offset = log->index->map->log_file_offset;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce for (p = &log->tail; *p != NULL; p = &(*p)->next) {
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek if ((*p)->hdr.file_seq >= file->hdr.file_seq) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce /* log replaced with file having same sequence as
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce previous one. shouldn't happen unless previous
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce log file was corrupted.. */
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek break;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek *p = file;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return file;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce}
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidênciostatic struct mail_transaction_log_file *
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidênciomail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio const char *path)
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio{
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio int fd;
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio fd = open(path, O_RDWR);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek if (fd == -1) {
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio if (errno != ENOENT) {
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio mail_index_file_set_syscall_error(log->index, path,
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio "open()");
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio return NULL;
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio }
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio fd = mail_transaction_log_file_create(log, path, 0, 0);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (fd == -1)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return NULL;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return mail_transaction_log_file_fd_open(log, path, fd);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcevoid mail_transaction_logs_clean(struct mail_transaction_log *log)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct mail_transaction_log_file **p, *next;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek for (p = &log->tail; *p != NULL; ) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if ((*p)->refcount != 0)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek p = &(*p)->next;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce else {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce next = (*p)->next;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_transaction_log_file_close(*p);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek *p = next;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (log->tail == NULL)
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce log->head = NULL;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce}
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekstatic int
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekmail_transaction_log_rotate(struct mail_transaction_log *log, int lock)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct mail_transaction_log_file *file;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct stat st;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek int fd;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (fstat(log->head->fd, &st) < 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_file_set_syscall_error(log->index,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek log->head->filepath,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "fstat()");
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce fd = mail_transaction_log_file_create(log, log->head->filepath,
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce st.st_dev, st.st_ino);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (fd == -1)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file = mail_transaction_log_file_fd_open(log, log->head->filepath, fd);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (file == NULL)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (lock) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (mail_transaction_log_file_lock(file) < 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->refcount--;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_transaction_logs_clean(log);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce i_assert(file->locked == lock);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (--log->head->refcount == 0)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_logs_clean(log);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce else
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_log_file_unlock(log->head);
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio i_assert(log->head != file);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek log->head = file;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 0;
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio}
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidênciostatic int mail_transaction_log_recreate(struct mail_transaction_log *log)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce unsigned int lock_id;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek int ret;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio if (mail_index_lock_shared(log->index, TRUE, &lock_id) < 0)
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio return -1;
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek ret = mail_transaction_log_rotate(log, FALSE);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_index_unlock(log->index, lock_id);
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek return ret;
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio}
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozekstatic int mail_transaction_log_refresh(struct mail_transaction_log *log)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct mail_transaction_log_file *file;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct stat st;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek const char *path;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio path = t_strconcat(log->index->filepath,
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio MAIL_TRANSACTION_LOG_PREFIX, NULL);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (stat(path, &st) < 0) {
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek mail_index_file_set_syscall_error(log->index, path, "stat()");
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek if (errno == ENOENT && log->head->locked) {
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio /* lost? */
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return mail_transaction_log_recreate(log);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio if (log->head != NULL &&
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio log->head->st_ino == st.st_ino &&
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio CMP_DEV_T(log->head->st_dev, st.st_dev)) {
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio /* same file */
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio return 0;
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek }
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio file = mail_transaction_log_file_open_or_create(log, path);
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio if (file == NULL)
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek i_assert(!file->locked);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (log->head != NULL) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (--log->head->refcount == 0)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_transaction_logs_clean(log);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio log->head = file;
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio return 0;
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio}
ab7b33fd7d820688545d5994a402cedf4bcdb6e1Fabiano Fidêncio
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceint mail_transaction_log_file_find(struct mail_transaction_log *log,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce uint32_t file_seq,
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio struct mail_transaction_log_file **file_r)
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio{
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek struct mail_transaction_log_file *file;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (file_seq > log->head->hdr.file_seq) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (mail_transaction_log_refresh(log) < 0)
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return -1;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek }
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce for (file = log->tail; file != NULL; file = file->next) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (file->hdr.file_seq == file_seq) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce *file_r = file;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return 1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce }
392f48c039d7a6d70bce6ae2d122042391653566Jakub Hrozek }
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return 0;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce}
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekstatic int
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekmail_transaction_log_file_sync(struct mail_transaction_log_file *file)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek const struct mail_transaction_header *hdr;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek const void *data;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce size_t size;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek uint32_t hdr_size;
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio data = buffer_get_data(file->buffer, &size);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek hdr = CONST_PTR_OFFSET(data, file->sync_offset -
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->buffer_offset);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek hdr_size = mail_index_offset_to_uint32(hdr->size);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (hdr_size == 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek /* unfinished */
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (file->mmap_base == NULL) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce size = file->sync_offset - file->buffer_offset;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek buffer_set_used_size(file->buffer, size);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return 0;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (hdr_size < sizeof(*hdr)) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek mail_transaction_log_file_set_corrupted(file,
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce "hdr.size too small (%u)", hdr_size);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce return -1;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (file->sync_offset - file->buffer_offset + hdr_size > size)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek break;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->sync_offset += hdr_size;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return 0;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek}
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekstatic int
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekmail_transaction_log_file_read(struct mail_transaction_log_file *file,
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce uoff_t offset)
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce{
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce void *data;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce size_t size;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce uint32_t read_offset;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce int ret;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce i_assert(file->mmap_base == NULL);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (file->buffer != NULL && file->buffer_offset > offset) {
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio /* we have to insert missing data to beginning of buffer */
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek size = file->buffer_offset - offset;
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek file->buffer_offset -= size;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce data = buffer_get_space_unsafe(file->buffer, 0, size);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek ret = pread_full(file->fd, data, size, offset);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek if (ret == 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_log_file_set_corrupted(file,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Unexpected end of file");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret < 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (errno == ESTALE) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* log file was deleted in NFS server,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce fail silently */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_file_set_syscall_error(file->log->index,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "pread()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->buffer == NULL) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->buffer =
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce buffer_create_dynamic(default_pool, LOG_PREFETCH);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->buffer_offset = offset;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* read all records */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce read_offset = file->buffer_offset + buffer_get_used_size(file->buffer);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce do {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (ret > 0)
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek read_offset += ret;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek size = read_offset - file->buffer_offset;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek buffer_set_used_size(file->buffer, size);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek } while (ret > 0 || (ret < 0 && errno == EINTR));
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (mail_transaction_log_file_sync(file) < 0)
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek return -1;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek if (ret == 0) {
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek /* EOF */
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek buffer_set_used_size(file->buffer,
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek file->sync_offset - file->buffer_offset);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek return 1;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek }
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (errno == ESTALE) {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek /* log file was deleted in NFS server, fail silently */
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek buffer_set_used_size(file->buffer,
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek offset - file->buffer_offset);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek return 0;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek mail_index_file_set_syscall_error(file->log->index, file->filepath,
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek "pread()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce}
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozekint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek uoff_t start_offset, uoff_t end_offset)
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek{
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek struct mail_index *index = file->log->index;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek size_t size;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct stat st;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek int ret, use_mmap;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek i_assert(start_offset <= end_offset);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (file->hdr.indexid == 0) {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek /* corrupted */
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek return 0;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek }
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (start_offset < sizeof(file->hdr)) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_log_file_set_corrupted(file,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "offset (%"PRIuUOFF_T") < header size (%"PRIuSIZE_T")",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce start_offset, sizeof(file->hdr));
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio /* with mmap_no_write we could alternatively just write to log with
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio msync() rather than pwrite(). that'd cause slightly more disk I/O,
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio so rather use more memory. */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce use_mmap = !index->mmap_disable && !index->mmap_no_write;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->buffer != NULL && file->buffer_offset <= start_offset) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce /* see if we already have it */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce size = buffer_get_used_size(file->buffer);
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (file->buffer_offset + size >= end_offset)
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce return 1;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->mmap_base != NULL || use_mmap) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (fstat(file->fd, &st) < 0) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce mail_index_file_set_syscall_error(index, file->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "fstat()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->mmap_base != NULL && (uoff_t)st.st_size == file->mmap_size &&
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->buffer_offset <= start_offset) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* it's all mmaped already */
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce i_assert(end_offset == (uoff_t)-1);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (mail_transaction_log_file_sync(file) < 0)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return 1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (file->buffer != NULL &&
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek (file->mmap_base != NULL || use_mmap)) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce buffer_free(file->buffer);
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->buffer = NULL;
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce }
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (file->mmap_base != NULL) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (munmap(file->mmap_base, file->mmap_size) < 0) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce mail_index_file_set_syscall_error(index, file->filepath,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce "munmap()");
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce }
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->mmap_base = NULL;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (!use_mmap) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce ret = mail_transaction_log_file_read(file, start_offset);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (ret <= 0) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce /* make sure we don't leave ourself in
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek inconsistent state */
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek if (file->buffer != NULL) {
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek buffer_free(file->buffer);
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek file->buffer = NULL;
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return ret;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce } else {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek file->mmap_size = st.st_size;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ,
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek MAP_SHARED, file->fd, 0);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (file->mmap_base == MAP_FAILED) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce file->mmap_base = NULL;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_index_file_set_syscall_error(index, file->filepath,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "mmap()");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce }
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (file->mmap_size > mmap_get_page_size()) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (madvise(file->mmap_base, file->mmap_size,
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek MADV_SEQUENTIAL) < 0) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce mail_index_file_set_syscall_error(index,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->filepath, "madvise()");
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->buffer = buffer_create_const_data(default_pool,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->mmap_base,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->mmap_size);
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce file->buffer_offset = 0;
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (mail_transaction_log_file_sync(file) < 0)
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce mail_transaction_log_file_set_corrupted(file,
73ce539aa70f43ccd5302b3ef8a02ff028558b12Jakub Hrozek "end_offset (%"PRIuUOFF_T") > current sync_offset "
73ce539aa70f43ccd5302b3ef8a02ff028558b12Jakub Hrozek "(%"PRIuSIZE_T")", end_offset, file->sync_offset);
73ce539aa70f43ccd5302b3ef8a02ff028558b12Jakub Hrozek return -1;
73ce539aa70f43ccd5302b3ef8a02ff028558b12Jakub Hrozek }
73ce539aa70f43ccd5302b3ef8a02ff028558b12Jakub Hrozek
73ce539aa70f43ccd5302b3ef8a02ff028558b12Jakub Hrozek return 1;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek}
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorcestatic int mail_transaction_log_lock_head(struct mail_transaction_log *log)
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce{
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce struct mail_transaction_log_file *file;
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce int ret = 0;
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce /* we want to get the head file locked. this is a bit racy,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce since by the time we have it locked a new log file may have been
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce created.
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek creating new log file requires locking the head file, so if we
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce can lock it and don't see another file, we can be sure no-one is
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce creating a new log at the moment */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce for (;;) {
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek file = log->head;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (mail_transaction_log_file_lock(file) < 0)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return -1;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce file->refcount++;
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek ret = mail_transaction_log_refresh(log);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek if (--file->refcount == 0) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce mail_transaction_logs_clean(log);
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek file = NULL;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce }
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (ret == 0 && log->head == file) {
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce /* success */
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek break;
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce }
8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1Jakub Hrozek
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce if (file != NULL)
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce mail_transaction_log_file_unlock(file);
a9d46b86993ee8d87fddf0ba50665c0b1b78ebb7Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (ret < 0)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce break;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* try again */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce return ret;
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce}
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorcestatic int mail_transaction_log_scan_pending(struct mail_transaction_log *log,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_index_transaction *t)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce struct mail_transaction_log_view *sync_view;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce const struct mail_transaction_header *hdr;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek const void *data;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek uint32_t max_cache_file_seq = 0;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek int ret;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek sync_view = mail_transaction_log_view_open(log);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek ret = mail_transaction_log_view_set(sync_view, t->view->log_file_seq,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek t->view->log_file_offset,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce log->head->hdr.file_seq, (uoff_t)-1,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce MAIL_TRANSACTION_TYPE_MASK);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce while ((ret = mail_transaction_log_view_next(sync_view,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce &hdr, &data, NULL)) == 1) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce case MAIL_TRANSACTION_CACHE_RESET: {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce const struct mail_transaction_cache_reset *reset = data;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce max_cache_file_seq = reset->new_file_seq;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce break;
f35f4e4c8bd5b834504c0554552d78db3624706aFabiano Fidêncio }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce }
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce /* make sure we're not writing cache_offsets to old cache file */
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (t->new_cache_file_seq == 0 && max_cache_file_seq != 0 &&
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce max_cache_file_seq != t->last_cache_file_seq &&
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce t->cache_updates != NULL) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek buffer_free(t->cache_updates);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek t->cache_updates = NULL;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (t->appends != NULL) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct mail_index_record *rec;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek size_t i, size;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce rec = buffer_get_modifyable_data(t->appends, &size);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek size /= sizeof(*rec);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek for (i = 0; i < size; i++)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek rec[i].cache_offset = 0;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek }
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce mail_transaction_log_view_close(sync_view);
942b4ce6e60e88e4e31600655fad8980f3986f68Jakub Hrozek return ret;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce}
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekstatic int log_append_buffer(struct mail_transaction_log_file *file,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek const buffer_t *buf, const buffer_t *hdr_buf,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek enum mail_transaction_type type, int external)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek struct mail_transaction_header hdr;
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik const void *data, *hdr_data;
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik size_t size, hdr_data_size;
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik uint32_t hdr_size;
bc7991db97482eb2ac77f7105ee4bb3d329acff7Lukas Slebodnik
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik data = buffer_get_data(buf, &size);
6c82774653f37945bdd0a311eb1ecc289cac683dLukas Slebodnik if (size == 0)
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce return 0;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce i_assert((size % 4) == 0);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (hdr_buf != NULL) {
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce hdr_data = buffer_get_data(hdr_buf, &hdr_data_size);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce i_assert((hdr_data_size % 4) == 0);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce } else {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce hdr_data = NULL;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce hdr_data_size = 0;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce }
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce memset(&hdr, 0, sizeof(hdr));
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce hdr.type = type;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce if (type == MAIL_TRANSACTION_EXPUNGE)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce hdr.type |= MAIL_TRANSACTION_EXPUNGE_PROT;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (external)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek hdr.type |= MAIL_TRANSACTION_EXTERNAL;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce hdr_size =
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce mail_index_uint32_to_offset(sizeof(hdr) + size + hdr_data_size);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce if (file->first_append_size == 0) {
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce /* size will be written later once everything is in disk */
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce file->first_append_size = hdr_size;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce } else {
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce hdr.size = hdr_size;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce if (pwrite_full(file->fd, &hdr, sizeof(hdr), file->sync_offset) < 0)
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce return -1;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce file->sync_offset += sizeof(hdr);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce if (hdr_data_size > 0) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek if (pwrite_full(file->fd, hdr_data, hdr_data_size,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek file->sync_offset) < 0)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek return -1;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce file->sync_offset += hdr_data_size;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce }
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (pwrite_full(file->fd, data, size, file->sync_offset) < 0)
7a162ca3ea0bf8ef6b13795a00baa28d17f6131dJakub Hrozek return -1;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek file->sync_offset += size;
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio return 0;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce}
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorcestatic const buffer_t *get_cache_reset_buf(struct mail_index_transaction *t)
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce{
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce struct mail_transaction_cache_reset u;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce buffer_t *buf;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek memset(&u, 0, sizeof(u));
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek u.new_file_seq = t->new_cache_file_seq;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce buf = buffer_create_static_hard(pool_datastack_create(), sizeof(u));
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce buffer_append(buf, &u, sizeof(u));
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce return buf;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce}
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozekstatic const buffer_t *
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozeklog_get_hdr_update_buffer(struct mail_index_transaction *t)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek{
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce buffer_t *buf;
942b4ce6e60e88e4e31600655fad8980f3986f68Jakub Hrozek struct mail_transaction_header_update u;
942b4ce6e60e88e4e31600655fad8980f3986f68Jakub Hrozek uint16_t offset;
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce int state = 0;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek memset(&u, 0, sizeof(u));
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek buf = buffer_create_dynamic(pool_datastack_create(), 256);
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce for (offset = 0; offset <= sizeof(t->hdr_change); offset++) {
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce if (offset < sizeof(t->hdr_change) && t->hdr_mask[offset]) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (state == 0) {
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce u.offset = offset;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek state++;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce }
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce } else {
if (state > 0) {
u.size = offset - u.offset;
buffer_append(buf, &u, sizeof(uint16_t)*2);
buffer_append(buf, t->hdr_change + u.offset,
u.size);
state = 0;
}
}
}
return buf;
}
static int
mail_transaction_log_append_ext_intro(struct mail_transaction_log_file *file,
struct mail_index_transaction *t,
uint32_t ext_id)
{
const struct mail_index_ext *ext;
struct mail_transaction_ext_intro *intro;
buffer_t *buf;
uint32_t idx;
size_t size;
if (!mail_index_map_get_ext_idx(t->view->map, ext_id, &idx)) {
/* new extension */
idx = (uint32_t)-1;
}
ext = t->view->index->extensions->data;
ext += ext_id;
if (t->ext_resizes == NULL) {
intro = NULL;
size = 0;
} else {
intro = buffer_get_modifyable_data(t->ext_resizes, &size);
size /= sizeof(*intro);
}
buf = buffer_create_dynamic(pool_datastack_create(), 128);
if (ext_id < size && intro[ext_id].name_size != 0) {
/* we're resizing it */
intro += ext_id;
i_assert(intro->ext_id == idx);
intro->name_size = idx != (uint32_t)-1 ? 0 :
strlen(ext->name);
buffer_append(buf, intro, sizeof(*intro));
} else {
/* generate a new intro structure */
intro = buffer_append_space_unsafe(buf, sizeof(*intro));
intro->ext_id = idx;
intro->hdr_size = ext->hdr_size;
intro->record_size = ext->record_size;
intro->record_align = ext->record_align;
intro->name_size = idx != (uint32_t)-1 ? 0 :
strlen(ext->name);
}
buffer_append(buf, ext->name, intro->name_size);
if ((buf->used % 4) != 0)
buffer_append_zero(buf, 4 - (buf->used % 4));
return log_append_buffer(file, buf, NULL, MAIL_TRANSACTION_EXT_INTRO,
t->view->external);
}
static int
mail_transaction_log_append_ext_intros(struct mail_transaction_log_file *file,
struct mail_index_transaction *t)
{
const struct mail_transaction_ext_intro *resize;
uint32_t ext_id, ext_count, update_count, resize_count;
buffer_t **update;
size_t size;
if (t->ext_rec_updates == NULL) {
update = NULL;
update_count = 0;
} else {
update = buffer_get_modifyable_data(t->ext_rec_updates, &size);
update_count = size / sizeof(*update);
}
if (t->ext_resizes == NULL) {
resize = NULL;
resize_count = 0;
} else {
resize = buffer_get_modifyable_data(t->ext_resizes, &size);
resize_count = size / sizeof(*resize);
}
ext_count = I_MAX(update_count, resize_count);
for (ext_id = 0; ext_id < ext_count; ext_id++) {
if ((ext_id < resize_count && resize[ext_id].name_size) ||
(ext_id < update_count && update[ext_id] != NULL)) {
if (mail_transaction_log_append_ext_intro(file, t,
ext_id) < 0)
return -1;
}
}
return 0;
}
int mail_transaction_log_append(struct mail_index_transaction *t,
uint32_t *log_file_seq_r,
uoff_t *log_file_offset_r)
{
struct mail_index_view *view = t->view;
struct mail_index *index;
struct mail_transaction_log *log;
struct mail_transaction_log_file *file;
struct mail_index_header idx_hdr;
uoff_t append_offset;
buffer_t **updates;
unsigned int i, lock_id;
size_t size;
int ret;
index = mail_index_view_get_index(view);
log = index->log;
if (!t->log_updates) {
/* nothing to append */
*log_file_seq_r = 0;
*log_file_offset_r = 0;
return 0;
}
if (log->index->log_locked) {
i_assert(view->external);
} else {
if (mail_transaction_log_lock_head(log) < 0)
return -1;
/* update sync_offset */
if (mail_transaction_log_file_map(log->head,
log->head->sync_offset,
(uoff_t)-1) < 0) {
mail_transaction_log_file_unlock(log->head);
return -1;
}
}
if (mail_index_lock_shared(log->index, TRUE, &lock_id) < 0) {
if (!log->index->log_locked)
mail_transaction_log_file_unlock(log->head);
return -1;
}
idx_hdr = *log->index->hdr;
mail_index_unlock(log->index, lock_id);
if (log->head->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_SIZE &&
log->head->last_mtime <
ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_MIN_TIME) {
/* we might want to rotate, but check first that everything is
synced in index. */
if (log->head->hdr.file_seq == idx_hdr.log_file_seq &&
log->head->sync_offset == idx_hdr.log_file_offset) {
if (mail_transaction_log_rotate(log, TRUE) < 0) {
/* that didn't work. well, try to continue
anyway */
}
}
}
file = log->head;
file->first_append_size = 0;
append_offset = file->sync_offset;
if (t->cache_updates != NULL &&
t->last_cache_file_seq < idx_hdr.cache_file_seq) {
/* cache_offsets point to old file, don't allow */
buffer_free(t->cache_updates);
t->cache_updates = NULL;
}
if (t->appends != NULL ||
(t->cache_updates != NULL && t->new_cache_file_seq == 0) ||
(t->ext_rec_updates != NULL && t->ext_rec_updates->used > 0)) {
if (mail_transaction_log_scan_pending(log, t) < 0) {
if (!log->index->log_locked)
mail_transaction_log_file_unlock(file);
return -1;
}
}
ret = 0;
/* send all extension introductions and resizes before appends
to avoid resize overhead as much as possible */
ret = mail_transaction_log_append_ext_intros(file, t);
if (t->appends != NULL && ret == 0) {
ret = log_append_buffer(file, t->appends, NULL,
MAIL_TRANSACTION_APPEND,
view->external);
}
if (t->updates != NULL && ret == 0) {
ret = log_append_buffer(file, t->updates, NULL,
MAIL_TRANSACTION_FLAG_UPDATE,
view->external);
}
if (t->new_cache_file_seq != 0) {
ret = log_append_buffer(file, get_cache_reset_buf(t), NULL,
MAIL_TRANSACTION_CACHE_RESET,
view->external);
}
if (t->cache_updates != NULL && ret == 0) {
ret = log_append_buffer(file, t->cache_updates, NULL,
MAIL_TRANSACTION_CACHE_UPDATE,
view->external);
}
if (t->ext_rec_updates == NULL) {
updates = NULL;
size = 0;
} else {
updates = buffer_get_modifyable_data(t->ext_rec_updates, &size);
size /= sizeof(*updates);
}
for (i = 0; i < size && ret == 0; i++) {
if (updates[i] == NULL)
continue;
ret = mail_transaction_log_append_ext_intro(file, t, i);
if (ret < 0)
break;
ret = log_append_buffer(file, updates[i], NULL,
MAIL_TRANSACTION_EXT_REC_UPDATE,
view->external);
}
if (t->expunges != NULL && ret == 0) {
ret = log_append_buffer(file, t->expunges, NULL,
MAIL_TRANSACTION_EXPUNGE,
view->external);
}
if (t->hdr_changed && ret == 0) {
ret = log_append_buffer(file, log_get_hdr_update_buffer(t),
NULL, MAIL_TRANSACTION_HEADER_UPDATE,
view->external);
}
if (ret < 0) {
mail_index_file_set_syscall_error(log->index, file->filepath,
"pwrite()");
}
if (ret == 0 && (t->updates != NULL || t->appends != NULL) &&
t->hide_transaction) {
mail_index_view_add_synced_transaction(view, file->hdr.file_seq,
append_offset);
}
if (ret == 0 && fsync(file->fd) < 0) {
/* we don't know how much of it got written,
it may be corrupted now.. */
mail_index_file_set_syscall_error(log->index, file->filepath,
"fsync()");
ret = -1;
}
if (ret == 0 && file->first_append_size != 0) {
/* synced - rewrite first record's header */
ret = pwrite_full(file->fd, &file->first_append_size,
sizeof(uint32_t), append_offset);
if (ret < 0) {
mail_index_file_set_syscall_error(log->index,
file->filepath,
"pwrite()");
}
}
if (ret < 0)
file->sync_offset = append_offset;
*log_file_seq_r = file->hdr.file_seq;
*log_file_offset_r = file->sync_offset;
if (!log->index->log_locked)
mail_transaction_log_file_unlock(file);
return ret;
}
int mail_transaction_log_sync_lock(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(!log->index->log_locked);
if (mail_transaction_log_lock_head(log) < 0)
return -1;
/* update sync_offset */
if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
(uoff_t)-1) < 0) {
mail_transaction_log_file_unlock(log->head);
return -1;
}
log->index->log_locked = TRUE;
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->sync_offset;
return 0;
}
void mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
{
i_assert(log->index->log_locked);
log->index->log_locked = FALSE;
mail_transaction_log_file_unlock(log->head);
}
void mail_transaction_log_get_head(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(log->index->log_locked);
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->sync_offset;
}