const char *line;
int ret;
+ i_stream_seek(file->input, *offset);
if ((ret = dbox_file_metadata_skip_header(file)) <= 0)
return ret;
/* first mail */
offset = file->file_header_size;
} else {
- offset = file->cur_offset + file->cur_physical_size;
+ offset = file->cur_offset + file->msg_header_size +
+ file->cur_physical_size;
if ((ret = dbox_file_seek_next_at_metadata(file, &offset)) <= 0)
return ret;
}
*offset_r = offset;
- *last_r = FALSE;
-
- ret = dbox_file_get_mail_stream(file, offset, &size, NULL, &expunged);
- if (ret <= 0)
- return ret;
- if (expunged) {
+ if (file->input != NULL && i_stream_is_eof(file->input)) {
*last_r = TRUE;
return 0;
}
- return 1;
+ *last_r = FALSE;
+
+ return dbox_file_get_mail_stream(file, offset, &size, NULL, &expunged);
}
static int
if (map_uid == 0) {
mail->open_file =
dbox_file_init_single(mbox, _mail->uid);
- } else {
- ret = dbox_map_lookup(mbox->storage->map, map_uid,
- &file_id, &mail->offset);
- if (ret <= 0) {
- if (ret == 0)
- mail_set_expunged(_mail);
+ } else if ((ret = dbox_map_lookup(mbox->storage->map,
+ map_uid, &file_id,
+ &mail->offset)) <= 0) {
+ if (ret < 0)
+ return -1;
+
+ /* map_uid doesn't exist anymore. either it
+ got just expunged or the map index is
+ corrupted. see if the message still exists
+ in the mailbox index. */
+ (void)mail_index_refresh(mbox->ibox.index);
+ if (mail_index_is_expunged(mbox->ibox.view,
+ _mail->seq)) {
+ mail_set_expunged(_mail);
return -1;
}
+
+ dbox_map_set_corrupted(mbox->storage->map,
+ "Unexpectedly lost map_uid=%u", map_uid);
+ mbox->storage->sync_rebuild = TRUE;
+ return -1;
+ } else {
mail->open_file =
dbox_file_init_multi(mbox->storage, file_id);
}
unsigned int committed:1;
};
+int dbox_map_open(struct dbox_map *map);
int dbox_map_refresh(struct dbox_map *map);
int dbox_map_view_lookup_rec(struct dbox_map *map, struct mail_index_view *view,
uint32_t seq, struct dbox_mail_lookup_rec *rec_r);
i_free(map);
}
-static int dbox_map_open(struct dbox_map *map)
+int dbox_map_open(struct dbox_map *map)
{
struct mail_storage *storage = &map->storage->storage;
enum mail_index_open_flags open_flags;
return ctx;
}
+static void
+dbox_map_sync_handle(struct dbox_map *map, struct mail_index_sync_ctx *sync_ctx)
+{
+ struct mail_index_sync_rec sync_rec;
+ uint32_t seq1, seq2;
+ uoff_t offset1, offset2;
+
+ mail_index_sync_get_offsets(sync_ctx, &seq1, &offset1, &seq2, &offset2);
+ if (offset1 != offset2 || seq1 != seq2) {
+ /* something had crashed. need a full resync. */
+ i_warning("dbox %s: Inconsistency in map index",
+ map->storage->storage_dir);
+ map->storage->sync_rebuild = TRUE;
+ } else {
+ while (mail_index_sync_next(sync_ctx, &sync_rec)) ;
+ }
+}
+
int dbox_map_transaction_commit(struct dbox_map_transaction_context **_ctx)
{
struct dbox_map_transaction_context *ctx = *_ctx;
struct mail_index_sync_ctx *sync_ctx;
struct mail_index_view *view;
struct mail_index_transaction *sync_trans, *trans = ctx->trans;
- uint32_t seq1, seq2;
- uoff_t offset1, offset2;
int ret;
*_ctx = NULL;
- i_free(ctx);
-
if (!ctx->changed) {
mail_index_transaction_rollback(&trans);
+ i_free(ctx);
return 0;
}
+ i_free(ctx);
/* use syncing to lock the transaction log, so that we always see
log's head_offset = tail_offset */
mail_index_transaction_rollback(&trans);
return -1;
}
-
- mail_index_sync_get_offsets(sync_ctx, &seq1, &offset1, &seq2, &offset2);
- if (offset1 != offset2 || seq1 != seq2) {
- /* something had crashed. need a full resync. */
- i_warning("dbox %s: Inconsistency in map index",
- map->storage->storage_dir);
- map->storage->sync_rebuild = TRUE;
- }
+ dbox_map_sync_handle(map, sync_ctx);
if (mail_index_transaction_commit(&trans) < 0 ||
mail_index_sync_commit(&sync_ctx) < 0) {
return 0;
}
-int dbox_map_remove_file_id(struct dbox_map_transaction_context *ctx,
- uint32_t file_id)
+int dbox_map_remove_file_id(struct dbox_map *map, uint32_t file_id)
{
- struct dbox_map *map = ctx->map;
+ struct dbox_map_transaction_context *map_trans;
const struct mail_index_header *hdr;
const struct dbox_mail_index_map_record *rec;
const void *data;
bool expunged;
uint32_t seq;
+ int ret = 0;
/* make sure the map is refreshed, otherwise we might be expunging
messages that have already been moved to other files. */
if (dbox_map_refresh(map) < 0)
return -1;
+ /* we need a per-file transaction, otherwise we can't refresh the map */
+ map_trans = dbox_map_transaction_begin(map);
+
hdr = mail_index_get_header(map->view);
for (seq = 1; seq <= hdr->messages_count; seq++) {
mail_index_lookup_ext(map->view, seq, map->map_ext_id,
&data, &expunged);
if (data == NULL) {
dbox_map_set_corrupted(map, "missing map extension");
- return -1;
+ ret = -1;
+ break;
}
rec = data;
if (rec->file_id == file_id) {
- ctx->changed = TRUE;
- mail_index_expunge(ctx->trans, seq);
+ map_trans->changed = TRUE;
+ mail_index_expunge(map_trans->trans, seq);
}
}
- return 0;
+ if (ret < 0)
+ dbox_map_transaction_rollback(&map_trans);
+ else
+ (void)dbox_map_transaction_commit(&map_trans);
+ return ret;
}
struct dbox_map_append_context *
{
struct dbox_file *const *files;
unsigned int i, count;
- uint32_t first_file_id, file_id, seq1, seq2;
- uoff_t offset1, offset2;
+ uint32_t first_file_id, file_id;
int ret;
/* start the syncing. we'll need it even if there are no file ids to
mail_index_reset_error(ctx->map->index);
return -1;
}
-
- mail_index_sync_get_offsets(ctx->sync_ctx, &seq1, &offset1,
- &seq2, &offset2);
- if (offset1 != offset2 || seq1 != seq2) {
- /* something had crashed. need a full resync. */
- i_warning("dbox %s: Inconsistency in map index",
- ctx->map->storage->storage_dir);
- ctx->map->storage->sync_rebuild = TRUE;
- }
+ dbox_map_sync_handle(ctx->map, ctx->sync_ctx);
if (dbox_map_get_next_file_id(ctx->map, ctx->sync_view, &file_id) < 0) {
mail_index_sync_rollback(&ctx->sync_ctx);
int dbox_map_update_refcounts(struct dbox_map_transaction_context *ctx,
const ARRAY_TYPE(seq_range) *map_uids, int diff);
-int dbox_map_remove_file_id(struct dbox_map_transaction_context *ctx,
- uint32_t file_id);
+int dbox_map_remove_file_id(struct dbox_map *map, uint32_t file_id);
/* Return all files containing messages with zero refcount. */
const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map);
{
struct dbox_map *map = ctx->storage->map;
const struct mail_index_header *hdr;
- struct dbox_rebuild_msg **msgs, *pos;
+ struct dbox_rebuild_msg **msgs, **pos;
struct dbox_rebuild_msg search_msg, *search_msgp = &search_msg;
struct dbox_mail_lookup_rec rec;
uint32_t seq;
/* map record points to non-existing message. */
mail_index_expunge(ctx->trans, seq);
} else {
- pos->map_uid = rec.map_uid;
- pos->seen_zero_ref_in_map = rec.refcount == 0;
+ (*pos)->map_uid = rec.map_uid;
+ (*pos)->seen_zero_ref_in_map = rec.refcount == 0;
}
}
rebuild_add_missing_map_uids(ctx, hdr->next_uid);
uint32_t map_uid)
{
struct dbox_rebuild_msg search_msg, *search_msgp = &search_msg;
- struct dbox_rebuild_msg *const *msgs;
+ struct dbox_rebuild_msg *const *msgs, **pos;
unsigned int count;
search_msg.map_uid = map_uid;
msgs = array_get(&ctx->msgs, &count);
- return bsearch(&search_msgp, msgs, count, sizeof(*msgs),
- dbox_rebuild_msg_uid_cmp);
+ pos = bsearch(&search_msgp, msgs, count, sizeof(*msgs),
+ dbox_rebuild_msg_uid_cmp);
+ return pos == NULL ? NULL : *pos;
}
static void
/* everything was ok */
}
- if (rec != NULL) {
+ if (rec != NULL) T_BEGIN {
/* keep this message */
rec->refcount++;
NULL, new_seq, uid);
new_dbox_rec.map_uid = rec->map_uid;
- mail_index_update_ext(ctx->trans, new_seq,
+ mail_index_update_ext(trans, new_seq,
mbox->dbox_ext_id,
&new_dbox_rec, NULL);
- }
+ } T_END;
}
}
while ((info = mailbox_list_iter_next(iter)) != NULL) {
if ((info->flags & (MAILBOX_NONEXISTENT |
MAILBOX_NOSELECT)) == 0) {
- if (rebuild_mailbox(ctx, info->name) < 0) {
+ T_BEGIN {
+ ret = rebuild_mailbox(ctx, info->name);
+ } T_END;
+ if (ret < 0) {
ret = -1;
break;
}
unsigned int dir_len;
int ret = 0;
+ if (dbox_map_open(ctx->storage->map) < 0)
+ return -1;
+
/* begin by locking the map, so that other processes can't try to
rebuild at the same time. */
ret = mail_index_sync_begin(ctx->storage->map->index, &ctx->sync_ctx,
str_truncate(path, dir_len);
str_append(path, d->d_name);
T_BEGIN {
- ret = rebuild_add_file(ctx, d->d_name);
+ ret = rebuild_add_file(ctx, str_c(path));
} T_END;
if (ret < 0) {
ret = -1;
#include "dbox-map.h"
#include "dbox-file.h"
#include "dbox-sync.h"
+#include "dbox-storage-rebuild.h"
#include "dbox-storage.h"
#include <stdio.h>
{
struct dbox_storage *storage = (struct dbox_storage *)_storage;
+ if (storage->sync_rebuild) {
+ if (dbox_storage_rebuild(storage) < 0)
+ return;
+ }
+
dbox_sync_cleanup(storage);
dbox_files_free(storage);
dbox_map_deinit(&storage->map);
}
mail_index_append(ctx->trans, file->uid, &seq);
- dbox_sync_rebuild_index_metadata(ctx, file, seq, file->uid);
+ T_BEGIN {
+ dbox_sync_rebuild_index_metadata(ctx, file, seq, file->uid);
+ } T_END;
return 0;
}
#endif
open_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
if (mail_index_open(ctx->backup_index, open_flags,
- box->storage->lock_method) < 0)
+ box->storage->lock_method) <= 0)
mail_index_free(&ctx->backup_index);
else
ctx->backup_view = mail_index_view_open(ctx->backup_index);
mail_index_view_close(&view);
if (ret == 0)
- ctx->mbox->storage->sync_rebuild = FALSE;
+ mbox->storage->sync_rebuild = FALSE;
return ret;
}
hdr = mail_index_get_header(ctx->sync_view);
if (hdr->uid_validity == 0) {
/* newly created index file */
+ i_warning("FIXME: newly created");
return 0;
}
dbox_sync_file_entry_hash,
dbox_sync_file_entry_cmp);
- for (;;) {
- if (!mail_index_sync_next(ctx->index_sync_ctx, &sync_rec))
- break;
+ while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec)) {
if ((ret = dbox_sync_add(ctx, &sync_rec)) <= 0)
break;
}
hash_table_iterate_deinit(&iter);
}
- if (ret == 0)
- ret = dbox_map_transaction_commit(&ctx->map_trans);
+ if (ret > 0 && ctx->map_trans != NULL) {
+ if (dbox_map_transaction_commit(&ctx->map_trans) < 0)
+ ret = -1;
+ }
if (box->v.sync_notify != NULL)
box->v.sync_notify(box, 0, 0);
if (data_size != 0 && data_size != 4) {
i_warning("dbox %s: Invalid dbox header size",
mbox->path);
- }
+ } else
+ i_warning("FIXME: initial sync");
return -1;
}
hdr = data;
return dbox_sync_begin(mbox, flags, ctx_r);
}
ret = 0;
+ i_warning("FIXME: poop");
} else {
if ((ret = dbox_sync_index(ctx)) > 0)
break;
ret = -1;
} else {
/* do a full resync and try again. */
+ i_warning("dbox %s: Rebuilding index",
+ ctx->mbox->path);
ret = dbox_sync_index_rebuild(mbox);
}
}
void dbox_sync_cleanup(struct dbox_storage *storage)
{
const ARRAY_TYPE(seq_range) *ref0_file_ids;
- struct dbox_map_transaction_context *map_trans;
struct dbox_file *file;
struct seq_range_iter iter;
unsigned int i = 0;
uint32_t file_id;
bool deleted;
- map_trans = dbox_map_transaction_begin(storage->map);
-
ref0_file_ids = dbox_map_get_zero_ref_files(storage->map);
seq_range_array_iter_init(&iter, ref0_file_ids); i = 0;
while (seq_range_array_iter_nth(&iter, i++, &file_id)) T_BEGIN {
if (dbox_file_open_or_create(file, &deleted) > 0 && !deleted)
(void)dbox_sync_file_cleanup(file);
else
- dbox_map_remove_file_id(map_trans, file_id);
+ dbox_map_remove_file_id(storage->map, file_id);
dbox_file_unref(&file);
} T_END;
-
- (void)dbox_map_transaction_commit(&map_trans);
}