Skip to content

Commit a33fa94

Browse files
Drop views, metadadta, and disconnect clients when auto-migrating
1 parent 092eb8b commit a33fa94

File tree

3 files changed

+76
-19
lines changed

3 files changed

+76
-19
lines changed

crates/datastore/src/locking_tx_datastore/committed_state.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use core::{convert::Infallible, ops::RangeBounds};
3030
use spacetimedb_data_structures::map::{HashSet, IntMap, IntSet};
3131
use spacetimedb_durability::TxOffset;
3232
use spacetimedb_lib::{db::auth::StTableType, Identity};
33-
use spacetimedb_primitives::{ColId, ColList, ColSet, IndexId, TableId};
33+
use spacetimedb_primitives::{ColId, ColList, ColSet, IndexId, TableId, ViewId};
3434
use spacetimedb_sats::{algebraic_value::de::ValueDeserializer, memory_usage::MemoryUsage, Deserialize};
3535
use spacetimedb_sats::{AlgebraicValue, ProductValue};
3636
use spacetimedb_schema::{
@@ -624,6 +624,10 @@ impl CommittedState {
624624
tx_data.has_rows_or_connect_disconnect(ctx.reducer_context())
625625
}
626626

627+
pub(super) fn drop_view_from_read_sets(&mut self, view_id: ViewId) {
628+
self.read_sets.remove_view(view_id)
629+
}
630+
627631
pub(super) fn merge(&mut self, tx_state: TxState, read_sets: ViewReadSets, ctx: &ExecutionContext) -> TxData {
628632
let mut tx_data = TxData::default();
629633
let mut truncates = IntSet::default();

crates/datastore/src/locking_tx_datastore/mut_tx.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ impl ViewReadSets {
109109
self.tables.entry(table_id).or_default().insert_scan(call);
110110
}
111111

112+
/// Removes keys for `view_id` from the read set
113+
pub fn remove_view(&mut self, view_id: ViewId) {
114+
self.tables.retain(|_, readset| {
115+
readset.remove_view(view_id);
116+
!readset.is_empty()
117+
});
118+
}
119+
112120
/// Merge or union read sets together
113121
pub fn merge(&mut self, readset: Self) {
114122
for (table_id, rs) in readset.tables {
@@ -134,6 +142,16 @@ impl TableReadSet {
134142
self.table_scans.iter()
135143
}
136144

145+
/// Is this read set empty?
146+
fn is_empty(&self) -> bool {
147+
self.table_scans.is_empty()
148+
}
149+
150+
/// Removes keys for `view_id` from the read set
151+
fn remove_view(&mut self, view_id: ViewId) {
152+
self.table_scans.retain(|info| info.view_id != view_id);
153+
}
154+
137155
/// Merge or union two read sets for this table
138156
fn merge(&mut self, readset: TableReadSet) {
139157
self.table_scans.extend(readset.table_scans);
@@ -199,6 +217,12 @@ impl MutTxId {
199217
.collect::<HashSet<_>>()
200218
.into_iter()
201219
}
220+
221+
/// Removes keys for `view_id` from the committed read set.
222+
/// Used for dropping views in an auto-migration.
223+
pub fn drop_view_from_committed_read_set(&mut self, view_id: ViewId) {
224+
self.committed_state_write_lock.drop_view_from_read_sets(view_id)
225+
}
202226
}
203227

204228
impl Datastore for MutTxId {
@@ -369,6 +393,8 @@ impl MutTxId {
369393
self.drop_st_view(view_id)?;
370394
self.drop_st_view_param(view_id)?;
371395
self.drop_st_view_column(view_id)?;
396+
self.drop_st_view_sub(view_id)?;
397+
self.drop_view_from_committed_read_set(view_id);
372398

373399
// Drop the view's backing table if materialized
374400
if let StViewRow {
@@ -637,6 +663,11 @@ impl MutTxId {
637663
self.delete_col_eq(ST_VIEW_COLUMN_ID, StViewColumnFields::ViewId.col_id(), &view_id.into())
638664
}
639665

666+
/// Drops the rows in `st_view_sub` for this `view_id`
667+
fn drop_st_view_sub(&mut self, view_id: ViewId) -> Result<()> {
668+
self.delete_col_eq(ST_VIEW_SUB_ID, StViewSubFields::ViewId.col_id(), &view_id.into())
669+
}
670+
640671
pub fn drop_table(&mut self, table_id: TableId) -> Result<()> {
641672
self.clear_table(table_id)?;
642673

crates/schema/src/auto_migrate.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ fn auto_migrate_view<'def>(plan: &mut AutoMigratePlan<'def>, old: &'def ViewDef,
546546
// 2. If we change the order of the columns or parameters
547547
// 3. If we change the types of the columns or parameters
548548
// 4. If we change the context parameter
549-
let Any(incompatible_return_type) = diff(plan.old, plan.new, |def| {
549+
let Any(_incompatible_return_type) = diff(plan.old, plan.new, |def| {
550550
def.lookup_expect::<ViewDef>(key).return_columns.iter()
551551
})
552552
.map(|col_diff| {
@@ -575,7 +575,7 @@ fn auto_migrate_view<'def>(plan: &mut AutoMigratePlan<'def>, old: &'def ViewDef,
575575
})
576576
.collect();
577577

578-
let Any(incompatible_param_types) = diff(plan.old, plan.new, |def| {
578+
let Any(_incompatible_param_types) = diff(plan.old, plan.new, |def| {
579579
def.lookup_expect::<ViewDef>(key).param_columns.iter()
580580
})
581581
.map(|col_diff| {
@@ -604,15 +604,24 @@ fn auto_migrate_view<'def>(plan: &mut AutoMigratePlan<'def>, old: &'def ViewDef,
604604
})
605605
.collect();
606606

607-
if old.is_anonymous != new.is_anonymous || incompatible_return_type || incompatible_param_types {
608-
plan.steps.push(AutoMigrateStep::AddView(new.key()));
609-
plan.steps.push(AutoMigrateStep::RemoveView(old.key()));
610-
611-
if !plan.disconnects_all_users() {
612-
plan.steps.push(AutoMigrateStep::DisconnectAllUsers);
613-
}
614-
} else {
615-
plan.steps.push(AutoMigrateStep::UpdateView(old.key()));
607+
// TODO: Uncomment and re-enable view auto-migrations without disconnecting clients
608+
//
609+
// if old.is_anonymous != new.is_anonymous || incompatible_return_type || incompatible_param_types {
610+
// plan.steps.push(AutoMigrateStep::AddView(new.key()));
611+
// plan.steps.push(AutoMigrateStep::RemoveView(old.key()));
612+
613+
// if !plan.disconnects_all_users() {
614+
// plan.steps.push(AutoMigrateStep::DisconnectAllUsers);
615+
// }
616+
// } else {
617+
// plan.steps.push(AutoMigrateStep::UpdateView(old.key()));
618+
// }
619+
620+
plan.steps.push(AutoMigrateStep::AddView(new.key()));
621+
plan.steps.push(AutoMigrateStep::RemoveView(old.key()));
622+
623+
if !plan.disconnects_all_users() {
624+
plan.steps.push(AutoMigrateStep::DisconnectAllUsers);
616625
}
617626

618627
Ok(())
@@ -1904,18 +1913,31 @@ mod tests {
19041913
let plan = ponder_auto_migrate(&old_def, &new_def).expect("auto migration should succeed");
19051914
let steps = &plan.steps[..];
19061915

1907-
assert!(!plan.disconnects_all_users(), "{name}, plan: {plan:#?}");
1916+
// TODO: Assert that we don't disconnect users once we have automatic view update in auto-migrations
1917+
//
1918+
// assert!(!plan.disconnects_all_users(), "{name}, plan: {plan:#?}");
1919+
1920+
// assert!(
1921+
// steps.contains(&AutoMigrateStep::UpdateView(&my_view)),
1922+
// "{name}, steps: {steps:?}"
1923+
// );
1924+
// assert!(
1925+
// !steps.contains(&AutoMigrateStep::AddView(&my_view)),
1926+
// "{name}, steps: {steps:?}"
1927+
// );
1928+
// assert!(
1929+
// !steps.contains(&AutoMigrateStep::RemoveView(&my_view)),
1930+
// "{name}, steps: {steps:?}"
1931+
// );
1932+
1933+
assert!(plan.disconnects_all_users(), "{name}, plan: {plan:#?}");
19081934

19091935
assert!(
1910-
steps.contains(&AutoMigrateStep::UpdateView(&my_view)),
1911-
"{name}, steps: {steps:?}"
1912-
);
1913-
assert!(
1914-
!steps.contains(&AutoMigrateStep::AddView(&my_view)),
1936+
steps.contains(&AutoMigrateStep::AddView(&my_view)),
19151937
"{name}, steps: {steps:?}"
19161938
);
19171939
assert!(
1918-
!steps.contains(&AutoMigrateStep::RemoveView(&my_view)),
1940+
steps.contains(&AutoMigrateStep::RemoveView(&my_view)),
19191941
"{name}, steps: {steps:?}"
19201942
);
19211943
}

0 commit comments

Comments
 (0)