> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Table Revisions

Status: In development.

Amp stores each table of a dataset as Parquet files in a directory of its [storage](/running-amp/storage). Each such
directory is a **table revision**: one physical copy of the table's data. A table can have several revisions, from
successive deployments, restores, or imports, but at most one is **active**, the one queries read.

Managing revisions lets you choose which copy a table serves, bring in data written elsewhere, rebuild what Amp knows
about a revision's files, and delete revisions you no longer need. You do it with [`ampctl table`](/clis/ampctl/table)
or the [Admin API](/managing-amp/admin-api/revisions). Most of the time, you don't need to: deploying a dataset creates
and activates its revisions, and [restoring a dataset](/managing-amp/datasets#restore-a-dataset-from-storage) handles
the common recovery cases.

## Prerequisites

* Amp running, with its Admin API reachable, and `ampctl` installed, as in
  [Managing Datasets](/managing-amp/datasets#prerequisites).
* For the examples: the dataset `acme/eth_mainnet@1.0.0`, deployed.

## Revisions

Each revision has:

* **A location ID**, a number that identifies it. Every command here takes one.
* **A path**, relative to the storage root, like `acme/eth_mainnet/blocks/0199f0c4-6f21-7b1e-9a3d-2c4e8b7f1a05`.
  Amp names the revisions it creates `namespace/dataset/table/` followed by a unique, time-ordered ID.
* **Whether it's active.** Queries read a table's active revision, and a table with no active revision can't be queried.
* **Its writer**, when a job writes to it: the ID of that [job](/managing-amp/jobs). While the writer is running,
  the revision can't be deleted, truncated, or pruned.

## List revisions

:::code-group
```bash [ampctl]
ampctl table list --active true
```

```bash [Admin API]
curl 'http://localhost:1610/revisions?active=true'
```
:::

```
Revisions (3):
  3 - acme/eth_mainnet transactions [active]
  2 - acme/eth_mainnet logs [active]
  1 - acme/eth_mainnet blocks [active]
```

`ampctl table ls` is an alias.

| Option                | Type              | Default | Description                                                      |
| --------------------- | ----------------- | ------- | ---------------------------------------------------------------- |
| `--active`, `-a`      | `true` or `false` | both    | Only list active, or inactive, revisions, like `--active false`. |
| `--limit`, `-l`       | integer           | `100`   | The most revisions to list, like `--limit 10`.                   |
| `--last-id <LAST_ID>` | integer           | none    | List the page after this location ID, like `--last-id 42`.       |

The Admin API takes the same as `active`, `limit`, and `last_id`.

## Get a revision

:::code-group
```bash [ampctl]
ampctl table get 1
```

```bash [Admin API]
curl http://localhost:1610/revisions/1
```
:::

```
→ Revision 1
  Path:      acme/eth_mainnet/blocks/0199f0c4-6f21-7b1e-9a3d-2c4e8b7f1a05
  Active:    true
  Writer:    8
  Dataset:   acme/eth_mainnet
  Manifest:  b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b
  Table:     blocks
```

## Register a revision

Registering creates an inactive revision for files at a path you give, relative to the storage root. Use it to bring in
a table's data from elsewhere, like another Amp's storage. Registering the same path again returns the same location
ID.

:::code-group
```bash [ampctl]
ampctl table register acme/eth_mainnet@1.0.0 blocks imported/eth_mainnet/blocks
```

```bash [Admin API]
curl -X POST http://localhost:1610/revisions \
  -H 'Content-Type: application/json' \
  -d '{"dataset": "acme/eth_mainnet@1.0.0", "table_name": "blocks", "path": "imported/eth_mainnet/blocks"}'
```
:::

```
✓ Revision registered for table blocks in dataset acme/eth_mainnet@1.0.0 (location_id: 42)
```

The Admin API returns `{"location_id": 42}`. The new revision knows nothing of its files yet:
[restore](/managing-amp/table-revisions#restore-a-revisions-files) them, then [activate](/managing-amp/table-revisions#activate-a-revision) it. [Restore from another storage
path](/managing-amp/datasets#restore-from-another-storage-path) walks through the whole import.

## Restore a revision's files

Restoring lists the files under the revision's path and records each file's metadata, so queries can read them. Use it
after registering a revision, or when the metadata database lost a revision's files.

:::code-group
```bash [ampctl]
ampctl table restore 42
```

```bash [Admin API]
curl -X POST http://localhost:1610/revisions/42/restore
```
:::

## Activate a revision

Activating a revision makes it the one queries read, and deactivates the table's other revisions, in one step: queries
never see the table with two active revisions, or none.

:::code-group
```bash [ampctl]
ampctl table activate acme/eth_mainnet@1.0.0 blocks 42
```

```bash [Admin API]
curl -X POST http://localhost:1610/revisions/42/activate \
  -H 'Content-Type: application/json' \
  -d '{"dataset": "acme/eth_mainnet@1.0.0", "table_name": "blocks"}'
```
:::

The table must already exist for the dataset, which it does once the dataset has been deployed or restored. Otherwise,
activating fails with `table 'blocks' not registered for dataset 'acme/eth_mainnet@1.0.0'`; use
`ampctl dataset restore acme/eth_mainnet@1.0.0 --table blocks --location-id 42` instead, which creates the table and
activates the revision.

## Deactivate a table

Deactivating marks every revision of a table inactive, so the table can no longer be queried. Its data stays.

:::code-group
```bash [ampctl]
ampctl table deactivate acme/eth_mainnet@1.0.0 blocks
```

```bash [Admin API]
curl -X POST http://localhost:1610/revisions/deactivate \
  -H 'Content-Type: application/json' \
  -d '{"dataset": "acme/eth_mainnet@1.0.0", "table_name": "blocks"}'
```
:::

## See a revision's file sizes

Amp works best with fewer, larger files. A revision's file size histogram shows whether it has many small ones, which
[compaction](/running-amp/storage/compaction) merges:

:::code-group
```bash [ampctl]
ampctl table histogram 42
```

```bash [Admin API]
curl http://localhost:1610/revisions/42/histogram
```
:::

```
→ Histogram for location 42
  Files:     403
  Total:     220.30 MiB
  Min size:  1.50 KiB
  Max size:  50.00 MiB
  Avg size:  559.77 KiB

  RANGE                FILES    TOTAL SIZE
  1 KB - 200 KB        312      15.26 MiB
  200 KB - 400 KB      50       14.31 MiB
  1 MB - 200 MB        41       190.73 MiB
```

The Admin API returns the same numbers in bytes:

```json
{
  "location_id": 42,
  "file_count": 403,
  "total_size": 231000000,
  "min_size": 1536,
  "max_size": 52428800,
  "avg_size": 573200,
  "buckets": [
    { "range": [1024, 204800], "file_count": 312, "total_size": 16000000 },
    { "range": [204800, 409600], "file_count": 50, "total_size": 15000000 },
    { "range": [1048576, 209715200], "file_count": 41, "total_size": 200000000 }
  ]
}
```

* **Buckets** are fixed: up to 1 KB, then steps of 200 KB up to 1 MB, steps of 200 MB up to 1 GB, steps of 1 GB up to
  10 GB, and one bucket for anything larger. Each `range` includes its lower bound and excludes its upper one, in bytes.
  Only buckets with files are listed.
* **Only current files count**: not the files waiting for [garbage collection](/running-amp/storage/garbage-collection),
  nor those already deleted.
* **A revision with no files** returns zeros and no buckets, as does a location ID that doesn't exist. To tell them
  apart, [get the revision](/managing-amp/table-revisions#get-a-revision).

## Prune a revision

A [reorg](/get-started/concepts/reorgs), or a compaction that didn't finish, can leave files in a revision that aren't
on its canonical chain of blocks. Queries ignore them, but they still take space. Pruning schedules them for [garbage
collection](/running-amp/storage/garbage-collection), which deletes them after a delay. The revision and its canonical
files stay.

:::code-group
```bash [ampctl]
ampctl table prune 42 --before-block 21000000
```

```bash [Admin API]
curl -X DELETE 'http://localhost:1610/revisions/42/prune?before_block=24000050'
```
:::

`ampctl` asks first, then reports:

```
⚠ This will schedule non-canonical segment files ending before block 24000050 for garbage collection (files will be eligible for deletion after 3600s). Continue? [y/N] y
✓ Revision 42 pruned (3 non-canonical segment files ending before block 24000050 scheduled for GC, deletion in 3600s)
```

The Admin API returns `{"files_scheduled": 3, "gc_delay_secs": 3600}`.

| Option                          | Type    | Default | Description                                                                                          |
| ------------------------------- | ------- | ------- | ---------------------------------------------------------------------------------------------------- |
| `--before-block <BEFORE_BLOCK>` | integer | none    | Only prune files that end before this block, like `--before-block 24000050`. API: `before_block`.    |
| `--gc-delay <GC_DELAY>`         | integer | `3600`  | How long, in seconds, before the files can be deleted, like `--gc-delay 7200`. API: `gc_delay_secs`. |
| `--force`, `-f`                 | flag    | off     | Don't ask first.                                                                                     |

:::warning
A client following a [streaming query](/querying/streaming-queries) across a reorg may need the files of the fork it was
reading to resume. Keep recent ones with `--before-block` if clients may still be recovering from a reorg.
:::

## Delete a revision

Deleting a revision removes it, and what Amp knows of its files, from the metadata database. The files stay in storage:
to delete them too, [truncate](/managing-amp/table-revisions#truncate-a-revision) it instead.

:::code-group
```bash [ampctl]
ampctl table delete 42
```

```bash [Admin API]
curl -X DELETE http://localhost:1610/revisions/42
```
:::

`ampctl table rm` is an alias. `ampctl` asks first, and `--force` (`-f`) skips the question. The Admin API answers
`204 No Content`.

## Truncate a revision

Truncating deletes a revision's files from storage, then the revision itself. Use it to free the space of a revision
you're done with.

:::code-group
```bash [ampctl]
ampctl table truncate 42
```

```bash [Admin API]
curl -X DELETE 'http://localhost:1610/revisions/42/truncate?concurrency=10'
```
:::

The Admin API returns `{"files_deleted": 1247}`.

| Option                        | Type    | Default | Description                                                                    |
| ----------------------------- | ------- | ------- | ------------------------------------------------------------------------------ |
| `--concurrency <CONCURRENCY>` | integer | `10`    | How many files to delete at once, like `--concurrency 20`. API: `concurrency`. |
| `--force`, `-f`               | flag    | off     | Don't ask first.                                                               |

Truncating isn't a single transaction: if it fails partway, run it again to finish.

## Before you delete, truncate, or prune

| Command    | Removes the revision | Deletes files                 | Revision must be inactive | Writer job must have finished |
| ---------- | -------------------- | ----------------------------- | ------------------------- | ----------------------------- |
| `delete`   | yes                  | no                            | yes                       | yes                           |
| `truncate` | yes                  | all of them                   | yes                       | yes                           |
| `prune`    | no                   | those off the canonical chain | no                        | yes                           |

* **Deactivate the revision first**, by [activating another one](/managing-amp/table-revisions#activate-a-revision) or
  [deactivating the table](/managing-amp/table-revisions#deactivate-a-table). Otherwise: `REVISION_IS_ACTIVE`.
* **Stop its writer first**: the writer job must be `COMPLETED`, `STOPPED`, or `FATAL`, so
  [stop the deployment](/managing-amp/datasets#stop-a-deployment) that writes it and wait until it's stopped. Otherwise:
  `revision with location ID '42' has an active writer job; stop the job before deleting` (`WRITER_JOB_NOT_TERMINAL`).

## Errors

| Error                                                             | Status                     | Cause                                                                                                                                                   |
| ----------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `revision with location ID '42' not found` (`REVISION_NOT_FOUND`) | `404`                      | No revision has that location ID.                                                                                                                       |
| `REVISION_IS_ACTIVE`                                              | `409`                      | The revision is active. Deactivate it first.                                                                                                            |
| `WRITER_JOB_NOT_TERMINAL`                                         | `409`                      | The job writing the revision is still running. Stop it first.                                                                                           |
| `DATASET_NOT_FOUND`                                               | `404`                      | The dataset or revision you named isn't registered.                                                                                                     |
| `TABLE_NOT_IN_MANIFEST`                                           | `404`                      | The dataset has no table of that name.                                                                                                                  |
| `TABLE_NOT_REGISTERED`                                            | `404`                      | The table has never been deployed or restored. See [Activate a revision](/managing-amp/table-revisions#activate-a-revision).                                                         |
| Plain text, with no error code                                    | `400`, `413`, `415`, `422` | Registering, activating, or deactivating with a body Amp can't read. See [Failures that aren't JSON](/managing-amp/admin-api#failures-that-arent-json). |

The [Admin API reference](/managing-amp/admin-api/revisions) lists every error each endpoint returns.
