mailbox-list-index-sync.c revision 5fb3bff645380804c9db2510940c41db6b8fdb01
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny/* Copyright (C) 2006 Timo Sirainen */
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny const char *name;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny /* dir is used if it's non-NULL, otherwise dir_offset is used */
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina /* The records are sorted by their name_hash */
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina ARRAY_DEFINE(records, struct mailbox_list_sync_record);
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina /* Offset to the original location in the index, or 0 for new dirs */
07b92f78d1751d8a2a538a440e1fdb24c59021e0Pavel Březina struct mailbox_list_sync_dir *root, *sync_root;
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce const char *name;
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozekmailbox_list_alloc_sync_dir(struct mailbox_list_index_sync_ctx *ctx,
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek sync_dir = p_new(ctx->pool, struct mailbox_list_sync_dir, 1);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek p_array_init(&sync_dir->records, ctx->pool, initial_count);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozekmailbox_list_copy_sync_dir(struct mailbox_list_index_sync_ctx *ctx,
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek const char *name;
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek unsigned int i;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (mailbox_list_index_get_dir(ctx->index, &offset, &dir) < 0)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce sync_dir = mailbox_list_alloc_sync_dir(ctx, dir->count +
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce sync_rec = array_append_space(&sync_dir->records);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce max_len = ctx->index->mmap_size - recs[i].name_offset;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce sync_rec->name = p_strndup(ctx->pool, name, max_len);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březinastatic int mailbox_list_sync_record_cmp(const void *_key, const void *_rec)
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina const struct mailbox_list_sync_lookup_key *key = _key;
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina const struct mailbox_list_sync_record *rec = _rec;
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březinamailbox_list_sync_dir_lookup(struct mailbox_list_sync_dir *dir,
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina unsigned int count;
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina /* binary search the current hierarchy level name. the values are
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina sorted primarily by their hash value and secondarily by the actual
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina rec = bsearch_insert_pos(&key, recs, count, sizeof(*rec),
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březinamailbox_list_alloc_add_record(struct mailbox_list_index_sync_ctx *ctx,
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina mail_index_append(ctx->trans, rec->uid, &rec->seq);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březinamailbox_list_index_sync_get_seq(struct mailbox_list_index_sync_ctx *ctx,
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce return mailbox_list_index_set_corrupted(ctx->index,
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny "Record with UID=0");
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek if (mail_index_lookup_uid_range(ctx->view, rec->uid, rec->uid,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce return mailbox_list_index_set_corrupted(ctx->index,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce "Desync: Record expunged from mail index");
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zelenymailbox_list_index_sync_int(struct mailbox_list_index_sync_ctx *ctx,
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny const char *name,
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny const char *p, *hier_name;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny unsigned int idx;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny hier_name = p == NULL ? name : t_strdup_until(name, p);
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce /* name ended with a separator */
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce /* two separators adjacently, skip this */
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny rec = mailbox_list_sync_dir_lookup(dir, hier_name, &idx);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny /* new record */
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny /* this record was copied from existing index.
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny the uid is known, but the sequence isn't. */
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek if (mailbox_list_index_sync_get_seq(ctx, rec) < 0) {
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny /* remember that we've seen this record */
234958be042980242fff6da936af674da877c5efSimo Sorcestatic int mailbox_list_index_get_root(struct mailbox_list_index_sync_ctx *ctx)
234958be042980242fff6da936af674da877c5efSimo Sorce if (ctx->index->mmap_size == sizeof(*ctx->index->hdr)) {
234958be042980242fff6da936af674da877c5efSimo Sorce /* root doesn't exist in the file yet */
234958be042980242fff6da936af674da877c5efSimo Sorce if (mailbox_list_copy_sync_dir(ctx, sizeof(*ctx->index->hdr),
234958be042980242fff6da936af674da877c5efSimo Sorce /* keep sync_root=root until we've built the sync_root path. */
234958be042980242fff6da936af674da877c5efSimo Sorce if (mailbox_list_index_sync_more(ctx, ctx->sync_path, &seq) < 0)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek return mailbox_list_index_sync_int(ctx, ctx->sync_path,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekstatic int sync_init_mail_sync(struct mailbox_list_index_sync_ctx *ctx)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek if (mail_index_sync_begin(ctx->index->mail_index, &ctx->mail_sync_ctx,
144e7bad57748aaab395b9fb8ad136cdad864a00Lukas Slebodnik /* we should have only external transactions in here, for which we
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek don't need to do anything but write them to the index */
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek while (mail_index_sync_next(ctx->mail_sync_ctx, &sync_rec) > 0)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek if (hdr->uid_validity != ctx->hdr.uid_validity) {
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek return mailbox_list_index_set_corrupted(ctx->index,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek "Desync: uid_validity changed");
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek ctx->trans = mail_index_transaction_begin(ctx->view, FALSE, TRUE);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek offsetof(struct mail_index_header, uid_validity),
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek &ctx->hdr.uid_validity, sizeof(ctx->hdr.uid_validity),
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekint mailbox_list_index_sync_init(struct mailbox_list_index *index,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek const char *path,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek /* add separator to end of path if it isn't there */
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek if (len > 0 && path[len-1] != index->separator)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek path = t_strdup_printf("%s%c", path, index->separator);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek pool = pool_alloconly_create("mailbox list index sync", 1024*32);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek ctx = p_new(pool, struct mailbox_list_index_sync_ctx, 1);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek /* mail index syncing acts as the only locking for us */
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekmailbox_list_index_sync_get_view(struct mailbox_list_index_sync_ctx *ctx)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekmailbox_list_index_sync_get_transaction(struct mailbox_list_index_sync_ctx *ctx)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekint mailbox_list_index_sync_more(struct mailbox_list_index_sync_ctx *ctx,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek return mailbox_list_index_sync_int(ctx, name, &dir, seq_r);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekmailbox_list_index_sync_grow(struct mailbox_list_index_sync_ctx *ctx,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek grow_size = new_fsize / 100 * MAILBOX_LIST_INDEX_GROW_PERCENTAGE;
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek i_assert(new_fsize >= ctx->hdr.used_space + size);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek if (file_set_size(index->fd, (off_t)new_fsize) < 0) {
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek mailbox_list_index_set_syscall_error(index, "file_set_size()");
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekmailbox_list_index_sync_alloc_space(struct mailbox_list_index_sync_ctx *ctx,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek /* all allocations must be 32bit aligned */
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek if (mailbox_list_index_sync_grow(ctx, size + 3) < 0)
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek *base_r = PTR_OFFSET(ctx->index->mmap_base, *base_offset_r);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekmailbox_list_index_sync_recreate_dir(struct mailbox_list_index_sync_ctx *ctx,
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek unsigned int src, dest, orig, count, nondeleted_count;
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek i_assert((offset_pos % sizeof(uint32_t)) == 0);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek /* count how much space we need and how much we wasted for deleted
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek nondeleted_count = 0; name_space_needed = 0; deleted_space = 0;
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek sync_recs = array_get_modifiable(&sync_dir->records, &count);
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek /* new record */
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek /* @UNSAFE */
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek if (mailbox_list_index_sync_alloc_space(ctx, name_space_needed,
(const char *)base;
if (seq != 0)
size);
dest++;
if (offset_pos == 0) {
unsigned int i, count;
unsigned int i, j, count;
partial) < 0)
if (count == 0)
for (i = j = 0; i < count; i++) {
partial) < 0)
bool partial;
if (ret < 0)
if (ret < 0)
return ret;