diff --git a/crates/core/src/db/relational_db.rs b/crates/core/src/db/relational_db.rs index 7e1c703f8da..c84f24e42d0 100644 --- a/crates/core/src/db/relational_db.rs +++ b/crates/core/src/db/relational_db.rs @@ -2591,7 +2591,40 @@ mod tests { } #[test] - fn test_view_tables_are_ephemeral() -> ResultTest<()> { + fn test_view_tables_are_ephemeral_in_commitlog() -> ResultTest<()> { + let stdb = TestDB::durable_without_snapshot_repo()?; + + let (view_id, table_id, _, _) = setup_view(&stdb)?; + + // Write some rows (reusing the same helper) + insert_view_row(&stdb, view_id, table_id, Identity::ONE, 10)?; + insert_view_row(&stdb, view_id, table_id, Identity::ZERO, 20)?; + + assert!( + !project_views(&stdb, table_id, Identity::ZERO).is_empty(), + "View table should NOT be empty after insert" + ); + + // Reopen the database — view tables must not persist + let stdb = stdb.reopen()?; + + // Validate that the view's backing table has been removed + assert!( + project_views(&stdb, table_id, Identity::ZERO).is_empty(), + "View table should be empty after reopening the database" + ); + + let tx = begin_mut_tx(&stdb); + let subs_rows = tx.lookup_st_view_subs(view_id)?; + assert!( + subs_rows.is_empty(), + "st_view_subs should be empty after reopening the database" + ); + Ok(()) + } + + #[test] + fn test_view_tables_are_ephemeral_with_snapshot() -> ResultTest<()> { let stdb = TestDB::durable()?; let (view_id, table_id, _, _) = setup_view(&stdb)?; @@ -2605,6 +2638,10 @@ mod tests { "View table should NOT be empty after insert" ); + let root = stdb.path().snapshots(); + let (_, repo) = make_snapshot(root.clone(), Identity::ZERO, 0, CompressType::None, false); + stdb.take_snapshot(&repo)?.expect("snapshot should succeed"); + // Reopen the database — view tables must not persist let stdb = stdb.reopen()?; diff --git a/crates/datastore/src/locking_tx_datastore/committed_state.rs b/crates/datastore/src/locking_tx_datastore/committed_state.rs index 6f7adf5ee41..d3b98399bff 100644 --- a/crates/datastore/src/locking_tx_datastore/committed_state.rs +++ b/crates/datastore/src/locking_tx_datastore/committed_state.rs @@ -1017,6 +1017,17 @@ impl CommittedState { (table, blob_store, pool) } + /// Returns an iterator over all persistent tables (i.e., non-ephemeral tables) + pub(super) fn persistent_tables_and_blob_store(&mut self) -> (impl Iterator, &HashMapBlobStore) { + ( + self.tables + .iter_mut() + .filter(|(table_id, _)| !self.ephemeral_tables.contains(*table_id)) + .map(|(_, table)| table), + &self.blob_store, + ) + } + pub fn report_data_size(&self, database_identity: Identity) { use crate::db_metrics::data_size::DATA_SIZE_METRICS; diff --git a/crates/datastore/src/locking_tx_datastore/datastore.rs b/crates/datastore/src/locking_tx_datastore/datastore.rs index d11a69b6409..481f3a1becb 100644 --- a/crates/datastore/src/locking_tx_datastore/datastore.rs +++ b/crates/datastore/src/locking_tx_datastore/datastore.rs @@ -282,12 +282,8 @@ impl Locking { tx_offset, ); - let CommittedState { - ref mut tables, - ref blob_store, - .. - } = *committed_state; - let snapshot_dir = repo.create_snapshot(tables.values_mut(), blob_store, tx_offset)?; + let (tables, blob_store) = committed_state.persistent_tables_and_blob_store(); + let snapshot_dir = repo.create_snapshot(tables, blob_store, tx_offset)?; Ok(Some((tx_offset, snapshot_dir))) }