mdbox-map.c revision b5d17f9b1224f496f18b45579a4253df3ae0dbba
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#define DBOX_FORCE_PURGE_MIN_BYTES (1024*1024*10)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#define MAP_STORAGE(map) (&(map)->storage->storage.storage)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid dbox_map_set_corrupted(struct dbox_map *map, const char *format, ...)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen "dbox map %s corrupted: %s",
de486b59018016977015ef42e6071155b60e82e1Timo Sirainendbox_map_init(struct mdbox_storage *storage, struct mailbox_list *root_list,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen map->index = mail_index_alloc(path, MDBOX_GLOBAL_INDEX_PREFIX);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen map->map_ext_id = mail_index_ext_register(map->index, "map",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen map->ref_ext_id = mail_index_ext_register(map->index, "ref", 0,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_get_permissions(root_list, NULL, &map->create_mode,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_get_dir_permissions(root_list, NULL, &map->create_dir_mode,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_set_permissions(map->index, map->create_mode,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int dbox_map_mkdir_storage(struct dbox_map *map)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mkdir_parents_chgrp(map->path, map->create_dir_mode,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen map->create_gid, map->create_gid_origin) < 0 &&
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenint dbox_map_open(struct dbox_map *map, bool create_missing)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* already opened */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen open_flags = MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY |
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_storage_settings_to_index_flags(MAP_STORAGE(map)->set);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* index not found - for now just return failure */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* some open files may have read partially written mails. now that
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen map syncing makes the new mails visible, we need to make sure the
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen partial data is flushed out of memory */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (mail_index_refresh(map->view->index) < 0) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (mail_index_view_sync_commit(&ctx, &delayed_expunges) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainenstatic int dbox_map_lookup_seq(struct dbox_map *map, uint32_t seq,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_lookup_ext(map->view, seq, map->map_ext_id,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dbox_map_set_corrupted(map, "file_id=0 for map_uid=%u", uid);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainendbox_map_get_seq(struct dbox_map *map, uint32_t map_uid, uint32_t *seq_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!mail_index_lookup_seq(map->view, map_uid, seq_r)) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* not found - try again after a refresh */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (!mail_index_lookup_seq(map->view, map_uid, seq_r))
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainenint dbox_map_lookup(struct dbox_map *map, uint32_t map_uid,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if ((ret = dbox_map_get_seq(map, map_uid, &seq)) <= 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (dbox_map_lookup_seq(map, seq, file_id_r, offset_r, &size) < 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenint dbox_map_view_lookup_rec(struct dbox_map *map, struct mail_index_view *view,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen uint32_t seq, struct dbox_mail_lookup_rec *rec_r)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen mail_index_lookup_uid(view, seq, &rec_r->map_uid);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen mail_index_lookup_ext(view, seq, map->map_ext_id, &data, &expunged);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen dbox_map_set_corrupted(map, "missing map extension");
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen memcpy(&rec_r->rec, data, sizeof(rec_r->rec));
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mail_index_lookup_ext(view, seq, map->ref_ext_id, &data, &expunged);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen dbox_map_set_corrupted(map, "missing ref extension");
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainenint dbox_map_get_file_msgs(struct dbox_map *map, uint32_t file_id,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen for (seq = 1; seq <= hdr->messages_count; seq++) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (dbox_map_view_lookup_rec(map, map->view, seq, &rec) < 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenint dbox_map_get_zero_ref_files(struct dbox_map *map,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* some internal error */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen for (seq = 1; seq <= hdr->messages_count; seq++) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mail_index_lookup_ext(map->view, seq, map->ref_ext_id,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_lookup_ext(map->view, seq, map->map_ext_id,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen seq_range_array_add(file_ids_r, 0, rec->file_id);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainendbox_map_transaction_begin(struct dbox_map *map, bool external)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen flags |= MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen ctx = i_new(struct dbox_map_transaction_context, 1);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->trans = mail_index_transaction_begin(map->view, flags);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainendbox_map_sync_handle(struct dbox_map *map, struct mail_index_sync_ctx *sync_ctx)
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen mail_index_sync_get_offsets(sync_ctx, &seq1, &offset1, &seq2, &offset2);
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen /* something had crashed. need a full resync. */
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen i_warning("dbox %s: Inconsistency in map index "
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen while (mail_index_sync_next(sync_ctx, &sync_rec)) ;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainenint dbox_map_transaction_commit(struct dbox_map_transaction_context *ctx)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* use syncing to lock the transaction log, so that we always see
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen log's head_offset = tail_offset */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ret = mail_index_sync_begin(map->index, &ctx->sync_ctx,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (mail_index_transaction_commit(&ctx->trans) < 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid dbox_map_transaction_set_failed(struct dbox_map_transaction_context *ctx)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid dbox_map_transaction_free(struct dbox_map_transaction_context **_ctx)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct dbox_map_transaction_context *ctx = *_ctx;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenint dbox_map_update_refcounts(struct dbox_map_transaction_context *ctx,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const ARRAY_TYPE(uint32_t) *map_uids, int diff)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int i, count;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen for (i = 0; i < count; i++) {
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen if (!mail_index_lookup_seq(map->view, *uidp, &seq)) {
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen /* we can't refresh map here since view has a
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen transaction open. */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen mail_index_lookup_ext(map->view, seq, map->ref_ext_id,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen cur_diff = data == NULL ? 0 : *((const uint16_t *)data);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen cur_diff += mail_index_atomic_inc_ext(ctx->trans, seq,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we're getting close to the 64k limit. fail early
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen to make it less likely that two processes increase
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen the refcount enough times to cross the limit */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen "Message has been copied too many times");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenint dbox_map_remove_file_id(struct dbox_map *map, uint32_t file_id)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct dbox_map_transaction_context *map_trans;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* make sure the map is refreshed, otherwise we might be expunging
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen messages that have already been moved to other files. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* we need a per-file transaction, otherwise we can't refresh the map */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen map_trans = dbox_map_transaction_begin(map, TRUE);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (seq = 1; seq <= hdr->messages_count; seq++) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_index_lookup_ext(map->view, seq, map->map_ext_id,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen dbox_map_set_corrupted(map, "missing map extension");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainendbox_map_append_begin(struct dbox_map *map, enum dbox_map_append_flags flags)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx = i_new(struct dbox_map_append_context, 1);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* refresh the map so we can try appending to the
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen latest files */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenstatic time_t day_begin_stamp(unsigned int interval)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* get the beginning of day/hour/minute depending on how large
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen the interval is */
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainenstatic bool dbox_try_open(struct dbox_map_append_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen want_altpath = (ctx->flags & DBOX_MAP_APPEND_FLAG_ALT) != 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (dbox_file_open_primary(file, ¬found) <= 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* already locked, we're possibly in the middle of purging it
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen in which case we really don't want to write there. */
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen if (dbox_file_is_in_alt(file) != want_altpath) {
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen /* different alt location than what we want, can't use it */
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainendbox_map_file_try_append(struct dbox_map_append_context *ctx,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen uint32_t file_id, time_t stamp, uoff_t mail_size,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct dbox_file_append_context **file_append_r,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct ostream **output_r, bool *retry_later_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen else if ((ret = dbox_file_try_lock(file)) <= 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* locking failed */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_error("stat(%s) failed: %m", file->cur_path);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* the file was unlinked between opening and locking it. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (dbox_file_get_append_stream(file_append, output_r) <= 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* couldn't append to this file */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if ((*output_r)->offset + mail_size > map->set->mdbox_rotate_size) {
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen /* file was too large after all */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* success */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* failure */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainendbox_map_is_appending(struct dbox_map_append_context *ctx, uint32_t file_id)
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen struct dbox_file_append_context *const *file_appends;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen unsigned int i, count;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* there shouldn't be many files open, don't bother with anything
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen file_appends = array_get(&ctx->file_appends, &count);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen for (i = 0; i < count; i++) {
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainendbox_map_find_existing_append(struct dbox_map_append_context *ctx,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen struct dbox_file_append_context *const *file_appends, *append;
0910ea0672c0295c442eb686cc41e98656831f37Timo Sirainen unsigned int i, count;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* first try to use files already used in this append */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen file_appends = array_get(&ctx->file_appends, &count);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen for (i = count; i > ctx->files_nonappendable_count; i--) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (append_offset + mail_size <= map->set->mdbox_rotate_size &&
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen dbox_file_get_append_stream(append, output_r) > 0)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* can't append to this file anymore. if we created this file,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen close it so we don't waste fds. if we didn't, we can't close
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen it without also losing our lock too early. */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (mfile->file_id == 0 && dbox_file_append_flush(append) == 0)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainendbox_map_find_first_alt(struct dbox_map_append_context *ctx,
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen struct mdbox_storage *dstorage = ctx->map->storage;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen struct mail_storage *storage = &dstorage->storage.storage;
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen /* we want to quickly find the latest alt file, but we also want to
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen avoid accessing the alt storage as much as possible. so we'll do
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen this by finding the lowest numbered file (n) from primary storage.
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen hopefully one of n-[1..m] is appendable in alt storage. */
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen "opendir(%s) failed: %m", dstorage->storage_dir);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen for (errno = 0; (d = readdir(dir)) != NULL; errno = 0) {
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen if (strncmp(d->d_name, MDBOX_MAIL_FILE_PREFIX,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen file_id = strtoul(d->d_name + strlen(MDBOX_MAIL_FILE_PREFIX),
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "readdir(%s) failed: %m", dstorage->storage_dir);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "closedir(%s) failed: %m", dstorage->storage_dir);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* find the newest message in alt storage from map view */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (seq = hdr->messages_count; seq > 0; seq--) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (dbox_map_lookup_seq(ctx->map, seq, &file_id,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainendbox_map_find_appendable_file(struct dbox_map_append_context *ctx,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct dbox_file_append_context **file_append_r,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen uint32_t seq, seq1, uid, file_id, min_file_id;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* try to find an existing appendable file */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen stamp = day_begin_stamp(map->set->mdbox_rotate_interval);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((ctx->flags & DBOX_MAP_APPEND_FLAG_ALT) == 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* we want to save to alt storage. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (dbox_map_find_first_alt(ctx, &min_file_id, &seq) < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (dbox_map_lookup_seq(map, seq, &file_id, &offset, &size) < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (seq_range_exists(&checked_file_ids, file_id))
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen seq_range_array_add(&checked_file_ids, 0, file_id);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (++backwards_lookup_count > MAX_BACKWARDS_LOOKUPS) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* we've wasted enough time here */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* first lookup: this should be enough usually, but we can't
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen be sure until after locking. also if messages were recently
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen moved, this message might not be the last one in the file. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (offset + size + mail_size >= map->set->mdbox_rotate_size)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* already checked this */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!dbox_map_file_try_append(ctx, file_id, stamp, mail_size,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* file is too old. the rest of the files are too. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* NOTE: we've now refreshed map view. there are no guarantees
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen about sequences anymore. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* FIXME: use retry_later somehow */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen !mail_index_lookup_seq_range(map->view, 1, uid-1,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint dbox_map_append_next(struct dbox_map_append_context *ctx, uoff_t mail_size,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct dbox_file_append_context **file_append_ctx_r,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen file_append = dbox_map_find_existing_append(ctx, mail_size, output_r);
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen ret = dbox_map_find_appendable_file(ctx, mail_size,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen else if (ret < 0)
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen /* create a new file */
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen file = (ctx->flags & DBOX_MAP_APPEND_FLAG_ALT) == 0 ?
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen ret = dbox_file_get_append_stream(file_append, output_r);
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen i_assert(file_append->first_append_offset == 0);
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen file_append->first_append_offset = file_append->output->offset;
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen array_append(&ctx->file_appends, &file_append, 1);
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainenvoid dbox_map_append_finish(struct dbox_map_append_context *ctx)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen appends = array_get_modifiable(&ctx->appends, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(count > 0 && appends[count-1].size == (uint32_t)-1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen cur_offset = appends[count-1].file_append->output->offset;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(cur_offset >= appends[count-1].offset);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen appends[count-1].size = cur_offset - appends[count-1].offset;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainendbox_map_get_next_file_id(struct dbox_map *map, struct mail_index_view *view,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen mail_index_get_header_ext(view, map->map_ext_id, &data, &data_size);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen dbox_map_set_corrupted(map, "hdr size=%"PRIuSIZE_T,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen /* first file */
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainenstatic int dbox_map_assign_file_ids(struct dbox_map_append_context *ctx,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen struct dbox_file_append_context *const *file_appends;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen unsigned int i, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* start the syncing. we'll need it even if there are no file ids to
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen be assigned. */
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen ret = mail_index_sync_begin(ctx->map->index, &ctx->sync_ctx,
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen mail_storage_set_internal_error(MAP_STORAGE(ctx->map));
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen dbox_map_sync_handle(ctx->map, ctx->sync_ctx);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (dbox_map_get_next_file_id(ctx->map, ctx->sync_view, &file_id) < 0) {
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen /* assign file_ids for newly created files */
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen file_appends = array_get(&ctx->file_appends, &count);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen for (i = 0; i < count; i++) {
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (dbox_file_append_flush(file_appends[i]) < 0) {
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen if (mdbox_file_assign_file_id(mfile, file_id++) < 0) {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen /* update the highest used file_id */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen mail_index_update_header_ext(ctx->trans != NULL ? ctx->trans :
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenint dbox_map_append_assign_map_uids(struct dbox_map_append_context *ctx,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen unsigned int i, count;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* append map records to index */
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen for (i = 0; i < count; i++) {
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen (struct mdbox_file *)appends[i].file_append->file;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_index_update_ext(ctx->trans, seq, ctx->map->map_ext_id,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_index_update_ext(ctx->trans, seq, ctx->map->ref_ext_id,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* assign map UIDs for appended records */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_index_append_finish_uids(ctx->trans, hdr->next_uid, &uids);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen i_assert(range[0].seq2 - range[0].seq1 + 1 == count);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* we don't really care about uidvalidity, but it can't be 0 */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen offsetof(struct mail_index_header, uid_validity),
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (mail_index_transaction_commit(&ctx->trans) < 0) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_internal_error(MAP_STORAGE(ctx->map));
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenint dbox_map_append_move(struct dbox_map_append_context *ctx,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const ARRAY_TYPE(seq_range) *expunge_map_uids)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen unsigned int i, j, map_uids_count, appends_count;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen appends = array_get(&ctx->appends, &appends_count);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen for (i = j = 0; i < map_uids_count; i++) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen (struct mdbox_file *)appends[j].file_append->file;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (!mail_index_lookup_seq(ctx->sync_view, uids[i], &seq))
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen seq_range_array_iter_init(&iter, expunge_map_uids); i = 0;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen while (seq_range_array_iter_nth(&iter, i++, &uid)) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (!mail_index_lookup_seq(ctx->sync_view, uid, &seq))
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenint dbox_map_append_commit(struct dbox_map_append_context *ctx)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen struct dbox_file_append_context **file_appends;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen unsigned int i, count;
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen file_appends = array_get_modifiable(&ctx->file_appends, &count);
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen for (i = 0; i < count; i++) {
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen if (dbox_file_append_commit(&file_appends[i]) < 0)
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_internal_error(MAP_STORAGE(map));
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainenvoid dbox_map_append_free(struct dbox_map_append_context **_ctx)
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen struct dbox_file_append_context **file_appends;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen unsigned int i, count;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen file_appends = array_get_modifiable(&ctx->file_appends, &count);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen for (i = 0; i < count; i++) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen files = array_get_modifiable(&ctx->files, &count);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen for (i = 0; i < count; i++) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenuint32_t dbox_map_get_uid_validity(struct dbox_map *map)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen /* refresh index in case it was just changed */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return hdr->uid_validity != 0 ? hdr->uid_validity :