Mercurial > dovecot > core-2.2
changeset 21454:447f2259ec6c
lib-storage: Lock autoexpunging so only a single process does it.
This hopefully helps to avoid duplicates with lazy_expunge plugin.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Thu, 26 Jan 2017 22:42:09 +0200 |
parents | 8d25d3692e26 |
children | a927a4f7aab1 |
files | src/lib-storage/mail-autoexpunge.c |
diffstat | 1 files changed, 54 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/mail-autoexpunge.c Sun Jan 29 01:08:23 2017 +0200 +++ b/src/lib-storage/mail-autoexpunge.c Thu Jan 26 22:42:09 2017 +0200 @@ -2,12 +2,54 @@ #include "lib.h" #include "ioloop.h" +#include "file-create-locked.h" #include "mailbox-list-iter.h" #include "mail-storage-private.h" #include "mail-namespace.h" #include "mail-user.h" #include "mail-autoexpunge.h" +#define AUTOEXPUNGE_LOCK_FNAME "dovecot.autoexpunge.lock" + +struct mailbox_autoexpunge_lock { + const char *path; + struct file_lock *lock; + int fd; +}; + +static void mailbox_autoexpunge_lock(struct mail_user *user, + struct mailbox_autoexpunge_lock *lock) +{ + struct file_create_settings lock_set; + bool created; + const char *home, *error; + int ret; + + /* Try to lock the autoexpunging. If the lock already exists, another + process is already busy with expunging, so we don't have to do it. + The easiest place where to store the lock file to is the home + directory, but allow autoexpunging to work even if we can't get + it. The lock isn't really required; it 1) improves performance + so that multiple processes won't do the same work unnecessarily, + and 2) it helps to avoid duplicates mails being added with + lazy_expunge. */ + if ((ret = mail_user_get_home(user, &home)) > 0) { + const struct mail_storage_settings *mail_set = + mail_user_set_get_storage_set(user); + i_zero(&lock_set); + lock_set.lock_method = mail_set->parsed_lock_method, + lock->path = t_strdup_printf("%s/"AUTOEXPUNGE_LOCK_FNAME, home); + lock->fd = file_create_locked(lock->path, &lock_set, + &lock->lock, &created, &error); + if (lock->fd == -1) { + if (errno != EAGAIN && errno != ENOENT) + i_error("autoexpunge: Couldn't lock %s: %s", lock->path, error); + } + } else if (ret == 0) { + i_warning("autoexpunge: User has no home directory, can't lock"); + } +} + static int mailbox_autoexpunge(struct mailbox *box, unsigned int interval_time, unsigned int max_mails) @@ -132,7 +174,9 @@ } } -static void mail_namespace_autoexpunge(struct mail_namespace *ns) +static void +mail_namespace_autoexpunge(struct mail_namespace *ns, + struct mailbox_autoexpunge_lock *lock) { struct mailbox_settings *const *box_set; const char *vname; @@ -145,6 +189,8 @@ (*box_set)->autoexpunge_max_mails == 0) continue; + mailbox_autoexpunge_lock(ns->user, lock); + if (strpbrk((*box_set)->name, "*?") != NULL) mailbox_autoexpunge_wildcards(ns, *box_set); else { @@ -161,10 +207,16 @@ void mail_user_autoexpunge(struct mail_user *user) { + struct mailbox_autoexpunge_lock lock = { .fd = -1 }; struct mail_namespace *ns; for (ns = user->namespaces; ns != NULL; ns = ns->next) { if (ns->alias_for == NULL) - mail_namespace_autoexpunge(ns); + mail_namespace_autoexpunge(ns, &lock); + } + if (lock.fd != -1) { + i_unlink(lock.path); + i_close_fd(&lock.fd); + file_lock_free(&lock.lock); } }