for last 7 days of messages remove large messages first, then by age

This commit is contained in:
holger krekel
2026-04-23 22:56:53 +02:00
parent 7f58c8b38a
commit 20f7aafcff
2 changed files with 47 additions and 1 deletions

View File

@@ -99,11 +99,29 @@ def scan_mailbox_messages(mbox):
return messages return messages
# Within this window, large messages are deleted before small ones.
DELETE_LARGE_FIRST_DAYS = 7
def expire_to_target(mbox, target_bytes): def expire_to_target(mbox, target_bytes):
cutoff = time.time() - DELETE_LARGE_FIRST_DAYS * 86400
messages = scan_mailbox_messages(mbox) messages = scan_mailbox_messages(mbox)
def sort_key(msg):
# prio 0: Older than cutoff -> remove oldest first
if msg.mtime < cutoff:
return (0, msg.mtime)
# prio 1: more recent than cutoff, large -> remove largest first
if msg.quota_size > 200000:
return (1, -msg.quota_size, msg.mtime)
# prio 2: more recent than cutoff, small -> remove oldest first
return (2, msg.mtime)
total_size = sum(m.quota_size for m in messages) total_size = sum(m.quota_size for m in messages)
removed = 0 removed = 0
for entry in sorted(messages): for entry in sorted(messages, key=sort_key):
if total_size <= target_bytes: if total_size <= target_bytes:
break break
(mbox / entry.path).unlink(missing_ok=True) (mbox / entry.path).unlink(missing_ok=True)

View File

@@ -1,6 +1,7 @@
import itertools import itertools
import os import os
import random import random
import shutil
import time import time
from datetime import datetime from datetime import datetime
from fnmatch import fnmatch from fnmatch import fnmatch
@@ -240,6 +241,33 @@ def test_expire_to_target(tmp_path):
assert len(scan_mailbox_messages(tmp_path)) == 1 assert len(scan_mailbox_messages(tmp_path)) == 1
def test_expire_to_target_prioritization(tmp_path):
def create_messages():
for sub in ("cur", "new"):
if (tmp_path / sub).exists():
shutil.rmtree(tmp_path / sub)
# prio 0: older than 7 days
_create_message(tmp_path, "cur", 5 * MB, days_old=10)
# prio 1: last 7 days, large (>200KB)
_create_message(tmp_path, "cur", 5 * MB, days_old=1)
# prio 2: last 7 days, small
_create_message(tmp_path, "cur", 1000, days_old=2)
# Shrink to 6MB: only the old message (prio 0) is removed.
create_messages()
assert expire_to_target(tmp_path, 6 * MB) == 1
msgs = scan_mailbox_messages(tmp_path)
assert len(msgs) == 2
assert all(m.mtime > time.time() - 7 * 86400 for m in msgs)
# Shrink to 1KB: old and recent-large removed, small survives.
create_messages()
assert expire_to_target(tmp_path, 1024) == 2
msgs = scan_mailbox_messages(tmp_path)
assert len(msgs) == 1
assert msgs[0].quota_size == 1000
def test_quota_expire_main(tmp_path, capsys): def test_quota_expire_main(tmp_path, capsys):
mbox = tmp_path / "user@example.org" mbox = tmp_path / "user@example.org"
_create_message(mbox, "cur", 2 * MB, days_old=5) _create_message(mbox, "cur", 2 * MB, days_old=5)