Metadata-Version: 2.1
Name: rustgzip
Version: 0.5.2
Summary: Rust gzip streams for Python 3.4+
Requires-Python: >=3.4
License: MIT
Description-Content-Type: text/markdown

# rustgzip 0.5.2

给 Python 3.4 及更新版本使用的 Rust gzip 加速包，导入名为 `rustgzip`。
本版发布稳定 Python 接口，并附带最新 Rust 研究源码；实验多核解压尚未开放 Python 入口，默认路径仍为顺序原生解压。详见 RELEASE-052.md。

## 1. 适合解决什么问题

适合顺序读取/写入 `.gz`、扫描 gzip 完整性和内存压缩解压。
Python 负责文件对象适配，Rust 负责 gzip 解析、DEFLATE、CRC32 和文件流循环。
动态库用 ctypes 加载，不依赖 CPython ABI，不需要 PyO3，不需要安装 isal/based58 等库。

生成的是标准 gzip，不是新格式，系统 gzip 和 Python 标准库都能解压。
支持多个 gzip member 串接及 member 后的零填充；非零尾部垃圾、截断、CRC/ISIZE 错误会报错。

## 2. 内网 UOS 安装

交付的 `rustgzip-0.5.2-py3-none-linux_x86_64.whl` 用于 **x86_64 Linux**。
它在 Debian 10 / glibc 2.28 环境构建，并用真实 Python 3.4.10 和 3.7 验证。
本次没有连接你的内网 UOS；实际发行版兼容性仍以运行结果为准。
安装后不需要 Rust 编译器，不需要联网。不是 ARM、龙芯或 Windows 安装包。

将 wheel 传到内网后执行；根据实际命令名调整 `python3.4`：

```bash
python3.4 -m pip install --no-index --no-deps ./rustgzip-0.5.2-py3-none-linux_x86_64.whl
python3.4 -c "import rustgzip; print(rustgzip.backend_info())"
```

没有 root 权限时，加 `--user`，或使用 `--target ./py-libs`：

```bash
python3.4 -m pip install --no-index --no-deps --target ./py-libs ./rustgzip-0.5.2-py3-none-linux_x86_64.whl
PYTHONPATH="$PWD/py-libs" python3.4 your_script.py
```

没有 pip 时，可以解压 `rustgzip-0.5.2-linux_x86_64-portable.zip`，将其中的
`rustgzip` 文件夹与自己的脚本放在同一目录。文件夹内的 `.py` 和 `.so` 都要保留。
这是完整的独立包，不需要把整个源码或 vendor 放进内网。

## 3. 直接替换你的读取代码

```python
import rustgzip as gzip

with gzip.open(stage_file, 'rb') as handle:
    while handle.read(1024 * 1024):
        pass
```

如果目的只是确认压缩包是否完整，可以进一步减少 Python 循环：

```python
import rustgzip

try:
    size = rustgzip.verify(stage_file)
    print('校验成功，解压后大小：%d 字节' % size)
except OSError as exc:
    print('校验失败：%s' % exc)
```

`verify` 在 Rust 内部循环，复用 1 MiB 缓冲，不生成解压文件。
**读取前几块、read(0) 或仅关闭文件，不等于完整性校验；必须完整读到 EOF。**

## 4. 其他常用方式

```python
import rustgzip as gzip

# 二进制写入。with 结束时会写完 gzip 尾部并处理磁盘错误。
with gzip.open('output.gz', 'wb', compresslevel=6) as handle:
    handle.write(b'hello\n')

# 文本写入与逐行读取；Python 3.4 不支持 f-string，因此示例也不使用。
with gzip.open('text.gz', 'wt', encoding='utf-8') as handle:
    handle.write('中文内容\n')
with gzip.open('text.gz', 'rt', encoding='utf-8') as handle:
    for line in handle:
        print(line.rstrip('\n'))

# 追加会新建一个标准 gzip member，不修改既有 member。
with gzip.open('output.gz', 'ab') as handle:
    handle.write(b'next\n')

packed = gzip.compress(b'hello', compresslevel=1)
plain = gzip.decompress(packed, max_output_size=16 * 1024 * 1024)

# 大文件读取时可复用 bytearray，减少 Python 分配。
buffer = bytearray(1024 * 1024)
with gzip.open('output.gz', 'rb') as handle:
    while True:
        count = handle.readinto(buffer)
        if not count:
            break
        # 在这里处理 buffer[:count]；需要避免复制时使用 memoryview(buffer)[:count]。
```

## 5. API 与边界

| 接口 | 行为 |
|---|---|
| `open(path, mode='rb', compresslevel=6, encoding=None, errors=None, newline=None, buffering=262144)` | 顺序文件流，支持 rb/wb/ab/xb 和文本模式 |
| `GzipFile(path, ...)` | 路径式便捷函数，不是标准库同名类 |
| `compress(data, compresslevel=6)` | bytes-like → gzip bytes，级别 0～9 |
| `decompress(data, max_output_size=536870912)` | 完整解压，默认最多 512 MiB 输出 |
| `verify(path, chunk_size=1048576)` | 完整校验并返回解压字节数；块大小 1 字节～64 MiB |
| `backend_info()` | 返回后端、包和 Python 版本，验证动态库是否可加载 |

- 支持 str/bytes 路径和现代 Python Path；支持 read/readinto/readline/迭代/write/flush/with。
- **不是标准库 gzip 的完整替代品**：不支持 seek/rewind、fileobj、fileno、mtime 参数或标准库类继承契约。
- `tell()` 返回处理后的逻辑字节位置；不能用它设置文件偏移。文本层有自己的位置规则。
- gzip 时间戳固定为 0，不存源文件名；压缩后的字节不保证与标准库逐字节一致。
- `flush()` 不是 fsync；成功关闭不等于已经保证断电持久化。
- `wb` 会截断既有文件，出错可能留下不完整输出。希望防覆盖时用 `xb`；重要输出建议先写临时文件，成功关闭后再由应用原子替换。
- 读取坏文件可能先得到部分数据，直到 CRC/EOF 检查时报错；不要在校验前把这些数据当成已验证结果。
- 文件流不限制解压总量；超大/不可信输入应由应用限制处理大小或时间。
- 内存解压的 max_output_size 限制输出字节数，实际峰值内存还包括输入、Rust 缓冲与 Python 返回副本。
- Rust 原生调用期间释放 GIL；不同文件流可以由线程并发处理。普通单 member gzip **没有多核并行解压**。
- 打开流后不要 fork 并复用它；子进程应重新打开自己的流。

## 6. 实测性能怎么看

`benchmark-linux-py34.json` 是 Debian 10 构建虚拟机、Python 3.4.10、zlib 1.2.11 的结果。
每类输入 16 MiB，每项测三轮取中位数；文件测试包含操作系统缓存，不是冷磁盘吞吐测试。

| 操作 | 本次相对 Python 3.4 标准库 |
|---|---|
| 内存压缩 | 约 1.50～3.23 倍 |
| 内存解压 | 约 2.56～4.62 倍 |
| open 分块读完 | 约 2.25～4.06 倍 |
| verify 整文件校验 | 约 3.04～3.82 倍 |

输入包含重复日志、变化字段的结构化日志和随机数据；**不能推广为所有文件的速度保证**。
Windows / Python 3.14 的内存解压测试有些比标准库慢，结果也如实保留在
`benchmark-windows.json`。不要用旧版 Python 的相对加速比推断新版 Python。

在真实 UOS 上复测：

```bash
python3.4 tools/benchmark.py 16 benchmark-my-uos.json
python3.4 tests/test_api.py
```

完整源码包内有这些脚本；测试使用临时生成的数据，不上传用户文件。

## 7. 后端与许可证

后端使用公开的 [flate2](https://github.com/rust-lang/flate2-rs) 和
[zlib-rs](https://github.com/trifectatechfoundation/zlib-rs)，开启运行时 CPU 特性检测。
构建不使用 `target-cpu=native`，避免在不支持本机指令集的 UOS CPU 上直接崩溃。
未复制 python-isal、python-zlib-ng 或 rapidgzip 实现，也没有将其性能宣传当作本包实测。

本项目新增封装为 MIT；依赖许可、版权告知、精确版本和来源说明见
`PROVENANCE.md`、`THIRD_PARTY_LICENSES/`。源码包附带公开 vendor，可离线构建，
未包含私有源码、密钥、运行数据或单位资料。

## 8. 从源码重建

构建需要 Rust 工具链、C 链接器；Python 运行时不需要它们。
本次验证的 Rust 为 Windows 1.99.0 / Linux 1.99.1。

```bash
cargo build --release --locked --offline
# Linux：将原生库放进 Python 包内，然后直接运行测试。
cp target/release/librustgzip_native.so python/rustgzip/
PYTHONPATH=python python3.4 tests/test_api.py
```

现代构建环境可运行 `python setup.py bdist_wheel`；较旧 Python 的构建工具已停止更新，
建议用现代 Python 构建 wheel，再在 Python 3.4 安装。wheel 使用 `py3-none-平台` 标签，
不伪装成纯 Python 或 manylinux 通用包。

`tools/package_release.py --native <动态库路径> --platform linux_x86_64` 可按白名单重打包。
不要直接压缩整个工作目录；build/target 中的编译缓存不是用户安装依赖。

## 9. 0.2.0 新增的缓冲区接口

`python
import rustgzip

output = bytearray(32 * 1024 * 1024)  # 由应用选择可信的容量上限，可以反复使用。
count = rustgzip.decompress_into(packed, output)
result = memoryview(output)[:count]  # 视图不复制完整结果；需要 bytes 时再显式转换。
`

容量不足、CRC/格式错误会抛出异常；失败后缓冲中的内容不可使用。
不要未经限制地根据 gzip 尾部 ISIZE 分配任意大内存，也不要在调用期间由其他线程访问 output。

源码学习和与 0.1.0 的逐项性能比较见 [UPSTREAM-REVIEW.md](UPSTREAM-REVIEW.md)。
本轮主要改善内存解压，文件 verify 没有本质提速，尚未实现普通单流多核解码。
0.2.0 的原生 ABI 为 2，0.3.0 为 3；0.3.1 / 0.4.0 为 4，后者新增可选并行扩展。
升级时替换整个包并重启 Python，不能混装 py 和动态库。

## 10. 0.3.0 的进一步优化

常见头部的内存解压直接使用同版本 zlib-rs 填充 Vec 剩余容量，复杂头部保留原解析器；串接文件跨 member 复用解码状态。API 用法不变，Python 3.4 仍受支持。

此次搜索、未采用的方案、性能波动及完整验证见 [OPTIMIZATION-030.md](OPTIMIZATION-030.md)。默认 verify 缓冲不变，普通单流多核解压仍未实现。

## 11. 0.3.1

修复刷新未到达文件、无效文本参数截断原文件、中断后的原生资源泄漏，以及缓冲扩容重试失败。
具体复现和修复见 [REVIEW-031.md](REVIEW-031.md)。原生 ABI 为 4，请替换完整包并重启使用它的 Python 进程。

Python 3.4 / 3.7 的运行回归各 82 项全部通过；Windows 通过 80 项，跳过 2 项 Linux 专用测试。
构建工具另有 7 项测试，请用现代 Python 运行 `python tests/test_packaging.py`。
性能 JSON 保留 0.3.0 的历史基线；本补丁以正确性为主，不宣称新增速度收益。

## 12. 0.4.0 可选并行实验

通过 `from rustgzip.experimental import compress_parallel, prefetch` 显式启用。
并行压缩保留 32 KiB 历史字典并合并 CRC，输出仍是单个标准 gzip member；
预取只把一个解码线程与调用方处理重叠，不是一个 gzip 流的多核解码。
原有 `open / compress / verify` 默认不变。

实验结果、使用示例、内存限制和失败处理见 [PARALLEL-040.md](PARALLEL-040.md)。
Linux Python 3.4 / 3.7 各 100 项运行测试通过；新增 4 项 Rust 并发正确性测试。
并行压缩只支持至多 512 MiB 的内存输入，大文件仍使用现有文件流接口。

## 13. 0.5.0 并行路径继续优化

并行压缩改用调用内固定工作线程，按块完成情况继续领取任务；调用线程参与计算。
新增 `rustgzip.experimental.compress_parallel_into`，可以直接写入已有缓冲，减少完整结果
分配与复制。原有默认接口不变。性能收益、退化配置和示例见
[OPTIMIZATION-050.md](OPTIMIZATION-050.md)。当前运行测试为 106 项，Rust 并发测试为 5 项。

## 14. 0.5.2 审查修复

修复关闭中断时的原生句柄泄漏、预取意外 StopIteration 被当成 EOF、预取关闭中断
未完成清理，以及超限可变输入先复制再拒绝。高压缩率块及时收缩冗余容量，并加强
发布包身份和路径检查。复现、内存对照和限制见 [REVIEW-051.md](REVIEW-051.md)。
当前运行测试 115 项（主接口 85、实验接口 30），发布工具测试 10 项。

## 15. 开发中的普通 gzip 文件并行验证

当前整体架构、未解决瓶颈和下一步实施方向，优先阅读
[架构瓶颈审计](ARCHITECTURE-BOTTLENECK-AUDIT.md)。它用三路径反事实和已知检查点
对照区分了符号成本、真实历史串行链与后端潜力；下面的局部实验成绩不能相加，
也不能当作已经完成普通 gzip 多核扩展。

审计后的第一步已实现独立符号内核：以任务输出为 LZ77 历史，结束时才构造尾窗，
并比较安全宽位读取。64 MiB 固定 CPU 对照中，未知历史日志从现有文件符号路径
约 177 提高到 329 MiB/s；这仅是第一阶段内核成绩，尚未接入工作池或 Python。
六项新增正确性测试、全部结果和接入条件见
[符号内核原型报告](SYMBOL-KERNEL-PROTOTYPE-REPORT.md)。

源码内部已加入自主符号解码、候选扫描、有界文件工作池和按真实历史提交 CRC 的
验证原型，没有预建索引；巨大候选超出预算时可从可信位置跨窗口继续处理。
本机 Rust 默认 debug 构建回归为 176 项通过、3 项测量测试默认跳过。

另有显式 `known-window-backend` 构建：可信真实历史下的直接文件解码已接入
zlib-rs 底层后端。未知窗口 worker 已支持有界连续多块任务，在完整块边界且
尾窗口没有 Marker 时自动交接；当前该构建 debug 回归 186 项通过，全部实验开关
debug/release 各 206 项通过；各有 3 项测量测试默认跳过。
原生处理量区分候选工作和可信采用量。功能默认不启用，适配限制、32 KiB 误区见
[P6 底层适配续篇](PARALLEL-DECODE-P6-LOWLEVEL-REPORT.md)，最新实现及本机开关
对照测速见 [worker 交接报告](PARALLEL-DECODE-WORKER-HANDOFF-REPORT.md)。

现已补充共享顺序提交层，Rust 内部支持文件到自有内存及预分配缓冲的真实输出，
并有默认关闭的分段计时；依据诊断加入原生状态复用及减少提交复制。
最新测量、输出失败契约与接口路线见
[输出与诊断报告](PARALLEL-DECODE-OUTPUT-AND-PROFILE-REPORT.md)。
这些不是已发布的 Python decompress_parallel 或 open_parallel。

后续已实现真实历史前缀、按压缩区间对齐的实验调度、u8 原生后缀及批量
match/stored 路径，并记录任务采用率、重解下界和丢弃分类。
32/64 MiB、1/2/4 worker 的实现和测量限制见
[对齐调度优化报告](PARALLEL-DECODE-ALIGNED-REPORT.md)。
进一步完成任务级尾窗恢复、原生缓冲复用、发布前一致性检查和 stored 长度前视；
最终较大样本的提速与剩余限制见
[固定成本优化报告](PARALLEL-DECODE-COST-OPTIMIZATION.md)。

最新一轮分离物理读缓存与解析事务、借用原生后缀、汇总历史依赖、复用符号读取状态，
并提供显式 stored 专用路径。64 MiB 同轮对照中随机和日志改善，stored 接近顺序基线，
但无任务的重复数据路径仍有退化；完整结果与尚未解决的问题见
[解码调优报告](PARALLEL-DECODE-TUNING-REPORT.md)。

另有显式 `intrablock-handoff` 试验：重放原始块头恢复 Huffman 表，仅在完整 token
结束且窗口完全已知时切换，因此可在某些大压缩块的 EOB 之前进入原生后端。
它尚未作为默认路径：大块隔离测试明显获益，但完整调度样本未显示普遍收益。
默认 8 位 Huffman 表保留，长码不再重复解析已经查过的前缀；9/10 位表和回退统计
仅作为显式诊断选项。实现条件、对照测量及限制见
[结构优化报告](PARALLEL-DECODE-STRUCTURAL-REPORT.md)。

进一步定位并修复无任务路径的批次分配、直接块状态重建和重复文件状态检查，
已证明没有可用网格的 Aligned 文件不再创建空闲线程。重复数据的旧退化明显收敛，
但日志的符号处理与顺序提交仍使并行路径慢于顺序基线；控制实验、正确性边界及
真实历史反馈的后续方案见 [退化定位报告](PARALLEL-DECODE-REGRESSION-REPORT.md)。

现已加入默认关闭的 `history-feedback` 实验：向运行中的推测任务提供精确原始
位起点的真实历史，解析当前窗口后尝试块内原生交接，不等待字典，旧 Marker
前缀及最终 CRC 仍完整校验。64 MiB 日志单 worker 能命中反馈，四 worker
尚未命中，整体仍慢于顺序基线；不能把该机制已实现等同于日志提速已完成。
安全边界、命中统计和开关对照见
[历史反馈实验报告](PARALLEL-DECODE-HISTORY-FEEDBACK-REPORT.md)。

后续显式 `unknown-prefix-yield` 实验在未知引用长期存在、符号前缀达到 256 KiB
后的完整块边界提前交付，由真实历史任务接续，不让 worker 原地等待字典。
64 MiB 日志四 worker 同轮由约 465 提升至 624 MiB/s，但仍低于顺序约 922 MiB/s，
2→4 worker 扩展也仍有限。它不是巨大 Huffman 块中途暂停功能，仍默认关闭；
正确性、失败回收和采用量见 [前缀交付实验报告](PARALLEL-DECODE-PREFIX-YIELD-REPORT.md)。

另有显式 `direct-native-output` 实验，使用已初始化 Vec 尾部直接接收 worker 原生
输出，减少 scratch→结果的复制。64/128 MiB 对照没有显示稳定的四线程收益，
因此仍默认关闭，不替换既有路径；初始化、失败回滚和复测结果见
[原生直接输出实验报告](PARALLEL-DECODE-DIRECT-OUTPUT-REPORT.md)。

时间线进一步确认日志已知历史任务基本串行：原生处理占比高不等于任务可并发。
显式 `coordinator-native` 在当前 member 实际采用 Marker 前缀后，让可信后继
直接由协调器连续推进，保留前方并行推测，并按需读取 stored 等价头信息。
128 MiB 同源码七轮对照中日志四 worker 约 624→667 MiB/s，单 worker 约
510→703 MiB/s；仍低于顺序基线，不能称四核扩展完成。确切主因、失败方案、
策略重置和最终对照见 [关键路径定位报告](PARALLEL-DECODE-CRITICAL-PATH-REPORT.md)。

块内交接现另有显式 `distance-bounded-handoff`：移除窗口已经真实时的块内 32 KiB
输出门槛；仅对终块，还可根据距离树上界使用已知短尾字典，保留更早 Marker。
单未知大动态块同轮约 1799→2174 MiB/s，符号前缀 32768→2 字节。普通日志仍
没有块内重放机会，不能套用该提升；终块限制、配额和完整管线实验证据见
[距离约束交接报告](PARALLEL-DECODE-DISTANCE-HANDOFF-REPORT.md)。

新增显式 `spare-native-output` 实验：worker 原生输出直接写 Vec 备用容量，
省掉尾部预清零，只发布实际写入的字节；失败回滚和终止规则继续生效。
普通数据有收益，隔离高压缩率样本也出现退化，按膨胀率自动回退的方案已因
误判撤回，因此继续默认关闭。最终三路测速、安全边界及测试见
[备用容量输出报告](PARALLEL-DECODE-SPARE-OUTPUT-REPORT.md)。

另有默认关闭的 `reuse-native-history`，在协调器导出块尾字典时复用已消费的
历史 Vec，避免逐块重新分配和清零。专项测试确认短/空窗口不会带出旧字节，
但两轮 128 MiB 对照未显示稳定吞吐收益，不能当成已完成的提速。
实现、安全边界和全部结果见 [历史缓冲复用报告](PARALLEL-DECODE-HISTORY-REUSE-REPORT.md)。

继续加入默认关闭的 `lazy-native-history` 与 `quiet-idle-workers`：真实历史只在
候选验证/反馈等确实需要时导出；队列为空时不广播任务通知，完成/取消等通知保留。
128 MiB 日志窗口导出由 1417 次降到 14 次；在按需历史开启后再省空队列通知，
四 worker 两轮约改善 1.9%、8.3%，但单 worker 部分配置仍有退化，仍慢于顺序。
实现、专项测试、通知计数和完整开关对照见
[按需历史与通知报告](PARALLEL-DECODE-LAZY-HISTORY-REPORT.md)。

**尚未提供 Python 调用入口，也没有 UOS 实机结论。** 本机已有端到端开关对照；
随机 Base64 样本经调参已实测超过同轮顺序基线；这不代表 stored、日志或所有
gzip 都能超过顺序路径，也不代表已经完成 UOS 上的多核验收。
当前发布包及上文的公共 API 仍保持 0.5.2 行为。实现范围、预算、测试和待完成事项见
[文件工作池报告](PARALLEL-DECODE-FILE-POOL-REPORT.md)。
