mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
for last 7 days of messages remove large messages first, then by age
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user