> ## Documentation Index
> Fetch the complete documentation index at: https://docs.startree.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Iceberg Deletion Vectors

> Apply Iceberg v3 Puffin deletion vectors at query time so External Tables reflect source-side row-level deletes and updates, not just appends.

<Warning>
  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.
</Warning>

Iceberg tables record row-level deletes and updates as **deletion vectors** (Puffin-format delete files) rather than rewriting data files in place. Historically, External Tables on Pinot only handled append-only Iceberg sources — row-level deletes and updates from the source were not reflected in query results. This release adds native support for reading and applying Iceberg v3 Puffin deletion vectors at query time, so External Tables stay correct as source data is updated or deleted.

## 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** — queries pin an explicit snapshot per table so all servers involved in a query agree on which snapshot (and therefore which deletes) to use. An invalid or not-yet-ready pinned snapshot fails the query rather than silently mixing snapshot state.

## Enabling deletion vectors

Set on the table's `ExternalTableSyncTask` config:

| Key                     | Default   | Description                                            |
| :---------------------- | :-------- | :----------------------------------------------------- |
| `enableDeletionVectors` | `false`   | Enable Iceberg deletion vector support for this table. |
| `deletionVectorSource`  | `iceberg` | Source format for deletion vectors.                    |

### Controller: snapshot readiness

| Key                                                     | Default  | Description                                                                   |
| :------------------------------------------------------ | :------- | :---------------------------------------------------------------------------- |
| `iceberg.snapshotProcessing.readiness.maxWaitMs`        | `600000` | Max time the controller waits for all servers to confirm a snapshot is ready. |
| `iceberg.snapshotProcessing.readiness.pollIntervalMs`   | `5000`   | Interval between readiness polls.                                             |
| `iceberg.snapshotProcessing.readiness.requestTimeoutMs` | `10000`  | Per-request timeout for a readiness poll call.                                |

The controller also exposes a readiness endpoint:

```
POST /tables/{tableNameWithType}/iceberg/isSnapshotReady?snapshotVersion=<snapshotId>
```

Returns `{"ready": true|false}`. Returns `412` if the table has not initialized a deletion-vector manager (i.e. `enableDeletionVectors=false`).

### Broker: pruning and pinning

| Key                                             | Default                            | Description                                                             |
| :---------------------------------------------- | :--------------------------------- | :---------------------------------------------------------------------- |
| `pinot.broker.iceberg.dv.data.dir`              | `/home/pinot/data/external-table/` | Local directory the broker uses for deletion-vector working data.       |
| `pinot.broker.iceberg.dv.warmup.parallelism`    | *(cores / 2)*                      | Parallelism for warming deletion-vector state at broker startup.        |
| `pinot.broker.iceberg.dv.warmup.tableTimeoutMs` | `30000`                            | Per-table timeout during warmup.                                        |
| `pinot.broker.iceberg.dv.warmup.totalTimeoutMs` | `300000`                           | Total warmup timeout across all tables.                                 |
| `pinot.broker.iceberg.dv.cacheRetryIntervalMs`  | `30000`                            | Retry interval when broker-side deletion-vector cache population fails. |

Broker-side deletion-vector pruning only activates for **OFFLINE** tables with `enableDeletionVectors=true` — it is a zero-cost no-op otherwise.

## Query-time snapshot pinning

Deletion-vector-enabled tables **require** an explicit pinned snapshot per query, set with the `snapshotVersionByTable` query option (this replaces the older single-table `snapshotVersion` option):

```sql theme={null}
SET snapshotVersionByTable = '{"nyc_taxi_trips_OFFLINE": 1234567890123456789}';
SELECT count(*) FROM nyc_taxi_trips;
```

If the pinned snapshot is invalid or not yet confirmed ready on all relevant servers, the query fails with a `QUERY_EXECUTION` error rather than returning results computed from a mix of snapshot states.

## Storage format

The deletion-vector index itself is stored as a sorted, dictionary-encoded, bloom-filtered **Parquet** file (`dv-index.parquet`) rather than JSON — cutting heap usage for large delete sets by roughly an order of magnitude compared to the original JSON-based format. There is no backward-compatibility bridge from the old JSON format; this applies to newly-synced deletion vector state.

## Observability

| Component  | Metric                                                                                                                                                                                                                                                                                                      | Meaning                                                                                                          |
| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- |
| Controller | `IS_EV_CONVERGENCE` (timer)                                                                                                                                                                                                                                                                                 | Time for all servers to converge on a snapshot's deletion-vector state.                                          |
| Controller | `SNAPSHOT_READINESS_POLL_TIME_MS` (timer)                                                                                                                                                                                                                                                                   | Time spent polling servers for readiness.                                                                        |
| Controller | `READINESS_POLL_SUCCESS` / `READINESS_POLL_ATTEMPTS` / `READINESS_POLL_FAST_FAIL` / `READINESS_POLL_TIMEOUT` / `READINESS_POLL_SKIPPED` (meters)                                                                                                                                                            | Outcome counters for the readiness poll loop. `READINESS_POLL_SKIPPED` fires when `enableDeletionVectors=false`. |
| Server     | `DELETION_VECTORS_LOADED` / `DELETION_VECTOR_DELETED_ROWS` / `DELETION_VECTOR_LOAD_FAILURES` / `DELETION_VECTOR_INDEX_FAST_FAIL` (meters)                                                                                                                                                                   | Deletion-vector load and application activity per server.                                                        |
| Broker     | `BROKER_ICEBERG_DV_ACTIVE_SNAPSHOTS_COUNT` (gauge), `BROKER_ICEBERG_DV_FILTERED_SEGMENTS_PER_QUERY`, `BROKER_ICEBERG_DV_PARQUET_DOWNLOAD_FAILURE`, `BROKER_ICEBERG_DV_PRUNE_FAILURE`, `BROKER_ICEBERG_DV_PIN_INVALID_SNAPSHOT`, `BROKER_ICEBERG_DV_WARMUP_FAILURES`, `BROKER_ICEBERG_DV_WARMUP_DURATION_MS` | Broker-side pruning and warmup health.                                                                           |

The run-status endpoint's `failurePhase` field (see [Observability](./observability#run-status)) 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?

Yes — it's required for deletion-vector-enabled tables. Without it, or with an invalid/not-yet-ready snapshot, the query fails rather than returning potentially inconsistent results.

### What happens to existing (JSON-format) deletion-vector state after upgrading?

There is no automatic migration from the JSON format. This feature targets newly-synced deletion vector state — check with StarTree support before relying on it against a table with pre-existing deletion-vector data.

### 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.
