Skip to content

Add CompactFor encoding — claiming EncodingType::CompactFor = 17 (#791)#791

Open
duxiao1212 wants to merge 3 commits into
facebookincubator:mainfrom
duxiao1212:export-D105755627
Open

Add CompactFor encoding — claiming EncodingType::CompactFor = 17 (#791)#791
duxiao1212 wants to merge 3 commits into
facebookincubator:mainfrom
duxiao1212:export-D105755627

Conversation

@duxiao1212

@duxiao1212 duxiao1212 commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary:

Space-efficient FOR encoder specialised for int64/uint64 (slot 17).

Relationship to FixedBitWidth

Same core algorithm (subtract baseline, bitpack residuals via FixedBitArray), but two wire-format improvements:

FixedBitWidth CompactFor Savings
Baseline Fixed sizeof(T) (8B for int64) Varint (1-10B) Up to 7B for int64; diminishes for smaller types (int32: max 3B, int8: ~0)
BitWidth Rounded up to byte boundary (4→8) Exact value (4 stays 4) Depends on data; can halve the bitpacked region

Everything else — FixedBitArray::bulkGet64WithBaseline decode, FixedBitArray::bufferSize sizing, FixedBitArray::set/bulkSet32 encode — is identical shared infrastructure. No code is duplicated; only the 10-line wire-format header differs.

Why int64 only (not all integer types)

The varint baseline savings scale with sizeof(T). For int64 (8B → 1-10B varint) the savings are substantial. For int32 (4B → 1-5B) they are moderate, and Pfor/SimdForBitpack already dominate those types in benchmarks (13/19 trait wins). For int8/int16 (1-2B) there is no savings at all. Extending to smaller types is trivial (remove static_assert, widen factory dispatch) but produces no practical benefit.

Wire format (after the standard 6-byte Encoding prefix):

[varint: baseline]      — min value (1-10 bytes)
[1 byte: bitWidth]      — bits per residual (0-64, exact)
[bitpacked residuals]   — FixedBitArray::bufferSize(N, bitWidth) bytes
                          (omitted when bitWidth == 0)

Encode: When bitWidth <= 32 (common — most int64 ranges fit in 32 bits), uses the template-unrolled FixedBitArray::bulkSet32 fast path. Falls back to per-element set() for wider bit widths.

Decode: FixedBitArray::bulkGet64WithBaseline(row, count, output, baseline) — the same branchless bulk path used by FixedBitWidthEncoding, with a single-load fast path for bitWidth ≤ 56.

readWithVisitor: Implements bulkScan() for the readWithVisitorFast path (unlike Pfor which uses the slow path). O(1) random access — no sequential state.

Auto-selection: Excluded from possibleEncodings() and defaultReadFactors(). Available only via explicit EncodingLayoutTree overrides until production bake-in.

Ported from AUS LONG_LIST_FOR_BITPACKED.

Differential Revision: D105755627

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label May 27, 2026
@meta-codesync

meta-codesync Bot commented May 27, 2026

Copy link
Copy Markdown

@duxiao1212 has exported this pull request. If you are a Meta employee, you can view the originating Diff in D105755627.

duxiao1212 added a commit to duxiao1212/nimble that referenced this pull request May 28, 2026
…ebookincubator#791)

Summary:
Pull Request resolved: facebookincubator#791

Space-efficient FOR encoder specialised for `int64`/`uint64` (slot 17).

**Relationship to `FixedBitWidth`**

Same core algorithm (subtract baseline, bitpack residuals via `FixedBitArray`), but two wire-format improvements:

| | `FixedBitWidth` | `CompactFor` | Savings |
|---|---|---|---|
| **Baseline** | Fixed `sizeof(T)` (8B for int64) | Varint (1-10B) | Up to 7B for int64; diminishes for smaller types (int32: max 3B, int8: ~0) |
| **BitWidth** | Rounded up to byte boundary (4→8) | Exact value (4 stays 4) | Depends on data; can halve the bitpacked region |

Everything else — `FixedBitArray::bulkGet64WithBaseline` decode, `FixedBitArray::bufferSize` sizing, `FixedBitArray::set`/`bulkSet32` encode — is identical shared infrastructure. No code is duplicated; only the 10-line wire-format header differs.

**Why int64 only (not all integer types)**

The varint baseline savings scale with `sizeof(T)`. For int64 (8B → 1-10B varint) the savings are substantial. For int32 (4B → 1-5B) they are moderate, and Pfor/SimdForBitpack already dominate those types in benchmarks (13/19 trait wins). For int8/int16 (1-2B) there is no savings at all. Extending to smaller types is trivial (remove `static_assert`, widen factory dispatch) but produces no practical benefit.

**Wire format** (after the standard 6-byte Encoding prefix):

```
[varint: baseline]      — min value (1-10 bytes)
[1 byte: bitWidth]      — bits per residual (0-64, exact)
[bitpacked residuals]   — FixedBitArray::bufferSize(N, bitWidth) bytes
                          (omitted when bitWidth == 0)
```

**Encode**: When `bitWidth <= 32` (common — most int64 ranges fit in 32 bits), uses the template-unrolled `FixedBitArray::bulkSet32` fast path. Falls back to per-element `set()` for wider bit widths.

**Decode**: `FixedBitArray::bulkGet64WithBaseline(row, count, output, baseline)` — the same branchless bulk path used by `FixedBitWidthEncoding`, with a single-load fast path for bitWidth ≤ 56.

**readWithVisitor**: Implements `bulkScan()` for the `readWithVisitorFast` path (unlike Pfor which uses the slow path). O(1) random access — no sequential state.

**Auto-selection**: Excluded from `possibleEncodings()` and `defaultReadFactors()`. Available only via explicit `EncodingLayoutTree` overrides until production bake-in.

Ported from AUS `LONG_LIST_FOR_BITPACKED`.

Differential Revision: D105755627
@meta-codesync meta-codesync Bot changed the title Add CompactFor encoding — claiming EncodingType::CompactFor = 17 Add CompactFor encoding — claiming EncodingType::CompactFor = 17 (#791) May 28, 2026
@duxiao1212 duxiao1212 force-pushed the export-D105755627 branch from 859da83 to 6c2ddf0 Compare May 28, 2026 13:42
Xiao Du and others added 3 commits May 28, 2026 06:44
Summary:
PFOR is a sparse-outlier patched Frame-of-Reference encoder ported from MRS's AusList SOTA encoder portfolio (D97646777). Bitpacks the bottom 90th-percentile of residuals at base bitwidth, stores the top 10% as (position, full value) exception patches. Wins on columns with rare large outliers where a pure FOR would inflate bitwidth to cover the worst case.

Wire format: [encType:1B][dataType:1B][rowCount:4B][min:GV32][baseBitWidth:1B][numExceptions:varint][exceptionPositions:varint[]][exceptionValues:varint[]][bitpacked baseResiduals][7B zero-pad tail]

Decode follows the post-D98819389-style optimization: pass 1 bitunpacks all residuals via byte-aligned loadU64; pass 2 patches the exceptions in.

Slot allocation: claiming EncodingType::Pfor = 15. Per WS8 audit (T271476729), slots 12/13/14 are contested by 4+ in-flight diffs (D103045783 ChunkedBitPacking=12, D103975634 FOR=13/SubIntSplit=14, D105064770/D105134978 Fsst=12/14, plus implied ChunkedALP=13). 15 is the next free slot at time of commit. If a contending diff lands first claiming 15, this diff will need rebase to next free.

Initial readFactor: 1.5 (conservative). Prevents auto-selection by ManualEncodingSelectionPolicy until baked in. Mirrors ChunkedBitPacking pattern.

Stale-binary risk: xldb/disco/user_experiments/util/WriteConfigurationUtil.cpp persists EncodingType through Configerator. Older readers will throw NIMBLE_UNREACHABLE on EncodingType::Pfor=15 until they pick up this build — fail-loud, not silent.

Differential Revision: D105270894
Summary: Second-order delta encoder for int64 columns: take double-deltas, zigzag-encode, FOR-baseline-shift, bitpack at minimum bitwidth. Wins on regular-interval timestamp data. Renamed from LongDoubleDeltaBitpack for naming consistency (no type prefix in Nimble convention).

Differential Revision: D105357210
…ebookincubator#791)

Summary:
Pull Request resolved: facebookincubator#791

Space-efficient FOR encoder specialised for `int64`/`uint64` (slot 17).

**Relationship to `FixedBitWidth`**

Same core algorithm (subtract baseline, bitpack residuals via `FixedBitArray`), but two wire-format improvements:

| | `FixedBitWidth` | `CompactFor` | Savings |
|---|---|---|---|
| **Baseline** | Fixed `sizeof(T)` (8B for int64) | Varint (1-10B) | Up to 7B for int64; diminishes for smaller types (int32: max 3B, int8: ~0) |
| **BitWidth** | Rounded up to byte boundary (4→8) | Exact value (4 stays 4) | Depends on data; can halve the bitpacked region |

Everything else — `FixedBitArray::bulkGet64WithBaseline` decode, `FixedBitArray::bufferSize` sizing, `FixedBitArray::set`/`bulkSet32` encode — is identical shared infrastructure. No code is duplicated; only the 10-line wire-format header differs.

**Why int64 only (not all integer types)**

The varint baseline savings scale with `sizeof(T)`. For int64 (8B → 1-10B varint) the savings are substantial. For int32 (4B → 1-5B) they are moderate, and Pfor/SimdForBitpack already dominate those types in benchmarks (13/19 trait wins). For int8/int16 (1-2B) there is no savings at all. Extending to smaller types is trivial (remove `static_assert`, widen factory dispatch) but produces no practical benefit.

**Wire format** (after the standard 6-byte Encoding prefix):

```
[varint: baseline]      — min value (1-10 bytes)
[1 byte: bitWidth]      — bits per residual (0-64, exact)
[bitpacked residuals]   — FixedBitArray::bufferSize(N, bitWidth) bytes
                          (omitted when bitWidth == 0)
```

**Encode**: When `bitWidth <= 32` (common — most int64 ranges fit in 32 bits), uses the template-unrolled `FixedBitArray::bulkSet32` fast path. Falls back to per-element `set()` for wider bit widths.

**Decode**: `FixedBitArray::bulkGet64WithBaseline(row, count, output, baseline)` — the same branchless bulk path used by `FixedBitWidthEncoding`, with a single-load fast path for bitWidth ≤ 56.

**readWithVisitor**: Implements `bulkScan()` for the `readWithVisitorFast` path (unlike Pfor which uses the slow path). O(1) random access — no sequential state.

**Auto-selection**: Excluded from `possibleEncodings()` and `defaultReadFactors()`. Available only via explicit `EncodingLayoutTree` overrides until production bake-in.

Ported from AUS `LONG_LIST_FOR_BITPACKED`.

Differential Revision: D105755627
@duxiao1212 duxiao1212 force-pushed the export-D105755627 branch from 6c2ddf0 to 71fd3f3 Compare May 28, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. fb-exported meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant