Repository navigation
feat(extract): multi-threaded parallel extraction engine and safe extent pre-allocation - #1207
Conversation
…s and harden atomic quota check in parallel extraction
|
|
||
| use indexmap::IndexMap; | ||
|
|
||
| #[cfg(feature = "parallel")] |
There was a problem hiding this comment.
Call this feature rayon because we may also add async support in the future, which would also enable parallelism.
There was a problem hiding this comment.
Updated in commit 7388583. Renamed the feature from parallel to rayon across Cargo.toml, conditional attributes, and test gates. This keeps feature naming idiomatic and reserves the namespace cleanly for any future async engine.
| /// Extracts archive contents in parallel across available CPU cores using a reader factory. | ||
| /// | ||
| /// The `reader_factory` closure is called to produce an independent reader instance | ||
| /// for each worker thread, ensuring independent file offsets and preventing concurrent seek collisions. |
There was a problem hiding this comment.
Document what the usual reader_factory implementations will be, such as || Ok(Cursor::new(&slice)), || file.try_clone(), and || Ok(positioned_io::Cursor::new(random_access_file)).
There was a problem hiding this comment.
Documented in commit 7388583. Added comprehensive rustdoc sections and examples for the canonical reader_factory patterns (|| Ok(Cursor::new(&slice)), || file.try_clone(), and || Ok(positioned_io::Cursor::new(random_access_file))) directly to par_extract_with_reader_factory and referenced in par_extract_with_reader_factory_and_options.
| fn test_par_extract_in_memory_cursor() { | ||
| let buf = Vec::new(); | ||
| let mut writer = ZipWriter::new(Cursor::new(buf)); | ||
| let options = SimpleFileOptions::default().compression_method(CompressionMethod::Stored); |
There was a problem hiding this comment.
Test this with all enabled read/write compression methods. We need to ensure the decompressors work okay when multiple instances exist.
There was a problem hiding this comment.
Added in commit 7388583. The test suite now checks all enabled read/write compression methods (Stored, Deflated, Bzip2, Zstd, Xz, Ppmd) and validates both multi-file batches for each codec and interleaved multi-codec extraction archives across worker threads, ensuring multi-instance decompressors are completely re-entrant and thread-safe.
…atterns, and test all compression methods
Summary
This PR introduces high-performance multi-threaded parallel extraction (
par_extract,par_extract_from_path) powered by Rayon behind an opt-inrayonCargo feature, alongside safe extent pre-allocation, sequential I/O hinting, and directory memoization for single-threaded extraction.Key Capabilities
Multi-Threaded Parallel Extraction Engine (
par_extract):par_extract,par_extract_with_options,par_extract_from_path, andpar_extract_with_reader_factory.reader_factory, sharing only the parsed, read-onlyArc<ZipArchiveMetadata>with zero central directory re-parsing.Safe Extent Pre-Allocation & Atomic Truncation:
File::set_lenup to a safe ceiling (MAX_PREALLOCATE_LEN = 64 MiB) to avoid filesystem fragmentation and metadata lock contention on NTFS and ext4/XFS.outfile.set_len(actual_len)atomically truncates the file back to its exact written length, preventing sparse/unallocated block leaks.VFS Directory Memoization & Sequential Scan Hint:
HashSet<PathBuf>, eliminating thousands of redundantmkdir/NtCreateFilesystem calls during deep tree extractions.FILE_FLAG_SEQUENTIAL_SCANto hint the NT Cache Manager to optimize page read-ahead and write-behind caching for sequential streams.Concurrency Hardening & Quota Protection:
IndexMap<PathBuf, usize>during the main thread scaffolding phase, dispatching only the last unique entry per path to Rayon. This completely eliminates WindowsERROR_SHARING_VIOLATION(code 32) and overwrite race conditions on archives with duplicate paths (e.g.foo.txtand./foo.txt).AtomicU64with relaxed fetch-and-add to enforce cumulativesize_limitquotas across concurrent threads, aborting immediately if the limit is breached.Benchmark Results
Measured on 240 MB payload (24 files x 10 MB each) on PCIe Gen4 NVMe SSD:
zip2(naive 8K stack copy)par_extract)Design & Compatibility Guarantees
rayon = ["dep:rayon"]. Default consumers incur zero new dependencies and zero binary size increase.archive.extract()API signature and behavior remain completely unchanged.-D warnings), and 9 integration stress tests across all enabled compression methods intests/extract_parallel.rs.Need help on this PR? Tag
@codesmith-botwith what you need.