Skip to content

Prepare v0.8.1 performance and internal architecture release - #29

Merged
mbroemme merged 23 commits into
masterfrom
next/v0.8.1
Oct 6, 2026
Merged

mbroemme merged 23 commits into
masterfrom
next/v0.8.1

Conversation

@mbroemme

@mbroemme mbroemme commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Bump the project version to 0.8.1 while preserving the existing public C API and 5:0:1 libtool ABI.
  • Improve patch performance by avoiding unnecessary COPY-result materialization, reducing patch-writer work, and separating patch reader and writer benchmarks.
  • Improve authenticated MPQE update performance by eliminating a redundant staging copy during transactions.
  • Improve full-file read performance by avoiding redundant sector-offset acquisition.
  • Improve writer duplicate detection by probing the hash table directly rather than performing unnecessary additional work.
  • Improve sector integrity verification by reusing sector buffers instead of repeatedly allocating temporary storage.
  • Add and standardize comprehensive developer benchmarks for readers, writers, streams, custom I/O sources, updates, patches, MPQE, compression, signatures, and integrity verification.
  • Expand regression coverage for custom archive sources and logical streams alongside the new benchmark coverage.
  • Complete a broad internal-header decomposition that removes the long-lived src/mpq-internal.h catch-all header and assigns private structures and wire-format responsibilities to focused modules.
  • Centralize MPQ header, hash-table, and block-table wire-format handling in their respective mpq-header, mpq-hash, and mpq-block modules with dedicated regression tests.
  • Move logical entry, archive, and writer state into focused private headers, reducing implicit cross-module dependencies.
  • Simplify MPQ crypt-table ownership by keeping the immutable crypt table directly in mpq-crypto.c.
  • Remove the generated src/mpq-crypt-buf.h, the historical tools/crypt_buf_gen.c generator, and the now-unused tools/ build integration while preserving the crypt table contents and behavior.
  • Fix (attributes) handling so all-zero MD5 rows are treated as unavailable placeholders rather than valid digests, preventing false verification failures.
  • Keep archive formats, public structures, public function signatures, language-facing native API, and ABI unchanged while substantially improving internal maintainability and performance.

Behavioral Change: MD5 Attributes

There is one intentional verification behavior correction. Some archives contain an MD5 array in (attributes) but use an all-zero 16-byte row as a placeholder for files without an MD5 value. v0.8.1 now treats such rows as unavailable MD5 metadata rather than comparing the all-zero value as an actual digest.

Consequently:

  • libmpq__file_attributes() no longer advertises MD5 availability for an all-zero row;
  • automatic verification during complete lossless reads skips such placeholder rows;
  • libmpq__file_verify() likewise skips unavailable all-zero MD5 entries;
  • genuine non-zero MD5 values continue to be verified normally.

Private Internal Interfaces

The internal source layout changes substantially, but these interfaces are private and are not part of the installed SDK. src/mpq-internal.h is removed and its responsibilities are distributed among focused internal modules:

  • mpq-header.[ch] owns MPQ header wire-format structures and serialization.
  • mpq-hash.[ch] owns hash-table representation and wire handling.
  • mpq-block.[ch] owns block-table and extended block-table representation and wire handling.
  • mpq-entry.h owns logical file/map entry state.
  • mpq-archive.h owns private archive state.
  • mpq-writer.h owns private writer state.

Because none of these private declarations are installed public interfaces, the refactoring does not constitute an API or ABI break.

Crypto Table Cleanup

The immutable MPQ crypt table is now defined directly in mpq-crypto.c. The following implementation artifacts are removed:

  • src/mpq-crypt-buf.h
  • tools/crypt_buf_gen.c
  • tools/Makefile.am
  • obsolete top-level tools/ build integration

The crypt-table values and resulting MPQ hashing, encryption, and decryption behavior remain unchanged.

Performance and Benchmark Improvements

v0.8.1 adds a significantly broader benchmark suite and uses it to address measurable internal overhead without changing public behavior.

Patch Processing

  • Avoid copying COPY results while materializing patch views.
  • Reduce unnecessary patch-writer work.
  • Split patch reader and writer benchmarks so the two paths can be measured independently.

Archive Updates

  • Avoid a duplicate MPQE staging copy during authenticated update transactions.

Archive Reads

  • Avoid redundant sector-offset acquisition during complete-file reads.

Archive Writing

  • Probe the hash table directly when checking for duplicate members.

Integrity Verification

  • Reuse sector buffers during verification instead of repeatedly allocating temporary buffers.

Benchmark Coverage

Dedicated benchmark programs now cover:

  • compression
  • MPQE
  • patch reading
  • patch writing
  • archive reading
  • signatures
  • custom archive sources
  • logical streams
  • transactional updates
  • integrity verification
  • archive writing

Developer benchmark tooling is standardized so these paths can be profiled consistently.

Internal Architecture Changes

Header Wire Format

MPQ header wire-format handling is centralized in mpq-header.[ch]. Dedicated tests verify header parsing and serialization independently from the rest of the reader/writer implementation.

Hash Tables

Hash-table wire-format logic moves into mpq-hash.[ch]. This gives hash-table representation, serialization, and related validation a clear module owner and corresponding regression coverage.

Block Tables

Classic and extended block-table wire-format handling moves into mpq-block.[ch]. The change removes duplicated representation knowledge from unrelated reader and writer code.

Private State Ownership

Logical entry, archive, and writer state are moved out of the global internal header into focused private headers. Remaining dependencies on mpq-internal.h are removed before deleting the header entirely.

Crypto Ownership

The static MPQ crypt table becomes an implementation detail of mpq-crypto.c, eliminating a generated internal header and the build-time generator used to create it.

Commit Overview

  • 42b8198 - chore(release): bump version
  • 9033a88 - perf(patch): avoid copying COPY results during view materialization
  • 374426e - perf(patch): reduce writer work and split reader and writer benchmarks
  • 79d5aa6 - perf(update): avoid duplicate MPQE staging copy
  • cc8e885 - chore(bench): standardize developer benchmark tooling
  • e3d438e - perf(reader): avoid redundant offset acquisition in full-file reads
  • 020937b - test(stream): add stream benchmarks and regression coverage
  • b893ebc - perf(writer): probe hash table for duplicate members
  • 43bd198 - test(mpqe): benchmark encoding, authenticated open, and reads
  • 2c308a6 - perf(verify): reuse sector buffers and benchmark integrity checks
  • 2ee4c35 - test(source): benchmark custom I/O and add source regressions
  • 33da377 - test(compression): benchmark production codec dispatch
  • 8d6df36 - style: fix C comment layout and MPQE benchmark wording
  • 951078c - refactor(mpq): centralize header wire-format handling
  • cecbf20 - refactor(mpq): centralize hash-table wire handling
  • bb10341 - refactor(mpq): centralize block-table wire handling
  • d61f610 - refactor(mpq): extract logical entry state into private header
  • a018aeb - refactor(mpq): extract archive state into private header
  • 5dba2f4 - refactor(mpq): move writer state to its private header
  • 5c63271 - refactor(mpq): remove internal header dependencies
  • eb34348 - refactor(mpq): remove unused internal header
  • 1f94c00 - refactor(crypto): keep MPQ crypt table in crypto source
  • 2ff1762 - fix(attributes): skip all-zero MD5 placeholders

Borrow decoded COPY bytes while staging patch views, eliminating a
result-sized allocation and copy without changing the owning output
contract of libmpq__patch_apply().

Add a non-installed benchmark for COPY, BSD0, and mixed patch chains.
Verify each generated transform before timing, use a monotonic POSIX
clock, and document how to run the benchmark.
Reuse computed MD5 values for patch metadata and attributes, and skip
BSD0 candidates that cannot beat the current selection while retaining
full validation for eligible candidates.

Add a dedicated writer-staging benchmark, keep the reader benchmark
focused on materialization, register both as non-installed tools, and
document their separate usage.
Decode MPQE input directly into the private working archive while
checking source identity and retaining archive validation.

Add a non-installed benchmark for ordinary, embedded, and MPQE updates;
test the plaintext working copy and document benchmark usage.
- Align run-count validation and best-of-N output across all three tools.
- Add aggregate build and run targets with Windows executable suffix support.
- Consolidate usage guidance in the developer guide.
Add a non-installed benchmark for archive opening, lookup, and extraction.
Strengthen offset-lifetime regression checks and poison benchmark buffers
before timed reads.
Benchmark stream opening, incremental reads, and seek workloads across
stored, compressed, and encrypted members. Add focused regression tests,
wire the targets into Automake, and document benchmark usage.
Avoid rehashing every previously written filename during archive creation.
Add an archive-writer benchmark and regression tests for duplicate identity,
locale/platform variants, and displaced hash entries.
Add benchmarks for Adler-32, CRC32/MD5, and signature verification,
with build targets and developer documentation.
Compare file-backed and memory-backed MPQ/MPQE reads, and cover
callback failures, range checks, and context ownership.
Measure encode and decode paths with deterministic inputs, and add the
non-installed benchmark to aggregate targets and developer guidance.
Make comments pass the source formatting checks and label the MPQE
source workload as random read_at rather than seek/read.
Move private header definitions into mpq-header.[ch] and use
shared encode/decode helpers in reader and rebuild paths.
Add exact-wire tests and build integration.
Move hash-entry definitions into mpq-hash.[ch] and use shared
encode/decode helpers in reader, writer, update, and patch paths.
Add exact-wire and slot-marker tests.
Move private block definitions into mpq-block.[ch] and use shared
base and extended table codecs across read and rebuild paths.
Add exact-wire, bounds, and overflow tests.
Move mpq_file_s and mpq_map_s from mpq-internal.h to mpq-entry.h
without changing their layouts. Include the private header in source
distributions.
Move archive state and pseudo-member names to mpq-archive.h.
Include it directly in archive consumers and add it to source
distributions. Leave writer internals in mpq-internal.h.
Move the unchanged mpq_writer structure into mpq-writer.h and
include its MD5 dependency there. Keep mpq-internal.h as a
transitional consumer of the focused writer header.
Move block and compression flags to their owning headers, replace the
private success macro with 0, and use direct includes across source,
tests, benchmarks, and fuzz code.
Delete the empty transitional header and remove it from the build
manifest.
Move the unchanged static table into mpq-crypto.c and remove the
generated header and obsolete generator. Drop their build, CI,
source-check, and documentation references.
Treat zero MD5 rows as unavailable so reads and explicit verification
do not report false mismatches. Add regression coverage and document
the per-file behavior.
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

Coverage report

Base: a781430b5ee2. Current CI run: 2ff17622f19d.

Metric Base PR Delta
Lines 84.02% 83.89% -0.13 pp
Functions 99.23% 99.24% +0.01 pp
Branches 69.93% 69.97% +0.04 pp

⚠️ Line coverage decreased by -0.13 percentage points.

Detailed coverage report

@mbroemme
mbroemme merged commit e6a7aa4 into master Oct 6, 2026
86 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant