From e813369ad35709293e35276a042d4663656852af Mon Sep 17 00:00:00 2001 From: Tomasz Szymczyszyn Date: Tue, 13 Oct 2026 20:38:08 +0200 Subject: [PATCH 1/5] libsql-server: make namespace creation all-or-nothing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `NamespaceStore::create` persisted the namespace config before setting the namespace up, and nothing undid it: a dump that failed to import left a "ghost" namespace (config without data) whose name could not be reused and which the next user request lazily turned into an empty database. A request cancelled mid-import ran no cleanup at all, since the error branch of the future is never reached when it is dropped, and the schema configurator had no cleanup even for errors. The metastore write is now the commit point and everything before it is reversible. Contract for callers: 2xx means complete; anything else, including a lost connection, means retry; `already exists` on the retry means the earlier attempt did complete. Reservation (store). `create` and `fork` write-lock the name's cache entry for the duration and keep the config in memory only. `publish` installs the finished namespace; `abort` (awaited on error paths) and `Drop` (the creating future was dropped, i.e. the request was cancelled) undo the attempt — config, then directory, then unpin — and only then release the lock, so waiters observe a namespace that does not exist, never a half-built one, and a retry issued the moment the error arrives neither races the cleanup nor finds leftovers. Replaces fork's ad-hoc guard, which blocked in place (panics on a current-thread runtime) and published before flushing. Marker and tombstones (namespace/incomplete.rs). A new namespace directory carries `.incomplete` (fsynced, so it is durable before anything else in the directory can be) until the config is persisted; the store removes it after publishing. A creation that finds a marked directory for a name the metastore does not know discards it, so a crash mid-import never blocks a retry; a startup sweep does the same and deletes leftover tombstones; the metastore's filesystem recovery skips marked directories. Directories are never deleted in place: `discard_dir` renames them into `/.discarded/` (instant; frees the path; a still-running import executor writes into the tombstone) and deletes in the background. `FreshDir` (primary and schema configurators) creates the marked directory synchronously, guard first, and discards it on drop. Fork marks its temporary directory, and only removes its destination on failure if it carries the marker. Metastore. `discard` (via the change queue, so it is ordered after a config store still queued when the request was cancelled) forgets a namespace unconditionally — `remove`'s linked-DB guards would otherwise leave a ghost when a linked-DB creation's flush fails. `existing_handle` looks a namespace up without registering it; `with()` and the fork source use it, and the lazy init re-checks existence, so a lookup racing the end of a failed creation cannot resurrect the name. `process`'s flush branch no longer holds `configs` across `try_process` (lock-order inversion against `remove`). Cache eviction. The reservation is the entry's write lock, which moka knows nothing about. If the cache evicted that entry during a long operation (capacity pressure): a concurrent lookup lazily opened the directory being written; the eviction listener awaited the lock and moka awaits async listeners inline from whichever cache op runs maintenance, so that op hung for the whole import and, once the write-op channel filled, so did every namespace load; an operation touching the cache while holding its own entry (fork) could deadlock. Now the locked entry is pinned in `in_flight`; `load_namespace` and `destroy` consult it first and wait on it; the listener spawns its shutdown only for pinned entries; `install` publishes into a fresh entry when the locked one was evicted, or hands the namespace to the old entry when the name was destroyed meanwhile (destroy is waiting on it). `shutdown` skips pinned entries; `create`/`fork` re-check `has_shutdown` before the commit. Empty cache entries. A rejected `acquire` (`already exists` for a namespace that is not loaded, e.g. a retry after a restart) left behind the empty entry its `get_with` inserted, and `try_get_with` returned that entry forever instead of loading the namespace. `acquire` removes the entry it created; `load_namespace` treats an empty, unlocked entry as a miss; `checkpoint` no longer inserts one for an unloaded namespace (the pre-existing source). Single-namespace mode: `create(default, Latest)` stays a config upsert; creating the default namespace from a dump while it exists is rejected instead of silently skipping the import. Needs async-lock 3 for `RwLock::write_arc` (already in the lockfile; the bump removes the duplicate 2.x). Dump tests set `tcp_capacity(4096)`: the fsync makes setup's following blocking fs ops slower in real time, turmoil advances simulated time while a host waits on them, and the dump store writes 1-byte chunks past turmoil's default 64-segment socket buffer. Tests. Store unit tests build a real `NamespaceStore` with a channel-fed streaming import: lookup waits across an eviction and sees the data, or "doesn't exist" when the import fails; destroy during creation; retry the instant the error returns; abort mid-import; discard vs remove's guards. Unit tests for the marker protocol, tombstones, sweep and metastore recovery. Integration (turmoil): failed creation leaves no trace (both importers, schema configurator), cancelled creation (cancel fires once the marker exists), concurrent requests wait, crash remnants discarded, unmarked directories untouched, marker on a published namespace ignored (create before any lookup after a restart), single-namespace dump create rejected. Rebased onto the false-404 fix (#56), whose semantics `with` and `load_namespace` keep: `with` checks for shutdown on every attempt, looks the namespace up again (up to three times) when the entry it got was emptied, and answers `NamespaceDoesntExist` only when the metastore has no record (otherwise `NamespaceUnavailable` or `NamespaceStoreShutdown`, both 503); `load_namespace` refuses to open a namespace once the store has shut down. `with` keeps `existing_handle`, so the retry cannot resurrect a destroyed record. An empty entry left in the cache is dropped with `evict_if_still_empty` (from #59): under moka's key lock, only if it is still the cached entry, still empty and unlocked. That replaces the `get`-then-`invalidate` pairs in `load_namespace` and `Reservation::acquire`, which could evict a fresh entry loaded in between. Dropped entries are counted in `libsql_server_namespace_left_empty_entry_dropped`. --- Cargo.lock | 25 +- libsql-server/Cargo.toml | 2 +- libsql-server/src/lib.rs | 7 + libsql-server/src/metrics.rs | 8 + .../src/namespace/configurator/fork.rs | 13 +- .../src/namespace/configurator/helpers.rs | 144 +- .../src/namespace/configurator/mod.rs | 10 + .../src/namespace/configurator/primary.rs | 32 +- .../src/namespace/configurator/schema.rs | 20 +- libsql-server/src/namespace/incomplete.rs | 270 ++++ libsql-server/src/namespace/meta_store.rs | 116 +- libsql-server/src/namespace/mod.rs | 21 + libsql-server/src/namespace/store.rs | 1389 ++++++++++++++--- libsql-server/tests/namespaces/dumps.rs | 157 +- libsql-server/tests/namespaces/lifecycle.rs | 389 +++++ libsql-server/tests/namespaces/mod.rs | 15 +- 16 files changed, 2246 insertions(+), 372 deletions(-) create mode 100644 libsql-server/src/namespace/incomplete.rs create mode 100644 libsql-server/tests/namespaces/lifecycle.rs diff --git a/Cargo.lock b/Cargo.lock index 436299524e..1b951752e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,22 +224,13 @@ dependencies = [ "zstd-safe 7.2.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.3.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] @@ -1920,12 +1911,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.3.1" @@ -1943,7 +1928,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.1", + "event-listener", "pin-project-lite", ] @@ -3010,7 +2995,7 @@ dependencies = [ "aes", "anyhow", "arbitrary", - "async-lock 2.8.0", + "async-lock", "async-recursion", "async-stream", "async-tempfile", @@ -3423,12 +3408,12 @@ version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" dependencies = [ - "async-lock 3.4.0", + "async-lock", "async-trait", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "event-listener 5.3.1", + "event-listener", "futures-util", "once_cell", "parking_lot", diff --git a/libsql-server/Cargo.toml b/libsql-server/Cargo.toml index e9721a32ba..6c11402828 100644 --- a/libsql-server/Cargo.toml +++ b/libsql-server/Cargo.toml @@ -11,7 +11,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0.66" -async-lock = "2.6.0" +async-lock = "3" async-stream = "0.3.5" async-tempfile = "0.4.0" async-trait = "0.1.58" diff --git a/libsql-server/src/lib.rs b/libsql-server/src/lib.rs index 10b46ae2d3..731f89d3b0 100644 --- a/libsql-server/src/lib.rs +++ b/libsql-server/src/lib.rs @@ -638,6 +638,13 @@ where ) .await?; + // Namespace creations the previous process died in the middle of leave marked + // directories (and tombstones of discarded ones) behind; clean them up before serving. + if let Err(e) = namespace::incomplete::sweep(&self.path, namespace_store.meta_store()).await + { + tracing::error!("failed to sweep unfinished namespace directories: {e}"); + } + self.spawn_monitoring_tasks(&mut task_manager, stats_receiver)?; // if namespaces are enabled, then bottomless must have set DB ID diff --git a/libsql-server/src/metrics.rs b/libsql-server/src/metrics.rs index 5f6aee411a..3a4b53235e 100644 --- a/libsql-server/src/metrics.rs +++ b/libsql-server/src/metrics.rs @@ -53,6 +53,14 @@ pub static NAMESPACE_EMPTIED_ENTRY_GAVE_UP: Lazy = Lazy::new(|| { ); register_counter!(NAME) }); +pub static NAMESPACE_LEFT_EMPTY_ENTRY_DROPPED: Lazy = Lazy::new(|| { + const NAME: &str = "libsql_server_namespace_left_empty_entry_dropped"; + describe_counter!( + NAME, + "number of empty namespace cache entries dropped so that the next lookup loads the namespace (left by a rejected creation, a failed reset or fork)" + ); + register_counter!(NAME) +}); pub static NAMESPACE_LOAD_LATENCY: Lazy = Lazy::new(|| { const NAME: &str = "libsql_server_namespace_load_latency"; describe_histogram!(NAME, "latency is us when loading a namespace"); diff --git a/libsql-server/src/namespace/configurator/fork.rs b/libsql-server/src/namespace/configurator/fork.rs index 80de9ab19c..ab82360e25 100644 --- a/libsql-server/src/namespace/configurator/fork.rs +++ b/libsql-server/src/namespace/configurator/fork.rs @@ -130,9 +130,13 @@ impl ForkTask { let dest_namespace = self.to_namespace.clone(); match self.try_fork().await { Err(e) => { - let _ = - tokio::fs::remove_dir_all(base_path.join("dbs").join(dest_namespace.as_str())) - .await; + // Only what this fork put there (the renamed, marked temp dir); a directory that + // was already at the destination is not ours to remove. + if let Err(e) = + crate::namespace::incomplete::discard_if_incomplete(&base_path, &dest_namespace) + { + tracing::error!(namespace = %dest_namespace, "failed to discard fork directory: {e}"); + } Err(e) } Ok(ns) => Ok(ns), @@ -145,6 +149,9 @@ impl ForkTask { let temp_dir = BLOCKING_RT .spawn_blocking(move || tempfile::tempdir_in(base_path)) .await??; + // Marked incomplete until the store has persisted the namespace's config, so that a + // fork that does not complete is discarded like any other unfinished creation. + crate::namespace::incomplete::mark_incomplete(temp_dir.path())?; let db_path = temp_dir.path().join("data"); if let Some(restore) = self.restore_to { diff --git a/libsql-server/src/namespace/configurator/helpers.rs b/libsql-server/src/namespace/configurator/helpers.rs index 023333be30..670f4a727c 100644 --- a/libsql-server/src/namespace/configurator/helpers.rs +++ b/libsql-server/src/namespace/configurator/helpers.rs @@ -19,8 +19,8 @@ use crate::namespace::broadcasters::BroadcasterHandle; use crate::namespace::meta_store::MetaStoreHandle; use crate::namespace::replication_wal::{make_replication_wal_wrapper, ReplicationWalWrapper}; use crate::namespace::{ - NamespaceBottomlessDbId, NamespaceBottomlessDbIdInit, NamespaceName, ResolveNamespacePathFn, - RestoreOption, + incomplete, NamespaceBottomlessDbId, NamespaceBottomlessDbIdInit, NamespaceName, + ResolveNamespacePathFn, RestoreOption, }; use crate::replication::ReplicationLogger; use crate::stats::Stats; @@ -28,6 +28,59 @@ use crate::{StatsSender, BLOCKING_RT, DB_CREATE_TIMEOUT, DEFAULT_AUTO_CHECKPOINT use super::{BaseNamespaceConfig, PrimaryConfig}; +/// The directory of a namespace that does not exist yet, created marked incomplete. +/// +/// If the guard is dropped before [`keep`](Self::keep) — setup failed, or the future creating +/// the namespace was dropped — the directory is discarded (atomically renamed away and deleted +/// in the background, see [`incomplete::discard_dir`]). The marker itself is removed by the +/// namespace store once the config is persisted. +pub(super) struct FreshDir { + base: Arc, + path: Option>, +} + +impl FreshDir { + /// Returns `None` when a namespace directory already exists at `db_path`. + /// + /// Synchronous on purpose: the guard exists before anything is created, and there is no + /// await point between creating the directory and marking it. + pub(super) fn begin(base: &Arc, db_path: &Arc) -> crate::Result> { + if db_path.try_exists()? { + return Ok(None); + } + let guard = Self { + base: base.clone(), + path: Some(db_path.clone()), + }; + incomplete::create_marked_dir(db_path)?; + Ok(Some(guard)) + } + + /// The namespace was set up; the directory stays. + pub(super) fn keep(mut self) { + self.path.take(); + } +} + +impl Drop for FreshDir { + fn drop(&mut self) { + let Some(path) = self.path.take() else { + return; + }; + tracing::info!( + path = %path.display(), + "namespace creation did not complete; discarding its directory" + ); + if let Err(e) = incomplete::discard_dir(&self.base, &path) { + // still marked: discarded by the next creation of the name, or by the startup sweep + tracing::error!( + path = %path.display(), + "failed to discard unfinished namespace directory: {e}" + ); + } + } +} + #[tracing::instrument(skip_all)] pub(super) async fn make_primary_connection_maker( primary_config: &PrimaryConfig, @@ -405,3 +458,90 @@ pub(super) async fn cleanup_primary( Ok(()) } + +#[cfg(test)] +mod test { + use super::*; + use crate::namespace::incomplete::INCOMPLETE_MARKER; + + async fn settle_background_deletes() { + for _ in 0..50 { + tokio::task::yield_now().await; + tokio::time::sleep(Duration::from_millis(2)).await; + } + } + + #[tokio::test] + async fn fresh_dir_is_discarded_unless_kept() { + let tmp = tempfile::tempdir().unwrap(); + let base: Arc = tmp.path().into(); + let path: Arc = tmp.path().join("dbs").join("ns").into(); + + let fresh = FreshDir::begin(&base, &path).unwrap().expect("fresh"); + assert!(path.join(INCOMPLETE_MARKER).exists()); + drop(fresh); + // the path is free synchronously, the tombstone goes away in the background + assert!(!path.exists(), "dropped before keep: discarded"); + settle_background_deletes().await; + assert!(std::fs::read_dir(tmp.path().join(".discarded")) + .unwrap() + .next() + .is_none()); + + let fresh = FreshDir::begin(&base, &path).unwrap().expect("fresh again"); + fresh.keep(); + assert!( + path.join(INCOMPLETE_MARKER).exists(), + "kept: stays, marker included" + ); + + assert!( + FreshDir::begin(&base, &path).unwrap().is_none(), + "an existing directory is not fresh" + ); + } + + #[tokio::test] + async fn fresh_dir_is_discarded_when_its_future_is_dropped() { + let tmp = tempfile::tempdir().unwrap(); + let base: Arc = tmp.path().into(); + let path: Arc = tmp.path().join("dbs").join("ns").into(); + let (ready, is_ready) = tokio::sync::oneshot::channel(); + + let setup = { + let (base, path) = (base.clone(), path.clone()); + async move { + let fresh = FreshDir::begin(&base, &path).unwrap(); + ready.send(()).unwrap(); + std::future::pending::<()>().await; // "the import" + fresh.map(FreshDir::keep); + } + }; + let setup = tokio::spawn(setup); + is_ready.await.unwrap(); + assert!(path.join(INCOMPLETE_MARKER).exists()); + setup.abort(); + let _ = setup.await; + assert!(!path.exists()); + } + + #[tokio::test] + async fn discard_if_incomplete_only_removes_marked_directories() { + let tmp = tempfile::tempdir().unwrap(); + let marked = tmp.path().join("dbs").join("marked"); + let unmarked = tmp.path().join("dbs").join("unmarked"); + for dir in [&marked, &unmarked] { + std::fs::create_dir_all(dir).unwrap(); + std::fs::write(dir.join("data"), b"junk").unwrap(); + } + std::fs::write(marked.join(INCOMPLETE_MARKER), b"").unwrap(); + + let ns = |s: &str| NamespaceName::from_string(s.into()).unwrap(); + assert!(incomplete::discard_if_incomplete(tmp.path(), &ns("marked")).unwrap()); + assert!(!incomplete::discard_if_incomplete(tmp.path(), &ns("unmarked")).unwrap()); + assert!(!incomplete::discard_if_incomplete(tmp.path(), &ns("absent")).unwrap()); + + assert!(!marked.exists()); + assert!(unmarked.join("data").exists()); + } +} diff --git a/libsql-server/src/namespace/configurator/mod.rs b/libsql-server/src/namespace/configurator/mod.rs index 064f9a8f7c..5e5c43cd9f 100644 --- a/libsql-server/src/namespace/configurator/mod.rs +++ b/libsql-server/src/namespace/configurator/mod.rs @@ -131,6 +131,16 @@ pub trait ConfigureNamespace { bottomless_db_id_init: NamespaceBottomlessDbIdInit, ) -> Pin> + Send + 'a>>; + /// Discard whatever a creation of `namespace` that did not complete left on disk, so that + /// the name starts from nothing. Only called for a name that is neither loaded nor known to + /// the metastore; must leave anything that does not carry the + /// [`INCOMPLETE_MARKER`](super::incomplete::INCOMPLETE_MARKER) alone. Synchronous so that + /// it can run while a creating future is being dropped (see `NamespaceStore`). + fn discard_incomplete(&self, namespace: &NamespaceName) -> crate::Result<()> { + let _ = namespace; + Ok(()) + } + fn fork<'a>( &'a self, from_ns: &'a Namespace, diff --git a/libsql-server/src/namespace/configurator/primary.rs b/libsql-server/src/namespace/configurator/primary.rs index f68405fad6..13297d0144 100644 --- a/libsql-server/src/namespace/configurator/primary.rs +++ b/libsql-server/src/namespace/configurator/primary.rs @@ -21,7 +21,7 @@ use crate::namespace::{ use crate::run_periodic_checkpoint; use crate::schema::{has_pending_migration_task, setup_migration_table}; -use super::helpers::cleanup_primary; +use super::helpers::{cleanup_primary, FreshDir}; use super::{BaseNamespaceConfig, ConfigureNamespace, PrimaryConfig}; pub struct PrimaryConfigurator { @@ -129,35 +129,31 @@ impl ConfigureNamespace for PrimaryConfigurator { ) -> Pin> + Send + 'a>> { Box::pin(async move { let db_path: Arc = self.base.base_path.join("dbs").join(name.as_str()).into(); - let fresh_namespace = !db_path.try_exists()?; - // FIXME: make that truly atomic. explore the idea of using temp directories, and it's implications - match self + // A brand-new directory is discarded again if setup fails or this future is dropped. + let fresh = FreshDir::begin(&self.base.base_path, &db_path)?; + let ns = self .try_new_primary( name.clone(), meta_store_handle, restore_option, resolve_attach_path, - db_path.clone(), + db_path, broadcaster, self.base.encryption_config.clone(), ) - .await - { - Ok(this) => Ok(this), - Err(e) if fresh_namespace => { - tracing::error!( - "an error occured while deleting creating namespace, cleaning..." - ); - if let Err(e) = tokio::fs::remove_dir_all(&db_path).await { - tracing::error!("failed to remove dirty namespace directory: {e}") - } - Err(e) - } - Err(e) => Err(e), + .await?; + if let Some(fresh) = fresh { + fresh.keep(); } + Ok(ns) }) } + fn discard_incomplete(&self, namespace: &NamespaceName) -> crate::Result<()> { + crate::namespace::incomplete::discard_if_incomplete(&self.base.base_path, namespace)?; + Ok(()) + } + fn cleanup<'a>( &'a self, namespace: &'a NamespaceName, diff --git a/libsql-server/src/namespace/configurator/schema.rs b/libsql-server/src/namespace/configurator/schema.rs index 275fd71e93..956b0141b1 100644 --- a/libsql-server/src/namespace/configurator/schema.rs +++ b/libsql-server/src/namespace/configurator/schema.rs @@ -13,7 +13,7 @@ use crate::namespace::{ }; use crate::schema::SchedulerHandle; -use super::helpers::{cleanup_primary, make_primary_connection_maker}; +use super::helpers::{cleanup_primary, make_primary_connection_maker, FreshDir}; use super::{BaseNamespaceConfig, ConfigureNamespace, PrimaryConfig}; pub struct SchemaConfigurator { @@ -52,9 +52,10 @@ impl ConfigureNamespace for SchemaConfigurator { ) -> std::pin::Pin> + Send + 'a>> { Box::pin(async move { let mut join_set = JoinSet::new(); - let db_path = self.base.base_path.join("dbs").join(name.as_str()); - - tokio::fs::create_dir_all(&db_path).await?; + let db_path: Arc = + self.base.base_path.join("dbs").join(name.as_str()).into(); + // A brand-new directory is discarded again if setup fails or this future is dropped. + let fresh = FreshDir::begin(&self.base.base_path, &db_path)?; let (connection_maker, wal_manager, stats) = make_primary_connection_maker( &self.primary_config, @@ -72,6 +73,10 @@ impl ConfigureNamespace for SchemaConfigurator { ) .await?; + if let Some(fresh) = fresh { + fresh.keep(); + } + Ok(Namespace { db: Database::Schema(SchemaDatabase::new( self.migration_scheduler.clone(), @@ -89,11 +94,16 @@ impl ConfigureNamespace for SchemaConfigurator { tasks: join_set, stats, db_config_store: db_config.clone(), - path: db_path.into(), + path: db_path, }) }) } + fn discard_incomplete(&self, namespace: &NamespaceName) -> crate::Result<()> { + crate::namespace::incomplete::discard_if_incomplete(&self.base.base_path, namespace)?; + Ok(()) + } + fn cleanup<'a>( &'a self, namespace: &'a NamespaceName, diff --git a/libsql-server/src/namespace/incomplete.rs b/libsql-server/src/namespace/incomplete.rs new file mode 100644 index 0000000000..3c907ec059 --- /dev/null +++ b/libsql-server/src/namespace/incomplete.rs @@ -0,0 +1,270 @@ +//! On-disk protocol for namespaces whose creation has not completed. +//! +//! A namespace directory carries [`INCOMPLETE_MARKER`] from the moment it is created until the +//! namespace's config has been persisted to the metastore. A directory that still carries it +//! belongs to a creation that did not complete — the request failed or was cancelled and the +//! cleanup could not finish, or the process died — and is garbage. +//! +//! Garbage is never deleted in place: [`discard_dir`] atomically renames the directory into +//! `/.discarded/` first, so that its path under `dbs/` is free immediately and nothing that +//! still has files open in it (an import executor finishing its rollback, say) can recreate +//! anything under the old path, and deletes the tombstone in the background. [`sweep`] removes +//! tombstones and marked orphans left by a crash at startup. +//! +//! See `docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`. + +use std::path::{Path, PathBuf}; +#[cfg(test)] +use std::sync::Arc; +#[cfg(test)] +use std::time::Duration; + +#[cfg(test)] +use crate::connection::config::DatabaseConfig; + +use super::meta_store::MetaStore; +use super::NamespaceName; + +/// Present in a namespace directory until its config has been persisted to the metastore. +pub(crate) const INCOMPLETE_MARKER: &str = ".incomplete"; + +/// Where discarded directories go before they are deleted. +const DISCARDED_DIR: &str = ".discarded"; + +/// Path of the directory of namespace `name`. +pub(crate) fn namespace_dir(base: &Path, name: &NamespaceName) -> PathBuf { + base.join("dbs").join(name.as_str()) +} + +/// Create the directory of a namespace that does not exist yet, marked incomplete. +/// +/// Synchronous (a few small filesystem operations) so that there is no await point between +/// creating the directory and marking it. The marker and the directory entry are fsynced: the +/// marker must be durable before anything else in the directory can be, or a power loss could +/// leave a directory with content but no marker, which nothing would dare discard. +pub(crate) fn create_marked_dir(db_path: &Path) -> std::io::Result<()> { + std::fs::create_dir_all(db_path)?; + mark_incomplete(db_path) +} + +/// Write the marker into an existing directory and make it durable. +pub(crate) fn mark_incomplete(db_path: &Path) -> std::io::Result<()> { + std::fs::File::create(db_path.join(INCOMPLETE_MARKER))?.sync_all()?; + std::fs::File::open(db_path)?.sync_all() +} + +/// Remove `db_path` (a namespace directory under `base`): rename it into the discarded area +/// right away and delete it in the background. Returns `Ok` if it does not exist. +/// +/// Synchronous so that it can run in `Drop` and on the blocking pool; the rename is instant, +/// the deletion is handed to the runtime (or done inline if there is none). +pub(crate) fn discard_dir(base: &Path, db_path: &Path) -> std::io::Result<()> { + let discarded = base.join(DISCARDED_DIR); + std::fs::create_dir_all(&discarded)?; + let name = db_path + .file_name() + .map(|n| n.to_string_lossy().into_owned()) + .unwrap_or_default(); + let tombstone = discarded.join(format!("{name}-{}", uuid::Uuid::new_v4())); + match std::fs::rename(db_path, &tombstone) { + Ok(()) => {} + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(()), + Err(e) => return Err(e), + } + tracing::info!( + path = %db_path.display(), + tombstone = %tombstone.display(), + "discarded namespace directory" + ); + delete_in_background(tombstone); + Ok(()) +} + +/// Discard the directory of `name` under `base` if it carries the marker. Directories without +/// the marker are left alone. +pub(crate) fn discard_if_incomplete(base: &Path, name: &NamespaceName) -> std::io::Result { + let db_path = namespace_dir(base, name); + if !db_path.join(INCOMPLETE_MARKER).try_exists()? { + return Ok(false); + } + tracing::warn!( + namespace = %name, + path = %db_path.display(), + "discarding namespace directory left by a creation that did not complete" + ); + discard_dir(base, &db_path)?; + metrics::increment_counter!("libsql_server_namespace_create_discarded_incomplete"); + Ok(true) +} + +fn delete_in_background(tombstone: PathBuf) { + let delete = move || { + if let Err(e) = std::fs::remove_dir_all(&tombstone) { + if e.kind() != std::io::ErrorKind::NotFound { + // left for `sweep` at the next start + tracing::error!( + path = %tombstone.display(), + "failed to delete discarded namespace directory: {e}" + ); + } + } + }; + match tokio::runtime::Handle::try_current() { + Ok(rt) => { + rt.spawn_blocking(delete); + } + Err(_) => delete(), + } +} + +/// Startup sweep: delete leftover tombstones and discard marked directories of namespaces the +/// metastore does not know (creations the process died in the middle of). +pub(crate) async fn sweep(base: &Path, meta_store: &MetaStore) -> std::io::Result<()> { + let discarded = base.join(DISCARDED_DIR); + if let Ok(entries) = std::fs::read_dir(&discarded) { + for entry in entries.flatten() { + tracing::warn!(path = %entry.path().display(), "deleting leftover discarded namespace directory"); + delete_in_background(entry.path()); + } + } + + let dbs = base.join("dbs"); + let Ok(entries) = std::fs::read_dir(&dbs) else { + return Ok(()); + }; + for entry in entries.flatten() { + if !entry.path().join(INCOMPLETE_MARKER).try_exists()? { + continue; + } + let Ok(name) = NamespaceName::from_string(entry.file_name().to_string_lossy().into_owned()) + else { + continue; + }; + if meta_store.exists(&name).await { + // persisted, but the marker was not removed yet (crash right after the commit); it + // is removed when the namespace is loaded + continue; + } + discard_if_incomplete(base, &name)?; + } + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::database::DatabaseKind; + use crate::namespace::meta_store::metastore_connection_maker; + + async fn meta_store(path: &Path) -> MetaStore { + let (maker, manager) = metastore_connection_maker(None, path).await.unwrap(); + MetaStore::new( + Default::default(), + path, + maker().unwrap(), + manager, + DatabaseKind::Primary, + ) + .await + .unwrap() + } + + fn ns(s: &str) -> NamespaceName { + NamespaceName::from_string(s.into()).unwrap() + } + + #[tokio::test] + async fn discard_dir_frees_the_path_immediately() { + let tmp = tempfile::tempdir().unwrap(); + let dir = tmp.path().join("dbs").join("foo"); + create_marked_dir(&dir).unwrap(); + std::fs::write(dir.join("data"), b"junk").unwrap(); + // a file is still open inside; the rename doesn't care, and neither does the deletion + let _open = std::fs::File::open(dir.join("data")).unwrap(); + + discard_dir(tmp.path(), &dir).unwrap(); + assert!(!dir.exists()); + // idempotent + discard_dir(tmp.path(), &dir).unwrap(); + + for _ in 0..100 { + if std::fs::read_dir(tmp.path().join(DISCARDED_DIR)) + .unwrap() + .next() + .is_none() + { + return; + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + panic!("tombstone was not deleted"); + } + + /// Startup: tombstones are deleted; marked directories of names the metastore doesn't + /// know are discarded; marked directories of known names and unmarked directories stay. + #[tokio::test] + async fn sweep_cleans_leftovers_of_a_crash() { + let tmp = tempfile::tempdir().unwrap(); + let base = tmp.path(); + let store = meta_store(base).await; + store + .handle(ns("known")) + .await + .store(Arc::new(DatabaseConfig::default())) + .await + .unwrap(); + + let tombstone = base.join(DISCARDED_DIR).join("old-123"); + std::fs::create_dir_all(&tombstone).unwrap(); + std::fs::write(tombstone.join("data"), b"junk").unwrap(); + let crashed = base.join("dbs").join("crashed"); + create_marked_dir(&crashed).unwrap(); + let known = base.join("dbs").join("known"); + create_marked_dir(&known).unwrap(); + let unmarked = base.join("dbs").join("unmarked"); + std::fs::create_dir_all(&unmarked).unwrap(); + + sweep(base, &store).await.unwrap(); + + assert!(!crashed.exists()); + assert!( + known.join(INCOMPLETE_MARKER).exists(), + "known: left for load" + ); + assert!(unmarked.exists()); + for _ in 0..100 { + if !tombstone.exists() { + return; + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + panic!("tombstone was not deleted"); + } + + /// Rebuilding an empty metastore from the filesystem must not adopt a directory whose + /// creation never completed. + #[tokio::test] + async fn recovery_from_fs_skips_marked_directories() { + let tmp = tempfile::tempdir().unwrap(); + let base = tmp.path(); + std::fs::create_dir_all(base.join("dbs").join("complete")).unwrap(); + create_marked_dir(&base.join("dbs").join("crashed")).unwrap(); + + let (maker, manager) = metastore_connection_maker(None, base).await.unwrap(); + let store = MetaStore::new( + crate::config::MetaStoreConfig { + allow_recover_from_fs: true, + ..Default::default() + }, + base, + maker().unwrap(), + manager, + DatabaseKind::Primary, + ) + .await + .unwrap(); + + assert!(store.exists(&ns("complete")).await); + assert!(!store.exists(&ns("crashed")).await); + } +} diff --git a/libsql-server/src/namespace/meta_store.rs b/libsql-server/src/namespace/meta_store.rs index 2c0916cd77..7c72964769 100644 --- a/libsql-server/src/namespace/meta_store.rs +++ b/libsql-server/src/namespace/meta_store.rs @@ -30,12 +30,23 @@ use crate::{ use super::NamespaceName; -type ChangeMsg = ( - NamespaceName, - Option>, - oneshot::Sender>, - bool, // flush -); +enum ChangeMsg { + /// Set the in-memory config of a namespace (`config: Some`) and/or persist its current + /// in-memory config (`flush`). + Update { + namespace: NamespaceName, + config: Option>, + ret: oneshot::Sender>, + flush: bool, + }, + /// Forget a namespace whose creation did not complete: drop its in-memory config and + /// whatever was persisted for it, unconditionally. Goes through the same queue as updates + /// so that it is ordered after any update to the same namespace that is still queued. + Discard { + namespace: NamespaceName, + ret: oneshot::Sender>, + }, +} type MetaStoreWalManager = WalWrapper, Sqlite3WalManager>; pub type MetaStoreConnection = libsql_sys::Connection, Sqlite3Wal>>; @@ -223,6 +234,17 @@ impl MetaStoreInner { if !entry.path().is_dir() { continue; } + if entry + .path() + .join(super::incomplete::INCOMPLETE_MARKER) + .try_exists()? + { + tracing::warn!( + "skipping `{}`: left by an interrupted namespace creation", + entry.path().display() + ); + continue; + } let config_path = entry.path().join("config.json"); let name = NamespaceName::from_string(entry.file_name().to_str().unwrap().to_string())?; @@ -306,7 +328,18 @@ impl MetaStoreInner { /// Handles config change updates by inserting them into the database and in-memory /// cache of configs. fn process(msg: ChangeMsg, inner: Arc) { - let (namespace, config, ret_chan, flush) = msg; + let (namespace, config, ret_chan, flush) = match msg { + ChangeMsg::Update { + namespace, + config, + ret, + flush, + } => (namespace, config, ret, flush), + ChangeMsg::Discard { namespace, ret } => { + let _ = ret.send(discard(&inner, &namespace)); + return; + } + }; if let Some(config) = config { let ret = if flush { try_process(&inner, &namespace, &config) @@ -330,12 +363,16 @@ fn process(msg: ChangeMsg, inner: Arc) { let _ = ret_chan.send(ret); } else { let ret = if flush { - let mut configs = inner.configs.blocking_lock(); - if let Some(config_watch) = configs.get_mut(&namespace) { - let config = config_watch.subscribe().borrow().clone(); - try_process(&inner, &namespace, &config.config) - } else { - Ok(()) + // Lock order: `remove` takes `conn` before `configs`; `try_process` takes `conn`, + // so `configs` must not be held across it. + let current = inner + .configs + .blocking_lock() + .get(&namespace) + .map(|config_watch| config_watch.borrow().config.clone()); + match current { + Some(config) => try_process(&inner, &namespace, &config), + None => Ok(()), } } else { Ok(()) @@ -344,6 +381,27 @@ fn process(msg: ChangeMsg, inner: Arc) { } } +/// Forget `namespace` unconditionally: the row and schema links, if any were written, and the +/// in-memory config. No consistency checks (unlike [`MetaStore::remove`]): this undoes a +/// creation that did not complete, so nothing can depend on the namespace yet. +fn discard(inner: &MetaStoreInner, namespace: &NamespaceName) -> Result<()> { + { + let mut conn = inner.conn.blocking_lock(); + let tx = conn.transaction()?; + tx.execute( + "DELETE FROM shared_schema_links WHERE namespace = ?", + [namespace.as_str()], + )?; + tx.execute( + "DELETE FROM namespace_configs WHERE namespace = ?", + [namespace.as_str()], + )?; + tx.commit()?; + } + inner.configs.blocking_lock().remove(namespace); + Ok(()) +} + fn try_process( inner: &MetaStoreInner, namespace: &NamespaceName, @@ -508,6 +566,31 @@ impl MetaStore { } } + /// Handle of a namespace the store knows; `None` otherwise. Unlike [`handle`](Self::handle) + /// this never registers the namespace, so it is the lookup for anything that must not + /// bring a namespace into existence as a side effect. + pub async fn existing_handle(&self, namespace: NamespaceName) -> Option { + let configs = self.inner.configs.lock().await; + let rx = configs.get(&namespace)?.subscribe(); + Some(MetaStoreHandle { + namespace, + inner: HandleState::External(self.changes_tx.clone(), rx), + }) + } + + /// Forget a namespace whose creation did not complete (see [`ChangeMsg::Discard`]). + /// + /// Blocking: meant for the blocking pool (the cleanup runs where the creating future is + /// being dropped). + pub fn discard_blocking(&self, namespace: NamespaceName) -> Result<()> { + let (ret, rcv) = oneshot::channel(); + self.changes_tx + .blocking_send(ChangeMsg::Discard { namespace, ret }) + .map_err(|e| Error::MetaStoreUpdateFailure(e.into()))?; + rcv.blocking_recv() + .map_err(|e| Error::MetaStoreUpdateFailure(e.into()))? + } + pub fn remove(&self, namespace: NamespaceName) -> Result>> { tracing::debug!("removing namespace `{}` from meta store", namespace); @@ -708,7 +791,12 @@ impl MetaStoreHandle { let (snd, rcv) = oneshot::channel(); changes_tx - .send((self.namespace.clone(), new_config, snd, flush)) + .send(ChangeMsg::Update { + namespace: self.namespace.clone(), + config: new_config, + ret: snd, + flush, + }) .await .map_err(|e| Error::MetaStoreUpdateFailure(e.into()))?; diff --git a/libsql-server/src/namespace/mod.rs b/libsql-server/src/namespace/mod.rs index 794df58a25..5a05e28361 100644 --- a/libsql-server/src/namespace/mod.rs +++ b/libsql-server/src/namespace/mod.rs @@ -23,6 +23,7 @@ pub use self::store::NamespaceStore; pub mod broadcasters; pub(crate) mod configurator; pub mod dump_import; +pub(crate) mod incomplete; pub mod meta_store; mod name; pub mod replication_wal; @@ -58,6 +59,20 @@ pub enum NamespaceBottomlessDbIdInit { FetchFromConfig, } +/// Remove the incomplete marker of the namespace directory `path`, if present. +pub(crate) async fn remove_incomplete_marker(path: &Path) -> std::io::Result<()> { + let marker = path.join(incomplete::INCOMPLETE_MARKER); + // Almost always absent (every cold load passes through here): a stat is cheaper than a + // trip to the blocking pool. + if !marker.exists() { + return Ok(()); + } + match tokio::fs::remove_file(marker).await { + Err(e) if e.kind() != std::io::ErrorKind::NotFound => Err(e), + _ => Ok(()), + } +} + /// A namespace isolates the resources pertaining to a database of type T #[derive(Debug)] pub struct Namespace { @@ -75,6 +90,12 @@ impl Namespace { &self.name } + /// Remove the [`incomplete::INCOMPLETE_MARKER`]: the namespace is now persisted in the + /// metastore (or was opened from it, which implies the same). + pub(crate) async fn mark_complete(&self) -> std::io::Result<()> { + remove_incomplete_marker(&self.path).await + } + async fn destroy(mut self) -> anyhow::Result<()> { self.tasks.shutdown().await; self.db.destroy(); diff --git a/libsql-server/src/namespace/store.rs b/libsql-server/src/namespace/store.rs index 051ae18381..3ab08f9a49 100644 --- a/libsql-server/src/namespace/store.rs +++ b/libsql-server/src/namespace/store.rs @@ -1,11 +1,16 @@ +use std::collections::HashMap; +use std::future::Future; +use std::pin::Pin; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use async_lock::RwLock; +use async_lock::{RwLock, RwLockWriteGuardArc}; use chrono::NaiveDateTime; use futures::TryFutureExt; use moka::future::Cache; +use moka::ops::compute::{CompResult, Op}; use once_cell::sync::OnceCell; +use parking_lot::Mutex; use tokio::task::JoinSet; use tokio::time::{Duration, Instant}; use tokio_stream::wrappers::BroadcastStream; @@ -16,7 +21,8 @@ use crate::connection::config::DatabaseConfig; use crate::database::DatabaseKind; use crate::error::Error; use crate::metrics::{ - NAMESPACE_EMPTIED_ENTRY, NAMESPACE_EMPTIED_ENTRY_GAVE_UP, NAMESPACE_LOAD_LATENCY, + NAMESPACE_EMPTIED_ENTRY, NAMESPACE_EMPTIED_ENTRY_GAVE_UP, NAMESPACE_LEFT_EMPTY_ENTRY_DROPPED, + NAMESPACE_LOAD_LATENCY, }; use crate::namespace::{NamespaceBottomlessDbId, NamespaceBottomlessDbIdInit, NamespaceName}; use crate::stats::Stats; @@ -29,11 +35,211 @@ use super::{Namespace, ResetCb, ResetOp, ResolveNamespacePathFn, RestoreOption}; type NamespaceEntry = Arc>>; -/// How many times `with` looks up a namespace whose cache entry was emptied -/// under it (by shutdown, eviction or destroy) before giving up. Dropping an -/// entry that was left empty is not a lookup and does not count. +/// How many times `with` looks a namespace up again after finding its entry emptied (by +/// shutdown, eviction or destroy) before it gives up. const MAX_EMPTIED_ENTRY_ATTEMPTS: usize = 3; +/// Entries of namespaces with a creation, fork or reset in progress, pinned so that lookups keep +/// finding (and waiting on) the locked entry even if the cache evicts it meanwhile. Otherwise a +/// concurrent lookup would run a lazy load of the directory the operation is writing to. +type InFlight = Arc>>; + +/// Remove `name` from `in_flight`, but only if it still maps to `entry` (another operation may +/// have taken the name over in the meantime). +fn unpin(in_flight: &InFlight, name: &NamespaceName, entry: &NamespaceEntry) { + let mut in_flight = in_flight.lock(); + if in_flight.get(name).is_some_and(|e| Arc::ptr_eq(e, entry)) { + in_flight.remove(name); + } +} + +/// A namespace name reserved for a creation (or fork) in progress. +/// +/// Holding a reservation holds the name's cache entry write-locked, so every other access to +/// the name — user requests, a second create, destroy — waits until the outcome is known. +/// [`publish`](Self::publish) installs the finished namespace. Dropping the reservation +/// unpublished (error, or the creating request was cancelled) undoes everything the creation +/// did — the namespace's config, and its directory if it is still marked incomplete — and only +/// then releases the lock, so waiters observe a namespace that does not exist, never a +/// half-built one, and a retry never races the cleanup. +/// +/// The entry is pinned in [`InFlight`] for the duration, so that lookups keep finding it (and +/// waiting on it) even if the cache evicts it in the meantime. +/// +/// The metastore row is only written after setup succeeds (see `create`), so the row's presence +/// implies a complete namespace. See `docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`. +struct Reservation { + guard: Option>>, + entry: NamespaceEntry, + store: NamespaceStore, + name: NamespaceName, + /// Selects the configurator that owns the namespace's directory. + config: Arc, +} + +impl Reservation { + /// Fails with `NamespaceAlreadyExist` if the namespace is loaded or known to the metastore. + /// + /// Must be called before `MetaStore::handle(name)`: `handle` inserts the name into the + /// in-memory config map that `exists` reads, so the name becomes visible only while it is + /// already locked here. + async fn acquire( + store: &NamespaceStore, + name: NamespaceName, + config: Arc, + ) -> crate::Result { + // Wait on the entry an operation in progress holds, if any, rather than on the cache's + // (which may be a fresh one if that entry was evicted). + let pinned = store.inner.in_flight.lock().get(&name).cloned(); + let entry = match pinned { + Some(entry) => entry, + None => { + store + .inner + .store + .get_with(name.clone(), async { Default::default() }) + .await + } + }; + if entry.try_write().is_none() { + tracing::debug!(namespace = %name, "waiting for an operation in progress on the namespace"); + } + let guard = entry.write_arc().await; + if guard.is_some() || store.inner.metadata.exists(&name).await { + if guard.is_none() { + // The namespace exists but is not loaded, and `get_with` just gave it an empty + // entry. Left there, lookups would find the empty entry before loading the + // namespace (see `load_namespace`); remove it again, but only if it is still + // that empty entry: a lookup may have loaded the namespace into a fresh one + // since the lock was released. + drop(guard); + store.evict_if_still_empty(&name, &entry).await; + } + return Err(Error::NamespaceAlreadyExist(name.to_string())); + } + store + .inner + .in_flight + .lock() + .insert(name.clone(), entry.clone()); + Ok(Self { + guard: Some(guard), + entry, + store: store.clone(), + name, + config, + }) + } + + /// Install the finished namespace and release the lock. + async fn publish(mut self, ns: Namespace) { + // `install` awaits (cache lookups). Keep the guard inside `self` across them: if this + // future is dropped there, `Drop` still sees an unpublished reservation and undoes the + // creation — rather than leaving the name pinned and the lock released. + { + let guard = self + .guard + .as_deref_mut() + .expect("a reservation is published at most once"); + self.store.install(&self.name, &self.entry, guard, ns).await; + } + let guard = self.guard.take().expect("checked above"); + // Unpin before unlocking: a lookup racing with us either still finds the pinned entry + // (and waits for the lock, then sees the namespace) or goes through the cache, where + // the namespace now is. + unpin(&self.store.inner.in_flight, &self.name, &self.entry); + drop(guard); + } +} + +impl Reservation { + /// The creation failed: undo it, then release the name. Awaited, so that by the time the + /// error reaches the caller the name is free and nothing is left of the attempt. + async fn abort(mut self) { + if let Some(cleanup) = self.take_cleanup() { + let _ = tokio::task::spawn_blocking(cleanup).await; + } + } + + /// Everything that undoes an unpublished creation, in the order that keeps the name + /// unobservable until it is clean. Blocking (`discard_blocking`). + fn take_cleanup(&mut self) -> Option { + let guard = self.guard.take()?; + metrics::increment_counter!("libsql_server_namespace_create_aborted"); + let store = self.store.clone(); + let name = self.name.clone(); + let entry = self.entry.clone(); + let config = self.config.clone(); + Some(move || { + // 1. The config: in memory and, if the commit happened but publishing didn't, the + // row. From here on lookups of the name are rejected before they reach the cache. + if let Err(e) = store.inner.metadata.discard_blocking(name.clone()) { + tracing::error!(namespace = %name, "failed to discard namespace config: {e}"); + } + // 2. The directory, if it is still marked incomplete (the configurator's own guard + // normally got it already; this covers forks and anything that guard missed). + if let Err(e) = store.get_configurator(&config).discard_incomplete(&name) { + tracing::error!(namespace = %name, "failed to discard namespace directory: {e}"); + } + // 3. Only now let anyone else at the name. + unpin(&store.inner.in_flight, &name, &entry); + drop(guard); + }) + } +} + +impl Drop for Reservation { + /// Neither published nor aborted: the creating future was dropped (the request was + /// cancelled, or the server is shutting down). + fn drop(&mut self) { + let Some(cleanup) = self.take_cleanup() else { + return; + }; + tracing::warn!( + namespace = %self.name, + "namespace creation was cancelled; discarding it" + ); + // We are running inside a future that is being dropped: hand the (blocking) cleanup to + // the blocking pool instead of blocking in place. The name stays locked until it ran. + match tokio::runtime::Handle::try_current() { + Ok(rt) => { + rt.spawn_blocking(cleanup); + } + Err(_) => cleanup(), + } + } +} + +/// Keeps a namespace entry pinned in [`InFlight`] while `reset` holds it locked (see +/// [`Reservation`] for why). Must be created after the lock is taken and dropped before it is +/// released. +struct Pinned { + in_flight: InFlight, + name: NamespaceName, + entry: NamespaceEntry, +} + +impl Pinned { + fn new(store: &NamespaceStore, name: NamespaceName, entry: NamespaceEntry) -> Self { + store + .inner + .in_flight + .lock() + .insert(name.clone(), entry.clone()); + Self { + in_flight: store.inner.in_flight.clone(), + name, + entry, + } + } +} + +impl Drop for Pinned { + fn drop(&mut self) { + unpin(&self.in_flight, &self.name, &self.entry); + } +} + /// Stores and manage a set of namespaces. pub struct NamespaceStore { pub inner: Arc, @@ -57,6 +263,7 @@ pub struct NamespaceStoreInner { broadcasters: BroadcasterRegistry, configurators: NamespaceConfigurators, db_kind: DatabaseKind, + in_flight: InFlight, } impl NamespaceStore { @@ -69,23 +276,41 @@ impl NamespaceStore { db_kind: DatabaseKind, ) -> crate::Result { tracing::trace!("Max active namespaces: {max_active_namespaces}"); + let in_flight: InFlight = Default::default(); let store = Cache::::builder() - .async_eviction_listener(move |name, ns, cause| { - tracing::debug!("evicting namespace `{name}` asynchronously: {cause:?}"); - // TODO(sarna): not clear if we should snapshot-on-evict... - // On the one hand, better to do so, because we have no idea - // for how long we're evicting a namespace. - // On the other, if there's lots of cache pressure, snapshotting - // very often will kill the machine's I/O. - Box::pin(async move { - // shutdown namespace - if let Some(ns) = ns.write().await.take() { - tracing::info!("namespace `{name}` deallocated"); - if let Err(e) = ns.shutdown(snapshot_at_shutdown).await { - tracing::error!("error deallocating `{name}`: {e}") + .async_eviction_listener({ + let in_flight = in_flight.clone(); + move |name, ns, cause| { + tracing::debug!("evicting namespace `{name}` asynchronously: {cause:?}"); + let pinned = in_flight.lock().contains_key(&name); + // TODO(sarna): not clear if we should snapshot-on-evict... + // On the one hand, better to do so, because we have no idea + // for how long we're evicting a namespace. + // On the other, if there's lots of cache pressure, snapshotting + // very often will kill the machine's I/O. + let shutdown = async move { + if let Some(ns) = ns.write().await.take() { + tracing::info!("namespace `{name}` deallocated"); + if let Err(e) = ns.shutdown(snapshot_at_shutdown).await { + tracing::error!("error deallocating `{name}`: {e}") + } } + }; + // moka runs this listener inline, from whichever cache operation happens + // to run maintenance, and awaits it. Normally that is what we want: it + // serialises the shutdown with a reload of the same name. But an entry + // write-locked by an operation in progress (create, fork, reset) stays + // locked for minutes; waiting for it here would stall the cache for + // everyone and deadlock the operation if it touches the cache itself. That + // operation installs its result elsewhere (see `install`), so for it the + // wait only has to happen off the maintenance path. + if pinned { + tokio::spawn(shutdown); + Box::pin(async {}) as Pin + Send>> + } else { + Box::pin(shutdown) } - }) + } }) .max_capacity(max_active_namespaces as u64) .time_to_idle(Duration::from_secs(86400)) @@ -102,6 +327,7 @@ impl NamespaceStore { broadcasters: Default::default(), configurators, db_kind, + in_flight, }), }) } @@ -129,7 +355,12 @@ impl NamespaceStore { .await??; let mut bottomless_db_id_init = NamespaceBottomlessDbIdInit::FetchFromConfig; - if let Some(ns) = self.inner.store.remove(&namespace).await { + // An operation in progress holds the namespace in its pinned entry (the cache's may be + // a fresh, empty one if that entry was evicted): wait on that one, so that we destroy + // what the operation produces rather than racing it. + let pinned = self.inner.in_flight.lock().get(&namespace).cloned(); + let cached = self.inner.store.remove(&namespace).await; + if let Some(ns) = pinned.or(cached) { // deallocate in-memory resources if let Some(ns) = ns.write().await.take() { bottomless_db_id_init = NamespaceBottomlessDbIdInit::Provided( @@ -148,8 +379,8 @@ impl NamespaceStore { } pub async fn checkpoint(&self, namespace: NamespaceName) -> crate::Result<()> { - // Only a loaded namespace has anything to checkpoint. Inserting an empty - // entry for one that is not loaded would leave it cached empty. + // A namespace that is not loaded has nothing to checkpoint. (`get_with(Default)` here + // used to leave an empty entry behind that lookups then mistook for the namespace.) let Some(entry) = self.inner.store.get(&namespace).await else { return Ok(()); }; @@ -179,13 +410,9 @@ impl NamespaceStore { .store .get_with(namespace.clone(), async { Default::default() }) .await; - // This write lock is held across `make_namespace` below. Do not add a - // cache call while it is held: moka runs its maintenance inline in - // cache calls and awaits the eviction listener, which waits for this - // lock. The same holds for `fork`'s `to_lock`. One such call predates - // this comment: on a replica, a namespace with a shared schema loads - // its schema through `with` during the replication handshake. let mut lock = entry.write().await; + // Declared after the lock so that it is unpinned before the lock is released. + let _pinned = Pinned::new(self, namespace.clone(), entry.clone()); if let Some(ns) = lock.take() { ns.destroy().await?; } @@ -203,7 +430,7 @@ impl NamespaceStore { .make_namespace(&namespace, db_config, restore_option) .await?; - lock.replace(ns); + self.install(&namespace, &entry, &mut lock, ns).await; Ok(()) } @@ -241,73 +468,43 @@ impl NamespaceStore { if !self.inner.metadata.exists(&from).await { return Err(crate::error::Error::NamespaceDoesntExist(from.to_string())); } - // Load the source as `with` does, so a source whose cache entry was - // emptied (by eviction, or left empty) is reloaded rather than failing - // the fork, and its errors are the same as `with`'s. - self.with(from.clone(), |_| ()).await?; - let to_entry = self - .inner - .store - .get_with(to.clone(), async { Default::default() }) - .await; - let mut to_lock = to_entry.write().await; - if to_lock.is_some() { - return Err(crate::error::Error::NamespaceAlreadyExist(to.to_string())); + let to_config = Arc::new(to_config); + let reservation = Reservation::acquire(self, to.clone(), to_config.clone()).await?; + match self.fork_reserved(&from, &to, to_config, timestamp).await { + Ok(to_ns) => { + self.publish(reservation, to_ns).await; + Ok(()) + } + Err(e) => { + tracing::warn!(from = %from, to = %to, error = %e, "fork failed"); + reservation.abort().await; + Err(e) + } } + } + /// The part of `fork` that runs with the target name reserved. + async fn fork_reserved( + &self, + from: &NamespaceName, + to: &NamespaceName, + to_config: Arc, + timestamp: Option, + ) -> crate::Result { // FIXME: we could potentially delete the namespace while trying to fork it - if !self.inner.metadata.exists(&from).await { + let Some(from_config) = self.inner.metadata.existing_handle(from.clone()).await else { return Err(crate::Error::NamespaceDoesntExist(from.to_string())); - } - - let from_config = self.inner.metadata.handle(from.clone()).await; - // Known hazard: `to_lock` is held across this cache call. moka runs its - // maintenance inline in cache calls and awaits the eviction listener, - // which waits for the evicted entry's write lock. If the cache is at - // capacity and picks the fresh, empty `to_entry` as its victim, the - // listener waits for the lock this task holds. The `with` above makes - // this a cache hit in the normal case, which lowers the exposure - // without removing it. Fixing it means reserving `to` outside the - // cache; see the follow-ups in PR #56. - let from_entry = self - .load_namespace(&from, from_config.clone(), RestoreOption::Latest) - .await?; + }; + let from_entry = self.load_namespace(from, from_config.clone()).await?; let from_lock = from_entry.read().await; let Some(from_ns) = &*from_lock else { - return Err(self.emptied_entry_error(&from).await); - }; - - struct Bomb { - store: MetaStore, - ns: NamespaceName, - should_delete: bool, - } - - impl Drop for Bomb { - fn drop(&mut self) { - if self.should_delete { - // we need to block in place because the inner connection may blocking, or - // unsing tokio's blocking methods (bottomless), which would cause a panic. - if let Err(e) = - tokio::task::block_in_place(|| self.store.remove(self.ns.clone())) - { - tracing::error!("failed to clean handle while forking: {e}"); - } - } - } - } - - let mut bomb = Bomb { - store: self.inner.metadata.clone(), - ns: to.clone(), - should_delete: true, + return Err(self.emptied_entry_error(from).await); }; let handle = self.inner.metadata.handle(to.clone()).await; - handle - .store_and_maybe_flush(Some(to_config.into()), false) - .await?; + // In memory only: the fork reads it; nothing is persisted until it succeeded. + handle.store_and_maybe_flush(Some(to_config), false).await?; let to_ns = self .get_configurator(&from_config.get()) .fork( @@ -320,12 +517,27 @@ impl NamespaceStore { ) .await?; - to_lock.replace(to_ns); - handle.flush().await?; - // defuse - bomb.should_delete = false; + if self.inner.has_shutdown.load(Ordering::Relaxed) { + return Err(Error::NamespaceStoreShutdown); + } + handle.flush().await?; // commit point + Ok(to_ns) + } - Ok(()) + /// Make a namespace whose config has just been persisted visible, then drop its marker. + /// + /// Visible first, then unmarked: a marker that outlives the namespace's publication is + /// harmless (removed when the namespace is next loaded), a complete directory without one + /// is not (it could not be told from a namespace that was never ours to discard). + async fn publish(&self, reservation: Reservation, ns: Namespace) { + let name = reservation.name.clone(); + let marker_dir = ns.path.clone(); + reservation.publish(ns).await; + if let Err(e) = super::remove_incomplete_marker(&marker_dir).await { + // The namespace is published and serves; the marker is removed at its next load. It + // matters only if the metastore is lost and rebuilt from the filesystem meanwhile. + tracing::error!(namespace = %name, "could not remove creation marker: {e}"); + } } pub async fn with_authenticated( @@ -351,21 +563,26 @@ impl NamespaceStore { where Fun: FnOnce(&Namespace) -> R, { + let lazily_created = + namespace == NamespaceName::default() || self.inner.allow_lazy_creation; for _ in 0..MAX_EMPTIED_ENTRY_ATTEMPTS { if self.inner.has_shutdown.load(Ordering::Relaxed) { return Err(Error::NamespaceStoreShutdown); } - if namespace != NamespaceName::default() - && !self.inner.metadata.exists(&namespace).await - && !self.inner.allow_lazy_creation - { - return Err(Error::NamespaceDoesntExist(namespace.to_string())); - } + // `handle` registers the name in the metastore's in-memory map as a side effect, + // which is what `exists` reads: a namespace that must already exist is looked up + // with the side-effect-free `existing_handle`, so that a lookup racing with the end + // of a failed creation, or with `destroy`, cannot bring the name back to life. + let handle = if lazily_created { + self.inner.metadata.handle(namespace.clone()).await + } else { + match self.inner.metadata.existing_handle(namespace.clone()).await { + Some(handle) => handle, + None => return Err(Error::NamespaceDoesntExist(namespace.to_string())), + } + }; - let handle = self.inner.metadata.handle(namespace.to_owned()).await; - let entry = self - .load_namespace(&namespace, handle, RestoreOption::Latest) - .await?; + let entry = self.load_namespace(&namespace, handle).await?; { let lock = entry.read().await; if let Some(ns) = &*lock { @@ -373,35 +590,64 @@ impl NamespaceStore { } } - // The namespace was taken out of the entry after we got it: by - // shutdown, by cache eviction, or by a concurrent destroy. That - // does not mean it is missing, so look it up again. Expected - // during a rolling restart and under cache pressure, once per + // The namespace was taken out of the entry after we got it: by shutdown, by cache + // eviction, or by a concurrent destroy. That does not mean it is missing, so look it + // up again. Expected during a rolling restart and under cache pressure, once per // waiting request: the counter is the signal, not the log. NAMESPACE_EMPTIED_ENTRY.increment(1); tracing::debug!(%namespace, "namespace cache entry was emptied while in use, looking it up again"); } - // Every lookup found an emptied entry. That is also where an entry - // that stays cached but empty ends up (a fork that failed before - // storing its record leaves one behind): the namespace answers - // `NamespaceUnavailable` until the entry is evicted or the server - // restarts. Dropping such an entry so that the next lookup reloads the - // namespace is left to a follow-up. let error = self.emptied_entry_error(&namespace).await; if matches!(error, Error::NamespaceUnavailable(_)) { - // Shutdown and a namespace that is really gone are not failures - // of the store, so the counter only records this outcome. + // Shutdown and a namespace that is really gone are not failures of the store, so + // the counter only records this outcome. NAMESPACE_EMPTIED_ENTRY_GAVE_UP.increment(1); } tracing::warn!(%namespace, %error, "namespace cache entry kept being emptied, giving up"); Err(error) } - /// The error for a namespace whose cache entry was emptied while it was - /// being used. `NamespaceDoesntExist` only when the metastore agrees: a - /// client must be able to trust it, and a namespace that still exists but - /// cannot be served right now is a temporary condition, not a missing one. + /// Removes `entry` from the cache if it is still the cached entry for `namespace` and still + /// empty, so that the next lookup loads the namespace afresh. It never fills an entry + /// itself. + /// + /// The checks run under moka's per-key compute lock: a loaded entry is never removed, and + /// neither is an entry whose lock is held at that moment, which covers an operation in + /// progress (create, fork, reset hold their entry write-locked). An operation that got the + /// entry from the cache but has not locked it yet can lose it here; it then fills an entry + /// the cache no longer holds, which `install` detects and re-inserts, and lookups find it + /// pinned in the meantime. One window stays: `Op::Remove` removes whatever the cache holds + /// when it runs, which moka does not tie to the entry the closure saw. That is detected + /// below; the requests holding a fresh entry removed that way see it emptied and look the + /// namespace up again. + async fn evict_if_still_empty(&self, namespace: &NamespaceName, entry: &NamespaceEntry) { + let result = self + .inner + .store + .entry_by_ref(namespace) + .and_compute_with(|cached| { + let still_empty = cached.is_some_and(|cached| { + Arc::ptr_eq(cached.value(), entry) + && entry.try_read().is_some_and(|lock| lock.is_none()) + }); + std::future::ready(if still_empty { Op::Remove } else { Op::Nop }) + }) + .await; + if let CompResult::Removed(removed) = result { + if Arc::ptr_eq(removed.value(), entry) { + tracing::debug!(%namespace, "dropped an empty namespace cache entry"); + NAMESPACE_LEFT_EMPTY_ENTRY_DROPPED.increment(1); + } else { + tracing::error!(%namespace, "dropped a different cache entry than the empty one"); + } + } + } + + /// The error for a namespace whose cache entry was emptied while it was being used. + /// `NamespaceDoesntExist` only when the metastore agrees: a client must be able to trust + /// it, and a namespace that still exists but cannot be served right now is a temporary + /// condition, not a missing one. async fn emptied_entry_error(&self, namespace: &NamespaceName) -> Error { if self.inner.has_shutdown.load(Ordering::Relaxed) { Error::NamespaceStoreShutdown @@ -448,37 +694,134 @@ impl NamespaceStore { Ok(ns) } + /// Install `ns` as namespace `name` at the end of an operation that held `entry` (the + /// name's cache entry) write-locked, with `slot` its locked content. + /// + /// Normally `entry` is still the cache's entry for the name and `ns` goes into it. If the + /// cache evicted `entry` meanwhile, `ns` goes into a fresh entry instead and `entry` is + /// left empty: the eviction listener waiting on it then finds nothing to shut down, and + /// lookups that waited on it fall through to the cache (see `load_namespace`). If the entry + /// is gone because the namespace was *destroyed* meanwhile, `ns` goes into `entry` after + /// all: `destroy` is waiting on it and shuts it down. + async fn install( + &self, + name: &NamespaceName, + entry: &NamespaceEntry, + slot: &mut Option, + ns: Namespace, + ) { + match self.inner.store.get(name).await { + Some(current) if Arc::ptr_eq(¤t, entry) => { + slot.replace(ns); + } + _ if !self.inner.metadata.exists(name).await => { + tracing::info!( + namespace = %name, + "namespace was destroyed while an operation on it was in progress" + ); + slot.replace(ns); + } + _ => { + tracing::info!( + namespace = %name, + "namespace entry was evicted while an operation on it was in progress; \ + re-inserting" + ); + self.inner + .store + .insert(name.clone(), Arc::new(RwLock::new(Some(ns)))) + .await; + } + } + } + + /// The entry of an existing namespace, loading it (`RestoreOption::Latest`) if needed. async fn load_namespace( &self, namespace: &NamespaceName, db_config: MetaStoreHandle, - restore_option: RestoreOption, ) -> crate::Result { - let init = async { - // Shutdown may have started since the caller checked. A namespace - // opened now would not be in the entries shutdown takes out, so - // nobody would ever shut it down. - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); + // An operation in progress on this namespace (create, fork, reset) holds its entry + // locked and pinned: wait on that entry rather than loading the directory it is working + // on (the cache may have evicted the entry meanwhile). If the operation leaves the entry + // empty — it failed, or the entry was evicted and the namespace it published was shut + // down by the eviction listener — decide like any other lookup: the metastore says + // whether the namespace exists, and the cache (re)loads it. + let pinned = self.inner.in_flight.lock().get(namespace).cloned(); + if let Some(entry) = pinned { + tracing::debug!( + namespace = %namespace, + "waiting for an operation in progress on the namespace" + ); + if entry.read().await.is_some() { + return Ok(entry); } - let ns = self - .make_namespace(namespace, db_config, restore_option) - .await?; - Ok(Some(ns)) - }; + if !self.inner.metadata.exists(namespace).await { + return Err(Error::NamespaceDoesntExist(namespace.to_string())); + } + } - let before_load = Instant::now(); - let ns = self - .inner - .store - .try_get_with( - namespace.clone(), - init.map_ok(|ns| Arc::new(RwLock::new(ns))), - ) - .await?; - NAMESPACE_LOAD_LATENCY.record(before_load.elapsed()); + let lazily_created = + *namespace == NamespaceName::default() || self.inner.allow_lazy_creation; + // Two rounds at most: an entry that is empty once nobody holds it locked is a leftover + // (of a reservation that was rejected, a reset that failed, a checkpoint of a namespace + // that was not loaded) and would make the namespace unreachable until the cache evicts + // it; drop it and load for real. + for round in 0..2 { + let loaded = AtomicBool::new(false); + let init = async { + loaded.store(true, Ordering::Relaxed); + // Shutdown may have started since the caller checked. A namespace opened now + // would not be in the entries shutdown takes out, so nobody would ever shut it + // down. + if self.inner.has_shutdown.load(Ordering::Relaxed) { + return Err(Error::NamespaceStoreShutdown); + } + // The caller checked that the namespace exists; re-check now that we are the + // one loading it, in case it was discarded or destroyed in between (otherwise + // we would bring an empty namespace into existence for a name the metastore + // doesn't know). + if !lazily_created && !self.inner.metadata.exists(namespace).await { + return Err(Error::NamespaceDoesntExist(namespace.to_string())); + } + let ns = self + .make_namespace(namespace, db_config.clone(), RestoreOption::Latest) + .await?; + // A namespace opened from the metastore is complete by definition; this only + // removes a marker left by a crash between persisting the config and removing + // it. + if let Err(e) = ns.mark_complete().await { + tracing::warn!(namespace = %namespace, "could not remove creation marker: {e}"); + } + Ok(Some(ns)) + }; - Ok(ns) + let before_load = Instant::now(); + let entry = self + .inner + .store + .try_get_with( + namespace.clone(), + init.map_ok(|ns| Arc::new(RwLock::new(ns))), + ) + .await?; + if loaded.load(Ordering::Relaxed) { + NAMESPACE_LOAD_LATENCY.record(before_load.elapsed()); + return Ok(entry); + } + + if round == 0 && entry.read().await.is_none() { + // The entry was emptied (by eviction, shutdown or destroy) while we waited on + // it, or something left it empty. Either way the namespace is not missing + // because of it: drop the entry if it is still cached, and load for real. + NAMESPACE_EMPTIED_ENTRY.increment(1); + tracing::debug!(%namespace, "namespace cache entry was emptied, looking it up again"); + self.evict_if_still_empty(namespace, &entry).await; + continue; + } + return Ok(entry); + } + unreachable!("the second round always returns") } #[tracing::instrument(skip_all, fields(namespace))] @@ -504,71 +847,88 @@ impl NamespaceStore { .await; }; - // With namespaces disabled, the default namespace can be auto-created, - // otherwise it's an error. + // With namespaces disabled, the default namespace always exists and `create` is an + // idempotent config upsert of it. Creating *from a dump* is not: the dump must never be + // skipped because the namespace happens to be loaded already, so that case takes the + // reserving path below like any other creation. // FIXME: move the default namespace check out of this function. - if self.inner.allow_lazy_creation || namespace == NamespaceName::default() { + if (self.inner.allow_lazy_creation || namespace == NamespaceName::default()) + && matches!(restore_option, RestoreOption::Latest) + { tracing::trace!("auto-creating the namespace"); - } else if self.inner.metadata.exists(&namespace).await { - return Err(Error::NamespaceAlreadyExist(namespace.to_string())); + let handle = self.inner.metadata.handle(namespace.clone()).await; + handle.store(Arc::new(db_config)).await?; + self.load_namespace(&namespace, handle).await?; + return Ok(()); } + // Nothing below is visible or durable until the namespace is complete: + // - the reservation locks the name; dropping it unpublished undoes the in-memory config; + // - the configurator removes a brand-new directory if setup fails or is cancelled; + // - the metastore row is written last, so its presence implies a complete namespace. + let started = Instant::now(); let db_config = Arc::new(db_config); - let handle = self.inner.metadata.handle(namespace.clone()).await; - tracing::debug!("storing db config"); - handle.store(db_config).await?; - tracing::debug!("completed storing db config, loading namespace"); - self.load_created(&namespace, handle, restore_option) - .await?; - - tracing::debug!("completed loading namespace"); - - Ok(()) + let reservation = Reservation::acquire(self, namespace.clone(), db_config.clone()).await?; + match self + .create_reserved(&namespace, db_config, restore_option) + .await + { + Ok(ns) => { + self.publish(reservation, ns).await; + tracing::info!( + namespace = %namespace, + elapsed_ms = started.elapsed().as_millis() as u64, + "namespace created" + ); + Ok(()) + } + Err(e) => { + tracing::warn!(namespace = %namespace, error = %e, "namespace creation failed"); + reservation.abort().await; + Err(e) + } + } } - /// Loads the namespace whose record `create` has just stored. If shutdown - /// started in between, `load_namespace` refuses before anything is opened - /// or written, and the record is removed again. Left in place, it would - /// make every retry answer "already exists" for a namespace that was never - /// loaded, so its restore option would never be applied. - async fn load_created( + /// The part of `create` that runs with the name reserved: everything up to and including + /// the commit point. + async fn create_reserved( &self, namespace: &NamespaceName, - handle: MetaStoreHandle, + db_config: Arc, restore_option: RestoreOption, - ) -> crate::Result<()> { - let error = match self.load_namespace(namespace, handle, restore_option).await { - Ok(_) => return Ok(()), - Err(error) => error, - }; - if matches!(error.as_ref(), Error::NamespaceStoreShutdown) { - let removed = tokio::task::spawn_blocking({ - let metadata = self.inner.metadata.clone(); - let namespace = namespace.clone(); - move || metadata.remove(namespace) - }) - .await; - match removed { - Ok(Ok(_)) => {} - Ok(Err(e)) => tracing::error!( - %namespace, - "failed to remove the record of a namespace whose creation shutdown interrupted: {e}" - ), - Err(e) => tracing::error!( - %namespace, - "failed to remove the record of a namespace whose creation shutdown interrupted: {e}" - ), - } + ) -> crate::Result { + let handle = self.inner.metadata.handle(namespace.clone()).await; + // In memory only: setup reads it; nothing is persisted until setup succeeded. + handle.store_and_maybe_flush(Some(db_config), false).await?; + // whatever a creation of this name that never completed left behind + self.get_configurator(&handle.get()) + .discard_incomplete(namespace)?; + tracing::debug!("setting up namespace"); + let ns = self + .make_namespace(namespace, handle.clone(), restore_option) + .await?; + if self.inner.has_shutdown.load(Ordering::Relaxed) { + return Err(Error::NamespaceStoreShutdown); } - Err(error) + tracing::debug!("storing db config"); + handle.flush().await?; // commit point + Ok(ns) } pub async fn shutdown(self) -> crate::Result<()> { let mut set = JoinSet::new(); self.inner.has_shutdown.store(true, Ordering::Relaxed); - for (_name, entry) in self.inner.store.iter() { + for (name, entry) in self.inner.store.iter() { let snapshow_at_shutdown = self.inner.snapshot_at_shutdown; + if self.inner.in_flight.lock().contains_key(&name) { + // A creation, fork or reset holds this entry locked, possibly for minutes. It + // notices the shutdown itself (`has_shutdown`) and discards its work; waiting + // here would hold up the shutdown of every other namespace. + tracing::warn!(namespace = %name, "operation in progress at shutdown; not waiting for it"); + continue; + } let mut lock = entry.write().await; if let Some(ns) = lock.take() { set.spawn(async move { @@ -648,15 +1008,22 @@ impl NamespaceStore { pub(crate) mod test { use std::path::Path; + use bytes::Bytes; + use tokio::sync::{mpsc, Semaphore}; + use tokio_stream::wrappers::ReceiverStream; + + use crate::connection::Connection as _; + use crate::namespace::configurator::{ + BaseNamespaceConfig, NamespaceConfigurators, PrimaryConfig, PrimaryConfigurator, + }; + use crate::namespace::dump_import::DumpImporterKind; + use crate::namespace::meta_store::{metastore_connection_maker, MetaStore}; + use crate::namespace::DumpSource; use axum::response::IntoResponse; use hyper::StatusCode; - use libsql_sys::wal::Sqlite3WalManager; use tempfile::tempdir; - use tokio::sync::Semaphore; use super::*; - use crate::namespace::configurator::{BaseNamespaceConfig, PrimaryConfig, PrimaryConfigurator}; - use crate::namespace::meta_store::metastore_connection_maker; pub(crate) async fn make_store(path: &Path) -> NamespaceStore { let (maker, manager) = metastore_connection_maker(None, path).await.unwrap(); @@ -672,18 +1039,18 @@ pub(crate) mod test { let base_config = BaseNamespaceConfig { base_path: path.to_path_buf().into(), extensions: Arc::new([]), - stats_sender: tokio::sync::mpsc::channel(1).0, - max_response_size: 100_000_000, - max_total_response_size: 100_000_000, + stats_sender: mpsc::channel(1).0, + max_response_size: 100000000000000, + max_total_response_size: 100000000000, max_concurrent_connections: Arc::new(Semaphore::new(10)), - max_concurrent_requests: 10_000, + max_concurrent_requests: 10000, encryption_config: None, connection_creation_timeout: None, disable_intelligent_throttling: false, dump_import: Default::default(), }; let primary_config = PrimaryConfig { - max_log_size: 1_000_000_000, + max_log_size: 1000000000, max_log_duration: None, bottomless_replication: None, scripted_backup: None, @@ -693,9 +1060,8 @@ pub(crate) mod test { configurators.with_primary(PrimaryConfigurator::new( base_config, primary_config, - Arc::new(Sqlite3WalManager::default), + Arc::new(libsql_sys::wal::Sqlite3WalManager::default), )); - NamespaceStore::new( false, false, @@ -708,6 +1074,354 @@ pub(crate) mod test { .unwrap() } + /// The reservation is taken a few awaits into `create`; wait for it rather than guess. + async fn wait_until_in_flight(store: &NamespaceStore, name: &NamespaceName) { + for _ in 0..500 { + if store.inner.in_flight.lock().contains_key(name) { + return; + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + panic!("creation of `{name}` never reserved the name"); + } + + fn slow_dump() -> (mpsc::Sender>, DumpSource) { + let (tx, rx) = mpsc::channel::>(8); + let dump = DumpSource::new(Box::new(ReceiverStream::new(rx))) + .with_importer(Some(DumpImporterKind::Streaming)); + (tx, dump) + } + + async fn count_test_rows(store: &NamespaceStore, ns: &str) -> crate::Result { + let maker = store + .with(NamespaceName::from_string(ns.into()).unwrap(), |ns| { + ns.db.connection_maker() + }) + .await?; + let conn = maker.create().await?; + Ok(conn.with_raw(|c| c.query_row("select count(*) from test", [], |r| r.get(0)))?) + } + + /// The cache evicts the entry of a namespace while it is being created (here: explicitly + /// invalidated, which takes the same path). A lookup issued afterwards must still wait for + /// the creation and then see the imported data, instead of lazily opening the directory the + /// import is writing to. + #[tokio::test] + async fn lookup_waits_for_creation_even_if_the_entry_was_evicted() { + let tmp = tempfile::tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + + let (tx, rx) = mpsc::channel::>(8); + let dump = DumpSource::new(Box::new(ReceiverStream::new(rx))) + .with_importer(Some(DumpImporterKind::Streaming)); + let create = tokio::spawn({ + let store = store.clone(); + let foo = foo.clone(); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; + assert!(!create.is_finished()); + + // "eviction" of the reserved entry + store.inner.store.invalidate(&foo).await; + store.inner.store.run_pending_tasks().await; + assert!(!store.inner.store.contains_key(&foo)); + + let lookup = tokio::spawn({ + let store = store.clone(); + async move { count_test_rows(&store, "foo").await } + }); + tokio::time::sleep(Duration::from_millis(200)).await; + assert!( + !lookup.is_finished(), + "the lookup must wait for the creation, not load the directory being imported into" + ); + + tx.send(Ok(Bytes::from_static(b"COMMIT;"))).await.unwrap(); + drop(tx); + create.await.unwrap().unwrap(); + assert_eq!(lookup.await.unwrap().unwrap(), 1); + // the namespace was published into a fresh cache entry and is served normally + assert!(store.inner.store.contains_key(&foo)); + assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 1); + assert!(store.inner.in_flight.lock().is_empty()); + } + + /// Same situation, but the creation fails: the waiting lookup must report that the + /// namespace does not exist, and nothing must be left behind. + #[tokio::test] + async fn lookup_sees_failure_of_creation_even_if_the_entry_was_evicted() { + let tmp = tempfile::tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + + let (tx, rx) = mpsc::channel::>(8); + let dump = DumpSource::new(Box::new(ReceiverStream::new(rx))) + .with_importer(Some(DumpImporterKind::Streaming)); + let create = tokio::spawn({ + let store = store.clone(); + let foo = foo.clone(); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; + + store.inner.store.invalidate(&foo).await; + store.inner.store.run_pending_tasks().await; + + let lookup = tokio::spawn({ + let store = store.clone(); + async move { count_test_rows(&store, "foo").await } + }); + tokio::time::sleep(Duration::from_millis(200)).await; + assert!(!lookup.is_finished()); + + tx.send(Ok(Bytes::from_static(b"THIS IS NOT SQL;"))) + .await + .unwrap(); + drop(tx); + assert!(create.await.unwrap().is_err()); + assert!(matches!( + lookup.await.unwrap(), + Err(Error::NamespaceDoesntExist(_)) + )); + assert!(!store.exists(&foo).await); + // the cleanup runs on the blocking pool; give it a moment + for _ in 0..50 { + if !tmp.path().join("dbs").join("foo").exists() { + break; + } + tokio::time::sleep(Duration::from_millis(20)).await; + } + assert!(!tmp.path().join("dbs").join("foo").exists()); + assert!(store.inner.in_flight.lock().is_empty()); + } + + /// `destroy` is issued while the namespace is still being created. It must wait for the + /// creation and destroy its result: nothing left in the cache, on disk or in the metastore, + /// and the name can be created again. (Before: the result could be re-inserted into the + /// cache as a live namespace whose directory `destroy` had just removed.) + #[tokio::test] + async fn destroy_during_creation_destroys_the_result() { + let tmp = tempfile::tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + + let (tx, dump) = slow_dump(); + let create = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; + // make it the interesting case: the cache no longer holds the reserved entry + store.inner.store.invalidate(&foo).await; + store.inner.store.run_pending_tasks().await; + + let destroy = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { store.destroy(foo, true).await } + }); + tokio::time::sleep(Duration::from_millis(100)).await; + assert!(!destroy.is_finished(), "destroy must wait for the creation"); + + tx.send(Ok(Bytes::from_static(b"COMMIT;"))).await.unwrap(); + drop(tx); + create.await.unwrap().unwrap(); + destroy.await.unwrap().unwrap(); + + assert!(!store.exists(&foo).await); + assert!(!store.inner.store.contains_key(&foo)); + assert!(!tmp.path().join("dbs").join("foo").exists()); + assert!(store.inner.in_flight.lock().is_empty()); + assert!(matches!( + count_test_rows(&store, "foo").await, + Err(Error::NamespaceDoesntExist(_)) + )); + + // and the name is free again + let (tx, dump) = slow_dump(); + let create = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1); COMMIT;", + ))) + .await + .unwrap(); + drop(tx); + create.await.unwrap().unwrap(); + assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 1); + } + + /// A failed creation is undone before the name is released, so a retry issued the moment + /// the failure is reported neither races the cleanup nor finds leftovers. + #[tokio::test] + async fn retry_right_after_failure_starts_clean() { + let tmp = tempfile::tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + let dir = tmp.path().join("dbs").join("foo"); + + for attempt in 0..3 { + let (tx, dump) = slow_dump(); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1); NOT SQL;", + ))) + .await + .unwrap(); + drop(tx); + let res = store + .create(foo.clone(), RestoreOption::Dump(dump), Default::default()) + .await; + assert!(res.is_err(), "attempt {attempt}"); + // no waiting: the path is free and the name unknown as soon as `create` returns + assert!(!dir.exists(), "attempt {attempt}"); + assert!(!store.exists(&foo).await, "attempt {attempt}"); + } + + let (tx, dump) = slow_dump(); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1); COMMIT;", + ))) + .await + .unwrap(); + drop(tx); + store + .create(foo.clone(), RestoreOption::Dump(dump), Default::default()) + .await + .unwrap(); + assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 1); + assert!(!dir + .join(crate::namespace::incomplete::INCOMPLETE_MARKER) + .exists()); + } + + /// The config of a namespace linked to a shared schema cannot be *removed* while the schema + /// has pending migration jobs — but it must always be possible to *discard* it when its + /// creation did not complete, or the name would be stuck (`exists` true, no row, no data). + #[tokio::test] + async fn discard_ignores_the_guards_of_remove() { + let tmp = tempfile::tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let linked = NamespaceName::from_string("linked".into()).unwrap(); + let handle = store.inner.metadata.handle(linked.clone()).await; + handle + .store_and_maybe_flush( + Some(Arc::new(DatabaseConfig { + shared_schema_name: Some(NamespaceName::from_string("schema".into()).unwrap()), + ..Default::default() + })), + false, + ) + .await + .unwrap(); + assert!(store.exists(&linked).await); + + let metadata = store.inner.metadata.clone(); + let name = linked.clone(); + tokio::task::spawn_blocking(move || metadata.discard_blocking(name)) + .await + .unwrap() + .unwrap(); + assert!(!store.exists(&linked).await); + } + + /// The creating task is aborted mid-import (the request was cancelled). The reservation is + /// dropped unpublished: config discarded, directory discarded, name released — and a + /// lookup that was waiting sees "doesn't exist". + #[tokio::test] + async fn aborted_creation_is_undone() { + let tmp = tempfile::tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + let dir = tmp.path().join("dbs").join("foo"); + + let (tx, dump) = slow_dump(); + let create = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; + assert!(dir + .join(crate::namespace::incomplete::INCOMPLETE_MARKER) + .exists()); + + let lookup = tokio::spawn({ + let store = store.clone(); + async move { count_test_rows(&store, "foo").await } + }); + tokio::time::sleep(Duration::from_millis(100)).await; + assert!(!lookup.is_finished()); + + create.abort(); + assert!(create.await.unwrap_err().is_cancelled()); + + assert!(matches!( + lookup.await.unwrap(), + Err(Error::NamespaceDoesntExist(_)) + )); + // the cleanup ran on the blocking pool; the lookup's completion proves the lock was + // released after it, so by now everything is undone + assert!(!store.exists(&foo).await); + assert!(!dir.exists()); + assert!(store.inner.in_flight.lock().is_empty()); + + // the importer's executor thread is still unwinding its channel; the name is free anyway + let (tx, dump) = slow_dump(); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1); COMMIT;", + ))) + .await + .unwrap(); + drop(tx); + store + .create(foo.clone(), RestoreOption::Dump(dump), Default::default()) + .await + .unwrap(); + assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 1); + } + async fn create(store: &NamespaceStore, name: &str) -> NamespaceName { let namespace = NamespaceName::from_string(name.to_string()).unwrap(); store @@ -816,10 +1530,7 @@ pub(crate) mod test { store.inner.has_shutdown.store(true, Ordering::Relaxed); let handle = store.inner.metadata.handle(namespace.clone()).await; - let error = store - .load_namespace(&namespace, handle, RestoreOption::Latest) - .await - .unwrap_err(); + let error = store.load_namespace(&namespace, handle).await.unwrap_err(); assert!( matches!(error.as_ref(), Error::NamespaceStoreShutdown), @@ -961,13 +1672,16 @@ pub(crate) mod test { drop(lock); let error = request.await.unwrap().unwrap_err(); - assert!(matches!(error, Error::NamespaceDoesntExist(_)), "{error:?}"); + assert!( + matches!(error.as_ref(), Error::NamespaceDoesntExist(_)), + "{error:?}" + ); destroy.await.unwrap().unwrap(); assert!(!store.inner.store.contains_key(&namespace)); } #[tokio::test] - async fn with_reports_unavailable_not_missing_for_an_entry_left_empty() { + async fn with_loads_a_namespace_whose_cached_entry_was_left_empty() { let tmp = tempdir().unwrap(); let store = make_store(tmp.path()).await; let namespace = create(&store, "ns").await; @@ -977,59 +1691,154 @@ pub(crate) mod test { // The namespace is taken out but its emptied entry stays cached, as an // entry left behind by a fork that failed before storing its record: - // every lookup finds it again. + // nothing else is going to refill it. lock.take().unwrap().shutdown(false).await.unwrap(); drop(lock); - // The metastore still has the namespace: giving up is temporary, not - // "missing". - let error = request.await.unwrap().unwrap_err(); - assert!(matches!(error, Error::NamespaceUnavailable(_)), "{error:?}"); - assert!(Arc::ptr_eq( - &store.inner.store.get(&namespace).await.unwrap(), - &entry - )); + assert_eq!(request.await.unwrap().unwrap(), namespace); + // The empty entry was dropped and a fresh one loaded; it was not filled. + let cached = store.inner.store.get(&namespace).await.unwrap(); + assert!(!Arc::ptr_eq(&cached, &entry)); + assert!(cached.read().await.is_some()); + assert!(entry.read().await.is_none()); + } + + #[tokio::test(flavor = "multi_thread")] + async fn requests_waiting_on_one_left_empty_entry_share_one_reloaded_namespace() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let namespace = create(&store, "ns").await; + let entry = store.inner.store.get(&namespace).await.unwrap(); + let mut lock = entry.write().await; + settle(&store, &entry).await; + const REQUESTS: usize = 8; + let requests: Vec<_> = (0..REQUESTS) + .map(|_| { + tokio::spawn({ + let store = store.clone(); + let namespace = namespace.clone(); + async move { store.with(namespace, |ns| ns.stats.clone()).await } + }) + }) + .collect(); + wait_until("every request holds the entry", || { + Arc::strong_count(&entry) >= 2 + REQUESTS + }) + .await; + + // The namespace is taken out and its emptied entry stays cached: every + // request finds it, and every one of them may try to drop it. + lock.take().unwrap().shutdown(false).await.unwrap(); + drop(lock); + + let mut stats = Vec::with_capacity(REQUESTS); + for request in requests { + stats.push(request.await.unwrap().unwrap()); + } + // One namespace, loaded once, into one fresh entry. + let cached = store.inner.store.get(&namespace).await.unwrap(); + assert!(!Arc::ptr_eq(&cached, &entry)); + let loaded = cached.read().await.as_ref().unwrap().stats.clone(); + assert!(stats.iter().all(|stats| Arc::ptr_eq(stats, &loaded))); + assert!(entry.read().await.is_none()); } #[tokio::test] - async fn create_removes_its_record_when_shutdown_starts_before_its_load() { + async fn evict_if_still_empty_drops_only_the_cached_unlocked_empty_entry() { let tmp = tempdir().unwrap(); let store = make_store(tmp.path()).await; - let namespace = NamespaceName::from_string("ns".to_string()).unwrap(); + let namespace = create(&store, "ns").await; + let cached = |store: &NamespaceStore| { + let store = store.clone(); + let namespace = namespace.clone(); + async move { store.inner.store.get(&namespace).await } + }; - // `create`'s steps up to its load, then shutdown starts: the only - // place where a stored record has no loaded namespace behind it. - assert!(!store.inner.metadata.exists(&namespace).await); - let handle = store.inner.metadata.handle(namespace.clone()).await; - handle - .store(Arc::new(DatabaseConfig::default())) - .await - .unwrap(); + // A loaded cached entry is not empty: it stays. + let loaded = cached(&store).await.unwrap(); + store.evict_if_still_empty(&namespace, &loaded).await; + assert!(Arc::ptr_eq(&cached(&store).await.unwrap(), &loaded)); + + // An empty entry that is not the cached one leaves the cached empty + // entry alone. + let empty: NamespaceEntry = Default::default(); + store + .inner + .store + .insert(namespace.clone(), empty.clone()) + .await; + let other: NamespaceEntry = Default::default(); + store.evict_if_still_empty(&namespace, &other).await; + assert!(Arc::ptr_eq(&cached(&store).await.unwrap(), &empty)); + + // An empty cached entry whose lock is held (it may be being filled) + // stays. Evicting it would wait for that lock, so bound the call. + let lock = empty.write().await; + tokio::time::timeout( + Duration::from_secs(10), + store.evict_if_still_empty(&namespace, &empty), + ) + .await + .expect("evicting a locked entry must not wait for its lock"); + assert!(Arc::ptr_eq(&cached(&store).await.unwrap(), &empty)); + drop(lock); + + // Once nobody holds it, the empty cached entry is dropped. + store.evict_if_still_empty(&namespace, &empty).await; + assert!(!store.inner.store.contains_key(&namespace)); + } + + /// Shutdown starts while a creation is setting the namespace up. The creation notices it + /// at its commit point and is undone: no record is left behind, so a retry against a fresh + /// store on the same files creates the namespace (with its dump) instead of answering + /// "already exists". + #[tokio::test] + async fn create_interrupted_by_shutdown_leaves_no_record() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + + let (tx, dump) = slow_dump(); + let create = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; store.inner.has_shutdown.store(true, Ordering::Relaxed); + tx.send(Ok(Bytes::from_static(b"COMMIT;"))).await.unwrap(); + drop(tx); - let error = store - .load_created(&namespace, handle, RestoreOption::Latest) - .await - .unwrap_err(); + let error = create.await.unwrap().unwrap_err(); assert!( matches!(error.as_ref(), Error::NamespaceStoreShutdown), "{error:?}" ); - assert!(!store.inner.metadata.exists(&namespace).await); + assert!(!store.exists(&foo).await); + assert!(store.inner.in_flight.lock().is_empty()); - // A retry against a fresh store on the same files creates the - // namespace instead of answering "already exists". drop(store); let store = make_store(tmp.path()).await; + let (tx, dump) = slow_dump(); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1); COMMIT;", + ))) + .await + .unwrap(); + drop(tx); store - .create( - namespace.clone(), - RestoreOption::Latest, - DatabaseConfig::default(), - ) + .create(foo.clone(), RestoreOption::Dump(dump), Default::default()) .await .unwrap(); - assert!(store.inner.store.get(&namespace).await.is_some()); + assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 1); } #[tokio::test] @@ -1052,6 +1861,67 @@ pub(crate) mod test { assert!(!store.inner.metadata.exists(&namespace).await); } + /// An empty entry left cached (a fork that failed before storing its record leaves one) is + /// taken by the creation's reservation and filled with the new namespace, with its dump + /// applied. Before, `create` got the empty entry back from the cache and returned without + /// loading anything. + #[tokio::test] + async fn create_over_a_left_empty_entry_applies_its_dump() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + let empty: NamespaceEntry = Default::default(); + store.inner.store.insert(foo.clone(), empty.clone()).await; + + let (tx, dump) = slow_dump(); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1), (2); COMMIT;", + ))) + .await + .unwrap(); + drop(tx); + store + .create(foo.clone(), RestoreOption::Dump(dump), Default::default()) + .await + .unwrap(); + + assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 2); + assert!(store.inner.in_flight.lock().is_empty()); + } + + /// Creating a namespace that exists but is not loaded is refused, and the empty entry the + /// reservation put in the cache for it is removed again, so the namespace stays reachable. + #[tokio::test] + async fn create_of_an_existing_unloaded_namespace_leaves_no_empty_entry() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let namespace = create(&store, "ns").await; + store.inner.store.invalidate(&namespace).await; + store.inner.store.run_pending_tasks().await; + + let error = store + .create( + namespace.clone(), + RestoreOption::Latest, + DatabaseConfig::default(), + ) + .await + .unwrap_err(); + + assert!( + matches!(error, Error::NamespaceAlreadyExist(_)), + "{error:?}" + ); + assert!(!store.inner.store.contains_key(&namespace)); + assert_eq!( + store + .with(namespace.clone(), |ns| ns.name().clone()) + .await + .unwrap(), + namespace + ); + } + #[tokio::test] async fn with_reports_shutdown_when_the_store_shuts_down_while_waiting() { let tmp = tempdir().unwrap(); @@ -1072,7 +1942,10 @@ pub(crate) mod test { drop(lock); let error = request.await.unwrap().unwrap_err(); - assert!(matches!(error, Error::NamespaceStoreShutdown), "{error:?}"); + assert!( + matches!(error.as_ref(), Error::NamespaceStoreShutdown), + "{error:?}" + ); shutdown.await.unwrap().unwrap(); } @@ -1151,26 +2024,12 @@ pub(crate) mod test { // `fork`'s cleanup on failure calls `block_in_place`, which panics on // the current-thread runtime and would hide the real error. #[tokio::test(flavor = "multi_thread")] - async fn fork_reports_unavailable_when_its_source_is_emptied_between_its_loads() { + async fn fork_loads_a_source_whose_cached_entry_was_left_empty() { let tmp = tempdir().unwrap(); let store = make_store(tmp.path()).await; let from = create(&store, "from").await; - let to = NamespaceName::from_string("to".to_string()).unwrap(); - // Holding the destination entry's lock stops the fork after it loaded - // its source through `with` and before it reads the source from its - // own lookup. - let to_entry: NamespaceEntry = Default::default(); - store.inner.store.insert(to.clone(), to_entry.clone()).await; - let to_lock = to_entry.write().await; - let fork = start_waiting(&store, &to_entry, { - let (from, to) = (from.clone(), to.clone()); - move |store| async move { store.fork(from, to, DatabaseConfig::default(), None).await } - }) - .await; - - // The source is taken out, and its emptied entry stays cached. - let from_entry = store.inner.store.get(&from).await.unwrap(); - from_entry + let entry = store.inner.store.get(&from).await.unwrap(); + entry .write() .await .take() @@ -1178,10 +2037,26 @@ pub(crate) mod test { .shutdown(false) .await .unwrap(); - drop(to_lock); + let to = NamespaceName::from_string("to".to_string()).unwrap(); - let error = fork.await.unwrap().unwrap_err(); - assert!(matches!(error, Error::NamespaceUnavailable(_)), "{error:?}"); + store + .fork(from.clone(), to.clone(), DatabaseConfig::default(), None) + .await + .unwrap(); + + assert_eq!( + store + .with(to.clone(), |ns| ns.name().clone()) + .await + .unwrap(), + to + ); + // The source was reloaded into a fresh entry; the left-empty one was + // not filled. + let cached = store.inner.store.get(&from).await.unwrap(); + assert!(!Arc::ptr_eq(&cached, &entry)); + assert!(cached.read().await.is_some()); + assert!(entry.read().await.is_none()); } #[tokio::test] diff --git a/libsql-server/tests/namespaces/dumps.rs b/libsql-server/tests/namespaces/dumps.rs index 958d24daab..c9410c392c 100644 --- a/libsql-server/tests/namespaces/dumps.rs +++ b/libsql-server/tests/namespaces/dumps.rs @@ -17,11 +17,11 @@ use crate::common::http::{Client, Response}; use crate::common::net::{TurmoilAcceptor, TurmoilConnector}; use crate::namespaces::{make_primary, make_primary_with_db_config}; -const BUFFERED: Option<&str> = Some("buffered"); -const STREAMING: Option<&str> = Some("streaming"); +pub(super) const BUFFERED: Option<&str> = Some("buffered"); +pub(super) const STREAMING: Option<&str> = Some("streaming"); /// `POST /v1/namespaces/:ns/create` with `dump_url` and, optionally, `dump_importer`. -async fn create_from_dump( +pub(super) async fn create_from_dump( client: &Client, ns: &str, dump_url: &str, @@ -39,17 +39,22 @@ async fn create_from_dump( .await } -fn file_url(path: &Path) -> String { +pub(super) fn file_url(path: &Path) -> String { format!("file:{}", path.display()) } -fn sim() -> Sim<'static> { +pub(super) fn sim() -> Sim<'static> { Builder::new() .simulation_duration(Duration::from_secs(1000)) + // Dumps are served in many small chunks that the server only starts reading once the + // namespace is set up (fsyncs, file creation — real time, during which turmoil keeps + // advancing simulated time and the dump store keeps writing). Real TCP would apply + // back-pressure; turmoil panics once its socket buffer (64 segments by default) is full. + .tcp_capacity(4096) .build() } -async fn count_rows(ns: &str, table: &str) -> anyhow::Result { +pub(super) async fn count_rows(ns: &str, table: &str) -> anyhow::Result { let db = Database::open_remote_with_connector( &format!("http://{ns}.primary:8080"), "", @@ -69,7 +74,7 @@ fn make_dump_store(sim: &mut Sim, chunks: Vec>) { } /// Like [`make_dump_store`], pausing `pause` (simulated time) before each chunk. -fn make_dump_store_paced( +pub(super) fn make_dump_store_paced( sim: &mut Sim, chunks: Vec>, pause: Duration, @@ -124,7 +129,39 @@ fn make_dump_store_chunked(sim: &mut Sim, dump: &'static str, chunk_size: usize) ); } -const SIMPLE_DUMP: &str = r#" +/// Serve `dump` from `dump-store:8080` in 64-byte chunks, 100ms (simulated) apart: with +/// turmoil's up-to-100ms message latency this keeps a creation in flight for a couple of +/// seconds, long enough for other requests to be issued while it runs. +pub(super) fn make_slow_dump_store(sim: &mut Sim, dump: &'static str) { + make_dump_store_paced( + sim, + dump.as_bytes() + .chunks(64) + .map(|c| Ok(Bytes::copy_from_slice(c))) + .collect(), + Duration::from_millis(100), + ); +} + +/// Ten rows, importable by both importers (no "attach" anywhere), ~1.1 KB so that +/// [`make_slow_dump_store`] delivers it in ~18 chunks. +pub(super) const SLOW_DUMP: &str = r#"PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, note TEXT); +INSERT INTO test VALUES (1, 'one', 'the first row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (2, 'two', 'the second row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (3, 'three', 'the third row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (4, 'four', 'the fourth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (5, 'five', 'the fifth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (6, 'six', 'the sixth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (7, 'seven', 'the seventh row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (8, 'eight', 'the eighth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (9, 'nine', 'the ninth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (10, 'ten', 'the tenth row of a dump that takes a while to arrive'); +COMMIT; +"#; + +pub(super) const SIMPLE_DUMP: &str = r#" PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; CREATE TABLE test (x); @@ -745,7 +782,7 @@ fn load_dump_with_nested_case_streaming() { /// Exercises framing across arbitrary HTTP body chunk boundaries, including inside multibyte /// characters, string literals with semicolons, comments and a trigger body. -const CHUNKY_DUMP: &str = r#"PRAGMA foreign_keys=OFF; +pub(super) const CHUNKY_DUMP: &str = r#"PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -- a comment; with a semicolon CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT); @@ -1437,68 +1474,88 @@ fn streaming_failure_under_backpressure() { sim.run().unwrap(); } -/// The admin request is abandoned while the import is still streaming in. The executor thread -/// must notice the closed channel, roll back and release the connection, so the server stays -/// healthy and the namespace can be used afterwards instead of being wedged by a half-open -/// transaction. -#[test] -fn streaming_cancelled_request_rolls_back() { +/// The admin request is abandoned while the dump is still being transferred. The namespace +/// must not survive in any form: the importer rolls back and releases its connection, the +/// configurator removes the directory and the store never persists the config, so the name is +/// immediately reusable (see `docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`). +fn cancelled_create_leaves_no_trace_with(importer: Option<&'static str>) { let mut sim = sim(); let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); make_primary(&mut sim, tmp.path().to_path_buf()); - // Deliver the dump slowly (64-byte chunks, 50ms apart) so the request is still in flight - // when it is abandoned. Few, large chunks also keep the number of unread segments below - // turmoil's simulated socket buffer once nobody reads them anymore. - make_dump_store_paced( - &mut sim, - CHUNKY_DUMP - .as_bytes() - .chunks(64) - .map(|c| Ok(Bytes::copy_from_slice(c))) - .collect(), - Duration::from_millis(50), - ); + // Deliver the dump slowly so the request is still in flight when it is abandoned. Few, + // large chunks also keep the number of unread segments below turmoil's simulated socket + // buffer once nobody reads them anymore. + make_slow_dump_store(&mut sim, SLOW_DUMP); sim.client("client", async move { let client = Client::new(); + let dir = tmp_path.join("dbs").join("foo"); + // Cancel once the creation is provably under way: the namespace directory exists and + // is marked incomplete (turmoil's random message latency makes a fixed delay either + // too early or too late). + let marker = dir.join(super::lifecycle::INCOMPLETE_MARKER); + let request = create_from_dump(&client, "foo", "http://dump-store:8080/", importer); let aborted = tokio::time::timeout( - Duration::from_millis(100), - create_from_dump(&client, "foo", "http://dump-store:8080/", STREAMING), + Duration::from_secs(10), + futures::future::select( + Box::pin(request), + Box::pin(async { + while !marker.exists() { + tokio::time::sleep(Duration::from_millis(20)).await; + } + }), + ), ) - .await; - assert!(aborted.is_err(), "the request should still be in flight"); + .await + .expect("the creation should have started"); + assert!( + matches!(aborted, futures::future::Either::Right(_)), + "the request should still be in flight" + ); + // `aborted` holds the request future: dropping it is the cancellation. + drop(aborted); // Let the server notice the closed connection (simulated time) and the executor thread // roll back and drop its connection (real time: the sim clock doesn't wait for it). tokio::time::sleep(Duration::from_secs(2)).await; std::thread::sleep(Duration::from_millis(300)); - // Depending on where the request was cut, the namespace was registered (pre-existing - // behavior: the metastore row survives a failed create) or not. Either way it must be - // usable now: no lingering write transaction, no partial data. + // The namespace does not exist, for the admin API, for users, and on disk. let resp = client - .post_raw("http://primary:9090/v1/namespaces/foo/create", json!({})) + .get("http://primary:9090/v1/namespaces/foo/config") .await?; - assert!( - resp.status() == StatusCode::OK || resp.status() == StatusCode::BAD_REQUEST, - "unexpected status {}", - resp.status() - ); - assert!(count_rows("foo", "test").await.is_err()); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + let err = count_rows("foo", "test").await.unwrap_err().to_string(); + assert!(err.contains("doesn't exist"), "unexpected error: {err}"); + super::lifecycle::wait_until_gone(&dir); + + // ... so the same name can be created again, from the same dump, and used. + let resp = create_from_dump(&client, "foo", "http://dump-store:8080/", importer).await?; + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(count_rows("foo", "test").await?, 10); let db = Database::open_remote_with_connector("http://foo.primary:8080", "", TurmoilConnector)?; let conn = db.connect()?; - conn.execute("create table after_cancel (x)", ()).await?; - conn.execute("insert into after_cancel values (1)", ()) - .await?; - assert_eq!(count_rows("foo", "after_cancel").await?, 1); - - // and other namespaces are unaffected - let resp = create_from_dump(&client, "bar", "http://dump-store:8080/", STREAMING).await?; - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!(count_rows("bar", "test").await?, 3); + conn.execute( + "insert into test values (11, 'eleven', 'written after the cancelled attempt')", + (), + ) + .await?; + assert_eq!(count_rows("foo", "test").await?, 11); + assert!(!marker.exists()); Ok(()) }); sim.run().unwrap(); } + +#[test] +fn cancelled_create_leaves_no_trace() { + cancelled_create_leaves_no_trace_with(BUFFERED); +} + +#[test] +fn cancelled_create_leaves_no_trace_streaming() { + cancelled_create_leaves_no_trace_with(STREAMING); +} diff --git a/libsql-server/tests/namespaces/lifecycle.rs b/libsql-server/tests/namespaces/lifecycle.rs new file mode 100644 index 0000000000..37e53fbcb4 --- /dev/null +++ b/libsql-server/tests/namespaces/lifecycle.rs @@ -0,0 +1,389 @@ +//! Namespace creation is all-or-nothing: after a failed, cancelled or crashed +//! `POST /v1/namespaces/:ns/create` the namespace either does not exist (no config, no +//! directory, name reusable) or is complete. See `docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`. + +use std::path::Path; +use std::time::Duration; + +use hyper::StatusCode; +use serde_json::json; +use tempfile::tempdir; + +use crate::common::http::Client; +use crate::namespaces::dumps::{ + count_rows, create_from_dump, file_url, make_slow_dump_store, sim, BUFFERED, SIMPLE_DUMP, + SLOW_DUMP, STREAMING, +}; +use crate::namespaces::{make_primary, make_single_namespace_primary}; + +pub(super) const INCOMPLETE_MARKER: &str = ".incomplete"; + +const BROKEN_DUMP: &str = r#" + BEGIN TRANSACTION; + CREATE TABLE test (x); + INSERT INTO test VALUES(1); + THIS IS NOT SQL; + COMMIT;"#; + +/// [`SLOW_DUMP`] with a syntax error right before the end. +const SLOW_BROKEN_DUMP: &str = r#"PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, note TEXT); +INSERT INTO test VALUES (1, 'one', 'the first row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (2, 'two', 'the second row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (3, 'three', 'the third row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (4, 'four', 'the fourth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (5, 'five', 'the fifth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (6, 'six', 'the sixth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (7, 'seven', 'the seventh row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (8, 'eight', 'the eighth row of a dump that takes a while to arrive'); +INSERT INTO test VALUES (9, 'nine', 'the ninth row of a dump that takes a while to arrive'); +THIS IS NOT SQL; +COMMIT; +"#; + +/// Directory removal after an aborted creation is handed to the runtime; poll (real time, the +/// blocking pool is not driven by the simulated clock) until it is gone. +pub(super) fn wait_until_gone(path: &Path) { + for _ in 0..100 { + if !path.exists() { + return; + } + std::thread::sleep(Duration::from_millis(20)); + } + panic!("{} still exists", path.display()); +} + +/// After a creation *failed* (as opposed to being cancelled) nothing of it is left by the time +/// the error is reported: no polling here. +async fn assert_absent(client: &Client, tmp: &Path, ns: &str) -> anyhow::Result<()> { + assert!( + !tmp.join("dbs").join(ns).exists(), + "{ns} directory left behind" + ); + let resp = client + .get(&format!("http://primary:9090/v1/namespaces/{ns}/config")) + .await?; + assert_eq!( + resp.status(), + StatusCode::NOT_FOUND, + "{ns} should not exist" + ); + let err = count_rows(ns, "test").await.unwrap_err().to_string(); + assert!(err.contains("doesn't exist"), "unexpected error: {err}"); + Ok(()) +} + +/// A dump that fails to import leaves nothing behind, and the name can be reused right away. +/// Before this change the config survived and the next access lazily created an empty database. +fn failed_create_leaves_no_trace_with(importer: Option<&'static str>, shared_schema: bool) { + let mut sim = sim(); + let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); + std::fs::write(tmp_path.join("broken.sql"), BROKEN_DUMP).unwrap(); + std::fs::write(tmp_path.join("good.sql"), SIMPLE_DUMP).unwrap(); + make_primary(&mut sim, tmp.path().to_path_buf()); + + sim.client("client", async move { + let client = Client::new(); + let create = |dump: &str| { + let mut body = json!({ "dump_url": file_url(&tmp_path.join(dump)), "shared_schema": shared_schema }); + if let Some(importer) = importer { + body["dump_importer"] = json!(importer); + } + client.post_raw("http://primary:9090/v1/namespaces/foo/create", body) + }; + + let resp = create("broken.sql").await?; + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + assert_absent(&client, &tmp_path, "foo").await?; + + let resp = create("good.sql").await?; + assert_eq!( + resp.status(), + StatusCode::OK, + "{}", + resp.body_string().await.unwrap_or_default() + ); + assert_eq!(count_rows("foo", "test").await?, 1); + assert!(!tmp_path.join("dbs/foo").join(INCOMPLETE_MARKER).exists()); + Ok(()) + }); + + sim.run().unwrap(); +} + +#[test] +fn failed_create_leaves_no_trace() { + failed_create_leaves_no_trace_with(BUFFERED, false); +} + +#[test] +fn failed_create_leaves_no_trace_streaming() { + failed_create_leaves_no_trace_with(STREAMING, false); +} + +#[test] +fn failed_create_leaves_no_trace_shared_schema() { + failed_create_leaves_no_trace_with(STREAMING, true); +} + +/// Requests for a namespace that is being created wait for the outcome: a second `create` +/// for the same name is rejected once the first one succeeded, and a user request issued +/// mid-import sees the complete data. +#[test] +fn concurrent_requests_wait_for_creation() { + let mut sim = sim(); + let tmp = tempdir().unwrap(); + make_primary(&mut sim, tmp.path().to_path_buf()); + make_slow_dump_store(&mut sim, SLOW_DUMP); + + sim.client("client", async move { + let client = Client::new(); + let slow = create_from_dump(&client, "foo", "http://dump-store:8080/", STREAMING); + // issued while the import is in progress (it takes ~2s of simulated time) + let second = async { + tokio::time::sleep(Duration::from_millis(500)).await; + client + .post_raw("http://primary:9090/v1/namespaces/foo/create", json!({})) + .await + }; + let user = async { + tokio::time::sleep(Duration::from_millis(500)).await; + count_rows("foo", "test").await + }; + let (slow, second, user) = tokio::join!(slow, second, user); + assert_eq!(slow?.status(), StatusCode::OK); + let second = second?; + assert_eq!(second.status(), StatusCode::BAD_REQUEST); + assert!(second.body_string().await?.contains("already exists")); + assert_eq!(user?, 10); + Ok(()) + }); + + sim.run().unwrap(); +} + +/// If the creation that others are waiting on fails, the waiters observe a namespace that does +/// not exist, and a subsequent `create` of the same name succeeds. +#[test] +fn concurrent_create_succeeds_after_failure() { + let mut sim = sim(); + let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); + std::fs::write(tmp_path.join("good.sql"), SIMPLE_DUMP).unwrap(); + make_primary(&mut sim, tmp.path().to_path_buf()); + make_slow_dump_store(&mut sim, SLOW_BROKEN_DUMP); + + sim.client("client", async move { + let client = Client::new(); + let slow = create_from_dump(&client, "foo", "http://dump-store:8080/", STREAMING); + // issued while the import is in progress (it takes ~2s of simulated time) + let user = async { + tokio::time::sleep(Duration::from_millis(500)).await; + count_rows("foo", "test").await + }; + let (slow, user) = tokio::join!(slow, user); + assert_eq!(slow?.status(), StatusCode::BAD_REQUEST); + let err = user.unwrap_err().to_string(); + assert!(err.contains("doesn't exist"), "unexpected error: {err}"); + assert_absent(&client, &tmp_path, "foo").await?; + + let resp = create_from_dump( + &client, + "foo", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(count_rows("foo", "test").await?, 1); + Ok(()) + }); + + sim.run().unwrap(); +} + +/// A directory left by a creation the process died in the middle of (it still carries the +/// marker, there is no config for it) is discarded by the next creation of that name, and is +/// not adopted as a namespace when the metastore is rebuilt from the filesystem. +#[test] +fn crash_remnant_is_discarded() { + let mut sim = sim(); + let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); + std::fs::write(tmp_path.join("good.sql"), SIMPLE_DUMP).unwrap(); + let remnant = tmp_path.join("dbs/foo"); + std::fs::create_dir_all(&remnant).unwrap(); + for f in [INCOMPLETE_MARKER, ".sentinel", "data", "wallog"] { + std::fs::write(remnant.join(f), b"junk").unwrap(); + } + make_primary(&mut sim, tmp.path().to_path_buf()); + + sim.client("client", async move { + let client = Client::new(); + // not recovered as a namespace at startup (the metastore was empty) + let resp = client + .get("http://primary:9090/v1/namespaces/foo/config") + .await?; + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + + let resp = create_from_dump( + &client, + "foo", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!( + resp.status(), + StatusCode::OK, + "{}", + resp.body_string().await.unwrap_or_default() + ); + assert_eq!(count_rows("foo", "test").await?, 1); + assert!(!remnant.join(INCOMPLETE_MARKER).exists()); + Ok(()) + }); + + sim.run().unwrap(); +} + +/// Directories without the marker are never touched by a creation, whatever is in them. +#[test] +fn unmarked_directory_is_left_alone() { + let mut sim = sim(); + let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); + std::fs::write(tmp_path.join("good.sql"), SIMPLE_DUMP).unwrap(); + let dir = tmp_path.join("dbs/foo"); + std::fs::create_dir_all(&dir).unwrap(); + std::fs::write(dir.join("keep.txt"), b"precious").unwrap(); + make_primary(&mut sim, tmp.path().to_path_buf()); + + sim.client("client", async move { + let client = Client::new(); + // No database in there, so the import proceeds into the existing directory ... + let resp = create_from_dump( + &client, + "foo", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(count_rows("foo", "test").await?, 1); + // ... and whatever was in it is left alone, before and after. + assert_eq!(std::fs::read(dir.join("keep.txt"))?, b"precious"); + assert!(!dir.join(INCOMPLETE_MARKER).exists()); + Ok(()) + }); + + sim.run().unwrap(); +} + +/// A marker on a namespace that *is* known to the metastore (the process died between +/// persisting the config and removing the marker) is harmless: `create` rejects the name, +/// the data is served, and the marker is dropped when the namespace is next loaded. +#[test] +fn marker_on_published_namespace_is_ignored() { + let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); + std::fs::write(tmp_path.join("good.sql"), SIMPLE_DUMP).unwrap(); + let marker = tmp_path.join("dbs/foo").join(INCOMPLETE_MARKER); + + let mut first = sim(); + make_primary(&mut first, tmp.path().to_path_buf()); + first.client("client", { + let tmp_path = tmp_path.clone(); + let marker = marker.clone(); + async move { + let client = Client::new(); + let resp = create_from_dump( + &client, + "foo", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!(resp.status(), StatusCode::OK); + assert!(!marker.exists()); + + // simulate a crash right after the config was persisted + std::fs::write(&marker, b"").unwrap(); + let resp = create_from_dump( + &client, + "foo", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + assert!(resp.body_string().await?.contains("already exists")); + assert_eq!(count_rows("foo", "test").await?, 1); + assert!(marker.exists(), "the marker is only removed on load"); + Ok(()) + } + }); + first.run().unwrap(); + drop(first); // the first server must be gone before the second opens the same files + + // restart: nothing is loaded yet, the marker is still there and the metastore knows the + // name. A `create` must be rejected on the strength of the metastore alone (not wipe the + // directory); then the namespace loads and the stale marker goes away. + let mut restarted = sim(); + make_primary(&mut restarted, tmp.path().to_path_buf()); + restarted.client("client", async move { + let client = Client::new(); + let resp = create_from_dump( + &client, + "foo", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + assert!(marker.exists(), "rejected before touching the directory"); + assert_eq!(count_rows("foo", "test").await?, 1); + wait_until_gone(&marker); + Ok(()) + }); + restarted.run().unwrap(); +} + +/// Single-namespace mode: `create` of the default namespace is a config upsert, but creating +/// it *from a dump* while it already exists must be rejected rather than silently skipping the +/// import (which is what happened before). +#[test] +fn single_namespace_mode_rejects_dump_into_existing_namespace() { + let mut sim = sim(); + let tmp = tempdir().unwrap(); + let tmp_path = tmp.path().to_path_buf(); + std::fs::write(tmp_path.join("good.sql"), SIMPLE_DUMP).unwrap(); + make_single_namespace_primary(&mut sim, tmp.path().to_path_buf()); + + sim.client("client", async move { + let client = Client::new(); + // config upsert of the (already created) default namespace still works + let resp = client + .post_raw( + "http://primary:9090/v1/namespaces/default/create", + json!({ "max_db_size": "1mb" }), + ) + .await?; + assert_eq!(resp.status(), StatusCode::OK); + + let resp = create_from_dump( + &client, + "default", + &file_url(&tmp_path.join("good.sql")), + STREAMING, + ) + .await?; + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + assert!(resp.body_string().await?.contains("already exists")); + Ok(()) + }); + + sim.run().unwrap(); +} diff --git a/libsql-server/tests/namespaces/mod.rs b/libsql-server/tests/namespaces/mod.rs index c33cc229c3..fa03c9b765 100644 --- a/libsql-server/tests/namespaces/mod.rs +++ b/libsql-server/tests/namespaces/mod.rs @@ -1,6 +1,7 @@ #![allow(deprecated)] mod dumps; +mod lifecycle; mod meta; mod shared_schema; @@ -20,6 +21,16 @@ fn make_primary(sim: &mut Sim, path: PathBuf) { } fn make_primary_with_db_config(sim: &mut Sim, path: PathBuf, db_config: DbConfig) { + make_primary_with(sim, path, db_config, false); +} + +/// A primary running in single-namespace mode (`--disable-namespaces`): only the default +/// namespace exists, and it is created at startup. +fn make_single_namespace_primary(sim: &mut Sim, path: PathBuf) { + make_primary_with(sim, path, DbConfig::default(), true); +} + +fn make_primary_with(sim: &mut Sim, path: PathBuf, db_config: DbConfig, single_namespace: bool) { init_tracing(); sim.host("primary", move || { let path = path.clone(); @@ -41,8 +52,8 @@ fn make_primary_with_db_config(sim: &mut Sim, path: PathBuf, db_config: DbConfig acceptor: TurmoilAcceptor::bind(([0, 0, 0, 0], 4567)).await?, tls_config: None, }), - disable_namespaces: false, - disable_default_namespace: true, + disable_namespaces: single_namespace, + disable_default_namespace: !single_namespace, ..Default::default() }; From 2172fa5466f27e4084fcfb14b383c680a70db30f Mon Sep 17 00:00:00 2001 From: Tomasz Szymczyszyn Date: Tue, 13 Oct 2026 20:38:25 +0200 Subject: [PATCH 2/5] docs: atomic namespace creation design and admin API contract Adds docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md (design, failure matrix, concurrency analysis, the eviction mechanism, and what the adversarial review changed), states the all-or-nothing creation contract and the single-namespace-mode behaviour in ADMIN_API.md, and marks the lifecycle items of the streaming dump import design (section 13) as fixed. --- docs/ADMIN_API.md | 19 ++ docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md | 349 +++++++++++++++++++++++++ docs/STREAMING_DUMP_IMPORT_DESIGN.md | 8 +- 3 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md diff --git a/docs/ADMIN_API.md b/docs/ADMIN_API.md index 651f43ebae..c15404aa13 100644 --- a/docs/ADMIN_API.md +++ b/docs/ADMIN_API.md @@ -53,6 +53,25 @@ Both importers produce the same data. Known differences: - invalid UTF-8 or NUL bytes yield `400` (buffered: `500`), and statements that return rows are executed with their rows discarded (buffered: `500`). +Creation is all-or-nothing. The namespace becomes visible, and its configuration is persisted, +only after it has been fully set up (including the dump import). If the request fails, is +cancelled by the client, or the server dies while it is in flight, the namespace either does not +exist (its name can be created again right away — a failed attempt is fully undone before the +error is returned) or is complete — never partially imported. Requests addressed to a namespace +while it is being created wait for the outcome. Directories of creations the server died in the +middle of are discarded at the next start (`/.discarded/` holds them until they are +deleted). For callers: + +- `2xx`: the namespace is complete; +- any other outcome, including a lost connection: retry the same request; a + `400 Namespace already exists` on the retry means the earlier attempt did complete. + +In single-namespace mode (`--disable-namespaces`) creating the default namespace is a +configuration upsert and always succeeds, except with a `dump_url`: a dump can only be imported +into a namespace that does not exist yet, so that request is rejected like any other. + +See `docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`. + ```HTTP DELETE /v1/namespaces/:namespace ``` diff --git a/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md b/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md new file mode 100644 index 0000000000..b022460951 --- /dev/null +++ b/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md @@ -0,0 +1,349 @@ +# Atomic namespace creation for `libsql-server` + +Stacked on `tszymczyszyn/streaming-dump-importer` (PR #51). Fixes the pre-existing lifecycle gap described in PR #51's design doc §13 and the review walkthrough: a failed, cancelled or crashed `POST /v1/namespaces/:ns/create` could leave a *ghost* namespace (metastore row without data), a directory without a row, or both. Sections marked *as built* note where the implementation differs from the sketches; §9 records what the adversarial review of PR #53 changed. + +--- + +## 1. Problem + + +`NamespaceStore::create` persists the namespace config **first** and only then runs the configurator's `setup` (directory, logger, connections, dump import). Three resources are mutated without a common commit point: + +| Resource | Written at | Cleaned on error | Cleaned on cancellation | Cleaned after crash | +|---|---|---|---|---| +| metastore row (`namespace_configs`) | start of `create` | **no** | **no** | n/a (persisted) | +| `dbs//` + `.sentinel` + SQLite/WAL/log files | during `setup` | primary only, if the dir was fresh | **no** (future dropped, `Err` branch never runs) | **no** | +| cache entry (`NamespaceEntry`) | end of `load_namespace` | n/a | n/a | n/a | + +Consequences: a failed create reserves the name forever (`NamespaceAlreadyExist` on retry) while user traffic lazily materialises an **empty** database; a cancelled create can leave any prefix of the resources; a client cannot tell from a non-200 whether the namespace now exists. `SchemaConfigurator::setup` has no cleanup at all. `fork` has a drop guard for the row but uses `block_in_place`, which panics on a current-thread runtime. + +Both dump importers run inside this sequence; the problem is independent of PR #51. + +## 2. Goals + +- **Contract:** after `create` returns a non-2xx, or the connection is lost, the namespace is either *absent* (no row, no data, name reusable) or *complete* (row persisted, data complete, serving). Never partial. +- Cancellation-safe (dropping the request future cleans up) and crash-tolerant (a process crash mid-import never blocks a retry). +- No lock-step changes to clients, replication, the metastore schema or the `DatabaseConfig` protobuf. +- Small: reuse the pattern `fork` already uses; one mechanism for `create` and `fork`. + +Non-goals: a server-side import timeout; idempotency keys / async create jobs; bottomless (not used in our deployment; untested with this change). The moka eviction hazard shared with `reset`/`fork` turned out to need fixing (§8). + +## 3. Design in one paragraph + + +Make the **metastore write the commit point** and make everything before it reversible. `create` reserves the name by write-locking its cache entry, puts the config in the metastore's *in-memory* map only (so `setup` can read it), runs `setup`, and only on success **flushes the row** and installs the namespace. A `Reservation` drop guard undoes the in-memory config if the future ends any other way — error *or* cancellation — and releases the lock only after that, so waiters never observe a half-built namespace. The filesystem gets the same treatment one layer down: `setup` wraps a brand-new directory in a `FreshDir` guard that removes it on drop. For crashes, a brand-new directory carries an `.incomplete` marker until the row is flushed; the next `create` of that name discards a marked directory. + +``` +create(name, restore, config) +│ +├─ Reservation::acquire(name) lock cache entry; reject if loaded or row exists +├─ handle = metadata.handle(name) ─┐ in-memory only; nothing on disk +├─ handle.store_and_maybe_flush(cfg, false) ┘ +├─ configurator.discard_incomplete(name) remove `dbs/` if it carries `.incomplete` +├─ ns = make_namespace(...) setup: FreshDir::begin → mkdir + marker … import … keep() +├─ handle.flush() ◄── COMMIT POINT: row persisted +├─ ns.mark_complete() remove `.incomplete` (best effort) +└─ reservation.publish(ns) entry := Some(ns); lock released + any Err / drop above ⇒ Reservation::drop ⇒ metadata.remove(name), then release lock + any Err / drop inside setup ⇒ FreshDir::drop ⇒ remove_dir_all(dbs/) +``` + +## 4. Components + +### 4.1 `Reservation` (store.rs) — replaces `fork`'s ad-hoc `Bomb` + +```rust +/// A namespace name reserved for a creation or fork in progress. +/// +/// Holding it holds the name's cache entry write-locked: user requests, a second create, +/// destroy and shutdown all wait until the outcome is known. `publish` installs the finished +/// namespace. Dropping it unpublished (error or cancelled request) removes the in-memory +/// config and only then releases the lock, so waiters see "doesn't exist", never a partial one. +struct Reservation { + guard: Option>>, + metadata: MetaStore, + name: NamespaceName, +} + +impl Reservation { + async fn acquire(store: &NamespaceStore, name: NamespaceName) -> crate::Result { + let entry = store.inner.store.get_with(name.clone(), async { Default::default() }).await; + let guard = entry.write_arc().await; + if guard.is_some() || store.inner.metadata.exists(&name).await { + return Err(Error::NamespaceAlreadyExist(name.to_string())); + } + Ok(Self { guard: Some(guard), metadata: store.inner.metadata.clone(), name }) + } + + fn publish(mut self, ns: Namespace) { + self.guard.take().expect("published once").replace(ns); + } +} + +impl Drop for Reservation { + fn drop(&mut self) { + let Some(guard) = self.guard.take() else { return }; + let (metadata, name) = (self.metadata.clone(), self.name.clone()); + tracing::warn!(namespace = %name, "namespace creation did not complete; discarding it"); + let cleanup = move || { + if let Err(e) = metadata.remove(name.clone()) { + tracing::error!(namespace = %name, "failed to discard namespace config: {e}"); + } + drop(guard); // release only once the name no longer exists + }; + match tokio::runtime::Handle::try_current() { + Ok(rt) => { rt.spawn_blocking(cleanup); } + Err(_) => cleanup(), + } + } +} +``` + +Why `write_arc`: the guard must outlive the `create` future (it moves into the cleanup task). Requires `async-lock = "3"` in `libsql-server/Cargo.toml` (3.4.0 is already in the lockfile transitively; `proxy.rs`'s `RwLockUpgradableReadGuard::upgrade` is unchanged in 3.x). + +`MetaStore::remove` takes blocking locks, hence `spawn_blocking` (no `block_in_place`, so it also works on turmoil's current-thread runtime). It deletes the row if one exists and the in-memory entry; both are what we want in every abort path, including "flush succeeded but publish didn't" (then the row is deleted again and the complete directory becomes a marked orphan, see §6). + +### 4.2 `create` (store.rs) + +```rust +pub async fn create(&self, namespace, restore_option, db_config) -> crate::Result<()> { + shutdown check — unchanged + shared_schema_name ⇒ fork(…) — unchanged (fork now uses Reservation, §4.6) + + // Single-namespace mode / default namespace: `create` is an idempotent config upsert of a + // namespace that always exists. Keep today's path for it, but only for `Latest`: creating + // *from a dump* must never silently skip the import because the namespace is already loaded + // (today it does), so dump creates always take the reserving path below. + if (self.inner.allow_lazy_creation || namespace == NamespaceName::default()) + && matches!(restore_option, RestoreOption::Latest) + { + let handle = self.inner.metadata.handle(namespace.clone()).await; + handle.store(Arc::new(db_config)).await?; + self.load_namespace(&namespace, handle, restore_option).await?; + return Ok(()); + } + + let reservation = Reservation::acquire(self, namespace.clone()).await?; + let handle = self.inner.metadata.handle(namespace.clone()).await; + handle.store_and_maybe_flush(Some(Arc::new(db_config)), false).await?; + self.get_configurator(&handle.get()).discard_incomplete(&namespace).await?; + let ns = self.make_namespace(&namespace, handle.clone(), restore_option).await?; + handle.flush().await?; // commit point + if let Err(e) = ns.mark_complete().await { // cosmetic from here on + tracing::warn!(namespace = %namespace, "could not remove creation marker: {e}"); + } + reservation.publish(ns); + Ok(()) +} +``` + +Ordering that matters: `acquire` before `handle()` (`handle()` inserts into the in-memory map, which is what `exists()` reads — so the name becomes visible only while it is already locked); `flush` before `publish` (durable before visible); `publish` consumes the reservation (no double cleanup). + +### 4.3 `FreshDir` (configurator/helpers.rs) — cancellation-safe directory + +> *As built (review):* `begin` is synchronous (guard constructed before anything is created, no await between `mkdir` and the marker), and `Drop` does not delete in place: it calls `incomplete::discard_dir`, which atomically **renames the directory into `/.discarded/-`** and deletes the tombstone in the background. The path under `dbs/` is therefore free the instant the guard drops, a retry can never race a half-finished `remove_dir_all`, and files a still-running import executor recreates land in the tombstone. The sketch below shows the original idea. + +```rust +/// Directory of a namespace that does not exist yet. Removed again if dropped before `keep`: +/// on error, or when the request creating the namespace is cancelled. +pub(super) struct FreshDir { path: Option> } + +impl FreshDir { + /// `None` if a namespace already lives at `db_path`. + pub(super) async fn begin(db_path: &Arc) -> crate::Result> { + if db_path.try_exists()? { return Ok(None); } + tokio::fs::create_dir_all(db_path).await?; + tokio::fs::File::create(db_path.join(INCOMPLETE_MARKER)).await?; + Ok(Some(Self { path: Some(db_path.clone()) })) + } + pub(super) fn keep(mut self) { self.path.take(); } +} + +impl Drop for FreshDir { + fn drop(&mut self) { + let Some(path) = self.path.take() else { return }; + let rm = async move { + match tokio::fs::remove_dir_all(&*path).await { + Ok(()) | Err(e) if e.kind() == ErrorKind::NotFound => {} + Err(e) => tracing::error!(path = %path.display(), "failed to remove unfinished namespace directory: {e}"), + } + }; + match tokio::runtime::Handle::try_current() { + Ok(rt) => { rt.spawn(rm); } + Err(_) => { let _ = std::fs::remove_dir_all(&*path); } + } + } +} +``` + +Used by `PrimaryConfigurator::setup` and `SchemaConfigurator::setup` (which gains cleanup it never had): + +```rust +let db_path: Arc = self.base.base_path.join("dbs").join(name.as_str()).into(); +let fresh = FreshDir::begin(&db_path).await?; +let ns = self.try_new_primary(…).await?; // on Err or drop, `fresh` removes the directory +if let Some(fresh) = fresh { fresh.keep(); } +Ok(ns) +``` + +`try_new_primary`'s own `create_dir_all` becomes redundant for the fresh case and stays harmless for existing directories. The `remove_dir_all`-on-error branch in `setup` is replaced by the guard (drop order: the `try_new_primary` future and its `JoinSet` are dropped before `fresh`, so background tasks are aborted before the directory goes). + +### 4.4 `.incomplete` marker — crash tolerance + +> *As built (review):* the protocol lives in `namespace/incomplete.rs` (`INCOMPLETE_MARKER`, `create_marked_dir`, `discard_dir`, `discard_if_incomplete`, `sweep`). `sweep` runs at startup (`lib.rs`, after the store is built): it deletes leftover tombstones and discards marked directories of names the metastore does not know. `fork` writes the marker into its temporary directory before renaming it into place, so an unfinished fork is discarded like any other unfinished creation. The order at the end of a creation is **flush → publish → remove marker** (not flush → mark → publish): a marker that outlives publication is harmless, a complete directory without one is not. + +- `pub(crate) const INCOMPLETE_MARKER: &str = ".incomplete";` in `namespace/mod.rs`. +- Created by `FreshDir::begin` for every brand-new directory. +- Removed by `Namespace::mark_complete(&self)` (`remove_file(self.path.join(MARKER))`, `NotFound` ok), called (a) by `create` after `flush`, (b) by `load_namespace`'s init after `make_namespace` — a namespace opened from the metastore is complete by definition, so lazily loaded namespaces (and single-namespace-mode auto-creation) never keep a marker. +- Acted upon only for a name the metastore does **not** know: by `ConfigureNamespace::discard_incomplete(name)` (new trait method, default no-op; primary and schema delegate to `incomplete::discard_if_incomplete`), which `create` calls after `acquire` — i.e. with no row and nothing loaded — and by the startup `sweep` under the same condition. That is the only situation in which a marked directory is unambiguously garbage. Lazy loads never act on it, so a stale marker on a published namespace (crash between `flush` and unmark) is removed, never acted upon. The metastore's filesystem recovery (`maybe_recover_from_fs`, empty metastore only) skips marked directories rather than adopting them. +- `MetaStoreInner::maybe_recover_from_fs` (metastore empty ⇒ adopt `dbs/*`) skips directories carrying the marker, so a crash during the very first creation on a fresh server does not get adopted as a namespace at the next start. + +A directory **without** a marker and without a row keeps today's semantics (`Dump` ⇒ `LoadDumpExistingDb`; `Latest` ⇒ adopted). Such directories can only come from pre-marker servers or manual intervention; being destructive there is not worth it. + +### 4.5 `Namespace::mark_complete` (namespace/mod.rs) + +```rust +pub(crate) async fn mark_complete(&self) -> std::io::Result<()> { + match tokio::fs::remove_file(self.path.join(INCOMPLETE_MARKER)).await { + Err(e) if e.kind() != ErrorKind::NotFound => Err(e), + _ => Ok(()), + } +} +``` + +### 4.6 `fork` (store.rs) + +Replace the `Bomb` + manual `to_lock` with `Reservation::acquire(to)`; order becomes `configurator.fork(…)` → `handle.flush()` → `reservation.publish(ns)` (today it publishes *then* flushes, so a flush failure leaves a running namespace without a row). Net code removal; same semantics otherwise. `ForkTask`'s temp-dir + rename stays, plus the marker (§4.4). *As built:* the source namespace is looked up with the side-effect-free `MetaStore::existing_handle` (§9). + +## 5. Flow for a dump import (streaming or buffered) + +1. Admin handler resolves `dump_url` (errors here touch nothing). +2. `create` → `Reservation::acquire` (`NamespaceAlreadyExist`, HTTP 400, if the name is loaded or has a row). +3. In-memory config; `discard_incomplete` (removes a crashed previous attempt, if any). +4. `setup`: `FreshDir::begin` (mkdir + marker) → logger, WAL, connection maker → `load_dump` → `keep()`. +5. `flush` — the namespace now exists durably. +6. `mark_complete`, `publish` — the namespace is now visible; waiters proceed. + +## 6. Failure matrix + +| Interrupted at | Error (returned) | Cancellation (future dropped) | Crash (process dies) | +|---|---|---|---| +| 1 | nothing to undo | nothing to undo | nothing | +| 2–3 (before `setup`) | `Reservation` removes in-memory config | same | nothing persisted; nothing on disk | +| 4, inside `setup` (incl. import) | `FreshDir` removes dir; `Reservation` removes config; executor rolls back SQLite | same (importer executor is uncancelled: closes channel → ROLLBACK → connection released; dir removal races with it benignly on POSIX, see §9) | marked orphan dir, no row ⇒ invisible; next `create` discards it | +| between `setup` and `flush` | config removed; **complete dir, marked** ⇒ next `create` discards and redoes | same | same | +| `flush` fails | row never written (single SQLite statement); as above | — | — | +| between `flush` and `publish` | `Reservation` deletes the row again; marked complete dir ⇒ discarded with it | same | row + marker + complete data ⇒ namespace **exists and serves**; marker removed on first lazy load | +| between `publish` and marker removal | — (published; a stale marker is harmless) | same | row + marker + complete data ⇒ serves; marker removed on first lazy load | +| after `publish` | — | response may be lost ⇒ client retries ⇒ `NamespaceAlreadyExist` ⇒ by the contract, complete | same | + +Client rule: **2xx ⇒ complete; anything else ⇒ retry; `NamespaceAlreadyExist` on retry ⇒ complete.** No inspection of tables needed. (For namespaces *created* through this path. The single-namespace-mode config upsert of the default namespace, and ghost rows left by older binaries, are outside it.) + +## 7. Concurrency + +- **Second `create` of the same name:** waits on the write lock; then `AlreadyExist` (first succeeded) or proceeds (first failed). Previously: `AlreadyExist` even after the first failed. +- **User request during creation (`with`)**: `exists()` is true (in-memory config), `load_namespace` finds the pinned, locked entry and waits for its read lock; then sees the namespace, or, if the creation failed, `NamespaceDoesntExist` because the metastore no longer knows the name. An entry emptied for any other reason (eviction, shutdown, destroy) is never reported as missing: the lookup looks again, and only the metastore decides 404 (the false-404 fix, #56). Same waiting behaviour as during `fork`/`reset`. See §8a for the lookup. +- **`destroy` during creation:** `metadata.remove` succeeds (in-memory only), then waits on the pinned entry's lock; when creation finishes, `install` notices the config is gone and hands the namespace to that entry, `destroy` takes and destroys it. Net: created then destroyed, in that order (`destroy_during_creation_destroys_the_result`). +- **Store shutdown during creation:** `shutdown` skips the pinned entry instead of waiting for it (§9); the creation notices `has_shutdown` at its commit point and is undone, so no record is left and a retry after the restart creates the namespace (`create_interrupted_by_shutdown_leaves_no_record`). +- **`handle()` side effect:** `MetaStore::handle` inserts a default config into the in-memory map (pre-existing). Keeping `acquire` strictly before `handle()` is what makes the reservation airtight; documented in code. + +## 8. Cache eviction during an operation (*as built*: fixed, not merely inherited) + +The reservation is the cache entry's lock, but moka knows nothing about that lock. If the cache evicts the entry during a long operation (capacity pressure: `--max-active-namespaces`, default 100, is reached and more namespaces get loaded; the 24 h idle expiry is irrelevant), three things used to go wrong — for `fork` and `reset` since before this change, and for `create` once it adopted the same reservation (previously `create` ran inside moka's `try_get_with`, which deduplicates in-flight inits and is immune): + +1. **Split-brain.** The cache slot is empty, so a concurrent lookup (`exists()` is true: the config is in memory) runs a lazy load and opens the directory the operation is writing to — a second live instance on the same files. +2. **Stalled maintenance.** moka 0.12 has no background thread: maintenance runs inline inside whatever cache operation trips it, and it *awaits* async eviction listeners. The listener did `entry.write().await`, i.e. it waited for the operation to finish. The unrelated request that happened to run maintenance hung for the duration; once the write-op channel filled, every namespace load on the node blocked. +3. **Self-deadlock.** If the operation holding the lock touched the cache itself (`fork` does: `load_namespace(from)`), maintenance could pick up the eviction of its own entry and wait on its own lock. The first version of the unit test below reproduced exactly this. + +Fix, in three parts: + +- **Pin.** `NamespaceStoreInner::in_flight: Mutex>`. `Reservation::acquire` (create, fork) and `reset` pin the locked entry; `load_namespace` consults the map *before* `try_get_with` and waits on the pinned entry instead of loading. If the entry ends up empty — the operation failed, or published elsewhere — the lookup falls through: `NamespaceDoesntExist` if the metastore no longer knows the name, otherwise the regular cache path. Unpin happens after the config removal (abort) or after the namespace is visible (publish), so no lookup can slip into a lazy load in between. `destroy` consults the map too. +- **Non-blocking eviction listener.** The listener spawns the shutdown on its own task and returns immediately, so maintenance never waits for an operation in progress. +- **Publish into a fresh entry when evicted.** `NamespaceStore::install` checks (by `Arc::ptr_eq`) that the locked entry is still the cache's entry for the name; if not, the namespace goes into a fresh entry and the orphaned one stays empty, so the spawned listener finds nothing to shut down and waiters fall through to the cache. Used by `create`, `fork` and `reset`. + +Unit tests (`namespace::store::test`) build a real `NamespaceStore`, start a streaming import fed from a channel, `invalidate` the reserved entry (same code path as eviction, including the listener) and check that a concurrent lookup waits and then sees the imported data (or `NamespaceDoesntExist` if the import fails), that the namespace ends up in the cache, and that nothing stays pinned. Without the pin the lookup returns early with an empty database; without the non-blocking listener the test deadlocks. + +## 8a. One lookup for every reader (*as built*, after the rebase onto #56) + +`load_namespace(name)` is the only way to get at a namespace, and it returns it read-locked (`LoadedNamespace`), so nothing can take the namespace out of its entry while the caller uses it. `with`, `fork` (for its source) and lazy `create` call it. One attempt (`lookup`) is: wait on a pinned entry if there is one (§8); otherwise `try_get_with`, loading on a miss; then read the entry. Each attempt starts with the shutdown check and the metastore check (`existing_handle`, so that a retry can never bring a destroyed name back). If the entry read is empty, the attempt drops the entry from the cache if it is still there (`evict_if_still_empty`, gated on `contains_key` so that an entry gone through eviction costs no cache call) and the lookup starts again, up to five times, then gives up with `NamespaceUnavailable` (503) unless the metastore says the name is gone (404) or the store has shut down (503). Each attempt is counted in `libsql_server_namespace_emptied_entry`, each give-up in `libsql_server_namespace_emptied_entry_gave_up`. + +Five attempts keep the budget the two nested loops had before the merge (three in `with` times two rounds in `load_namespace`). Where the cache holds the working set, eviction happens at shutdown only and the second attempt succeeds. In the live eviction check, which runs the cache at a third of the hot set so that entries live for milliseconds, three attempts gave up on about one request in 20,000 and five on none in 340,000. The base answered "doesn't exist" after the first. + +## 9. Adversarial review of PR #53 — what changed (*as built*) + +Reviewers (correctness, architecture, testing, operations) plus a manual pass found the following; all fixed in the fourth commit. + +| Sev | Finding | Resolution | +|---|---|---| +| HIGH | Directory removal was spawned and unordered against releasing the name: a retry "right away" (the documented contract) could race `remove_dir_all`; tests hid it with `wait_until_gone`. | `discard_dir`: atomic rename into `.discarded/` (sync, in `Drop`), background delete, startup `sweep`. Error paths now `await` the reservation's cleanup (`Reservation::abort`); `Drop` is for cancellation only. `retry_right_after_failure_starts_clean` asserts the path and the name are free the moment the error is returned. | +| HIGH | `MetaStore::remove` returns early (`HasLinkedDbs`, `PendingMigrationOnSchema`) **before** dropping the in-memory config; reachable for a linked-DB create whose flush fails ⇒ ghost. | `MetaStore::discard_blocking`: unconditional, goes through the metastore's own change queue (so it is also ordered after a config store that was still queued when the request was cancelled). `discard_ignores_the_guards_of_remove`. | +| HIGH | `install`'s `Arc::ptr_eq` fallback could not tell eviction from `destroy`: destroy-during-create re-inserted a live namespace whose directory destroy had just removed; name wedged. | Fallback re-checks `exists()`: config gone ⇒ hand the namespace to the old entry (destroy is waiting on it); `destroy` prefers the pinned entry. `destroy_during_creation_destroys_the_result`. | +| HIGH | Cancellation between `flush` and `publish` after `mark_complete` ⇒ row deleted, complete dir **unmarked** ⇒ `LoadDumpExistingDb` forever. | Order is flush → publish → remove marker. | +| HIGH | Fork's destination (renamed temp dir) carried no marker ⇒ a cancelled fork left an unmarked orphan and `ENOTEMPTY` on retry. | Marker written into the temp dir. | +| HIGH (found while testing) | A rejected `acquire` (`AlreadyExist` for an existing but unloaded namespace, e.g. a retry after restart) left the empty entry its `get_with` inserted ⇒ every lookup found the empty entry instead of loading ⇒ namespace unreachable until eviction. `checkpoint` has had the same latent bug. | `acquire` drops the empty entry it created; `load_namespace` treats an empty, unlocked entry as a miss and reloads (self-heals `checkpoint`/failed-`reset`/failed-`fork` leftovers too). Both drop it with `evict_if_still_empty`: under moka's key lock, only if it is still the cached entry, still empty and unlocked, so a fresh entry loaded in between is never evicted. `marker_on_published_namespace_is_ignored` creates before any lookup after a restart. | +| MED | ABBA: `remove` takes `conn` then `configs`; `process`'s flush branch held `configs` across `try_process` (`conn`). Now on every create. | `configs` released before `try_process`. | +| MED | Spawning the eviction listener unconditionally dropped moka's per-key serialisation for *normal* evictions (reload could overlap the old instance's shutdown). | Listener awaits inline unless the entry is pinned (`in_flight` shared with the closure). | +| MED | `shutdown` waited on an in-flight create's lock; `create` never re-checked `has_shutdown`. | Pinned entries skipped at shutdown (warn); `has_shutdown` re-checked before the commit point. | +| MED | `with()` called `MetaStore::handle`, which *inserts* into the map `exists()` reads: a lookup racing the end of a failed creation resurrected the name. | `MetaStore::existing_handle` (non-inserting) for namespaces that must exist; lazy init re-checks `exists()`. | +| MED | `FreshDir::begin` had two awaits before the guard existed. | Synchronous; guard first. | +| MED | Cancel tests could fire before the creation started (turmoil latency) and so pass vacuously; the restart test never reached the `\|\| exists` guard. | Cancel once `dbs/foo/.incomplete` exists; create before any lookup after restart; "usable afterwards" assertion restored. | +| LOW | Marked orphans were only reclaimed by a `create` of the same name; `maybe_recover_from_fs` skip untested; success not logged. | Startup `sweep`; `recovery_from_fs_skips_marked_directories`, `sweep_cleans_leftovers_of_a_crash`; `info!("namespace created")` with elapsed, `warn!` with the error on failure, distinct message on cancellation. | + +LOW items closed in the follow-up commit: `publish` keeps the guard inside the reservation across `install`'s awaits, so a cancellation there undoes the creation instead of leaking the pin; `remove_incomplete_marker` stats before taking the blocking-pool hop (every cold load passes through it); a failure to remove the marker after publish is logged at `error`; `FreshDir`'s log is `info` (every failed create, including client errors, passes through it); `acquire` logs when it has to wait; store-level `aborted_creation_is_undone` test (`JoinHandle::abort` mid-import); the restart test drops the first server before starting the second; the unmarked-directory test asserts the outcome. + +Also closed: the marker and its directory entry are fsynced on creation (`mark_incomplete`), so the marker is durable before anything else in the directory can be; `checkpoint` no longer mints an empty cache entry for an unloaded namespace (the pre-existing source of the same wedge); `ForkTask::fork` only removes a failed fork's destination if it carries the marker. + +Not changed: after an *abort* the (empty) cache entry stays until a lookup heals it or the cache evicts it — it counts toward capacity but is never served; a metastore rebuilt from the filesystem (`destroy_on_error` + `allow_recover_from_fs`) in the milliseconds between a namespace's flush and its unmark would skip that namespace. Bottomless is not used in our deployment and this change is untested with it. + +**Upgrade / downgrade.** Ghost rows and unmarked orphan directories left by failed creates on *older* binaries are untouched (everything here is marker-gated); for them the old remedy stays: `DELETE /v1/namespaces/:ns`, then create again. Downgrading the binary is safe: the metastore schema and the config protobuf are unchanged; an old binary ignores `.incomplete` and `.discarded/` (it may adopt a marked orphan via `maybe_recover_from_fs` on an empty metastore, as it always could with any leftover directory). + +## 10. Interaction with the streaming importer + +On cancellation the reader future is dropped, the executor thread sees the closed channel, rolls back and drops its connection — concurrently with the directory being discarded. The directory is renamed, not deleted in place, so whatever the executor still writes lands in the tombstone; on POSIX, renaming a directory with open files in it is harmless. The tombstone is deleted in the background, or by `sweep` at the next start. + +## 11. Observability + +- `warn!` on every abort path (`Reservation`: "namespace creation did not complete; discarding it"; `FreshDir`: "… removing its directory"; `discard_incomplete`: "discarding namespace directory left by an interrupted creation"), with the namespace / path. +- Counters `libsql_server_namespace_create_aborted` and `libsql_server_namespace_create_discarded_incomplete` (*as built:* no `stage` label — the logs carry the detail). +- The contract of §6 is stated in `docs/ADMIN_API.md` under namespace creation. + +## 12. Tests (turmoil, `tests/namespaces/lifecycle.rs` and `dumps.rs`) + +*As built.* 9 of the 11 integration tests fail on the unfixed code; the other two pin behaviour that must hold both before and after. + +1. `failed_create_leaves_no_trace{,_streaming,_shared_schema}`: invalid dump ⇒ 400; `GET /v1/namespaces/foo/config` ⇒ 404 (was 200); hrana ⇒ "doesn't exist" (was "no such table"); `dbs/foo` gone; `create` again with a valid dump ⇒ 200, data present, no marker. +2. `cancelled_create_leaves_no_trace{,_streaming}` (replaces `streaming_cancelled_request_rolls_back`, which tolerated "OK or BAD_REQUEST" on retry): request abandoned mid-transfer ⇒ config 404, hrana "doesn't exist", directory gone, retry from the same dump ⇒ 200 with all rows. +3. `concurrent_requests_wait_for_creation`: a second `create` and a user query issued during a ~2 s import wait; afterwards the second gets `already exists` and the query sees all rows. `concurrent_create_succeeds_after_failure`: the import fails ⇒ the waiting query gets "doesn't exist" and a new `create` succeeds. +4. `crash_remnant_is_discarded`: `dbs/foo/{.incomplete,.sentinel,data,wallog}` exists before the server starts ⇒ not adopted by the metastore (config 404), `create foo` from a dump ⇒ 200. `unmarked_directory_is_left_alone`: a marker-less `dbs/foo/keep.txt` survives a `create`. `marker_on_published_namespace_is_ignored`: marker added to a published namespace ⇒ `create` ⇒ `already exists`, data served; after a restart the marker is gone. +5. `single_namespace_mode_rejects_dump_into_existing_namespace`: config upsert of `default` still works; `create default` from a dump ⇒ `already exists` (was: 200, dump silently skipped). +6. Unit (`configurator::helpers::test`): `FreshDir` removed on drop and when its enclosing future is dropped, kept on `keep()`; `discard_incomplete` removes only marked directories. +7. `fork_namespace`, `shared_schema::*` and all dump tests unchanged. +8. `namespace::store::test::lookup_{waits_for_creation,sees_failure_of_creation}_even_if_the_entry_was_evicted` (§8), `destroy_during_creation_destroys_the_result`, `retry_right_after_failure_starts_clean`, `discard_ignores_the_guards_of_remove`; `namespace::incomplete::test::*` (§9). + +Slow-transfer tests use `make_slow_dump_store` (64-byte chunks, 100 ms apart): with turmoil's random 0–100 ms message latency, concurrent requests are issued 500 ms in and the import lasts ~2 s. + +## 13. Scope + +| File | Change | +|---|---| +| `libsql-server/Cargo.toml` | `async-lock = "3"` | +| `namespace/store.rs` | `Reservation` (+ `abort`); `create`/`fork` reserving paths; `load_namespace`/`lookup` (one lookup for every reader: pinned entries, empty-entry healing with `evict_if_still_empty`, `mark_complete`, the false-404 fix's retry and 503 semantics from #56, §8a); `in_flight` pin map, pin-aware eviction listener, `install`, `shutdown` (§8, §9); `refuse_if_shut_down` at every entry point and commit point, `reset`'s included. | +| `namespace/incomplete.rs` | marker, `discard_dir` (tombstones), `discard_if_incomplete`, `sweep` | +| `namespace/meta_store.rs` | `ChangeMsg` enum with `Discard`, `discard_blocking`, `existing_handle`, lock-order fix | +| `lib.rs` | startup `sweep` | +| `namespace/mod.rs` | `remove_incomplete_marker`, `Namespace::mark_complete` | +| `namespace/configurator/mod.rs` | `ConfigureNamespace::discard_incomplete` (default no-op) | +| `namespace/configurator/helpers.rs` | `FreshDir`, `discard_incomplete` helper | +| `namespace/configurator/{primary,schema,fork}.rs` | use `FreshDir`; implement `discard_incomplete`; drop ad-hoc cleanup; fork marks its temp dir | +| `namespace/meta_store.rs` | skip marked dirs in `maybe_recover_from_fs` | +| `docs/ADMIN_API.md`, PR #51 design doc §13 | contract; mark the lifecycle item as fixed | +| tests | §11 | + +Branch `tszymczyszyn/atomic-namespace-create` off `tszymczyszyn/streaming-dump-importer`, which is stacked on the false-404 fix (#56): #56, then #51, then this. Each PR targets the branch below it until that merges. + +## 14. Alternatives considered + +- **Row first with a lifecycle state (`creating`/`ready`).** Needs a metastore schema or protobuf change that replicates to replicas via the config handshake, plus a startup sweep that knows configurator paths. More moving parts for the same guarantee. +- **Import into a temp directory and rename.** The logger, stats and connection maker capture the path at open; publishing would require close → rename → reopen, and bottomless would see a restore decision on reopen. `fork` can do it because it only writes a raw `data` file before opening. +- **Dedup via moka `try_get_with` instead of an explicit lock.** When the initialising future is dropped, moka lets another waiter run *its* init — a lazy `with()` would then create an empty namespace. The explicit reservation makes waiters observe the outcome instead. +- **Making `with()` fail fast ("namespace is being created") instead of waiting.** Cleaner UX for minute-long imports, but changes behaviour for `reset`/`fork` too; can be layered on later without touching this design. diff --git a/docs/STREAMING_DUMP_IMPORT_DESIGN.md b/docs/STREAMING_DUMP_IMPORT_DESIGN.md index 840c446096..3749968c7c 100644 --- a/docs/STREAMING_DUMP_IMPORT_DESIGN.md +++ b/docs/STREAMING_DUMP_IMPORT_DESIGN.md @@ -592,12 +592,12 @@ Metrics (`metrics` 0.21 macros with labels): ## 13. Pre-existing issues this design does not fix (state them in the PR) -1. `NamespaceStore::create` stores the namespace config in the metastore **before** loading. On import failure the directory is removed (`PrimaryConfigurator::setup`) but the metastore row stays, so a later request to the namespace lazily creates an **empty** database. Existing tests rely on this (`select … from test` errors because the table is missing, not because the namespace is missing). -2. If the Admin HTTP request is cancelled mid-import, `setup`'s cleanup does not run (the future is dropped). The streaming executor still rolls back SQLite state, but the directory and `.sentinel` remain. -3. No server-side timeout exists for dump imports; the Admin HTTP request stays open for the whole import. Clients must not time out, or must tolerate (2). +1. ~~`NamespaceStore::create` stores the namespace config in the metastore **before** loading. On import failure the directory is removed (`PrimaryConfigurator::setup`) but the metastore row stays, so a later request to the namespace lazily creates an **empty** database.~~ **Fixed** by the stacked change described in `docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`: the config is persisted only after setup succeeds, and a failed or cancelled creation leaves nothing behind. +2. ~~If the Admin HTTP request is cancelled mid-import, `setup`'s cleanup does not run (the future is dropped). The streaming executor still rolls back SQLite state, but the directory and `.sentinel` remain.~~ **Fixed**, same change (drop guards for the directory and the reservation of the name). +3. No server-side timeout exists for dump imports; the Admin HTTP request stays open for the whole import. Clients must not time out; if they do, the creation is discarded and can be retried (see the creation contract in `docs/ADMIN_API.md`). 4. Bottomless, if enabled, has its own frame buffering/backpressure outside this design. -None of these is fixed here. #53, stacked on this change, makes namespace creation all-or-nothing and addresses (1) and (2); until it lands, an operator deletes a namespace left behind by a failed import. +(1) and (2) are fixed by the stacked all-or-nothing namespace creation (`docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md`). (3) and (4) are not addressed here. --- From 27f1f73a7b36a7e2c45ef24afaa858e0f852959c Mon Sep 17 00:00:00 2001 From: Tomasz Szymczyszyn Date: Tue, 13 Oct 2026 20:38:25 +0200 Subject: [PATCH 3/5] docs: component and before/after diagrams for atomic namespace creation Embedded in the design doc as PNGs. --- docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md | 6 ++++++ .../atomic-namespace-create-before-after.png | Bin 0 -> 123136 bytes .../atomic-namespace-create-components.png | Bin 0 -> 196567 bytes 3 files changed, 6 insertions(+) create mode 100644 docs/images/atomic-namespace-create-before-after.png create mode 100644 docs/images/atomic-namespace-create-components.png diff --git a/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md b/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md index b022460951..17e929ff2c 100644 --- a/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md +++ b/docs/ATOMIC_NAMESPACE_CREATE_DESIGN.md @@ -6,6 +6,8 @@ Stacked on `tszymczyszyn/streaming-dump-importer` (PR #51). Fixes the pre-existi ## 1. Problem +![Before and after](images/atomic-namespace-create-before-after.png) + `NamespaceStore::create` persists the namespace config **first** and only then runs the configurator's `setup` (directory, logger, connections, dump import). Three resources are mutated without a common commit point: @@ -30,6 +32,10 @@ Non-goals: a server-side import timeout; idempotency keys / async create jobs; b ## 3. Design in one paragraph +![Components and ownership](images/atomic-namespace-create-components.png) + +*Who owns what: numbered arrows are the happy path, dashed red the undo. The second diagram (§1) contrasts the old and new sequence.* + Make the **metastore write the commit point** and make everything before it reversible. `create` reserves the name by write-locking its cache entry, puts the config in the metastore's *in-memory* map only (so `setup` can read it), runs `setup`, and only on success **flushes the row** and installs the namespace. A `Reservation` drop guard undoes the in-memory config if the future ends any other way — error *or* cancellation — and releases the lock only after that, so waiters never observe a half-built namespace. The filesystem gets the same treatment one layer down: `setup` wraps a brand-new directory in a `FreshDir` guard that removes it on drop. For crashes, a brand-new directory carries an `.incomplete` marker until the row is flushed; the next `create` of that name discards a marked directory. diff --git a/docs/images/atomic-namespace-create-before-after.png b/docs/images/atomic-namespace-create-before-after.png new file mode 100644 index 0000000000000000000000000000000000000000..af6172c4067907d49df25a5fba87c07d81eec8d3 GIT binary patch literal 123136 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%0Aasoe9OA9A0627D7~IN8Y& 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 Z2ZvF+kA)>f>(PK8IVoky5^+Pn{|CR~7o-3H literal 0 HcmV?d00001 diff --git a/docs/images/atomic-namespace-create-components.png b/docs/images/atomic-namespace-create-components.png new file mode 100644 index 0000000000000000000000000000000000000000..522f26d5298fb8299ba606f8311b694fa222b820 GIT binary patch literal 196567 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

?0x^L? za%*jkNU~pU&U}P*@K++%bG_ouWx=0^$+gW~>>B&~8wT@nPgEL*63ccT<`O`L)PBnD zxCsq+zs2qS^LQ{c9Y^j(qM?X=WO?y%pSE>D<}7hJ(TfSv+X1Cn?E9%{OM4gfDVn>+ z?xz+_A$0FBUcmWkj@<&?P-QXo(Awg9;{>%(-9DG=_{9D6`1m+hZsT$zK!dHKwQDW) z5~yzyMtU_-glSYMZ<;Gh-!}43bz!L{`^K-`Ts%0Dbqw1mobCPP3FI6mW*;(E;MyNE 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®$gDvv*(z7>7!1Ps0D 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 Nr=_lUw?q{g`acql4l@7% literal 0 HcmV?d00001 From f1dc57c91a86f64d386492dafadad5dd7a1ecfb5 Mon Sep 17 00:00:00 2001 From: Tomasz Szymczyszyn Date: Fri, 16 Oct 2026 15:37:20 +0200 Subject: [PATCH 4/5] libsql-server: one retry layer for an emptied namespace entry `load_namespace` now returns the namespace read-locked (`LoadedNamespace`) instead of its cache entry, and owns the whole lookup: the metastore check (`existing_handle`, so that no lookup can bring a destroyed name back), the cache lookup or load, and the retry. When the entry it found is empty it drops it from the cache (if it is still there) and looks again, up to five times, then gives up with the 503 or the metastore-backed 404. `with` and `fork` make one call each; the second retry loop in `with`, the two rounds in `load_namespace` and `fork`'s own "source emptied" arm are gone, and an emptied entry is counted once. Five lookups keep the budget the two nested loops had. In the live eviction check (cache at a third of the hot set) three lookups gave up on about one request in 20,000; five on none in 340,000. The drop of an emptied entry is gated on `contains_key`, which records no access: after a real eviction the key is gone, and the compute call behind the drop would only run moka's maintenance in the retrying task. This also makes the one mutation the unit tests could not see before visible: an emptied entry answered as "doesn't exist" now fails seven tests, because the read happens inside the retry. `reset` refuses to install its result once shutdown has begun, like `create` and `fork` refuse to commit: `shutdown` does not wait for a reset in progress, so a namespace installed then would never be shut down. The ten shutdown checks share `refuse_if_shut_down`. New tests: `reset_interrupted_by_shutdown_installs_nothing`, `shutdown_does_not_wait_for_a_creation_in_progress`. --- libsql-server/src/namespace/store.rs | 383 +++++++++++++++++---------- 1 file changed, 244 insertions(+), 139 deletions(-) diff --git a/libsql-server/src/namespace/store.rs b/libsql-server/src/namespace/store.rs index 3ab08f9a49..a383545454 100644 --- a/libsql-server/src/namespace/store.rs +++ b/libsql-server/src/namespace/store.rs @@ -4,7 +4,7 @@ use std::pin::Pin; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use async_lock::{RwLock, RwLockWriteGuardArc}; +use async_lock::{RwLock, RwLockReadGuardArc, RwLockWriteGuardArc}; use chrono::NaiveDateTime; use futures::TryFutureExt; use moka::future::Cache; @@ -35,9 +35,31 @@ use super::{Namespace, ResetCb, ResetOp, ResolveNamespacePathFn, RestoreOption}; type NamespaceEntry = Arc>>; -/// How many times `with` looks a namespace up again after finding its entry emptied (by -/// shutdown, eviction or destroy) before it gives up. -const MAX_EMPTIED_ENTRY_ATTEMPTS: usize = 3; +/// A namespace held read-locked in its cache entry, so that nothing can take it out of the +/// entry (eviction, shutdown, destroy) while it is in use. Only `load_namespace` makes one, +/// after it saw the entry filled. +pub(crate) struct LoadedNamespace(RwLockReadGuardArc>); + +impl std::ops::Deref for LoadedNamespace { + type Target = Namespace; + + fn deref(&self) -> &Namespace { + self.0 + .as_ref() + .expect("a LoadedNamespace is only made from a filled entry") + } +} + +/// How many times a lookup finds its entry emptied (by shutdown, eviction or destroy) before +/// it gives up with `NamespaceUnavailable`. +/// +/// Where the cache holds the working set, eviction happens at shutdown only and the second +/// lookup succeeds. The budget matters only for a cache far too small for its working set, +/// where entries live for milliseconds: at a third of the working set, three lookups gave up +/// on about one request in 20,000 and five on none in 340,000. The lookups are cheap; only the +/// one that loads the namespace is not, and a load is as likely to be evicted at once as any +/// other entry, so nothing is gained by spending more. +const MAX_EMPTIED_ENTRY_ATTEMPTS: usize = 5; /// Entries of namespaces with a creation, fork or reset in progress, pinned so that lookups keep /// finding (and waiting on) the locked entry even if the cache evicts it meanwhile. Otherwise a @@ -336,10 +358,18 @@ impl NamespaceStore { self.inner.metadata.exists(namespace).await } - pub async fn destroy(&self, namespace: NamespaceName, prune_all: bool) -> crate::Result<()> { + /// Nothing starts, and no operation in progress commits or installs anything, once shutdown + /// has begun: a namespace opened or installed after `shutdown` collected the entries would + /// never be shut down. + fn refuse_if_shut_down(&self) -> crate::Result<()> { if self.inner.has_shutdown.load(Ordering::Relaxed) { return Err(Error::NamespaceStoreShutdown); } + Ok(()) + } + + pub async fn destroy(&self, namespace: NamespaceName, prune_all: bool) -> crate::Result<()> { + self.refuse_if_shut_down()?; // destroy on-disk database and backups let db_config = tokio::task::spawn_blocking({ @@ -396,9 +426,7 @@ impl NamespaceStore { namespace: NamespaceName, restore_option: RestoreOption, ) -> anyhow::Result<()> { - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown.into()); - } + self.refuse_if_shut_down()?; // The process for reseting is as follow: // - get a lock on the namespace entry, if the entry exists, then it's a lock on the entry, @@ -429,6 +457,9 @@ impl NamespaceStore { let ns = self .make_namespace(&namespace, db_config, restore_option) .await?; + // `shutdown` does not wait for a reset in progress (its entry is pinned), so a namespace + // installed now would never be shut down. + self.refuse_if_shut_down()?; self.install(&namespace, &entry, &mut lock, ns).await; @@ -460,9 +491,7 @@ impl NamespaceStore { to_config: DatabaseConfig, timestamp: Option, ) -> crate::Result<()> { - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } + self.refuse_if_shut_down()?; // check that the source namespace exists if !self.inner.metadata.exists(&from).await { @@ -493,14 +522,8 @@ impl NamespaceStore { timestamp: Option, ) -> crate::Result { // FIXME: we could potentially delete the namespace while trying to fork it - let Some(from_config) = self.inner.metadata.existing_handle(from.clone()).await else { - return Err(crate::Error::NamespaceDoesntExist(from.to_string())); - }; - let from_entry = self.load_namespace(from, from_config.clone()).await?; - let from_lock = from_entry.read().await; - let Some(from_ns) = &*from_lock else { - return Err(self.emptied_entry_error(from).await); - }; + let from_ns = self.load_namespace(from).await?; + let from_config = from_ns.db_config_store.clone(); let handle = self.inner.metadata.handle(to.clone()).await; // In memory only: the fork reads it; nothing is persisted until it succeeded. @@ -508,7 +531,7 @@ impl NamespaceStore { let to_ns = self .get_configurator(&from_config.get()) .fork( - from_ns, + &from_ns, from_config, to.clone(), handle.clone(), @@ -517,9 +540,7 @@ impl NamespaceStore { ) .await?; - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } + self.refuse_if_shut_down()?; handle.flush().await?; // commit point Ok(to_ns) } @@ -549,9 +570,7 @@ impl NamespaceStore { where Fun: FnOnce(&Namespace) -> R + 'static, { - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } + self.refuse_if_shut_down()?; if !auth.is_namespace_authorized(&namespace) { return Err(Error::NamespaceDoesntExist(namespace.to_string())); } @@ -563,49 +582,14 @@ impl NamespaceStore { where Fun: FnOnce(&Namespace) -> R, { - let lazily_created = - namespace == NamespaceName::default() || self.inner.allow_lazy_creation; - for _ in 0..MAX_EMPTIED_ENTRY_ATTEMPTS { - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } - // `handle` registers the name in the metastore's in-memory map as a side effect, - // which is what `exists` reads: a namespace that must already exist is looked up - // with the side-effect-free `existing_handle`, so that a lookup racing with the end - // of a failed creation, or with `destroy`, cannot bring the name back to life. - let handle = if lazily_created { - self.inner.metadata.handle(namespace.clone()).await - } else { - match self.inner.metadata.existing_handle(namespace.clone()).await { - Some(handle) => handle, - None => return Err(Error::NamespaceDoesntExist(namespace.to_string())), - } - }; - - let entry = self.load_namespace(&namespace, handle).await?; - { - let lock = entry.read().await; - if let Some(ns) = &*lock { - return Ok(f(ns)); - } - } - - // The namespace was taken out of the entry after we got it: by shutdown, by cache - // eviction, or by a concurrent destroy. That does not mean it is missing, so look it - // up again. Expected during a rolling restart and under cache pressure, once per - // waiting request: the counter is the signal, not the log. - NAMESPACE_EMPTIED_ENTRY.increment(1); - tracing::debug!(%namespace, "namespace cache entry was emptied while in use, looking it up again"); - } + let ns = self.load_namespace(&namespace).await?; + Ok(f(&ns)) + } - let error = self.emptied_entry_error(&namespace).await; - if matches!(error, Error::NamespaceUnavailable(_)) { - // Shutdown and a namespace that is really gone are not failures of the store, so - // the counter only records this outcome. - NAMESPACE_EMPTIED_ENTRY_GAVE_UP.increment(1); - } - tracing::warn!(%namespace, %error, "namespace cache entry kept being emptied, giving up"); - Err(error) + /// Whether a lookup of `namespace` creates it when it does not exist (the default namespace + /// when namespaces are disabled, and every namespace on a replica). + fn lazily_created(&self, namespace: &NamespaceName) -> bool { + *namespace == NamespaceName::default() || self.inner.allow_lazy_creation } /// Removes `entry` from the cache if it is still the cached entry for `namespace` and still @@ -735,12 +719,57 @@ impl NamespaceStore { } } - /// The entry of an existing namespace, loading it (`RestoreOption::Latest`) if needed. - async fn load_namespace( + /// An existing namespace, read-locked in its entry; loaded (`RestoreOption::Latest`) if it + /// is not in the cache. + /// + /// The entry it finds may be emptied before it gets to read it (by eviction, shutdown or a + /// concurrent destroy), or may have been left empty (by a reservation that was rejected or + /// a reset that failed). Neither means the namespace is missing, so the lookup is repeated, + /// up to `MAX_EMPTIED_ENTRY_ATTEMPTS` times, after dropping the empty entry from the cache + /// so that the next lookup loads for real. Only the metastore decides that a namespace does + /// not exist. Expected during a rolling restart and under cache pressure, once per waiting + /// request: the counter is the signal, not the log. + async fn load_namespace(&self, namespace: &NamespaceName) -> crate::Result { + for _ in 0..MAX_EMPTIED_ENTRY_ATTEMPTS { + self.refuse_if_shut_down()?; + // `handle` registers the name in the metastore's in-memory map as a side effect, + // which is what `exists` reads: a namespace that must already exist is looked up + // with the side-effect-free `existing_handle`, so that a lookup racing with the end + // of a failed creation, or with `destroy`, cannot bring the name back to life. + let db_config = if self.lazily_created(namespace) { + self.inner.metadata.handle(namespace.clone()).await + } else { + match self.inner.metadata.existing_handle(namespace.clone()).await { + Some(handle) => handle, + None => return Err(Error::NamespaceDoesntExist(namespace.to_string())), + } + }; + match self.lookup(namespace, &db_config).await? { + Some(ns) => return Ok(ns), + None => { + NAMESPACE_EMPTIED_ENTRY.increment(1); + tracing::debug!(%namespace, "namespace cache entry was emptied, looking it up again"); + } + } + } + + let error = self.emptied_entry_error(namespace).await; + if matches!(error, Error::NamespaceUnavailable(_)) { + // Shutdown and a namespace that is really gone are not failures of the store, so + // the counter only records this outcome. + NAMESPACE_EMPTIED_ENTRY_GAVE_UP.increment(1); + } + tracing::warn!(%namespace, %error, "namespace cache entry kept being emptied, giving up"); + Err(error) + } + + /// One attempt of `load_namespace`. `Ok(None)` means the entry it found was empty, and has + /// been dropped from the cache if it was still there. + async fn lookup( &self, namespace: &NamespaceName, - db_config: MetaStoreHandle, - ) -> crate::Result { + db_config: &MetaStoreHandle, + ) -> crate::Result> { // An operation in progress on this namespace (create, fork, reset) holds its entry // locked and pinned: wait on that entry rather than loading the directory it is working // on (the cache may have evicted the entry meanwhile). If the operation leaves the entry @@ -753,75 +782,67 @@ impl NamespaceStore { namespace = %namespace, "waiting for an operation in progress on the namespace" ); - if entry.read().await.is_some() { - return Ok(entry); + let lock = entry.read_arc().await; + if lock.is_some() { + return Ok(Some(LoadedNamespace(lock))); } + drop(lock); if !self.inner.metadata.exists(namespace).await { return Err(Error::NamespaceDoesntExist(namespace.to_string())); } } - let lazily_created = - *namespace == NamespaceName::default() || self.inner.allow_lazy_creation; - // Two rounds at most: an entry that is empty once nobody holds it locked is a leftover - // (of a reservation that was rejected, a reset that failed, a checkpoint of a namespace - // that was not loaded) and would make the namespace unreachable until the cache evicts - // it; drop it and load for real. - for round in 0..2 { - let loaded = AtomicBool::new(false); - let init = async { - loaded.store(true, Ordering::Relaxed); - // Shutdown may have started since the caller checked. A namespace opened now - // would not be in the entries shutdown takes out, so nobody would ever shut it - // down. - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } - // The caller checked that the namespace exists; re-check now that we are the - // one loading it, in case it was discarded or destroyed in between (otherwise - // we would bring an empty namespace into existence for a name the metastore - // doesn't know). - if !lazily_created && !self.inner.metadata.exists(namespace).await { - return Err(Error::NamespaceDoesntExist(namespace.to_string())); - } - let ns = self - .make_namespace(namespace, db_config.clone(), RestoreOption::Latest) - .await?; - // A namespace opened from the metastore is complete by definition; this only - // removes a marker left by a crash between persisting the config and removing - // it. - if let Err(e) = ns.mark_complete().await { - tracing::warn!(namespace = %namespace, "could not remove creation marker: {e}"); - } - Ok(Some(ns)) - }; - - let before_load = Instant::now(); - let entry = self - .inner - .store - .try_get_with( - namespace.clone(), - init.map_ok(|ns| Arc::new(RwLock::new(ns))), - ) + let loaded = AtomicBool::new(false); + let init = async { + loaded.store(true, Ordering::Relaxed); + // Shutdown may have started since the caller checked. A namespace opened now + // would not be in the entries shutdown takes out, so nobody would ever shut it + // down. + self.refuse_if_shut_down()?; + // The caller checked that the namespace exists; re-check now that we are the + // one loading it, in case it was discarded or destroyed in between (otherwise + // we would bring an empty namespace into existence for a name the metastore + // doesn't know). + if !self.lazily_created(namespace) && !self.inner.metadata.exists(namespace).await { + return Err(Error::NamespaceDoesntExist(namespace.to_string())); + } + let ns = self + .make_namespace(namespace, db_config.clone(), RestoreOption::Latest) .await?; - if loaded.load(Ordering::Relaxed) { - NAMESPACE_LOAD_LATENCY.record(before_load.elapsed()); - return Ok(entry); + // A namespace opened from the metastore is complete by definition; this only + // removes a marker left by a crash between persisting the config and removing + // it. + if let Err(e) = ns.mark_complete().await { + tracing::warn!(namespace = %namespace, "could not remove creation marker: {e}"); } + Ok(Some(ns)) + }; - if round == 0 && entry.read().await.is_none() { - // The entry was emptied (by eviction, shutdown or destroy) while we waited on - // it, or something left it empty. Either way the namespace is not missing - // because of it: drop the entry if it is still cached, and load for real. - NAMESPACE_EMPTIED_ENTRY.increment(1); - tracing::debug!(%namespace, "namespace cache entry was emptied, looking it up again"); - self.evict_if_still_empty(namespace, &entry).await; - continue; - } - return Ok(entry); + let before_load = Instant::now(); + let entry = self + .inner + .store + .try_get_with( + namespace.clone(), + init.map_ok(|ns| Arc::new(RwLock::new(ns))), + ) + .await?; + if loaded.load(Ordering::Relaxed) { + NAMESPACE_LOAD_LATENCY.record(before_load.elapsed()); + } + + let lock = entry.read_arc().await; + if lock.is_some() { + return Ok(Some(LoadedNamespace(lock))); + } + drop(lock); + // Emptied by an eviction, the entry is already out of the cache; only an entry that + // was left empty is still there. `contains_key` records no access and runs no + // maintenance, unlike the compute call behind `evict_if_still_empty`. + if self.inner.store.contains_key(namespace) { + self.evict_if_still_empty(namespace, &entry).await; } - unreachable!("the second round always returns") + Ok(None) } #[tracing::instrument(skip_all, fields(namespace))] @@ -831,9 +852,7 @@ impl NamespaceStore { restore_option: RestoreOption, db_config: DatabaseConfig, ) -> crate::Result<()> { - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } + self.refuse_if_shut_down()?; if let Some(shared_schema_name) = &db_config.shared_schema_name { // we hold a lock for the duration of the namespace creation @@ -858,7 +877,7 @@ impl NamespaceStore { tracing::trace!("auto-creating the namespace"); let handle = self.inner.metadata.handle(namespace.clone()).await; handle.store(Arc::new(db_config)).await?; - self.load_namespace(&namespace, handle).await?; + self.load_namespace(&namespace).await?; return Ok(()); } @@ -908,9 +927,7 @@ impl NamespaceStore { let ns = self .make_namespace(namespace, handle.clone(), restore_option) .await?; - if self.inner.has_shutdown.load(Ordering::Relaxed) { - return Err(Error::NamespaceStoreShutdown); - } + self.refuse_if_shut_down()?; tracing::debug!("storing db config"); handle.flush().await?; // commit point Ok(ns) @@ -1530,7 +1547,11 @@ pub(crate) mod test { store.inner.has_shutdown.store(true, Ordering::Relaxed); let handle = store.inner.metadata.handle(namespace.clone()).await; - let error = store.load_namespace(&namespace, handle).await.unwrap_err(); + // `lookup` rather than `load_namespace`: this targets the check inside the load itself, + // which `load_namespace`'s own check before each attempt would mask. + let Err(error) = store.lookup(&namespace, &handle).await else { + panic!("the load was not refused"); + }; assert!( matches!(error.as_ref(), Error::NamespaceStoreShutdown), @@ -1841,6 +1862,90 @@ pub(crate) mod test { assert_eq!(count_test_rows(&store, "foo").await.unwrap(), 1); } + #[tokio::test] + async fn reset_interrupted_by_shutdown_installs_nothing() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = create(&store, "foo").await; + + let (tx, dump) = slow_dump(); + let reset = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { store.reset(foo, RestoreOption::Dump(dump)).await } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; + // Shutdown does not wait for the reset in progress; it must not install its result. + store.inner.has_shutdown.store(true, Ordering::Relaxed); + tx.send(Ok(Bytes::from_static(b"COMMIT;"))).await.unwrap(); + drop(tx); + + let error = reset.await.unwrap().unwrap_err(); + assert!( + matches!( + error.downcast_ref::(), + Some(Error::NamespaceStoreShutdown) + ), + "{error:?}" + ); + let entry = store + .inner + .store + .get(&foo) + .await + .expect("the entry stays cached"); + assert!(entry.read().await.is_none(), "a namespace was installed"); + assert!(store.inner.in_flight.lock().is_empty()); + } + + #[tokio::test] + async fn shutdown_does_not_wait_for_a_creation_in_progress() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + let bar = create(&store, "bar").await; + + let (tx, dump) = slow_dump(); + let create = tokio::spawn({ + let (store, foo) = (store.clone(), foo.clone()); + async move { + store + .create(foo, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &foo).await; + + // The creation is blocked on its dump and holds its entry locked. Shutdown must finish + // without it, and still shut the other namespaces down. + tokio::time::timeout(Duration::from_secs(5), store.clone().shutdown()) + .await + .expect("shutdown waited for the creation in progress") + .unwrap(); + assert!( + store.inner.store.get(&bar).await.is_none(), + "the other namespace was not shut down" + ); + + tx.send(Ok(Bytes::from_static(b"COMMIT;"))).await.unwrap(); + drop(tx); + let error = create.await.unwrap().unwrap_err(); + assert!( + matches!(error.as_ref(), Error::NamespaceStoreShutdown), + "{error:?}" + ); + assert!(!store.exists(&foo).await); + } + #[tokio::test] async fn create_after_shutdown_is_refused() { let tmp = tempdir().unwrap(); From 3415426586c5395f31cc23bbebee3265fd4aa22c Mon Sep 17 00:00:00 2001 From: Tomasz Szymczyszyn Date: Fri, 16 Oct 2026 15:58:23 +0200 Subject: [PATCH 5/5] libsql-server: more namespace store tests around emptied entries - lookups racing a destroy do not resurrect the namespace (no record, directory or filled entry afterwards; 20 rounds of 8 lookups); - reset and destroy of a namespace whose entry was left empty; - a create and a fork racing for one destination: the fork waits for the create's reservation, then is rejected, and leaves nothing behind; - lazy creation (what a replica runs with): an evicted namespace is reloaded and giving up is "unavailable", never "doesn't exist"; - a 10 s randomized run (`#[ignore]`): 12 tasks create, fork, look up, checkpoint and evict up to 60 namespaces; no lookup of a created namespace may fail, and afterwards every namespace is servable, no unlocked empty entry is cached, nothing is pinned, no marker remains. The randomized run leaves `destroy` out: a lookup whose entry was evicted can be loading while `destroy` removes the directory, which fails the destroy with `Directory not empty` and can leave a loaded namespace cached for a name the metastore no longer knows. That predates this change. It also keeps evictions rare: a lookup whose entry is emptied again after each of its three loads gives up with `NamespaceUnavailable` by design. `make_store` takes the lazy-creation flag and the cache capacity. --- libsql-server/src/namespace/store.rs | 358 ++++++++++++++++++++++++++- 1 file changed, 356 insertions(+), 2 deletions(-) diff --git a/libsql-server/src/namespace/store.rs b/libsql-server/src/namespace/store.rs index a383545454..5f49f2aaed 100644 --- a/libsql-server/src/namespace/store.rs +++ b/libsql-server/src/namespace/store.rs @@ -1043,6 +1043,16 @@ pub(crate) mod test { use super::*; pub(crate) async fn make_store(path: &Path) -> NamespaceStore { + make_store_with(path, false, 10).await + } + + /// `allow_lazy_creation` is what a replica runs with: a lookup of an unknown namespace + /// creates it. `max_active_namespaces` is the cache's capacity. + async fn make_store_with( + path: &Path, + allow_lazy_creation: bool, + max_active_namespaces: usize, + ) -> NamespaceStore { let (maker, manager) = metastore_connection_maker(None, path).await.unwrap(); let meta_store = MetaStore::new( Default::default(), @@ -1080,9 +1090,9 @@ pub(crate) mod test { Arc::new(libsql_sys::wal::Sqlite3WalManager::default), )); NamespaceStore::new( + allow_lazy_creation, false, - false, - 10, + max_active_namespaces, meta_store, configurators, DatabaseKind::Primary, @@ -1946,6 +1956,350 @@ pub(crate) mod test { assert!(!store.exists(&foo).await); } + /// Lookups racing a destroy must not bring the namespace back: no record, no directory, + /// no filled cache entry once both are done. The window is between a lookup's metastore + /// check and its load; it cannot be hit deterministically, so this hammers it. + #[tokio::test] + async fn lookups_racing_a_destroy_do_not_resurrect_the_namespace() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = NamespaceName::from_string("foo".into()).unwrap(); + + for _ in 0..20 { + create(&store, "foo").await; + let destroyed = Arc::new(AtomicBool::new(false)); + let lookups: Vec<_> = (0..8) + .map(|_| { + tokio::spawn({ + let (store, foo, destroyed) = + (store.clone(), foo.clone(), destroyed.clone()); + async move { + let mut after_destroy_ok = 0; + while !destroyed.load(Ordering::Relaxed) { + let was_destroyed = destroyed.load(Ordering::Relaxed); + let result = store.with(foo.clone(), |_| ()).await; + match result { + Ok(()) if was_destroyed => after_destroy_ok += 1, + Ok(()) => {} + Err(e) => assert!( + matches!(e.as_ref(), Error::NamespaceDoesntExist(_)), + "{e:?}" + ), + } + tokio::task::yield_now().await; + } + after_destroy_ok + } + }) + }) + .collect(); + tokio::task::yield_now().await; + store.destroy(foo.clone(), true).await.unwrap(); + destroyed.store(true, Ordering::Relaxed); + for lookup in lookups { + assert_eq!(lookup.await.unwrap(), 0, "a lookup served after destroy"); + } + + assert!(!store.exists(&foo).await); + assert!(!tmp.path().join("dbs").join("foo").exists()); + if let Some(entry) = store.inner.store.get(&foo).await { + assert!(entry.read().await.is_none(), "a namespace was resurrected"); + } + store.inner.store.invalidate(&foo).await; + assert!(store.inner.in_flight.lock().is_empty()); + } + } + + #[tokio::test] + async fn reset_of_a_namespace_whose_entry_was_left_empty() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = create(&store, "foo").await; + let entry = store.inner.store.get(&foo).await.unwrap(); + entry + .write() + .await + .take() + .unwrap() + .shutdown(false) + .await + .unwrap(); + + store + .reset(foo.clone(), RestoreOption::Latest) + .await + .unwrap(); + + let cached = store.inner.store.get(&foo).await.unwrap(); + assert!(cached.read().await.is_some(), "reset installed nothing"); + assert!(store.inner.in_flight.lock().is_empty()); + store.with(foo, |_| ()).await.unwrap(); + } + + #[tokio::test] + async fn create_and_fork_racing_for_one_destination() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let src = create(&store, "src").await; + let dst = NamespaceName::from_string("dst".into()).unwrap(); + + let (tx, dump) = slow_dump(); + let create = tokio::spawn({ + let (store, dst) = (store.clone(), dst.clone()); + async move { + store + .create(dst, RestoreOption::Dump(dump), Default::default()) + .await + } + }); + tx.send(Ok(Bytes::from_static( + b"BEGIN TRANSACTION; CREATE TABLE test (x); INSERT INTO test VALUES (1);", + ))) + .await + .unwrap(); + wait_until_in_flight(&store, &dst).await; + let fork = tokio::spawn({ + let (store, src, dst) = (store.clone(), src.clone(), dst.clone()); + async move { store.fork(src, dst, Default::default(), None).await } + }); + // The fork waits for the reservation the create holds. + tokio::time::sleep(Duration::from_millis(50)).await; + assert!(!fork.is_finished()); + tx.send(Ok(Bytes::from_static(b"COMMIT;"))).await.unwrap(); + drop(tx); + + create.await.unwrap().unwrap(); + let error = fork.await.unwrap().unwrap_err(); + assert!( + matches!(error.as_ref(), Error::NamespaceAlreadyExist(_)), + "{error:?}" + ); + // The create's result is what is served, and the rejected fork left nothing behind. + assert_eq!(count_test_rows(&store, "dst").await.unwrap(), 1); + assert!(store.inner.in_flight.lock().is_empty()); + assert!(!tmp + .path() + .join("dbs") + .join("dst") + .join(".incomplete") + .exists()); + } + + #[tokio::test] + async fn destroy_of_a_namespace_whose_entry_was_left_empty() { + let tmp = tempdir().unwrap(); + let store = make_store(tmp.path()).await; + let foo = create(&store, "foo").await; + let entry = store.inner.store.get(&foo).await.unwrap(); + entry + .write() + .await + .take() + .unwrap() + .shutdown(false) + .await + .unwrap(); + + store.destroy(foo.clone(), true).await.unwrap(); + + assert!(!store.exists(&foo).await); + assert!(!tmp.path().join("dbs").join("foo").exists()); + assert!(store.inner.store.get(&foo).await.is_none()); + let error = store.with(foo, |_| ()).await.unwrap_err(); + assert!( + matches!(error.as_ref(), Error::NamespaceDoesntExist(_)), + "{error:?}" + ); + } + + /// On a replica every lookup may create the namespace, so no lookup ever answers "doesn't + /// exist", and an entry emptied while a request waits is reloaded like on a primary. + #[tokio::test] + async fn lazy_creation_reloads_an_evicted_namespace_and_never_reports_it_missing() { + let tmp = tempdir().unwrap(); + let store = make_store_with(tmp.path(), true, 10).await; + let namespace = NamespaceName::from_string("ns".into()).unwrap(); + // Created by the lookup itself. + store.with(namespace.clone(), |_| ()).await.unwrap(); + assert!(store.exists(&namespace).await); + + let entry = store.inner.store.get(&namespace).await.unwrap(); + let mut lock = entry.write().await; + let request = start_waiting_request(&store, &namespace, &entry).await; + let eviction = tokio::spawn({ + let store = store.clone(); + let namespace = namespace.clone(); + async move { store.inner.store.invalidate(&namespace).await } + }); + wait_until("the entry is evicted", || { + !store.inner.store.contains_key(&namespace) + }) + .await; + lock.take().unwrap().shutdown(false).await.unwrap(); + drop(lock); + + assert_eq!(request.await.unwrap().unwrap(), namespace); + eviction.await.unwrap(); + assert!(store + .inner + .store + .get(&namespace) + .await + .unwrap() + .read() + .await + .is_some()); + + // With the entry left empty for good, giving up is "unavailable", not "missing". + let entry = store.inner.store.get(&namespace).await.unwrap(); + entry + .write() + .await + .take() + .unwrap() + .shutdown(false) + .await + .unwrap(); + let error = store.emptied_entry_error(&namespace).await; + assert!(matches!(error, Error::NamespaceUnavailable(_)), "{error:?}"); + } + + /// Random `with`, `create`, `fork`, `checkpoint` and eviction for a while, on up to 60 + /// namespaces, with one operation in fifty evicting an entry, so that entries are emptied + /// while in use all the time. Nothing is destroyed, so every "doesn't exist" is a false one. + /// + /// Checked throughout: a lookup of a created namespace never fails, and a create or fork is + /// either accepted or rejected with "already exists". Checked at the end: every created + /// namespace is servable, no unlocked empty entry is left, nothing is pinned, and no + /// `.incomplete` marker remains. + /// + /// `destroy` is left out on purpose: a lookup whose entry was evicted may be loading + /// (creating files) while `destroy` removes the directory, which fails the destroy with + /// `Directory not empty` and can leave a loaded namespace cached for a name the metastore + /// no longer knows. That predates this change and is not fixed by it. + /// + /// The cache is larger than the number of namespaces, and evictions are rare, on purpose. + /// A lookup gives up with `NamespaceUnavailable` when its entry is emptied again after each + /// of `MAX_EMPTIED_ENTRY_ATTEMPTS` loads. A full cache does that (moka's admission policy + /// can evict a freshly loaded entry at once), and so does evicting one name from twelve + /// tasks faster than a load takes. Both are the designed outcome of eviction outrunning + /// loads (the base answered "doesn't exist" after the first load), not what this test is + /// about. + /// + /// Slow, so not part of the default run: + /// `cargo nextest run -p libsql-server --run-ignored only -E 'test(random_operations)'`. + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] + #[ignore] + async fn random_operations_keep_the_store_consistent() { + use std::sync::atomic::AtomicUsize; + + let tmp = tempdir().unwrap(); + const NAMES: usize = 60; + let store = make_store_with(tmp.path(), false, 1000).await; + let names: Vec = (0..NAMES) + .map(|i| NamespaceName::from_string(format!("ns{i}")).unwrap()) + .collect(); + // Number of namespaces known to exist; `names[..created]` are safe to look up. + for name in &names[..10] { + create(&store, name.as_str()).await; + } + let created = Arc::new(AtomicUsize::new(10)); + let deadline = Instant::now() + Duration::from_secs(10); + + let workers: Vec<_> = (0..12) + .map(|worker| { + tokio::spawn({ + let (store, names, created) = (store.clone(), names.clone(), created.clone()); + async move { + let mut seed = 0x9E3779B97F4A7C15u64 ^ (worker as u64 + 1); + let mut next = || { + seed ^= seed << 13; + seed ^= seed >> 7; + seed ^= seed << 17; + seed + }; + let mut ops = 0u64; + while Instant::now() < deadline { + let known = created.load(Ordering::SeqCst); + let pick = |next: &mut dyn FnMut() -> u64| { + names[(next() % known.max(1) as u64) as usize].clone() + }; + match next() % 50 { + 0..=9 if known < NAMES => { + // Create or fork the next name; whoever is second gets + // "already exists". Only a success makes it known. + let name = names[known].clone(); + let r = if known > 0 && next() % 2 == 0 { + store + .fork(pick(&mut next), name, Default::default(), None) + .await + } else { + store + .create(name, RestoreOption::Latest, Default::default()) + .await + }; + match r { + Ok(()) => { + created.store(known + 1, Ordering::SeqCst); + } + Err(e) => assert!( + matches!(e.as_ref(), Error::NamespaceAlreadyExist(_)), + "create/fork: {e:?}" + ), + } + } + 10 if known > 0 => { + store.inner.store.invalidate(&pick(&mut next)).await + } + 11..=15 if known > 0 => { + // May fail with SQLITE_BUSY under concurrent writes. + let _ = store.checkpoint(pick(&mut next)).await; + } + _ if known > 0 => { + let name = pick(&mut next); + if let Err(e) = store.with(name.clone(), |_| ()).await { + panic!("lookup of {name}: {e:?}"); + } + } + _ => tokio::task::yield_now().await, + } + ops += 1; + } + ops + } + }) + }) + .collect(); + let mut ops = 0; + for worker in workers { + ops += worker.await.unwrap(); + } + let known = created.load(Ordering::SeqCst); + eprintln!("{ops} operations on {known} namespaces"); + assert!( + ops > 1000 && known > 10, + "only {ops} operations, {known} namespaces" + ); + + store.inner.store.run_pending_tasks().await; + assert!(store.inner.in_flight.lock().is_empty()); + for name in &names[..known] { + store.with(name.clone(), |_| ()).await.unwrap(); + assert!(!tmp + .path() + .join("dbs") + .join(name.as_str()) + .join(".incomplete") + .exists()); + } + for (name, entry) in store.inner.store.iter() { + let lock = entry + .try_read() + .expect("nothing holds an entry locked any more"); + assert!(lock.is_some(), "{name}: an unlocked empty entry was left"); + } + } + #[tokio::test] async fn create_after_shutdown_is_refused() { let tmp = tempdir().unwrap();