expire: remove large dovecot index and index cache files

This commit is contained in:
missytake
2026-02-03 15:48:08 +01:00
parent be35244371
commit 27443ca044
4 changed files with 21 additions and 16 deletions

View File

@@ -17,14 +17,14 @@ from chatmaild.config import read_config
FileEntry = namedtuple("FileEntry", ("path", "mtime", "size")) FileEntry = namedtuple("FileEntry", ("path", "mtime", "size"))
def iter_mailboxes(basedir, maxnum): def iter_mailboxes(basedir, maxnum, tmpfs_index):
if not os.path.exists(basedir): if not os.path.exists(basedir):
print_info(f"no mailboxes found at: {basedir}") print_info(f"no mailboxes found at: {basedir}")
return return
for name in os_listdir_if_exists(basedir)[:maxnum]: for name in os_listdir_if_exists(basedir)[:maxnum]:
if "@" in name: if "@" in name:
yield MailboxStat(basedir + "/" + name, name) yield MailboxStat(basedir + "/" + name, name, tmpfs_index)
def get_file_entry(path): def get_file_entry(path):
@@ -49,12 +49,14 @@ def os_listdir_if_exists(path):
class MailboxStat: class MailboxStat:
last_login = None last_login = None
def __init__(self, basedir, name): def __init__(self, basedir, name, tmpfs_index):
self.basedir = str(basedir) self.basedir = str(basedir)
self.name = name self.name = name
self.messages = [] self.messages = []
self.extrafiles = [] self.extrafiles = []
self.scandir(self.basedir) self.scandir(self.basedir)
if tmpfs_index:
self.scandir("/dev/shm/" + name)
def scandir(self, folderdir): def scandir(self, folderdir):
for name in os_listdir_if_exists(folderdir): for name in os_listdir_if_exists(folderdir):
@@ -148,6 +150,9 @@ class Expiry:
changed = True changed = True
if changed: if changed:
self.remove_file(f"{mbox.basedir}/maildirsize") self.remove_file(f"{mbox.basedir}/maildirsize")
for file in mbox.extrafiles:
if "dovecot.index" in file.path.split("/")[-1] and file.size > 500 * 1024:
self.remove_file(file.path)
def get_summary(self): def get_summary(self):
return ( return (
@@ -200,7 +205,9 @@ def main(args=None):
maxnum = int(args.maxnum) if args.maxnum else None maxnum = int(args.maxnum) if args.maxnum else None
exp = Expiry(config, dry=not args.remove, now=now, verbose=args.verbose) exp = Expiry(config, dry=not args.remove, now=now, verbose=args.verbose)
for mailbox in iter_mailboxes(str(config.mailboxes_dir), maxnum=maxnum): for mailbox in iter_mailboxes(
str(config.mailboxes_dir), maxnum, config.tmpfs_index
):
exp.process_mailbox_stat(mailbox) exp.process_mailbox_stat(mailbox)
print(exp.get_summary()) print(exp.get_summary())

View File

@@ -159,7 +159,7 @@ def main(args=None):
maxnum = int(args.maxnum) if args.maxnum else None maxnum = int(args.maxnum) if args.maxnum else None
rep = Report(now=now, min_login_age=int(args.min_login_age), mdir=args.mdir) rep = Report(now=now, min_login_age=int(args.min_login_age), mdir=args.mdir)
for mbox in iter_mailboxes(str(config.mailboxes_dir), maxnum=maxnum): for mbox in iter_mailboxes(str(config.mailboxes_dir), maxnum, config.tmpfs_index):
rep.process_mailbox_stat(mbox) rep.process_mailbox_stat(mbox)
rep.dump_summary() rep.dump_summary()

View File

@@ -47,7 +47,7 @@ def mbox1(example_config):
mboxdir = example_config.mailboxes_dir.joinpath(addr) mboxdir = example_config.mailboxes_dir.joinpath(addr)
mboxdir.mkdir() mboxdir.mkdir()
fill_mbox(mboxdir) fill_mbox(mboxdir)
return MailboxStat(mboxdir, addr) return MailboxStat(mboxdir, addr, False)
def test_deltachat_folder(example_config): def test_deltachat_folder(example_config):
@@ -58,7 +58,7 @@ def test_deltachat_folder(example_config):
mbox2dir = mboxdir.joinpath(".DeltaChat") mbox2dir = mboxdir.joinpath(".DeltaChat")
mbox2dir.mkdir() mbox2dir.mkdir()
fill_mbox(mbox2dir) fill_mbox(mbox2dir)
mb = MailboxStat(mboxdir, addr) mb = MailboxStat(mboxdir, addr, False)
assert len(mb.messages) == 2 assert len(mb.messages) == 2
@@ -71,7 +71,11 @@ def test_filentry_ordering(tmp_path):
def test_no_mailbxoes(tmp_path, capsys): def test_no_mailbxoes(tmp_path, capsys):
assert [] == list(iter_mailboxes(str(tmp_path.joinpath("notexists")), maxnum=10)) assert [] == list(
iter_mailboxes(
str(tmp_path.joinpath("notexists")), maxnum=10, tmpfs_index=False
)
)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert "no mailboxes" in err assert "no mailboxes" in err
@@ -88,13 +92,13 @@ def test_stats_mailbox(mbox1):
create_new_messages(mbox1.basedir, ["large-extra"], size=1000) create_new_messages(mbox1.basedir, ["large-extra"], size=1000)
create_new_messages(mbox1.basedir, ["index-something"], size=3) create_new_messages(mbox1.basedir, ["index-something"], size=3)
mbox2 = MailboxStat(mbox1.basedir, mbox1.name) mbox2 = MailboxStat(mbox1.basedir, mbox1.name, False)
assert len(mbox2.extrafiles) == 5 assert len(mbox2.extrafiles) == 5
assert mbox2.extrafiles[0].size == 1000 assert mbox2.extrafiles[0].size == 1000
# cope well with mailbox dirs that have no password (for whatever reason) # cope well with mailbox dirs that have no password (for whatever reason)
Path(mbox1.basedir).joinpath("password").unlink() Path(mbox1.basedir).joinpath("password").unlink()
mbox3 = MailboxStat(mbox1.basedir, mbox1.name) mbox3 = MailboxStat(mbox1.basedir, mbox1.name, False)
assert mbox3.last_login is None assert mbox3.last_login is None

View File

@@ -74,12 +74,6 @@ mail_location = maildir:{{ config.mailboxes_dir }}/%u:INDEX=/dev/shm/%u
mail_location = maildir:{{ config.mailboxes_dir }}/%u mail_location = maildir:{{ config.mailboxes_dir }}/%u
{% endif %} {% endif %}
# index/cache files are not very useful for chatmail relay operations
# but it's not clear how to disable them completely.
# According to https://doc.dovecot.org/2.3/settings/advanced/#core_setting-mail_cache_max_size
# if the cache file becomes larger than the specified size, it is truncated by dovecot
mail_cache_max_size = 500K
namespace inbox { namespace inbox {
inbox = yes inbox = yes