← All projects

Database changes · Developer tooling

Database migration rehearsal

A database migration from legacy asset tags to unique normalized keys. It preserves old-application access during backfill and resumes after an interrupted batch.

Migration tool with executed crash recovery and a theoretical PostgreSQL rollout

Recorded migration outcomes for valid, duplicate, null and empty input fixtures.
Recorded migration outcomes for valid, duplicate, null and empty input fixtures.

Implementation

The recipe expands a populated SQLite schema and uses compatibility triggers to maintain the new key when the old application writes. New reads fall back to normalized legacy tags during the overlap.

Backfill commits in batches, with progress and data in the same transaction. After an injected interruption, a new database connection resumes from rows still missing a key.

Cutover requires a completed backfill and explicit retirement of the old contract. Contraction replaces the legacy column with required, nonempty, unique keys and checks that IDs and descriptions remain unchanged.

The operational rehearsal adds real process termination during backfill and contraction, controlled overlap writes, an archived-tag forward recovery, size/batch sweeps, and a separate theoretical PostgreSQL lock/index run.

Inputs and assumptions

  • The reference case has 5,000 generated ASCII asset tags and 250-row batches. It interrupts after three committed batches.
  • This recipe uses SQLite and a single asset table without dependent tables. The old-application contract is represented by explicit fixture metadata.
  • Legacy tags are trimmed and converted to lowercase. Duplicate, null, and empty normalized keys are rejected.

Results

Recorded results for the included reference case
Automated checks passed14 / 14
Reference rows after contraction5000
Rows committed before interruption750
Rows completed after restart4250
ID and description contentPreserved
Invalid fixture types rejectedDuplicate, null, and empty keys
Operational and theoretical acceptance checks10 / 10
Report figures (1)
The reference migration resumed after 750 committed rows, completed the remaining 4,250, and preserved the IDs and descriptions.
The reference migration resumed after 750 committed rows, completed the remaining 4,250, and preserved the IDs and descriptions.

Open the full report ↗

Verification

14 regression tests and four fixture outcomes passed, plus 10 operational acceptance checks covering process kills, overlap traffic, forward recovery, 100,000-row fixtures, held locks and theoretical PostgreSQL lock/index recovery.

python verify.py
Download the verification record ↓

Additional scenarios

10 outcomes checked through executed synthetic operations. The report lists the expected and observed outcomes for each check.

Read the validation report ↗

Project files

The ZIP contains the source, inputs, results, and instructions. These files are also available individually.

Download project ZIP · 84 KB
Archive checksum

SHA-256

bf3d6d13afc498fb3d5f09b6b45a6351a515623bf4e831f85dc498e0186b3891
Original project scopeArchived brief PDF ↗

Run locally

Python 3.10 or newer with SQLite / Python standard library / Linux for the subprocess SIGKILL operational drills

Extract the ZIP and open a terminal in the migration-rehearsal folder. The README includes setup and usage details.

python rehearse.py --rows 5000 --batch-size 250 --interrupt-after 3 --out results/manual
python verify.py
python operations.py

Limits

  • SQLite crash, traffic and size cases are executed. PostgreSQL table-lock and concurrent-index decisions are modeled from documented semantics, not observed server behavior.
  • The synthetic recipe has one asset table. Timings and controlled writer behavior do not establish production concurrency or downtime guarantees.
  • SIGKILL checks process recovery with normal host storage; power loss and faulty storage hardware are outside that evidence.
  • Contraction removes original tag formatting. The executed forward recovery requires the retained tag archive and preserves newer content; it is not an automatic application downgrade.