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 deletion vectors (Puffin-format delete files) rather than rewriting data files in place. External Tables read and apply Iceberg v3 Puffin deletion vectors 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. Server-side loading — each server decodes the Iceberg Puffin deletion files relevant to its segments and applies them when answering a query, so deleted/updated rows are excluded from results.
  2. 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.
  3. 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 iceberg.dv.* keys (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. The number of snapshots kept queryable (and therefore pinnable — see Query-time snapshot pinning) is bounded by snapshot retention, iceberg.snapshotProcessing.retention.maxActiveVersions (default 5).

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: pruning and pinning

Broker-side pruning also requires pinot.broker.data.dir to point at the cluster’s deep-store root (StarTree Cloud sets this); without it the broker cannot read snapshot state and affected queries fail. 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 (retried in the background; see pinot.broker.iceberg.dv.cacheRetryIntervalMs). Only snapshots in the active set can be pinned, and the set’s size is bounded by snapshot retention (iceberg.snapshotProcessing.retention.maxActiveVersions, default 5) — 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, Puffin files fetched in cache mode live under the instance data directory (dv-puffin-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 IS_EV_CONVERGENCE or SNAPSHOT_READINESS_POLL 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 — deletion vectors are an Iceberg-specific capability (deletionVectorSource=iceberg), tied to Iceberg’s Puffin delete-file format.