Skip to main content
This feature requires StarTree release 0.16.0 or later, and must be enabled on demand — contact StarTree support to activate it. It is offered as a preview capability; validate it in a non-production environment before relying on it.
Iceberg tables record row-level deletes and updates as merge-on-read delete files rather than rewriting data files in place — either native v3 Puffin deletion vectors, or standard v2 Parquet equality and position delete files. For both REST and Hive Metastore catalogs, the controller’s snapshot sync materializes applicable deletes into a per-file delete bitmap at sync time, and servers apply that bitmap at query time, so query results stay correct as source data is updated or deleted — the source doesn’t have to be append-only.

How it works

  1. Sync-time materialization (v2 only) — for standard Iceberg v2 equality and Parquet position deletes, the controller’s snapshot sync reads the applicable delete files using Iceberg’s scan-planning rules (partition spec, partition tuple, data sequence number; equality columns resolve by field ID even across renamed/dropped columns) and builds a per-file delete bitmap, written as a Puffin-format blob alongside the snapshot’s dv-index.parquet and cached separately from native source Puffin files. Native v3 Puffin deletion vectors are already in this form and skip materialization.
  2. Server-side loading — each server decodes the resulting deletion-vector index (materialized v2 bitmap or native v3 Puffin) for its segments and applies it when answering a query, so deleted/updated rows are excluded from results.
  3. Atomic snapshot readiness — before a new Iceberg snapshot becomes visible to queries, the controller polls every server until all of them confirm they’ve loaded the deletion vectors for that snapshot. This avoids a window where some servers see the new snapshot’s deletes and others don’t.
  4. Broker-side pinning and consistency — the broker pins every query to a single snapshot per table so all servers involved in a query agree on which snapshot (and therefore which deletes) to use. By default it pins the newest active snapshot automatically and injects the snapshotVersionByTable option for the servers; a query can also pin an explicit snapshot (see Query-time snapshot pinning). An invalid explicitly-pinned snapshot fails the query rather than silently mixing snapshot state.

Enabling deletion vectors

Set on the table’s ExternalTableSyncTask config: Changes to enableDeletionVectors and deletionVectorSource (and to the table’s catalog or storage credentials) take effect on the servers without a restart — the deletion-vector readers are rebuilt when the table config changes.
Upgrade every controller and server first. enableDeletionVectors=true is only safe once every controller and server in the cluster runs a build that supports derived row-delete blobs. Creating or enabling it earlier can publish artifacts older servers can’t read. An existing v3 Puffin table can keep running through a rolling upgrade; don’t introduce v2 equality or position delete files to it, and don’t flip the flag on an existing table, until the upgrade completes. After enabling the flag on an existing table, sync a fresh Iceberg snapshot before relying on row-delete results — previously published snapshot artifacts are immutable and aren’t reprocessed under the same snapshot ID.
Incompatible with the Star-tree index. Table-config validation rejects a Star-tree index (explicit starTreeIndexConfigs or enableDefaultStarTree) on a table with enableDeletionVectors=true, and the reverse — enabling deletion vectors on a table that already has a Star-tree index configured. Deletion vectors filter rows per query, and Star-tree’s precomputed aggregates can’t be reconciled against that. Remove the Star-tree index configuration or disable deletion vectors. See Supported Indexes.
How Puffin delete files are read is no longer a table setting. The per-table iceberg.dv.fetch.mode, iceberg.dv.puffinCache.maxBytes, and iceberg.dv.puffinCache.downloadTimeoutMs keys are retired (0.16.x). Puffin files are now cached by the server’s persistent disk cache, which StarTree manages; if an old table config still carries these keys, they are ignored.
The number of snapshots kept queryable (and therefore pinnable — see Query-time snapshot pinning) is bounded by snapshot retention, iceberg.snapshotProcessing.retention.maxActiveVersions (default 2).

Controller: snapshot readiness

Each server exposes a readiness endpoint, which the controller polls:
Returns {"ready": true|false} plus additive load-progress fields the controller’s poller uses for stall detection — loaded, total, inFlight, consecutiveLoadFailures, and lastLoadError (present only when set). Older pollers ignore the extra fields; a server that omits them (older build) is treated as deadline-only, never assumed to be stalled. The check is non-blocking: it answers from the server’s in-memory state and, if the deletion vectors aren’t loaded yet, kicks off a background load and returns ready: false — so the first poll for a new snapshot normally reports not-ready. Returns 412 when the table is not configured for deletion vectors (enableDeletionVectors=false) or the deletion-vector index for the requested snapshot is missing or unreadable.

Controller: IS/EV convergence

Before polling for snapshot readiness, the controller waits for every affected segment’s Helix ideal-state and external-view to converge: Broker-side snapshot pruning activates for OFFLINE External Tables when any of these is true on the table: enableDeletionVectors=true, enableSnapshotConsistency=true (a flag the onboarding/sync flow sets automatically for snapshotting catalogs — pins queries to the last completed snapshot so they never see a half-ingested one), or segment groups enabled. It is a zero-cost no-op otherwise.

Query-time snapshot pinning

You do not need to pin a snapshot yourself: for a pruning-enabled table the broker automatically resolves each query to the newest active snapshot and injects the server-required snapshotVersionByTable option. Set the option explicitly only to pin a query to a specific snapshot (time travel / reproducing an earlier state):
If an explicitly pinned snapshot is not in the table’s active set (expired, never existed, or not yet confirmed ready on all servers), the query fails with a QUERY_EXECUTION error rather than returning results computed from a mix of snapshot states. A query also fails when the table has no active snapshots at all yet (nothing fully synced), or when the broker hasn’t finished loading the pinned snapshot’s segment state locally (the broker retries in the background). Only snapshots in the active set can be pinned, and the set’s size is bounded by snapshot retention (iceberg.snapshotProcessing.retention.maxActiveVersions, default 2) — so time travel reaches back at most that many snapshots.

Storage format

The deletion-vector index itself is stored as a dictionary-encoded Parquet file (dv-index.parquet), with rows sorted by segment name within each row group and per-row-group bloom filters, which keeps heap usage low even for large delete sets and supports lazy point lookups. On the servers, cached Puffin files live in the persistent disk cache; the cache survives restarts and is cleaned up when the table is deleted.

Observability

The run-status endpoint’s failurePhase field (see Observability) can also report WAITING_FOR_SEGMENTS_ONLINE or WAITING_FOR_SERVERS_READY when a sync run fails during deletion-vector convergence.

FAQs

Do I need to set snapshotVersionByTable on every query once deletion vectors are enabled?

No — the broker pins each query to the newest active snapshot automatically and injects the option for the servers. Set it explicitly only for time travel to a specific snapshot; an explicit pin that isn’t in the active set fails the query rather than returning potentially inconsistent results.

Does this work for raw S3 Parquet (non-Iceberg) External Tables?

No — this is an Iceberg-specific capability (deletionVectorSource=iceberg), covering both native v3 Puffin deletion vectors and standard v2 equality/position delete files; raw Parquet listings have no Iceberg delete-file concept to apply.