#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
static int
-mail_transaction_log_file_sync(struct mail_transaction_log_file *file);
+mail_transaction_log_file_sync(struct mail_transaction_log_file *file,
+ bool *retry_r);
static void
log_file_set_syscall_error(struct mail_transaction_log_file *file,
mail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
{
struct mail_transaction_log_file **p;
+ bool retry;
file->sync_offset = file->hdr.hdr_size;
file->sync_highest_modseq = file->hdr.initial_modseq;
if (file->buffer != NULL) {
/* if we read any unfinished data, make sure the buffer gets
truncated. */
- (void)mail_transaction_log_file_sync(file);
+ (void)mail_transaction_log_file_sync(file, &retry);
buffer_set_used_size(file->buffer,
file->sync_offset - file->buffer_offset);
}
}
static int
-mail_transaction_log_file_sync(struct mail_transaction_log_file *file)
+mail_transaction_log_file_sync(struct mail_transaction_log_file *file,
+ bool *retry_r)
{
const struct mail_transaction_header *hdr;
const void *data;
i_assert(file->sync_offset >= file->buffer_offset);
+ *retry_r = FALSE;
+
data = buffer_get_data(file->buffer, &size);
if (file->buffer_offset + size < file->sync_offset) {
mail_transaction_log_file_set_corrupted(file,
file->buffer_offset + (uoff_t)size, file->sync_offset);
/* fix the sync_offset to avoid crashes later on */
file->sync_offset = file->buffer_offset + size;
- return -1;
+ return 0;
}
while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
hdr = CONST_PTR_OFFSET(data, file->sync_offset -
if (trans_size < sizeof(*hdr)) {
mail_transaction_log_file_set_corrupted(file,
"hdr.size too small (%u)", trans_size);
- return -1;
+ return 0;
}
if (file->sync_offset - file->buffer_offset + trans_size > size)
/* transaction has been fully written */
if ((ret = log_file_track_sync(file, hdr, trans_size)) <= 0) {
if (ret < 0)
- return -1;
+ return 0;
break;
}
}
if ((uoff_t)st.st_size != file->last_size) {
file->last_size = st.st_size;
+ *retry_r = TRUE;
return 0;
}
}
if (file->locked) {
mail_transaction_log_file_set_corrupted(file,
"Unexpected garbage at EOF");
- return -1;
+ return 0;
}
/* The size field will be updated soon */
mail_index_flush_read_cache(file->log->index, file->filepath,
"Invalid transaction log size "
"(%"PRIuUOFF_T" vs %u): %s", file->sync_offset,
file->log->head->hdr.prev_file_offset, file->filepath);
- return -1;
+ return 0;
}
return 1;
mail_transaction_log_file_read(struct mail_transaction_log_file *file,
uoff_t start_offset, bool nfs_flush)
{
+ bool retry;
int ret;
i_assert(file->mmap_base == NULL);
mail_transaction_log_file_need_nfs_flush(file)) {
/* we didn't read enough data. flush and try again. */
return mail_transaction_log_file_read(file, start_offset, TRUE);
- } else if ((ret = mail_transaction_log_file_sync(file)) <= 0) {
- i_assert(ret != 0); /* ret=0 happens only with mmap */
- } else {
- i_assert(file->sync_offset >= file->buffer_offset);
+ } else if ((ret = mail_transaction_log_file_sync(file, &retry)) == 0) {
+ i_assert(!retry); /* retry happens only with mmap */
}
+ i_assert(file->sync_offset >= file->buffer_offset);
buffer_set_used_size(file->buffer,
file->sync_offset - file->buffer_offset);
return ret;
uoff_t start_offset)
{
struct stat st;
+ bool retry;
int ret;
/* we are going to mmap() this file, but it's not necessarily
if (file->buffer != NULL && file->buffer_offset <= start_offset &&
(uoff_t)st.st_size == file->buffer_offset + file->buffer->used) {
/* we already have the whole file mapped */
- if ((ret = mail_transaction_log_file_sync(file)) < 0)
- return 0;
- if (ret > 0)
- return 1;
+ if ((ret = mail_transaction_log_file_sync(file, &retry)) != 0 ||
+ !retry)
+ return ret;
/* size changed, re-mmap */
}
if (mail_transaction_log_file_mmap(file) < 0)
return -1;
- if ((ret = mail_transaction_log_file_sync(file)) < 0)
- return 0;
- } while (ret == 0);
+ ret = mail_transaction_log_file_sync(file, &retry);
+ } while (retry);
- return 1;
+ return ret;
}
int mail_transaction_log_file_map(struct mail_transaction_log_file *file,