Storage

Storage Acceleration

The acceleration registry — ordinary heap tables with rebuildable columnar files beside them.

Acceleration in RVBBIT is a registry, not a table type. Every accelerated table is an ordinary Postgres heap table; adding it to the acceleration registry tells RVBBIT to maintain additional representations of its data beside the heap, so analytical queries can take faster paths while ordinary Postgres remains correct and available.

The contract is simple:

  • heap is the source of truth,
  • accelerator files are rebuildable,
  • missing or stale files do not make normal SQL incorrect,
  • the router chooses a faster path only when it can preserve SQL semantics.

Add A Table To The Registry#

rvbbit.enable_table registers an existing heap table for acceleration and installs the dirty-tracking triggers. A refresh then builds the first files:

SELECT rvbbit.enable_table('events'::regclass);
SELECT rvbbit.refresh_acceleration('events'::regclass);
rvbbit.enable_table(
    reloid          regclass,
    convert_to_heap boolean DEFAULT true   -- normalize an AM-bound table back to heap
) RETURNS jsonb

The registry itself is the rvbbit.tables catalog table (one row per registered table, with an acceleration_enabled flag). Membership checks and listing:

SELECT rvbbit.is_rvbbit_table('events'::regclass);

SELECT * FROM rvbbit.list_tables();
-- table_oid | table_name | n_row_groups | n_deletes

USING rvbbit Sugar#

CREATE TABLE ... USING rvbbit still works, and it is deliberately just sugar: a DDL event trigger registers the new table in the acceleration registry and immediately normalizes it to a plain heap table. The rvbbit access method is a compatibility alias for heap — the registry row is the acceleration contract, not the access method.

CREATE TABLE events (
  id         bigint,
  account_id bigint,
  created_at timestamptz,
  payload    jsonb
) USING rvbbit;   -- heap table + registry row, in one statement

This matters operationally: because accelerated tables are real heap tables, pg_dump, restore, logical replication, and DROP EXTENSION all behave the way they would on any Postgres database.

Remove A Table#

rvbbit.disable_table unregisters a table: it disables acceleration, drops the dirty-tracking triggers, and leaves the heap untouched (rvbbit.detach_table is a compatibility alias for the same thing):

SELECT rvbbit.disable_table('events'::regclass);

What It Builds#

Structure Purpose
Canonical Parquet General columnar scan layer.
Vortex layout Newer columnar format that can be served through DuckDB.
Hive layouts Partitioned/segmented variants for pruning-friendly workloads.
Lance datasets Vector/text acceleration where Lance is a better fit.
Hot memory cache Decoded Arrow batches for small hot tables.
Metadata tables Watermarks, row groups, stats, generations, operations, phases.

Most Postgres column types map straight to Arrow (numbers, text, timestamps, date, jsonb, bytea, real[] vectors). Types without a native Arrow form — uuid, numeric, inet/cidr/macaddr, time/interval, and enums — are stored as canonical text and reconstructed to the real type on read, so a uuid column (Salesforce keys, say) stays a uuid to SQL with comparisons, joins, and ORDER BY intact. Genuinely unsupported types (ranges, composites, geometry) simply keep the table on the heap path.

Refresh, Rebuild, Compact#

Use these words precisely:

Term Meaning
Refresh Incrementally write accelerator files for rows after the watermark.
Rebuild Recreate accelerator state from heap.
Compact Rewrite/coalesce accelerator files and tombstones. This is maintenance, not the normal write path.

API:

-- Refresh: incrementally write accelerator files after the watermark.
-- Layout variants are (re)built by default; pass refresh_variants => false to skip them.
SELECT rvbbit.refresh_acceleration('events'::regclass);

-- Rebuild: recreate accelerator state from heap (full heap re-scan).
SELECT rvbbit.rebuild_acceleration('events'::regclass);

-- Compact: rewrite/coalesce accelerator files and tombstones.
SELECT rvbbit.compact('events'::regclass);

To automate when these run — as a value-vs-cost policy with per-table SLOs, budgets, and the accel_tick heartbeat — see Accelerator Freshness.

Observability#

Acceleration operations are visible from SQL:

SELECT *
FROM rvbbit.acceleration_status
ORDER BY table_name;

Inspect recent work:

SELECT *
FROM rvbbit.acceleration_operations
ORDER BY started_at DESC
LIMIT 20;

Phase-level timings:

SELECT *
FROM rvbbit.acceleration_operation_phases
ORDER BY started_at DESC
LIMIT 50;

For a per-table freshness/demand summary (drift, dirty time, slow-path scans), read rvbbit.accel_freshness — see Accelerator Freshness. For runtime health of the execution engines themselves (Duck, DataFusion, GPU GQE), call rvbbit.accelerator_runtime_status(false) or the broader rvbbit.doctor(false).

Layouts#

A table can have more than one physical layout. The router prefers the layout that matches the query shape, available files, and correctness state.

SELECT *
FROM rvbbit.layout_variant_status
WHERE table_oid = 'events'::regclass;

Vortex plus Duck has been the strongest large-table path in benchmark runs, but DataFusion/native paths still win edge cases, and on GPU hosts the NVIDIA GQE route competes for large scans. The registry exposes those paths as first-class candidates so the router can pick the best engine per query.

Heap Fallback#

Acceleration never requires truncating the heap. Keeping heap as gold source matters for:

  • ordinary Postgres reads and writes,
  • pg_dump and pg_restore,
  • extension upgrades,
  • rebuild after file loss,
  • correctness fallback when an accelerator layer is stale or unsupported.

This means refresh latency is operationally important, but not correctness critical. Reporting tables can refresh in the background, and transactional tables can fall back to heap until the accelerator catches up.

Knobs#

Common knobs:

Knob Purpose
rvbbit.compact_vortex_layout Build Vortex files.
rvbbit.compact_hive_layout Build Hive-style segmented layouts.
rvbbit.hot_store_budget_mb Per-backend memory budget for hot decoded batches.
rvbbit.hot_store_route_max_rows Maximum rows for automatic hot-memory routing.

Layout variants are (re)built after a canonical refresh by default (refresh_variants defaults to true on both rvbbit.refresh_acceleration and rvbbit.rebuild_acceleration); pass refresh_variants => false to skip them. You can also (re)build them on their own with rvbbit.refresh_layout_variants('events'::regclass).

Keep variant builds bounded. Hive can be useful, but poor key choices can increase file count and load time without helping query plans.