fixes etc.
--HG--
branch : HEAD
size_t expunge_idx, update_idx;
uint32_t next_uid;
- unsigned int lock_id, dirty_lock_id;
+ unsigned int lock_id;
unsigned int sync_appends:1;
- unsigned int have_dirty:1;
};
int mail_index_sync_update_index(struct mail_index_sync_ctx *sync_ctx,
struct mail_index_view *view;
struct mail_index_header hdr;
struct mail_transaction_log_view *log_view;
+
+ unsigned int have_dirty:1;
};
void mail_index_header_update_counts(struct mail_index_header *hdr,
if (seq1 == 0)
return;
+ if ((syncrec->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
+ ctx->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
+ ctx->have_dirty = TRUE;
+ }
+
update_keywords = FALSE;
for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
if (syncrec->add_keywords[i] != 0)
struct mail_index_sync_rec rec;
const struct mail_index_record *appends;
unsigned int append_count;
- uint32_t count, file_seq, src_idx, dest_idx, dirty_flag;
+ uint32_t count, file_seq, src_idx, dest_idx, i;
uint32_t seq1, seq2;
uoff_t file_offset;
unsigned int lock_id;
ctx.hdr = *index->hdr;
ctx.log_view = sync_ctx->view->log_view;
- dirty_flag = sync_ctx->have_dirty ? MAIL_INDEX_HDR_FLAG_HAVE_DIRTY : 0;
- if ((ctx.hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != dirty_flag) {
- ctx.hdr.flags ^= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
- changed = TRUE;
- }
-
/* see if we need to update sync headers */
if (ctx.hdr.sync_stamp != sync_stamp && sync_stamp != 0) {
ctx.hdr.sync_stamp = sync_stamp;
ctx.hdr.log_file_seq = file_seq;
ctx.hdr.log_file_offset = file_offset;
+ if ((ctx.hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) &&
+ !ctx.have_dirty) {
+ /* do we have dirty flags anymore? */
+ for (i = 0; i < map->records_count; i++) {
+ if (map->records[i].flags & MAIL_INDEX_MAIL_FLAG_DIRTY)
+ break;
+ }
+ if (i == map->records_count)
+ ctx.hdr.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
+ }
+
if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
map->mmap_used_size = index->hdr->header_size +
map->records_count * sizeof(struct mail_index_record);
dest = buffer_get_data(ctx->updates_buf, &dest_count);
dest_count /= sizeof(*dest);
- for (i = 0; src != src_end; ) {
+ for (i = 0; src != src_end; src++) {
new_update = *src;
/* insert it into buffer, split it in multiple parts if needed
ctx->sync_appends;
}
-int mail_index_sync_set_dirty(struct mail_index_sync_ctx *ctx, uint32_t seq)
-{
- if (ctx->dirty_lock_id == 0) {
- if (mail_index_lock_exclusive(ctx->index,
- &ctx->dirty_lock_id) < 0)
- return -1;
- }
-
- /* FIXME: maybe this should go through transaction log anyway?
- doesn't work well with non-mmaped indexes.. */
- i_assert(seq <= ctx->view->map->records_count);
- ctx->view->map->records[seq-1].flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
- ctx->have_dirty = TRUE;
- return 0;
-}
-
int mail_index_sync_end(struct mail_index_sync_ctx *ctx,
uint32_t sync_stamp, uint64_t sync_size)
{
ret = -1;
}
- if (ctx->dirty_lock_id == 0)
- mail_index_unlock(ctx->index, ctx->dirty_lock_id);
-
mail_index_unlock(ctx->index, ctx->lock_id);
mail_transaction_log_sync_unlock(ctx->index->log);
mail_index_view_close(ctx->view);
if (idx < size && data[idx].uid2 < update.uid1)
idx++;
- i_assert(idx == size || data[idx].uid1 < update.uid1);
+ i_assert(idx == size || data[idx].uid1 <= update.uid1);
/* insert it into buffer, split it in multiple parts if needed
to make sure the ordering stays the same */
last = update.uid2;
update.uid2 = data[idx].uid1-1;
- buffer_insert(t->updates, idx * sizeof(update),
- &update, sizeof(update));
- data = buffer_get_modifyable_data(t->updates, NULL);
- size++;
+ if (update.uid1 <= update.uid2) {
+ buffer_insert(t->updates, idx * sizeof(update),
+ &update, sizeof(update));
+ data = buffer_get_modifyable_data(t->updates, NULL);
+ size++;
+ }
update.uid1 = update.uid2+1;
update.uid2 = last;
return 1;
}
-static void
+#define FLAG_UPDATE_IS_INTERNAL(u, empty) \
+ (((u)->add_flags | (u)->remove_flags) == MAIL_INDEX_MAIL_FLAG_DIRTY && \
+ memcmp((u)->add_keywords, empty, INDEX_KEYWORDS_BYTE_COUNT) == 0 && \
+ memcmp((u)->add_keywords, empty, INDEX_KEYWORDS_BYTE_COUNT) == 0)
+
+static int
mail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
struct mail_index_sync_rec *rec)
{
+ static keywords_mask_t empty_keywords = { 0, };
const struct mail_transaction_header *hdr = ctx->hdr;
const void *data = ctx->data;
const struct mail_transaction_flag_update *update =
CONST_PTR_OFFSET(data, ctx->data_offset);
- ctx->data_offset += sizeof(*update);
+ for (;;) {
+ ctx->data_offset += sizeof(*update);
+ if (!FLAG_UPDATE_IS_INTERNAL(update, empty_keywords))
+ break;
+
+ if (ctx->data_offset == ctx->hdr->size)
+ return 0;
+ }
mail_index_sync_get_update(rec, update);
break;
}
default:
i_unreached();
}
+ return 1;
}
int mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
uoff_t offset;
int ret;
- if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) {
- ctx->data_offset = 0;
- do {
- ret = mail_index_view_sync_next_trans(ctx, &seq,
- &offset);
- if (ret < 0)
- return -1;
-
- if (ctx->last_read)
- return 0;
-
- if (!ctx->skipped) {
- view->log_file_seq = seq;
- view->log_file_offset = offset +
- sizeof(*ctx->hdr) + ctx->hdr->size;
+ do {
+ if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) {
+ ctx->data_offset = 0;
+ do {
+ ret = mail_index_view_sync_next_trans(ctx, &seq,
+ &offset);
+ if (ret < 0)
+ return -1;
+
+ if (ctx->last_read)
+ return 0;
+
+ if (!ctx->skipped) {
+ view->log_file_seq = seq;
+ view->log_file_offset = offset +
+ sizeof(*ctx->hdr) +
+ ctx->hdr->size;
+ }
+ } while (ret == 0);
+
+ if (ctx->skipped) {
+ mail_index_view_add_synced_transaction(view,
+ seq,
+ offset);
}
- } while (ret == 0);
-
- if (ctx->skipped) {
- mail_index_view_add_synced_transaction(view, seq,
- offset);
}
- }
+ } while (!mail_index_view_sync_get_rec(ctx, sync_rec));
- mail_index_view_sync_get_rec(ctx, sync_rec);
return 1;
}
struct mail_index_sync_rec *sync_rec);
/* Returns 1 if there's more to sync, 0 if not. */
int mail_index_sync_have_more(struct mail_index_sync_ctx *ctx);
-/* Mark given message to be dirty, ie. we couldn't temporarily change the
- message flags in storage. Dirty messages are tried to be synced again in
- next sync. */
-int mail_index_sync_set_dirty(struct mail_index_sync_ctx *ctx, uint32_t seq);
/* End synchronization by unlocking the index and closing the view.
sync_stamp/sync_size in header is updated to given values. */
int mail_index_sync_end(struct mail_index_sync_ctx *ctx,
/* Mark index file corrupted. Invalidates all views. */
void mail_index_mark_corrupted(struct mail_index *index);
-/* Check and fix any found problems. If index is broken beyond repair, calls
- mail_index_reset() and returns 0. Otherwise returns -1 if there was some
+/* Check and fix any found problems. If index is broken beyond repair, it's
+ marked corrupted and 0 is returned. Otherwise returns -1 if there was some
I/O error or 1 if everything went ok. */
int mail_index_fsck(struct mail_index *index);
mail_storage_set_index_error(ibox);
if (sc->expunge != NULL) {
- // FIXME: these are UIDs now..
for (i = expunges_count*2; i > 0; i -= 2) {
seq = expunges[i-1];
if (seq > messages_count)
struct maildir_index_sync_context {
struct index_mailbox *ibox;
- struct mail_index_view *view;
+ struct mail_index_view *view;
struct mail_index_sync_ctx *sync_ctx;
+ struct mail_index_transaction *trans;
struct mail_index_sync_rec sync_rec;
uint32_t seq;
+ int have_dirty, last_dirty;
};
static int maildir_expunge(struct index_mailbox *ibox, const char *path,
uint8_t flags8;
keywords_mask_t keywords;
+ ctx->last_dirty = FALSE;
+
(void)maildir_filename_get_flags(path, &flags, keywords);
flags8 = flags;
if (errno == ENOENT)
return 0;
- if (ENOSPACE(errno)) {
- if (mail_index_sync_set_dirty(ctx->sync_ctx, ctx->seq) < 0)
- return -1;
+ if (ENOSPACE(errno) || errno == EACCES) {
+ memset(keywords, 0, sizeof(keywords));
+ mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_ADD,
+ MAIL_INDEX_MAIL_FLAG_DIRTY, keywords);
+ ctx->last_dirty = TRUE;
return 1;
}
{
struct mail_index_sync_rec *sync_rec = &ctx->sync_rec;
struct mail_index_view *view = ctx->view;
+ const struct mail_index_record *rec;
uint32_t seq, seq1, seq2, uid;
switch (sync_rec->type) {
for (ctx->seq = seq1; ctx->seq <= seq2; ctx->seq++) {
if (mail_index_lookup_uid(view, ctx->seq, &uid) < 0)
return -1;
- if (maildir_file_do(ibox, uid, maildir_sync_flags,
- ctx) < 0)
+ if (maildir_file_do(ibox, uid,
+ maildir_sync_flags, ctx) < 0)
return -1;
+ if (!ctx->last_dirty) {
+ /* if this flag was dirty, drop it */
+ if (mail_index_lookup(view, ctx->seq, &rec) < 0)
+ return -1;
+ if (rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) {
+ keywords_mask_t keywords;
+
+ memset(keywords, 0, sizeof(keywords));
+ mail_index_update_flags(ctx->trans,
+ ctx->seq, MODIFY_REMOVE,
+ MAIL_INDEX_MAIL_FLAG_DIRTY,
+ keywords);
+ }
+ }
}
break;
}
int maildir_sync_last_commit(struct index_mailbox *ibox)
{
struct maildir_index_sync_context ctx;
+ const struct mail_index_header *hdr;
+ uint32_t seq;
+ uoff_t offset;
int ret;
if (ibox->commit_log_file_seq == 0)
ibox->commit_log_file_seq,
ibox->commit_log_file_offset);
if (ret > 0) {
+ if (mail_index_get_header(ctx.view, &hdr) == 0 &&
+ (hdr->flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0)
+ ctx.have_dirty = TRUE;
+
+ ctx.trans = mail_index_transaction_begin(ctx.view, FALSE);
+
while ((ret = mail_index_sync_next(ctx.sync_ctx,
&ctx.sync_rec)) > 0) {
if (maildir_sync_record(ibox, &ctx) < 0) {
break;
}
}
+ if (mail_index_transaction_commit(ctx.trans, &seq, &offset) < 0)
+ ret = -1;
if (mail_index_sync_end(ctx.sync_ctx, 0, 0) < 0)
ret = -1;
}
i_assert(ret == 0); /* view is locked, can't happen */
trans = mail_index_transaction_begin(view, FALSE);
+ sync_ctx.trans = trans;
seq = 0;
iter = maildir_uidlist_iter_init(ibox->uidlist);
mail_index_expunge(trans, seq);
}
+ /* now, sync the index */
+ while ((ret = mail_index_sync_next(sync_ctx.sync_ctx,
+ &sync_ctx.sync_rec)) > 0) {
+ if (maildir_sync_record(ibox, &sync_ctx) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+
if (ret < 0)
mail_index_transaction_rollback(trans);
else {
}
}
- /* now, sync the index */
- while ((ret = mail_index_sync_next(sync_ctx.sync_ctx,
- &sync_ctx.sync_rec)) > 0) {
- if (maildir_sync_record(ibox, &sync_ctx) < 0) {
- ret = -1;
- break;
- }
- }
-
sync_stamp = ibox->dirty_cur_time != 0 ? 0 : ibox->last_cur_mtime;
if (mail_index_sync_end(sync_ctx.sync_ctx, sync_stamp, 0) < 0)
ret = -1;