JingsongLi commented on code in PR #9845: URL: https://github.com/apache/paimon/pull/9845#discussion_r4022190339
########## docs/docs/concepts/spec/manifest.md: ########## @@ -63,6 +63,227 @@ skip manifests before opening them. Each extra file belongs exclusively to one manifest. It is retained and cleaned up together with that manifest during snapshot, tag, or changelog deletion. +### Manifest Sidecar + +`ManifestSidecar` provides a binary sidecar for selecting complete Avro manifest blocks +using independent partition, row-ID and bucket coverage. A sidecar uses the +`<manifest-file-name>.avro.sidecar` naming convention. Readers find it through an explicit +`.avro.sidecar` reference in the manifest metadata's `_EXTRA_FILES`, without probing a +derived file name. The Avro schemas and `_VERSION` identifiers remain unchanged. + +The utility includes construction, validation, block selection and optional caching. Table +writers and scans do not yet invoke it automatically. Callers are responsible for publishing +sidecar references, managing file ownership, applying entry filters and reconciling ADD/DELETE +entries after block selection. `build` returns null without opening files when `Settings.write` +is false. Otherwise it reads the completed physical manifest and returns sidecar bytes; it does +not write or publish another file. + +`Settings` contains `write` and `read` switches for the calling writer and scan, and enables +row-ID and bucket payload generation independently. Partition generation is always enabled, +including the empty partition tuple for unpartitioned tables. Missing or invalid +metadata makes only the affected block's dimension unavailable. There is no sidecar byte budget: +construction keeps complete coverage and `read` consumes the entire file once it is opened. + +`read` returns null immediately when `Settings.read` is false, without inspecting metadata, +accessing the cache or opening files. An absent sidecar reference or an `IOException` also +returns null, allowing the caller to fall back to the manifest. If the thread is interrupted, the I/O failure is propagated as +`UncheckedIOException`. Other exceptions and errors propagate unchanged. `select` validates +supplied bytes directly and reports invalid containers with `IOException`. + +Version 1 uses the following layout. Container `int` and `long` fields are signed, fixed-width +4-byte and 8-byte big-endian integers. Encoding IDs are unsigned bytes with separate namespaces. +Payload counts and envelopes use the same fixed-width types; delta streams use the +variable-length encoding described below. + +```text +magic : 4 bytes // ASCII PMSC +formatVersion : int // 1 +manifestLength : long +manifestEntryCount : long // ADD + DELETE +avroHeaderLength : int +avroHeader : bytes // original schema, codec and sync marker +partitionCount : int +partitionDictionary[] + partitionByteLength : int + partitionBytes : bytes // existing manifest BinaryRow serialization +blockCount : int +blocks[] // original physical order + offset : long + length : long // complete encoded block, including sync marker + recordCount : long + partitionEncoding : byte + if partitionEncoding != 0: + partitionPayloadLength : int + partitionPayload : bytes + rowIdEncoding : byte + if rowIdEncoding != 0: + rowIdPayloadLength : int + rowIdPayload : bytes + bucketEncoding : byte + if bucketEncoding != 0: + bucketPayloadLength : int + bucketPayload : bytes +checksum : 32 bytes // SHA-256 of all preceding bytes +``` + +The block ID is its position. Its first entry ordinal is the sum of preceding record counts +and is not stored. Each complete partition tuple appears once in the dictionary, including +all its fields and nulls. The scan's partition type interprets the existing serialized tuple. +Partition predicates are evaluated once per dictionary entry. + +| Dimension | Encoding | Payload | +| --- | --- | --- | +| 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. | +| Bucket | `1` | Count and delta/varint-compressed sorted unique packed bucket/count pairs. | +| Any | Other nonzero ID | Skip the declared payload length; treat only this dimension as unavailable. | + +Only nonzero encodings are followed by a length and payload. Payload lengths exclude the +encoding and length fields, but include the count and other fields within the payload. +All three encoding-1 payloads have positive counts no greater than the block's record count. +Encoding 0 represents unavailable coverage, rather than encoding 1 with a zero count. + +#### Delta Encoding + +Each payload starts with a fixed-width count (`int`); row-ID payloads also have fixed-width +`min` and `span` fields (`long`). Only integers in the following delta stream use +nonnegative unsigned LEB128 varints, occupying one to nine bytes for values from 0 through +`Long.MAX_VALUE`. Seven value bits are stored per byte, least significant group first; the +high bit indicates another byte follows. +Encodings use the shortest representation. There is no ZigZag transformation or padding. + +A sorted sequence is delta-encoded from a specified base. Each value contributes one +unsigned varint containing its difference from the preceding value. The first difference +is relative to the base: + +```text +deltas[] : varint +value[0] = base + deltas[0] +value[i] = value[i - 1] + deltas[i] +``` + +The shared `DeltaVarintCodec` utility writes each delta immediately and reads values on +demand, using `VarLengthIntUtils` for varints. Counts and bounds are supplied by the caller. +The reader checks overflow and value bounds and requires the buffer to end after all +expected values have been consumed. It can stop early without materializing the sequence. + +#### Partition Payload + +When `partitionEncoding == 1`, the block stores IDs of all distinct partition tuples +represented by its entries: + +```text +partitionPayload + partitionIdCount : int // N > 0 Review Comment: You can introduce a `intsDeltaPayload`: - count - deltas[] Partition and row Id and bucket all refer to it. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
