bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen Saving new mails: After transaction is committed and synced, trigger
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen vsize updating. Lock vsize updates. Check if the message count +
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen last-indexed-uid are still valid. If they are, add all the missing new
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen mails. Unlock.
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen Fetching vsize: Lock vsize updates. Check if the message count +
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen last-indexed-uid are still valid. If not, set them to zero. Add all
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen the missing mails. Unlock.
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen Expunging mails: Check if syncing would expunge any mails. If so, lock the
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen vsize updates before locking syncing (to avoid deadlocks). Check if the
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen message count + last-indexed-uid are still valid. If not, unlock vsize and
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen do nothing else. Otherwise, for each expunged mail whose UID <=
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen last-indexed-uid, decrease the message count and the vsize in memory. After
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen syncing is successfully committed, write the changes to header. Unlock.
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen Note that the final expunge handling with some mailbox formats is done while
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen syncing is no longer locked. Because of this we need to have the vsize
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen locking. The final vsize header update requires committing a transaction,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen which internally is the same as a sync lock. So to avoid deadlocks we always
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen need to lock vsize updates before sync.
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen#define INDEXER_HANDSHAKE "VERSION\tindexer\t1\t0\n"
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen struct mailbox_index_vsize vsize_hdr, orig_vsize_hdr;
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenstatic void vsize_header_refresh(struct mailbox_vsize_update *update)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen update->view = mail_index_view_open(update->box->index);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen mail_index_get_header_ext(update->view, update->box->vsize_hdr_ext_id,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen memcpy(&update->vsize_hdr, data, sizeof(update->vsize_hdr));
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenindex_mailbox_vsize_check_rebuild(struct mailbox_vsize_update *update)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen if (!mail_index_lookup_seq_range(update->view, 1,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen if (update->vsize_hdr.message_count != seq2) {
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen "vsize-hdr has invalid message-count (%u < %u)",
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* some messages have been expunged, rescan */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenindex_mailbox_vsize_update_init(struct mailbox *box)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen update = i_new(struct mailbox_vsize_update, 1);
2864ce8150abac6890408c77aad10dd522633ff4Timo Sirainenstatic bool vsize_update_lock_full(struct mailbox_vsize_update *update,
bd94a2a86e27f4809d087a8269bc4ccdd5f4ede3Timo Sirainen ret = mailbox_lock_file_create(box, VSIZE_LOCK_SUFFIX, lock_secs,
99e9dc500f54366263d1de804d933030df0385a2Timo Sirainen /* don't log lock timeouts, because we're somewhat expecting
99e9dc500f54366263d1de804d933030df0385a2Timo Sirainen them. Especially when lock_secs is 0. */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenbool index_mailbox_vsize_update_try_lock(struct mailbox_vsize_update *update)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenbool index_mailbox_vsize_update_wait_lock(struct mailbox_vsize_update *update)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen return vsize_update_lock_full(update, VSIZE_UPDATE_MAX_LOCK_SECS);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenbool index_mailbox_vsize_want_updates(struct mailbox_vsize_update *update)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenindex_mailbox_vsize_update_write(struct mailbox_vsize_update *update)
ede2466e3f1b7fdf1ceb35909a5fd4182a06c56bAki Tuomi memcmp(&update->orig_vsize_hdr, &update->vsize_hdr,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* no changes */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen trans = mail_index_transaction_begin(update->view,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen mail_index_update_header_ext(trans, update->box->vsize_hdr_ext_id,
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainenstatic void index_mailbox_vsize_notify_indexer(struct mailbox *box)
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen path = t_strconcat(box->storage->user->set->base_dir,
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen "Can't start vsize building on background: "
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen str_append_tabescaped(str, box->storage->user->username);
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen if (write_full(fd, str_data(str), str_len(str)) < 0) {
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen "Can't start vsize building on background: "
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenvoid index_mailbox_vsize_update_deinit(struct mailbox_vsize_update **_update)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen struct mailbox_vsize_update *update = *_update;
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen index_mailbox_vsize_notify_indexer(update->box);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenvoid index_mailbox_vsize_hdr_expunge(struct mailbox_vsize_update *update,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen "vsize-hdr's message_count shrank below 0");
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen "vsize-hdr's vsize shrank below 0");
abd812f275c5366feea20f25081d1c9296e552efTimo Sirainenindex_mailbox_vsize_hdr_add_missing(struct mailbox_vsize_update *update,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen struct mailbox_index_vsize *vsize_hdr = &update->vsize_hdr;
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen mailbox_get_open_status(update->box, STATUS_UIDNEXT, &status);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen if (vsize_hdr->highest_uid + 1 >= status.uidnext) {
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* nothing to do - we should have usually caught this already
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen before locking */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* note that update->view may be more up-to-date than box->view.
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen we'll just add whatever new mails are in box->view. if we'll notice
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen that some of the new mails are missing, we'll need to stop there
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen since that expunge will be applied later on to the vsize header. */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen if (!mail_index_lookup_seq_range(update->box->view,
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* nothing existed, but update uidnext */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen mail_search_build_add_seqset(search_args, seq1, seq2);
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi trans = mailbox_transaction_begin(update->box, 0, "vsize update");
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL,
abd812f275c5366feea20f25081d1c9296e552efTimo Sirainen else if (update->box->storage->set->mail_vsize_bg_after_count == 0)
abd812f275c5366feea20f25081d1c9296e552efTimo Sirainen mails_left = update->box->storage->set->mail_vsize_bg_after_count;
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen /* if there are any more mails whose vsize can't be
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen looked up from cache, abort and finish on
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen background. */
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
a0cd302bcb827678f9c9c2ca1d0a3f0d3c0b3563Timo Sirainen mailbox_get_last_mail_error(update->box) == MAIL_ERROR_LOOKUP_ABORTED) {
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen /* abort and finish on background */
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen mail_storage_set_error(update->box->storage, MAIL_ERROR_INUSE,
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen "Finishing vsize calculation on background");
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen if (mail->mail_stream_opened || mail->mail_metadata_accessed) {
ca004511f36c090b07c6f097cf237ce836d8faf6Timo Sirainen /* slow vsize lookup */
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainen /* success, cache all */
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainen /* search failed, cache only up to highest seen uid */
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainenint index_mailbox_get_virtual_size(struct mailbox *box,
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, &status);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen update = index_mailbox_vsize_update_init(box);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen if (update->vsize_hdr.highest_uid + 1 == status.uidnext &&
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen update->vsize_hdr.message_count == status.messages) {
2c759e5193bb1013513eb96768f43693d2ffc963Timo Sirainen /* up to date */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen metadata_r->virtual_size = update->vsize_hdr.vsize;
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* we need to update it - lock it if possible. if not, update it
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen anyway internally even though we won't be saving the result. */
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen (void)index_mailbox_vsize_update_wait_lock(update);
abd812f275c5366feea20f25081d1c9296e552efTimo Sirainen ret = index_mailbox_vsize_hdr_add_missing(update, TRUE);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen metadata_r->virtual_size = update->vsize_hdr.vsize;
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainenint index_mailbox_get_physical_size(struct mailbox *box,
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen /* if physical size = virtual size always for the storage, we can
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen use the optimized vsize code for this */
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen if (index_mailbox_get_virtual_size(box, metadata_r) < 0)
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen metadata_r->physical_size = metadata_r->virtual_size;
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen /* do it the slow way (we could implement similar logic as for vsize,
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen but for now it's not really needed) */
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0)
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi trans = mailbox_transaction_begin(box, 0, "mailbox physical size");
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen ctx = mailbox_search_init(trans, search_args, NULL,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi errstr = mailbox_get_last_internal_error(box, &error);
dae42444ac716f397a41f6f72c2581f304bb6e5bTimo Sirainen i_error("Couldn't get size of mail UID %u in %s: %s",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi box->vname, mailbox_get_last_internal_error(box, NULL));
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainenvoid index_mailbox_vsize_update_appends(struct mailbox *box)
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen update = index_mailbox_vsize_update_init(box);
9963bef626fd9ea227fb606e8b1694cdb1ab39aaTimo Sirainen /* update here only if we don't need to rebuild the whole vsize. */
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen if (index_mailbox_vsize_want_updates(update)) {
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen /* Get the UIDNEXT only after checking that vsize updating is
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen even potentially wanted for this mailbox. We especially
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen don't want to do this with imapc, because it could trigger
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen a remote STATUS (UIDNEXT) call. */
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen mailbox_get_open_status(update->box, STATUS_UIDNEXT, &status);
0b45d816c73e0bfba55d84fb50005ba2714ac0faTimo Sirainen if (update->vsize_hdr.highest_uid + 1 != status.uidnext &&