Skip to content

Integrate tiered storage - #6305

Draft
kim wants to merge 47 commits into
masterfrom
kim/tiered-storage-integration
Draft

kim wants to merge 47 commits into
masterfrom
kim/tiered-storage-integration

Conversation

@kim

@kim kim commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Description of Changes

Integrates tiered storage into the rest of the codebase.

This is a big change, because every call site that may access a page or blob
becomes fallible due to the possibility of fault errors.

Much of this is mechanical, but note that transaction commit becomes a two-step
process with this patch: first, all pages and blobs affected by the transaction
are faulted in if necessary, and pinned so they can't be evicted until the
transaction completes. Then, the transaction is actually applied -- this remains
infallible and therefore atomic.

API and ABI breaking changes

Internal only.

Rollback safety impact

Currently rollback safe.

Expected complexity level and risk

5

Testing

@kim
kim added this pull request to stack #6306 October 15, 2026 14:44
joshua-spacetime added a commit that referenced this pull request Oct 16, 2026
Remove nine newly added Deep storage tests (429 lines) at the user's request to reduce the review diff. This removes new coverage for resident/tiered storage, prepared inserts, page reuse, and blob pins. Existing tests from #6305 and all production code remain unchanged.

Validation: 112 existing spacetimedb-table library tests pass; clippy for the library and tests passes with -D warnings.
joshua-spacetime added a commit that referenced this pull request Oct 16, 2026
Remove the local macOS benchmarking accommodations from the review diff. Restore the original unconditional Table=328 assertion and keep TxState=144, which accounts for the inline transaction blob map. Non-macOS compiled code is unchanged.

Native macOS builds again fail the original size checks, as on #6305; a compatibility patch is saved outside the branch for future local profiling.

Validation: rustfmt and git diff --check; exact diff is six deleted lines. Native clippy confirms the expected Table size assertion failure (328 versus 336). Linux checks were not rerun locally.
@kim
kim force-pushed the kim/tiered-storage-integration branch from 7625b27 to b840802 Compare October 19, 2026 06:31
Comment thread crates/table/src/bflatn_to.rs Resolved
Comment thread crates/table/src/table.rs Resolved
Comment thread crates/table/src/table.rs Resolved
Comment thread crates/table/src/table.rs Resolved

@joshua-spacetime joshua-spacetime left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More rollback safety concerns. It would be good to add some rollback tests if they're indeed legitimate.

@kim
kim force-pushed the kim/tiered-storage-integration branch from 8c3a919 to 4a229fb Compare October 22, 2026 16:10
@kim
kim removed this pull request from stack #6306 October 22, 2026 16:12
@kim
kim added this pull request to stack #6360 October 22, 2026 16:21
@kim
kim force-pushed the kim/tiered-storage-integration branch 5 times, most recently from f9e3421 to 89a9a07 Compare October 23, 2026 22:51
@kim
kim force-pushed the kim/tiered-storage-integration branch from 89a9a07 to 002db2f Compare October 23, 2026 23:06
joshua-spacetime added a commit that referenced this pull request Oct 29, 2026
Remove nine newly added Deep storage tests (429 lines) at the user's request to reduce the review diff. This removes new coverage for resident/tiered storage, prepared inserts, page reuse, and blob pins. Existing tests from #6305 and all production code remain unchanged.

Validation: 112 existing spacetimedb-table library tests pass; clippy for the library and tests passes with -D warnings.
joshua-spacetime added a commit that referenced this pull request Oct 29, 2026
Remove the local macOS benchmarking accommodations from the review diff. Restore the original unconditional Table=328 assertion and keep TxState=144, which accounts for the inline transaction blob map. Non-macOS compiled code is unchanged.

Native macOS builds again fail the original size checks, as on #6305; a compatibility patch is saved outside the branch for future local profiling.

Validation: rustfmt and git diff --check; exact diff is six deleted lines. Native clippy confirms the expected Table size assertion failure (328 versus 336). Linux checks were not rerun locally.
@joshua-spacetime
joshua-spacetime force-pushed the kim/tiered-storage-integration branch 3 times, most recently from bb400af to 8eb4f30 Compare October 31, 2026 00:14
@kim
kim removed this pull request from stack #6360 November 3, 2026 07:03
@kim
kim changed the base branch from kim/tiered-storage-base to master November 3, 2026 16:33
@kim
kim added this pull request to stack #6533 November 9, 2026 11:43
Integrates tiered storage, replacing `Pages` with `PageSet` and
`BlobStore` with `BlobSet`. Handles fallible object acquisition
everywhere.

Also implements two-phase transaction commit, which preflights the
transaction and pins all affected objects. This allows the actual merge
into the committed state to be infallible and therefore atomic.
kim and others added 23 commits November 11, 2026 09:22
If the pointer map needs to be rebuilt, rebuild it first before
committing the changes.
This prevents unnecessarily faulting in blobs.

With tiered storage, constructing a RowRef requires to load a
BlobReadSet, so calling `scan_rows` with an empty BlobSet is not
equivalent to the previous `NullBlobStore`.
Fallibly collect blob references before mutating anything.
Delete rows by marking all pages as absent.
`MutTxId::delete_by_row_value`, too
To make this possible, introduce a `PinnedRow` that works like an owned
`RowRef`. When a pinned row is in scope, potentially faulting functions
can be unwrapped, as they are guaranteed to not fault the pinned row's
page.
# Description of Changes

Tiered storage makes loading rows fallible. Some cleanup,
result-construction, and duplicate-lookup paths looked up rows again
even though they already held the required page and blob pins.

This PR reuses those existing pins, making the distinction between
acquiring a row and using an already-loaded row clearer:

- **Cleanup:** Expose the existing `Table::delete_unchecked` helper to
the datastore and use it to delete rows whose pins are already held. Its
deletion implementation is unchanged.
- **Update results:** Retain the replacement row’s pins through
confirmation and construct the returned `RowRef` from them, avoiding
another lookup after mutation.
- **Duplicate lookup:** Pass a borrowed `RowRef` constructed from
existing pins into lookup and comparison helpers to avoid redundant row
acquisition.

# API and ABI breaking changes

N/A

# Rollback safety impact

N/A

# Expected complexity level and risk

3

# Testing

Relies on existing coverage
# Description of Changes

Tiered storage makes loading rows fallible. When mutation code already
holds a `PinnedRow`, it can reuse the row’s page and blob pins instead
of performing another storage lookup during cleanup.

This PR uses those existing pins more consistently, keeping cleanup free
of additional storage reads and making unsafe mutation error behavior
easier to reason about:
- Route insert/update comparison failures through existing cleanup,
using the attempted row’s retained pins.
- Restore the old row’s index entries without repeating duplicate-row
comparisons.
- During insertion, load the committed row being returned before
removing its transaction-local deletion marker.

The PR also extends commit preparation to pin pages needed for
pointer-map hash-collision comparisons. This protects committed-state,
since those comparisons must not encounter a storage failure after
committed rows have already been changed.

# API and ABI breaking changes

N/A

# Rollback safety impact

N/A

# Expected complexity level and risk

3

# Testing

Existing coverage
## Description of Changes

Fix two cases where rolling back a transaction could leave committed
tables with different duplicate-detection or uniqueness behavior:

- **Preserve the pointer map when undoing a non-unique index addition.**
Adding that index leaves the existing pointer map untouched, but
rollback previously replaced it with `None`. Subsequent duplicate checks
could panic. Restore the saved map only when undoing a unique index
addition.
- **Preserve indexes that were already unique before adding a
constraint.** Rollback previously made every matching index non-unique,
including indexes enforcing an existing constraint. Convert and record
only previously non-unique indexes, so undo reverses only changes made
by this operation.

Both fixes use the existing undo records.

## API and ABI breaking changes

N/A

## Rollback safety impact

N/A

## Expected complexity level and risk

2

## Testing

- Verify that rolling back unique and non-unique index additions
restores the pointer map and preserves duplicate detection.
- Verify that rolling back an additional unique constraint preserves the
original constraint, its index uniqueness, and rejection of conflicting
inserts.
# Description of Changes

Add `st_table_cache_policy` to persist each table’s caching policy and
enable the local disk paging implemented in #6352. Tables default to
remaining in memory, preserving existing behavior. Changes include:

- Add `st_table_cache_policy` to store each table’s policy. Tables
without an entry default to remaining in memory.
- Apply policies when creating tables and loading a database. System
tables and blobs remain in memory.

# API and ABI breaking changes

N/A

# Rollback safety impact

N/A

# Expected complexity level and risk

3

# Testing

TODO

---------

Signed-off-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Kim Altintop <kim@eagain.io>
Unrelated, but useful for integration.
@joshua-spacetime
joshua-spacetime force-pushed the kim/tiered-storage-integration branch from d6c2152 to 6b008a9 Compare November 11, 2026 17:33
joshua-spacetime and others added 4 commits November 11, 2026 09:37
# Description of Changes

Adds a bunch of metrics related to tiered storage.

# API and ABI breaking changes

N/A

# Rollback safety impact

N/A

# Expected complexity level and risk

2

# Testing

TBD
…om a snapshot (#6543)

This works by first installing all objects as resident, and then
evicting until the low watermark is reached.

Not yet optimal, as we could use hardlinks instead of flushing.

The guarantee that a catalog entry that has a permit was written by the
same storage instance allows to skip redundant writes.

# API and ABI breaking changes

N/A

# Rollback safety impact

N/A

# Expected complexity level and risk

2

# Testing

Existing
@kim
kim force-pushed the kim/tiered-storage-integration branch from 88b9570 to dc54b21 Compare November 12, 2026 12:12
# Description of Changes

Enable `NoRequirement` cache policy migrations. Same as `RequiredOnDisk`
for standalone.

# API and ABI breaking changes

N/A

# Rollback safety impact

N/A

# Expected complexity level and risk

1

# Testing

Existing

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants