Skip to content

[Draft] chore(api-db): squash the world, and introduce a tool + process for doing so#906

Closed
chet wants to merge 1 commit into
NVIDIA:mainfrom
chet:squash-the-world
Closed

[Draft] chore(api-db): squash the world, and introduce a tool + process for doing so#906
chet wants to merge 1 commit into
NVIDIA:mainfrom
chet:squash-the-world

Conversation

@chet

@chet chet commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Description

Our 300+ migrations have gotten a little crazy, and I've been wanting to squash it down somehow, because with the uptick in repo activity, this is just going to keep getting crazier. This introduces a process for doing so!

The idea is we now have a LAST_SQUASH_VERSION constant that we track, and any time we want to squash, we:

  • Run our squash-migrations tool, which dumps the current schema and transforms in into a migration-friendly schema.
  • Bump LAST_SQUASH_VERSION to the timestamp in the migration.
  • Delete the old migrations.

When the carbide-api-migrate job runs, it will clean out the _sqlx_migrations table up until LAST_SQUASH_VERSION, and then apply the squash migration, which should be a noop, ensuring all existing tests continue to pass.

I also dropped a README.md into the migrations directory explaining how to use the tool.

This PR has been put together with the tool itself via cargo run -p squash-migrations -- --delete-old.

Sets LAST_SQUASH_VERSION to 20260411215700 and introduces the 20260411215700_squash_snapshot.sql squashed migration.

Also: after merging, I'll block any open PRs with pending migrations to make sure the PR gets rebased + the migration timestamp gets bumped before going in.

Tests included in the tool.

Signed-off-by: Chet Nichols III chetn@nvidia.com

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Related Issues (Optional)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Additional Notes

@chet chet requested a review from a team as a code owner April 11, 2026 22:01
@chet chet assigned kensimon and unassigned kensimon Apr 11, 2026
@chet chet requested a review from kensimon April 11, 2026 22:01
@github-actions

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-04-11 22:03:00 UTC | Commit: e01eff6

@chet chet requested a review from Matthias247 April 11, 2026 22:03
@chet chet force-pushed the squash-the-world branch 3 times, most recently from 21b004a to 11b1bb4 Compare April 11, 2026 22:57
…oing so

Our 300+ migrations have gotten a little crazy, and I've been wanting to squash it down somehow. This introduces a process for doing so!

The idea is we now have a `LAST_SQUASH_VERSION` constant that we track, and any time we want to squash, we:
- Run our `squash-migrations` tool, which dumps the current schema and transforms in into a migration-friendly schema.
- Bump `LAST_SQUASH_VERSION` to the timestamp in the migration.
- Delete the old migrations.

When the `carbide-api-migrate` job runs, it will clean out the `_sqlx_migrations` table up until `LAST_SQUASH_VERSION`, and then apply the squash migration, which should be a noop, ensuring all existing tests continue to pass.

I also dropped a `README.md` into the migrations directory explaining how to use the tool. This PR has been put together with the tool itself, which includes tests.

Signed-off-by: Chet Nichols III <chetn@nvidia.com>
@chet chet force-pushed the squash-the-world branch from 11b1bb4 to 8d9434c Compare April 12, 2026 07:36
}

#[tokio::main]
async fn main() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Have you seen the xtask crate in crates/xtask? I put it there as a home for the Cargo.toml validator we use (e.g. cargo xtask check-workspace-deps [--fix]), and I kinda figured it'd be the home for any random "repo automation" stuff we want that needs to be written in rust. I got the idea from https://github.com/matklad/cargo-xtask (which is just a document describing the pattern, we don't actually need any dependencies to do it.)

This might be a good fit as an xtask subcommand if you're so inclined.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh yeah, that sounds good. I'll do that (whatever this ends up looking like per the feedback below, at least).

-- For zero-DPU hosts the states map will be empty, which matches the
-- code path in the state handler (it immediately skips to HostInit).

UPDATE machines m

@kensimon kensimon Apr 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What happens if we deploy this branch to an environment that hasn't run this migration yet? I don't see anything in the squashed migration file that does any of this update logic...

Ditto 20260403042500_backfill_rack_id_switches_power_shelves.sql, and basically any file that has UPDATE in it.

I wonder if we should do something like this instead:

  1. Move all old migrations to migrations-old
  2. Make the last migration file in migrations-old our "barrier" migration
  3. Put the squashed migration in the new migrations dir
  4. For any site that has already applied the barrier migration, run the new squashed migration, and do all the stuff you're doing in this PR
  5. For any site that has not applied the barrier migration yet (ie. _sqlx_migrations.version is older than the barrier), have an OLD_MIGRATOR that runs the migrations out of migrations-old, run that first, then go to step 4.
  6. We can keep migrations-old around until we're confident everyone has migrated (and it won't be slowing us down for things like unit tests or anything.)

Also, I guess if we're really doing that, we don't actually need to run the squashed migration on any production databases... we can instead run the OLD_MIGRATOR up to the barrier, then skip the big squashed snapshot (maybe inserting a synthetic _sqlx_migrations row), and then we can continue on with the remaining (new) migrations without having to run a (relatively risky) huge squashed migrations row on a mature database.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yupppp -- I like it. Let me put some extra thought into this tonight, but I'll make adjustments to it based on your comments, and then pass it back to you.

@ajf

ajf commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

I linked a bug #1077 that I think we could use this tool to fix that. There's an issue where old migrations worked on an older version of PG, but not on a new version so it's impossible to do a DB migration if an old migration is incompatible with a new DB version.

@github-actions

Copy link
Copy Markdown

This PR has been inactive for 30 days and will be closed soon.
Please push commits or comment to keep it open.

@ajf

ajf commented May 26, 2026

Copy link
Copy Markdown
Collaborator

@chet when you can you pick this back up?

@chet

chet commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

@ajf This week

@chet chet marked this pull request as draft May 29, 2026 02:52
@copy-pr-bot

copy-pr-bot Bot commented May 29, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@chet

chet commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

Marking as Draft. Been poking at it today. Plan on putting it back into normal status tomorrow.

@chet chet changed the title chore(api-db): squash the world, and introduce a tool + process for doing so [Draft] chore(api-db): squash the world, and introduce a tool + process for doing so May 30, 2026
@ajf

ajf commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Chet let's pick this up for 2.1, I think your approach here is correct. But I don't think we can get to it yet.

@ajf ajf closed this Jun 30, 2026
@kensimon kensimon mentioned this pull request Jul 8, 2026
10 tasks
kensimon added a commit that referenced this pull request Jul 9, 2026
This moves to a single snapshotted .sql file of the whole database
schema, and archives old migrations to a pre-squash directory.

Compatibility with existing deployments is maintained by splitting into
three `sqlx::migrate::Migrator` instances:

- One for the pre-squash migrations
- One for the squashed migration
- One for the post-squash migrations

Whether we're an existing deployment or not is determined by the
presence of the `_sqlx_migrations` table.

For existing deployments, they will migrate through the pre-squash
migrations first (skipping any we've already migrated), then migrate
through the new migrations directory, intentionally skipping the single
squash migration via Migrator::skip.

For new deployments, the inverse happens: If we don't see a
_sqlx_migrations table, we run the squash migration first, then all the
other migrations.

If other PR's are open at the time this is under review and are merged,
it will not cause any issues: We run the squash migration from
crates/api-db/migrations first in its own migrator (or skip it if we're
an existing deployment running the legacy migrations), *then* we run
every other migration in that directory. So if another migration is
added, it will still be run at the correct time.

The approach generalizes to multiple squashes: We can do all this again
in the future and it's just another entry to add to `MIGRATION_LAYOUT`.

Also included is a cargo xtask for performing the squashing, using
@chet's PR #906 as a base.

## Related issues
#1077

## Type of Change
- [ ] **Add** - New feature or capability
- [ ] **Change** - Changes in existing functionality
- [ ] **Fix** - Bug fixes
- [ ] **Remove** - Removed features or deprecated functionality
- [X] **Internal** - Internal changes (refactoring, tests, docs, etc.)

## Breaking Changes
- [ ] **This PR contains breaking changes**

## Testing
- [X] Unit tests added/updated
- [ ] Integration tests added/updated
- [X] Manual testing performed
- [ ] No testing required (docs, internal refactor, etc.)

## Additional Notes
Tested locally via devspace, by deploying the main branch via `devspace
deploy -n nico-system`, then checking out this branch, and doing it
again, and ensuring the migration worked and looked as expected. Then
did the same after starting the database from scratch and just deploying
this branch, verifying the migrations table had a single entry.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants