mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-03 22:04:57 +08:00
Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
"""分配器空闲页归还:按进程实际加载的分配器选择 jemalloc purge 或 glibc malloc_trim,以及线程缓存刷新。"""
|
||||
"""
|
||||
分配器空闲页归还:按进程实际加载的分配器选择 jemalloc purge 或 glibc malloc_trim,以及线程缓存刷新。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -11,30 +13,42 @@ from app.scheduler.maintenance import SchedulerMaintenanceOwner
|
||||
|
||||
|
||||
class _FakeSymbol:
|
||||
"""模拟 ctypes 导出函数,记录调用参数与签名设置。"""
|
||||
"""
|
||||
模拟 ctypes 导出函数,记录调用参数与签名设置。
|
||||
"""
|
||||
|
||||
def __init__(self, result: int = 0):
|
||||
"""保存预设状态码并初始化可观察的原生函数调用记录。"""
|
||||
"""
|
||||
保存预设状态码并初始化可观察的原生函数调用记录。
|
||||
"""
|
||||
self.result = result
|
||||
self.calls: list[tuple] = []
|
||||
self.argtypes = None
|
||||
self.restype = None
|
||||
|
||||
def __call__(self, *args):
|
||||
"""记录调用参数并返回预设结果,模拟可观察的原生符号。"""
|
||||
"""
|
||||
记录调用参数并返回预设结果,模拟可观察的原生符号。
|
||||
"""
|
||||
self.calls.append(args)
|
||||
return self.result
|
||||
|
||||
|
||||
class _FakeLib:
|
||||
"""只暴露给定符号的伪 libc,缺失符号与真实 ctypes 一样返回 AttributeError。"""
|
||||
"""
|
||||
只暴露给定符号的伪 libc,缺失符号与真实 ctypes 一样返回 AttributeError。
|
||||
"""
|
||||
|
||||
def __init__(self, **symbols):
|
||||
"""登记本次测试可见的分配器符号。"""
|
||||
"""
|
||||
登记本次测试可见的分配器符号。
|
||||
"""
|
||||
self._symbols = symbols
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""用属性缺失异常模拟真实动态库中不存在的符号。"""
|
||||
"""
|
||||
用属性缺失异常模拟真实动态库中不存在的符号。
|
||||
"""
|
||||
try:
|
||||
return self._symbols[name]
|
||||
except KeyError:
|
||||
@@ -43,7 +57,9 @@ class _FakeLib:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _fresh_symbol_resolution():
|
||||
"""符号解析按进程缓存;每个用例换用不同的伪 libc,前后都清空缓存。"""
|
||||
"""
|
||||
符号解析按进程缓存;每个用例换用不同的伪 libc,前后都清空缓存。
|
||||
"""
|
||||
runtime_gc._process_libc.cache_clear()
|
||||
runtime_gc._jemalloc_mallctl.cache_clear()
|
||||
yield
|
||||
@@ -53,17 +69,23 @@ def _fresh_symbol_resolution():
|
||||
|
||||
@pytest.fixture
|
||||
def linux(monkeypatch):
|
||||
"""固定平台判断,使测试可在 macOS 上验证 Linux 分配器分支。"""
|
||||
"""
|
||||
固定平台判断,使测试可在 macOS 上验证 Linux 分配器分支。
|
||||
"""
|
||||
monkeypatch.setattr(runtime_gc.sys, "platform", "linux")
|
||||
|
||||
|
||||
def _use_lib(monkeypatch, lib) -> None:
|
||||
"""替换进程符号表,避免测试调用真实分配器。"""
|
||||
"""
|
||||
替换进程符号表,避免测试调用真实分配器。
|
||||
"""
|
||||
monkeypatch.setattr(runtime_gc.ctypes, "CDLL", lambda _name: lib)
|
||||
|
||||
|
||||
def test_jemalloc_purges_all_arenas(linux, monkeypatch):
|
||||
"""jemalloc 可用时清理所有 arena,并避免额外调用 glibc。"""
|
||||
"""
|
||||
jemalloc 可用时清理所有 arena,并避免额外调用 glibc。
|
||||
"""
|
||||
mallctl = _FakeSymbol()
|
||||
trim = _FakeSymbol()
|
||||
_use_lib(monkeypatch, _FakeLib(mallctl=mallctl, malloc_trim=trim))
|
||||
@@ -76,7 +98,9 @@ def test_jemalloc_purges_all_arenas(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_jemalloc_failure_does_not_fall_back_to_glibc(linux, monkeypatch):
|
||||
"""jemalloc 清理失败不能误用另一种分配器的释放接口。"""
|
||||
"""
|
||||
jemalloc 清理失败不能误用另一种分配器的释放接口。
|
||||
"""
|
||||
mallctl = _FakeSymbol(result=22)
|
||||
trim = _FakeSymbol()
|
||||
_use_lib(monkeypatch, _FakeLib(mallctl=mallctl, malloc_trim=trim))
|
||||
@@ -86,7 +110,9 @@ def test_jemalloc_failure_does_not_fall_back_to_glibc(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_glibc_trims_when_jemalloc_absent(linux, monkeypatch):
|
||||
"""没有 jemalloc 时才允许通过 glibc 归还空闲页。"""
|
||||
"""
|
||||
没有 jemalloc 时才允许通过 glibc 归还空闲页。
|
||||
"""
|
||||
trim = _FakeSymbol(result=1)
|
||||
_use_lib(monkeypatch, _FakeLib(malloc_trim=trim))
|
||||
|
||||
@@ -95,18 +121,24 @@ def test_glibc_trims_when_jemalloc_absent(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_unknown_allocator_is_a_no_op(linux, monkeypatch):
|
||||
"""缺少两类分配器符号时保持无操作。"""
|
||||
"""
|
||||
缺少两类分配器符号时保持无操作。
|
||||
"""
|
||||
_use_lib(monkeypatch, _FakeLib())
|
||||
|
||||
assert runtime_gc.release_allocator_memory() is None
|
||||
|
||||
|
||||
def test_non_linux_platform_skips_native_calls(monkeypatch):
|
||||
"""非 Linux 平台不能尝试访问 Linux 分配器接口。"""
|
||||
"""
|
||||
非 Linux 平台不能尝试访问 Linux 分配器接口。
|
||||
"""
|
||||
monkeypatch.setattr(runtime_gc.sys, "platform", "darwin")
|
||||
|
||||
def unexpected(_name):
|
||||
"""一旦发生不应有的原生库加载,就明确令用例失败。"""
|
||||
"""
|
||||
一旦发生不应有的原生库加载,就明确令用例失败。
|
||||
"""
|
||||
raise AssertionError("非 Linux 平台不应加载 C 库")
|
||||
|
||||
monkeypatch.setattr(runtime_gc.ctypes, "CDLL", unexpected)
|
||||
@@ -115,7 +147,9 @@ def test_non_linux_platform_skips_native_calls(monkeypatch):
|
||||
|
||||
|
||||
def test_full_gc_releases_allocator_after_collect(monkeypatch):
|
||||
"""完整回收必须先归还 Python 对象,再归还分配器空闲页。"""
|
||||
"""
|
||||
完整回收必须先归还 Python 对象,再归还分配器空闲页。
|
||||
"""
|
||||
order: list[str] = []
|
||||
monkeypatch.setattr("app.scheduler.maintenance.gc.collect", lambda: order.append("collect") or 3)
|
||||
monkeypatch.setattr(
|
||||
@@ -129,7 +163,9 @@ def test_full_gc_releases_allocator_after_collect(monkeypatch):
|
||||
|
||||
|
||||
def test_thread_cache_flush_uses_jemalloc(linux, monkeypatch):
|
||||
"""线程缓存刷新只调用所属线程的 jemalloc tcache 接口。"""
|
||||
"""
|
||||
线程缓存刷新只调用所属线程的 jemalloc tcache 接口。
|
||||
"""
|
||||
mallctl = _FakeSymbol()
|
||||
_use_lib(monkeypatch, _FakeLib(mallctl=mallctl))
|
||||
|
||||
@@ -138,12 +174,16 @@ def test_thread_cache_flush_uses_jemalloc(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_thread_cache_flush_resolves_symbols_once(linux, monkeypatch):
|
||||
"""高频刷新复用已解析的动态库符号,避免每次重新加载。"""
|
||||
"""
|
||||
高频刷新复用已解析的动态库符号,避免每次重新加载。
|
||||
"""
|
||||
mallctl = _FakeSymbol()
|
||||
loads: list[str] = []
|
||||
|
||||
def load(_name):
|
||||
"""记录动态库解析次数并返回同一组可用符号。"""
|
||||
"""
|
||||
记录动态库解析次数并返回同一组可用符号。
|
||||
"""
|
||||
loads.append("load")
|
||||
return _FakeLib(mallctl=mallctl)
|
||||
|
||||
@@ -158,7 +198,9 @@ def test_thread_cache_flush_resolves_symbols_once(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_thread_cache_flush_is_a_no_op_without_jemalloc(linux, monkeypatch):
|
||||
"""没有 jemalloc 时线程缓存刷新不能转而调用 glibc。"""
|
||||
"""
|
||||
没有 jemalloc 时线程缓存刷新不能转而调用 glibc。
|
||||
"""
|
||||
trim = _FakeSymbol()
|
||||
_use_lib(monkeypatch, _FakeLib(malloc_trim=trim))
|
||||
|
||||
@@ -168,7 +210,9 @@ def test_thread_cache_flush_is_a_no_op_without_jemalloc(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_background_thread_enabled_at_runtime(linux, monkeypatch):
|
||||
"""后台线程在当前进程启用,同时保留无关的继承配置。"""
|
||||
"""
|
||||
后台线程在当前进程启用,同时保留无关的继承配置。
|
||||
"""
|
||||
monkeypatch.setenv("MALLOC_CONF", "narenas:8,dirty_decay_ms:5000")
|
||||
mallctl = _FakeSymbol()
|
||||
_use_lib(monkeypatch, _FakeLib(mallctl=mallctl))
|
||||
@@ -180,7 +224,9 @@ def test_background_thread_enabled_at_runtime(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_inherited_background_thread_conf_is_stripped(linux, monkeypatch):
|
||||
"""剔除继承的后台线程选项,保留其它分配器设置。"""
|
||||
"""
|
||||
剔除继承的后台线程选项,保留其它分配器设置。
|
||||
"""
|
||||
monkeypatch.setenv(
|
||||
"MALLOC_CONF",
|
||||
"background_thread:true,max_background_threads:1,narenas:8,dirty_decay_ms:5000,muzzy_decay_ms:0",
|
||||
@@ -194,7 +240,9 @@ def test_inherited_background_thread_conf_is_stripped(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_conf_with_only_background_thread_is_removed(linux, monkeypatch):
|
||||
"""后台线程选项被清空后应删除空环境变量。"""
|
||||
"""
|
||||
后台线程选项被清空后应删除空环境变量。
|
||||
"""
|
||||
monkeypatch.setenv("MALLOC_CONF", "background_thread:false")
|
||||
_use_lib(monkeypatch, _FakeLib(mallctl=_FakeSymbol()))
|
||||
|
||||
@@ -203,7 +251,9 @@ def test_conf_with_only_background_thread_is_removed(linux, monkeypatch):
|
||||
|
||||
|
||||
def test_background_thread_is_a_no_op_without_jemalloc(linux, monkeypatch):
|
||||
"""非 jemalloc 进程不启用后台回收线程。"""
|
||||
"""
|
||||
非 jemalloc 进程不启用后台回收线程。
|
||||
"""
|
||||
monkeypatch.delenv("MALLOC_CONF", raising=False)
|
||||
_use_lib(monkeypatch, _FakeLib(malloc_trim=_FakeSymbol()))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user