Skip to content

Catalog schema

The modak.* tables are the coordination contract between the extension and the workers. They are the only channel, there is no RPC. Every atomic handoff is a plain Postgres transaction. The schema lives in sql/catalog.sql and is created and migrated automatically by the worker at startup (modak.schema_meta stamps the installed version).

All columns stay executor-portable (plain ints, text, jsonb) because pg_duckdb may push read-path queries down to DuckDB.

Data model

Each table models one concern. modak.tables holds registration config and nothing else: everything that changes at runtime lives in its own row keyed by table_id, and all of it cascades on unregister.

erDiagram
    storage_profiles ||--o{ tables : "warehouse binding"
    tables ||--|| cutline : "seam + lake pointer"
    tables ||--o{ partitions : "lifecycle map"
    tables ||--o{ delta : "correction overlay"
    tables ||--o{ read_pins : "active readers"
    tables ||--o{ op_log : "journal"
    tables ||--o{ load_labels : "load ledger"
    tables ||--o| copy_progress : "transient copy state"
    tables ||--o| lake_stats : "monitoring snapshot"
    tables ||--o| maintenance_requests : "pending trigger"

modak.storage_profiles

Named warehouse bindings tables register against (see Storage profiles). The seeded default profile has a blank warehouse and NULL format, both meaning "resolve from the worker's environment". A partial unique index keeps exactly one default.

Column Meaning
profile_name Primary key, referenced by modak.tables.storage_profile
lake_format Lake plugin id. NULL = worker env
warehouse Warehouse root. '' = worker env
lake_config Non-secret key=value config overrides, any provider
credential_ref Names a credential set in the worker's environment (MODAK_CREDENTIALS_<REF>). NULL = worker default
is_default The profile new registrations get without --profile

modak.tables

Registered logical tables. One row per registration, written at register time and only touched again for policy edits. CHECK constraints keep mode-specific columns coherent (mirror plumbing only on mirrored rows, retention and keep-heap only on tiered rows).

Column Meaning
table_id The user table's OID, as bigint
schema_name, table_name The registered relation
primary_key_cols Merge key (array, composite keys supported)
tier_key_col The aging column rows tier by
partition_scheme Lake partition layout, e.g. {"width": 3600}
lake_format Lake plugin id (iceberg)
lake_table_ref The format's name for the cold table (path or catalog identifier)
storage_profile The storage profile the lake lives on
mode tiered or mirrored
publication_name, slot_name Mirrored: CDC plumbing
heap_retention_lag Mirrored: heap retention window. NULL = keep all
lake_retention_lag Tiered: expire lake rows this far behind the cut-line. NULL = keep forever
keep_heap Tiered: never drop heap partitions, a trigger mirrors their DML into the delta
maintenance_policy Per-table maintenance overrides (format-interpreted keys). NULL = all defaults

modak.cutline

The seam, per table, always advanced together in one transaction. The published lake pointer lives here because it must move in the same row-update as S: a reader that sees the cut-line sees the matching physical pointer.

Column Meaning
tier_key_hi T: rows with tier_key >= T live in Postgres
lake_snapshot_id S: pinned cold-store version consistent with T
replicated_lsn F: the mirror frontier (WAL position). NULL for tiered tables
retention_line R: lake rows with tier_key < R are expired. NULL = nothing expired yet
lake_props The published pointer to S, e.g. Iceberg's metadata_location and snapshot_id

Connectors reading the seam should treat retention_line as the floor of the table: rows below it exist in old lake snapshots but not in the current one, and writes targeting them are rejected by the extension.

modak.partitions

Partition lifecycle map: hot → sealing → tiering → tiered → dropped, with tier-key bounds per partition.

modak.delta

The correction overlay for cold rows, merged on read, folded by compaction.

Column Meaning
pk Canonical text PK (composite keys joined with chr(31), escaped)
op 0 = upsert, 1 = tombstone
tier_key Of the target cold row (< T)
old_tier_key Set when the row moved tiers: the partition the lake still holds the image in, where the fold's delete lands
version Newest-wins ordering (sequence-assigned), guards the fold clear
payload Row image. Tombstones keep the pk fields

modak.read_pins

Active read pins. The oldest pin is the reclaim and compaction horizon. Pins are transaction-scoped rows with an expires_at bound.

modak.op_log

Idempotency + crash-resume journal for every lake-writing operation (op_id, op_kind, phase, snapshot, details). Op kinds: tiering, compaction, maintenance, retention, ingest, load.

modak.load_labels

The Stream Load label ledger: a label commits with its batch, replays return the recorded result, staged labels await lake adoption.

modak.maintenance_requests

Pending out-of-schedule maintenance triggers, at most one per table. modak-worker maintain and the console upsert a row (requested_by records who asked), the leader claims it with a DELETE ... RETURNING so exactly one run fires. The result lands in modak.op_log like any scheduled pass.

modak.lake_stats

Lake health, one row per table, refreshed by the worker. stats and warnings are owned by the format plugin (counter names and health judgments differ per format), policy is a snapshot of the maintenance settings the table ran with at collection time.

modak.copy_progress

In-flight mirrored initial copies: the slot's consistent point, the last copied PK, and chunks done. The row exists only while the copy runs, and a re-run of register resumes from it.

modak.status

The operational view, one row per table for humans and dashboards:

SELECT * FROM modak.status;
--  table_id | schema_name | table_name | mode | cutline_t | cutline_s |
--  mirror_frontier | retention_line | cutline_updated_at | delta_backlog |
--  read_pins | copying | partition_states