Skip to content

Add optional ZFile index compression - #465

Merged
liulanzheng merged 1 commit into
containerd:mainfrom
williswus:feat/zfile-index-compression
Nov 8, 2026
Merged

liulanzheng merged 1 commit into
containerd:mainfrom
williswus:feat/zfile-index-compression

Conversation

@williswus

Copy link
Copy Markdown
Contributor

ZFile already compresses data blocks, but stores the block-length index uncompressed. This PR adds optional index compression using the existing format’s flag bit 5.

Changes:

  • Add CompressArgs::compress_index and the --compress-index CLI flag, disabled by default.
  • Share index writing across the whole-file writer and both streaming builders.
  • Support LZ4 and ZSTD, retaining raw indexes when compression provides no space savings or exceeds codec limits.
  • Validate metadata, sizes, checksums and decoded block lengths before exposing the file for reads.
  • Handle short source reads and enforce index limits before buffering additional input.

Format choices:

  • With bit 5 clear, index_size remains the entry count.
  • With bit 5 set, it records compressed bytes; the decoded entry count is derived from the original file size and block size.
  • The index checksum covers the stored bytes.

Existing raw indexes remain supported. Older readers cannot read compressed indexes, so compression remains opt-in. I have not compared these format choices with the historical ease implementation.

Validation:

  • Debug build with QAT disabled.
  • Full zfile_test suite: all 12 tests passed.
  • Coverage includes both codecs, all writers, header/trailer paths, raw fallback, short reads and malformed inputs.
  • git diff --check passed.

Comment thread src/overlaybd/zfile/index_compression.h Outdated
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge this file into zfile.cpp

Comment thread src/overlaybd/zfile/zfile.cpp Outdated
}

// Shared by the whole-file writer and both streaming builders.
static int write_index(IFile *file, const std::vector<uint32_t> &lengths,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why static? why not let it be a member of ZFileBuilderBase?

pht->opt.use_dict);

if (index_bytes > trailer_offset - pht->index_offset)
LOG_ERROR_RETURN(0, false, "invalid index bytes or size. ");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it necessary to change so much here?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

An unresolved out-of-bounds read needs correction, and historical format compatibility still requires human review.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Adds opt-in ZFile index compression while preserving raw indexes by default.

Changes:

  • Adds LZ4/ZSTD index compression shared by all writers.
  • Exposes API and CLI options.
  • Strengthens validation and adds round-trip and malformed-input tests.
File Description
src/​tools/​overlaybd-zfile.cpp Adds --compress-index.
src/​overlaybd/​zfile/​zfile.cpp Integrates index compression and validation.
src/​overlaybd/​zfile/​test/​test.cpp Tests writers, codecs, and invalid inputs.
src/​overlaybd/​zfile/​index_compression.h Implements index codec helpers.
src/​overlaybd/​zfile/​format_spec.md Documents compressed-index storage and compatibility.
src/​overlaybd/​zfile/​compressor.h Adds the opt-in API setting.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/overlaybd/zfile/zfile.cpp Resolved
Comment thread src/overlaybd/zfile/zfile.cpp Outdated

// Whole-index codecs use CPU routines: data-block/QAT buffer limits do not apply.
// Return 1 for compressed output, 0 to keep the original, or -1 on codec error.
static int compress_index_buffer(const void *src, size_t size, uint8_t algo,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a member of ZFileBuilderBase.

Comment thread src/overlaybd/zfile/zfile.cpp Outdated
}

// A successful decode must restore exactly the expected index byte count.
static int decompress_index_buffer(const void *src, size_t size, void *dst,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a member of ZFileBuilderBase.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Reusing on-disk flag bit 5 requires human compatibility review against historical compressed-index implementations.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Comment thread src/overlaybd/zfile/zfile.cpp Outdated
}

// Check before buffering or queueing data, not after the index has already grown.
static int check_input_size(uint64_t current_size, size_t count, uint32_t block_size) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put it into ZFileBuilderBase, not necessarily static.

Comment thread src/overlaybd/zfile/zfile.cpp Outdated
virtual int fini() = 0;
// Whole-index codecs use CPU routines: data-block/QAT buffer limits do not apply.
// Return 1 for compressed output, 0 to keep the original, or -1 on codec error.
static int compress_index_buffer(const void *src, size_t size, uint8_t algo,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not necessarily static

Comment thread src/overlaybd/zfile/zfile.cpp Outdated
}

// A successful decode must restore exactly the expected index byte count.
static int decompress_index_buffer(const void *src, size_t size, void *dst,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not necessarily static

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The size-limit check can block indefinitely on an open pipe after overflow is already known because it waits for a full batch or EOF instead of checking after each successful read.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Check input size after each read to avoid blocking on overflow

src/​overlaybd/​zfile/​zfile.cpp:1375

The size-limit check runs only after a full batch or EOF. If the accepted input has reached the maximum and a pipe supplies one extra byte but remains open, this loop attempts another read and can block indefinitely instead of returning EFBIG, even though the overflow is already known. Check the accumulated batch size after each successful read before requesting more input.

Review effort: Balanced

Comment thread src/overlaybd/zfile/format_spec.md Outdated
| flags | 32 | uint64_t | bits for flags* (see later for details) |
| index_offset | 40 | uint64_t | index offset |
| index_size | 48 | uint64_t | size of the index section, possibly compressed base on flags |
| index_size | 48 | uint64_t | entry count when bit 5 is 0; compressed byte count when bit 5 is 1 |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bit 5 --> FLAG_SHIFT_IDX_COMP ?

Allow ZFile writers to compress the block-length index with LZ4 or
ZSTD when requested. Keep the raw index when compression does not
reduce its size. Validate stored and decoded indexes before use.

Signed-off-by: Willis Wu <willis060510@gmail.com>
@williswus
williswus force-pushed the feat/zfile-index-compression branch from 0438df3 to 9a5e7f2 Compare November 7, 2026 16:05
@liulanzheng
liulanzheng merged commit f084bf5 into containerd:main Nov 8, 2026
3 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.

5 participants