Skip to content

[core] Add standalone manifest sidecar format and utilities - #9845

Merged
JingsongLi merged 14 commits into
apache:masterfrom
leaves12138:codex/manifest-sidecar-format
Sep 16, 2026
Merged

JingsongLi merged 14 commits into
apache:masterfrom
leaves12138:codex/manifest-sidecar-format

Conversation

@leaves12138

@leaves12138 leaves12138 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Purpose

Introduce a standalone manifest sidecar format and utilities for selecting physical Avro blocks using independent partition, row-ID and bucket coverage. This provides the block-selection building block; automatic integration with table writers, scans and cleanup remains separate work.

  • Define a four-byte magic, version, original Avro header, partition dictionary, physical block directory, independent coverage payloads and SHA-256 checksum. Counts, lengths and offsets use canonical unsigned varints. Manifest length and entry count are validated against the supplied ManifestFileMeta instead of duplicated in the sidecar.
  • Share the count-prefixed intsDeltaPayload through the streaming DeltaVarintCodec. Row-ID coverage keeps fixed-width minRowId and maxRowId followed by sorted interior endpoints. Bucket pairs are sorted and stored as paired bucket/total-bucket sequences; totals use ZigZag deltas to preserve decreases after rescaling.
  • Always generate partition coverage. Row-ID and bucket generation are controlled by method arguments; callers decide whether to build or read a sidecar.
  • Include validation, conservative fallback, sequential selected-block reads and optional bounded caching. Sidecar reads and selected-block reads use separate buffers.

Tests

  • Java 8: 55 targeted tests passed, including Checkstyle and Spotless checks.
  • Coverage includes golden format fixtures, 64-bit row-ID boundaries and gaps, decreasing bucket totals and rescaling, malformed/truncated varints, directory validation, unavailable dimensions, interruption behavior, real manifest rewrites, cache behavior and large block reads.
  • Independent review probes: 1,000 generated sidecars with 16,000 filter combinations matched an entry-level oracle. All tested truncations were rejected; 10,000 checksum-recomputed framing/payload mutations produced no unchecked parser failures.
mvn -B -ntp -nsu -pl paimon-core -am -DwildcardSuites=none -DfailIfNoTests=false -Dflink.forkCount=2 -Dtest=DeltaVarintCodecTest,ManifestSidecarTest,ManifestBlockIndexTest test

@XiaoHongbo-Hope

Copy link
Copy Markdown
Contributor

Suggestion:Could we use .avro.index instead of .avro.sidecar ? Or do you want to distinguish it from data file indexes?

@JingsongLi JingsongLi 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.

  1. We should probably remove maxBytes; it is always effective once the file is opened.
  2. The row IDs, partition data, or bucket data within a block should be designed using a lightweight, compressed storage format, such as delta encoding combined with RLE. (Should be sorted too)
  3. Four bytes are sufficient for the magic number.
  4. manifestNameHash is too tightly coupled; I don't think it's necessary.
  5. Partition data should always be enabled.

@leaves12138

Copy link
Copy Markdown
Contributor Author

Suggestion:Could we use .avro.index instead of .avro.sidecar ? Or do you want to distinguish it from data file indexes?

Yes, I want to name it sidecar, a special format for manifest file

@leaves12138
leaves12138 marked this pull request as draft September 15, 2026 13:24
@leaves12138

leaves12138 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

RLE increased the sidecar size in the tested sample because nearly all row-ID endpoint deltas formed runs of length one. We therefore removed RLE and use delta encoding with varints, which reduced the sidecar size by over 50% compared with the original fixed-width encoding.

@leaves12138
leaves12138 marked this pull request as ready for review September 15, 2026 14:07
}

/** Read/write switches and optional payloads. Partition coverage is always enabled. */
public static final class Settings {

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.

Remove this class, just use arguement.


/** Read/write switches and optional payloads. Partition coverage is always enabled. */
public static final class Settings {
public final boolean write;

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.

Remove this.

/** Read/write switches and optional payloads. Partition coverage is always enabled. */
public static final class Settings {
public final boolean write;
public final boolean read;

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.

Remove this.

Comment thread docs/docs/concepts/spec/manifest.md Outdated
```text
magic : 4 bytes // ASCII PMSC
formatVersion : int // 1
manifestLength : long

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.

Remove this.

Comment thread docs/docs/concepts/spec/manifest.md Outdated
magic : 4 bytes // ASCII PMSC
formatVersion : int // 1
manifestLength : long
manifestEntryCount : long // ADD + DELETE

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.

Remove this.

Comment thread docs/docs/concepts/spec/manifest.md Outdated
formatVersion : int // 1
manifestLength : long
manifestEntryCount : long // ADD + DELETE
avroHeaderLength : int

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.

var int

Comment thread docs/docs/concepts/spec/manifest.md Outdated
manifestEntryCount : long // ADD + DELETE
avroHeaderLength : int
avroHeader : bytes // original schema, codec and sync marker
partitionCount : int

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.

var int. All need var int use var int, except too big.

Comment thread docs/docs/concepts/spec/manifest.md Outdated
| --- | --- | --- |
| Any | `0` | Unavailable; only the encoding byte is present. |
| Partition | `1` | Count and delta/varint-compressed sorted unique dictionary IDs. |
| Row ID | `1` | Interval count, minimum, span, and delta/varint-compressed interior endpoints. |

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.

Sorted?

Comment thread docs/docs/concepts/spec/manifest.md Outdated

```text
partitionPayload
partitionIdCount : int // N > 0

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.

You can introduce a intsDeltaPayload:

  • count
  • deltas[]

Partition and row Id and bucket all refer to it.

Comment thread docs/docs/concepts/spec/manifest.md Outdated

```text
rowIdPayload
rangeCount : int // N > 0

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.

  • minRowId
  • maxRowId
  • intsDeltaPayload

Comment thread docs/docs/concepts/spec/manifest.md Outdated

```text
bucketPayload
pairCount : int // N > 0

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.

  • sort by bucket
  • bucket intsDeltaPayload
  • totalBucket intsDeltaPayload

@leaves12138

Copy link
Copy Markdown
Contributor Author
  1. We should probably remove maxBytes; it is always effective once the file is opened.
  2. The row IDs, partition data, or bucket data within a block should be designed using a lightweight, compressed storage format, such as delta encoding combined with RLE. (Should be sorted too)
  3. Four bytes are sufficient for the magic number.
  4. manifestNameHash is too tightly coupled; I don't think it's necessary.
  5. Partition data should always be enabled.

Done

Comment thread docs/docs/concepts/spec/manifest.md Outdated
if bucketEncoding != 0:
bucketPayloadLength : varint
bucketPayload : bytes
checksum : 32 bytes // SHA-256 of all preceding bytes

@JingsongLi JingsongLi Sep 16, 2026

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.

Use crc32c 4 bytes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will use CRC32 to verify

Comment thread docs/docs/concepts/spec/manifest.md Outdated

```text
partitionPayload
intsDeltaPayload // N > 0 dictionary IDs, base = 0

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.

longsDeltaPayload

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

partitionPayload are ints, but row id payload are longs, I will comment it in manifest.md

}

private static int readInt(ByteBuffer in) throws IOException {
long value = VarLengthIntUtils.decodeLong(in);

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.

add decodeInt to VarLengthIntUtils

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK

@leaves12138
leaves12138 force-pushed the codex/manifest-sidecar-format branch from fdd01c5 to e016a05 Compare September 16, 2026 08:02
@JingsongLi

Copy link
Copy Markdown
Contributor

+1

@JingsongLi
JingsongLi merged commit c4bb875 into apache:master Sep 16, 2026
10 of 17 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.

3 participants