0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2025-06-11 14:26:50 +00:00
Files
ad hoc 0d5dc18ce1 rename migration tables ()
* rename __libsql_migration_tasks to sqlite3_libsql_tasks

* rename job tables
2024-03-13 11:03:55 +00:00

58 lines
3.2 KiB
Rust

//! This module contains code related to schema migration.
//! When an query that performs writes is sent to a schema database (`shared_schema: true`), then
//! this query is executed exactly one on every database that uses that schema database as a source
//! of truth (`shared_schema_name: '<my_schema_db>`), by way of this schema migration process:
//! - The migration is first performed against the schema db in a dry run (we create a transaction,
//! execute the migration and rollback and roll it back).
//! - If the schema db migration was successfull then we enqueue a `MigrationJob` in the job queue.
//! Also, for every database referring to the schema, we enqueue a `MigrationTask` that refers to
//! the job.
//! - The `Scheduler` is in charge of stepping jobs and tasks to completion.
//! - In the initial state of the migration, all the tasks are in `MigrationTaskStatus::Enqueue` state,
//! and the corresponding job is in `MigrationJobStatus::WaitingForDryRun`.
//! - The scheduler gets a batch of task in the `Enqueued` state from the database, and schedules
//! them on for a dry-run on the its worker pool.
//! - When a task is in `Enqueued` state, it is first enqueued to the database's own queue (a table
//! named `sqlite3_libsql_tasks`), and it is set to `Enqueued`. The scheduler then performs a
//! dry run on the migration on that database, setting the outcome of the dry-run to the databases
//! queue in the same transaction. If the dry-run was successfull, the status is set to
//! `DryRunSuccessfull`, otherwise, it is set to `DryRunFailure`, and the error message is saved.
//! By atomically changing the status of the task as we perform the migration, we ensure that in
//! case of failure, we'll always either safely re-perform the task, or collect the result of a
//! prior execution.
//! - The scheduler attempts to drive all tasks to the state `DryRunSuccessfull` before stepping
//! the job's status. If one tasks fails the dry-run, then the migration is aborted.
//! - If all the tasks sucessfully performed the dry-run, then the job is stepped to
//! `DryRunSuccessfull`, at which point, potential waiter are notified.
//! - The scheduler then steps the job to the `WaitingRun` status, and the task status is updated
//! to `Run`. Each task now perform the migration for real, and report their status, in the same
//! manner as the dry-run, except for the fact that the migration is actually committed.
//! - If all tasks are successfull, then the scheduler performs the migration on the schema, and
//! update the job's state to it's final state, `RunSuccess`.
pub(crate) mod db;
mod error;
mod handle;
mod message;
mod migration;
mod result_builder;
mod scheduler;
mod status;
pub use db::{get_migration_details, get_migrations_summary};
pub use error::Error;
pub use handle::SchedulerHandle;
pub use message::SchedulerMessage;
pub use migration::*;
pub use scheduler::Scheduler;
pub use status::{MigrationDetails, MigrationJobStatus, MigrationSummary, MigrationTaskStatus};
use crate::connection::program::Program;
pub fn validate_migration(migration: &Program) -> Result<(), Error> {
if migration.steps().iter().any(|s| s.query.stmt.kind.is_txn()) {
Err(Error::MigrationContainsTransactionStatements)
} else {
Ok(())
}
}