mdbox-storage-rebuild.c revision 8a743d6403fe59aa6fcfd15b422ceeb13fd1a725
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen struct mdbox_map_mail_index_header orig_map_hdr;
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen ARRAY_DEFINE(msgs, struct mdbox_rebuild_msg *);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenmdbox_storage_rebuild_init(struct mdbox_storage *storage,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ctx = i_new(struct mdbox_storage_rebuild_context, 1);
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen ctx->pool = pool_alloconly_create("dbox map rebuild", 1024*256);
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen ctx->guid_hash = hash_table_create(default_pool, ctx->pool, 0,
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainenmdbox_storage_rebuild_deinit(struct mdbox_storage_rebuild_context *ctx)
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainenstatic int mdbox_rebuild_msg_offset_cmp(const void *p1, const void *p2)
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen const struct mdbox_rebuild_msg *const *m1 = p1, *const *m2 = p2;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic int mdbox_rebuild_msg_uid_cmp(struct mdbox_rebuild_msg *const *m1,
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainenstatic int rebuild_file_mails(struct mdbox_storage_rebuild_context *ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen while ((ret = dbox_file_seek_next(file, &offset, &last)) >= 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if ((ret = dbox_file_metadata_read(file)) < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* file is corrupted. fix it and retry. */
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen /* use existing file header if it was ok */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen /* seek to the offset where we last left off */
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen guid = dbox_file_metadata_get(file, DBOX_METADATA_GUID);
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen "Message is missing GUID");
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen rec = p_new(ctx->pool, struct mdbox_rebuild_msg, 1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen rec->rec_size = file->input->v_offset - offset;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen rec->mail_size = dbox_file_get_plaintext_size(file);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mail_generate_guid_128_hash(guid, rec->guid_128);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen old_rec = hash_table_lookup(ctx->guid_hash, rec->guid_128);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hash_table_insert(ctx->guid_hash, rec->guid_128, rec);
61ddcdc28f50d9cb9994fcc4ad63f9dff0e80628Timo Sirainen else if (rec->mail_size == old_rec->mail_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* two mails' GUID and size are the same, which quite
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen likely means that their contents are the same as
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen well. we'll compare the mail sizes instead of the
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen record sizes, because the records' metadata may
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen save this duplicate mail with refcount=0 to the map,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen so it will eventually be purged. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* duplicate GUID, but not a duplicate message. */
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen old_rec->file_id, old_rec->offset, old_rec->mail_size,
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen rec->guid_hash_next = old_rec->guid_hash_next;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenrebuild_rename_file(struct mdbox_storage_rebuild_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *dir, const char **fname_p, uint32_t *file_id_r)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen const char *old_path, *new_path, *fname = *fname_p;
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen old_path = t_strconcat(dir, "/", fname, NULL);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen new_path = t_strdup_printf("%s/"MDBOX_MAIL_FILE_FORMAT,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* use link()+unlink() instead of rename() to make sure we
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen don't overwrite any files. */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_error("link(%s, %s) failed: %m", old_path, new_path);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainenstatic int rebuild_add_file(struct mdbox_storage_rebuild_context *ctx,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen id_str = fname + strlen(MDBOX_MAIL_FILE_PREFIX);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (str_to_uint32(id_str, &file_id) < 0 || file_id == 0) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen /* m.*.broken files are created by file fixing
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen m.*.lock files are created if flock() isn't available */
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (ext == NULL || (strcmp(ext, ".broken") != 0 &&
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen "Skipping file with missing ID: %s/%s",
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (!seq_range_exists(&ctx->seen_file_ids, file_id)) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* duplicate file. either readdir() returned it twice
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (unlikely) or it exists in both alt and primary storage.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen to make sure we don't lose any mails from either of the
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainen files, give this file a new ID and rename it. */
5e40ed3f0a2c2acddc9b8eab59670c7a850114c5Timo Sirainen if (rebuild_rename_file(ctx, dir, &fname, &file_id) < 0)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen seq_range_array_add(&ctx->seen_file_ids, 0, file_id);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen file = mdbox_file_init(ctx->storage, file_id);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if ((ret = dbox_file_open(file, &deleted)) > 0 && !deleted)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_error("mdbox rebuild: Failed to fix file %s/%s", dir, fname);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenrebuild_add_missing_map_uids(struct mdbox_storage_rebuild_context *ctx,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen unsigned int i, count;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen msgs = array_get_modifiable(&ctx->msgs, &count);
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen for (i = 0; i < count; i++) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen mail_index_update_ext(ctx->atomic->sync_trans, seq,
unsigned int count;
static struct mdbox_rebuild_msg *
return TRUE;
return FALSE;
const void *data;
bool expunged;
map_uid = 0;
} T_END;
const void *data;
int ret;
if (ret <= 0) {
int ret = 0;
MAILBOX_NOSELECT)) == 0) {
T_BEGIN {
} T_END;
if (ret < 0) {
return ret;
int ret;
if (ret < 0)
if (ret <= 0) {
unsigned int i, count;
for (i = 0; i < count; i++) {
const void *data;
bool expunged;
unsigned int i, count;
struct dirent *d;
int ret = 0;
} T_END;
return ret;
const void *data;
FALSE) < 0)
int ret;
if (ret == 0) {
return ret;
int ret;
return ret;