mail-index-write.c revision 39087f589d24f3072f220c2ed4528ee323f129ff
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2003-2015 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "read-full.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen#include "mail-index-private.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "mail-transaction-log-private.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdio.h>
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#define MAIL_INDEX_MIN_UPDATE_SIZE 1024
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen/* if we're updating >= count-n messages, recreate the index */
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen#define MAIL_INDEX_MAX_OVERWRITE_NEG_SEQ_COUNT 10
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic int mail_index_create_backup(struct mail_index *index)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const char *backup_path, *tmp_backup_path;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen int ret;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (index->fd != -1) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* we very much want to avoid creating a backup file that
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen hasn't been written to disk yet */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (fdatasync(index->fd) < 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mail_index_set_error(index, "fdatasync(%s) failed: %m",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen index->filepath);
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen backup_path = t_strconcat(index->filepath, ".backup", NULL);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen tmp_backup_path = t_strconcat(backup_path, ".tmp", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = link(index->filepath, tmp_backup_path);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ret < 0 && errno == EEXIST) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (unlink(tmp_backup_path) < 0 && errno != ENOENT) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_set_error(index, "unlink(%s) failed: %m",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen tmp_backup_path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ret = link(index->filepath, tmp_backup_path);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (ret < 0) {
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen if (errno == ENOENT) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* no dovecot.index file, ignore */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mail_index_set_error(index, "link(%s, %s) failed: %m",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen index->filepath, tmp_backup_path);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return -1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (rename(tmp_backup_path, backup_path) < 0) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen mail_index_set_error(index, "rename(%s, %s) failed: %m",
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen tmp_backup_path, backup_path);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen return -1;
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen }
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen return 0;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic int mail_index_recreate(struct mail_index *index)
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen{
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen struct mail_index_map *map = index->map;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct ostream *output;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen unsigned int base_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = 0, fd;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen i_assert(map->hdr.indexid == index->indexid);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen fd = mail_index_create_tmp_file(index, index->filepath, &path);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (fd == -1)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen return -1;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen output = o_stream_create_fd_file(fd, 0, FALSE);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen o_stream_cork(output);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen base_size = I_MIN(map->hdr.base_header_size, sizeof(map->hdr));
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen o_stream_nsend(output, &map->hdr, base_size);
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen o_stream_nsend(output, CONST_PTR_OFFSET(map->hdr_base, base_size),
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen map->hdr.header_size - base_size);
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen o_stream_nsend(output, map->rec_map->records,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen map->rec_map->records_count * map->hdr.record_size);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen o_stream_nflush(output);
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen if (o_stream_nfinish(output) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_file_set_syscall_error(index, path, "write()");
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen ret = -1;
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen }
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen o_stream_destroy(&output);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (ret == 0 && index->fsync_mode != FSYNC_MODE_NEVER) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fdatasync(fd) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_file_set_syscall_error(index, path,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "fdatasync()");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (close(fd) < 0) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen mail_index_file_set_syscall_error(index, path, "close()");
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if ((index->flags & MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS) != 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen (void)mail_index_create_backup(index);
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0 && rename(path, index->filepath) < 0) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen mail_index_set_error(index, "rename(%s, %s) failed: %m",
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen path, index->filepath);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ret = -1;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (ret < 0)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_unlink(path);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen return ret;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen}
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_write(struct mail_index *index, bool want_rotate)
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen{
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen struct mail_index_map *map = index->map;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen const struct mail_index_header *hdr = &map->hdr;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_assert(index->log_sync_locked);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (index->readonly)
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen return;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (!MAIL_INDEX_IS_IN_MEMORY(index)) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (mail_index_recreate(index) < 0) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen (void)mail_index_move_to_memory(index);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen return;
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen }
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen index->last_read_log_file_seq = hdr->log_file_seq;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen index->last_read_log_file_head_offset = hdr->log_file_head_offset;
4b41116563110d00330896a568eff1078c382827Timo Sirainen index->last_read_log_file_tail_offset = hdr->log_file_tail_offset;
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (want_rotate &&
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen hdr->log_file_seq == index->log->head->hdr.file_seq &&
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen hdr->log_file_tail_offset == hdr->log_file_head_offset)
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen (void)mail_transaction_log_rotate(index->log, FALSE);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen