JingsongLi commented on code in PR #9845:
URL: https://github.com/apache/paimon/pull/9845#discussion_r4023176465


##########
docs/docs/concepts/spec/manifest.md:
##########
@@ -63,6 +63,242 @@ 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` reads the completed physical manifest 
and returns
+sidecar bytes; it does not write or publish another file.
+
+Callers decide whether to invoke `build` and `read`; these utilities have no 
read/write switches.
+`build` and `Builder` accept `rowIdEnabled` and `bucketEnabled` arguments for 
independent
+payload generation. 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 for an absent sidecar reference or an `IOException`, 
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. Counts, lengths, offsets and the version 
use canonical
+nonnegative unsigned LEB128 varints. Counts and payload lengths are bounded by 
`Integer.MAX_VALUE`;
+block offsets, lengths and record counts are bounded by `Long.MAX_VALUE`. 
Row-ID envelope
+endpoints remain fixed-width, eight-byte big-endian longs. Encoding IDs are 
unsigned bytes
+with separate namespaces. The existing serialized partition tuple bytes are 
unchanged.
+
+```text
+magic : 4 bytes                         // ASCII PMSC
+formatVersion : varint                 // 1
+avroHeaderLength : varint
+avroHeader : bytes                      // original schema, codec and sync 
marker
+partitionCount : varint
+partitionDictionary[]
+  partitionByteLength : varint
+  partitionBytes : bytes                // existing manifest BinaryRow 
serialization
+blockCount : varint
+blocks[]                               // original physical order
+  offset : varint
+  length : varint                       // complete encoded block, including 
sync marker
+  recordCount : varint
+  partitionEncoding : byte
+  if partitionEncoding != 0:
+    partitionPayloadLength : varint
+    partitionPayload : bytes
+  rowIdEncoding : byte
+  if rowIdEncoding != 0:
+    rowIdPayloadLength : varint
+    rowIdPayload : bytes
+  bucketEncoding : byte
+  if bucketEncoding != 0:
+    bucketPayloadLength : varint
+    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` | `intsDeltaPayload` of sorted unique dictionary IDs. |
+| Row ID | `1` | Minimum, maximum, and `intsDeltaPayload` of sorted interior 
interval endpoints. |
+| Bucket | `1` | Two paired `intsDeltaPayload` sequences: sorted bucket IDs 
and their recorded total bucket counts. |
+| 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.
+Partition IDs and bucket pairs have positive counts no greater than the 
block's record count.
+Row-ID coverage contains one or more intervals; its interior endpoint count 
can be zero for
+a single interval. Encoding 0 represents unavailable coverage, not an empty 
known set.
+
+#### Integer Delta Payload
+
+Partition, row-ID and both bucket sequences share this structure:
+
+```text
+intsDeltaPayload
+  count : varint
+  deltas[count] : varint
+```
+
+The count is in `[0, Integer.MAX_VALUE]`. Nonnegative deltas use 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 without padding.
+
+A nondecreasing 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 the count and then each delta 
immediately,
+and reads values on demand using `VarLengthIntUtils`. A reader consumes 
exactly the declared
+number of values, leaving any following sequence available in the buffer. 
Callers check
+their enclosing payload boundaries. Counts, overflow and value bounds are 
checked without
+materializing arrays. Reads may stop early.
+
+Only the `totalBuckets` sequence uses signed differences, because totals need 
not increase
+when pairs are sorted by bucket. Its differences use ZigZag before unsigned 
varint encoding:
+`encoded = (delta << 1) ^ (delta >> 63)` and
+`delta = (encoded >>> 1) ^ -(encoded & 1)`. Values are nonnegative ints, so 
encoded deltas
+are at most `2 * Integer.MAX_VALUE` and require at most five bytes. The field 
defines this
+signed mode; no additional mode byte is stored. Other sequences use 
nonnegative differences.
+
+#### Partition Payload
+
+When `partitionEncoding == 1`, the block stores IDs of all distinct partition 
tuples
+represented by its entries:
+
+```text
+partitionPayload
+  intsDeltaPayload                    // N > 0 dictionary IDs, base = 0

Review Comment:
   longsDeltaPayload



-- 
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]

Reply via email to