@@ -44,6 +44,7 @@ use spacetimedb_table::{
4444} ;
4545use std:: collections:: BTreeMap ;
4646use std:: sync:: Arc ;
47+ use thin_vec:: ThinVec ;
4748
4849/// Contains the live, in-memory snapshot of a database. This structure
4950/// is exposed in order to support tools wanting to process the commit
@@ -593,12 +594,23 @@ impl CommittedState {
593594 pub ( super ) fn merge ( & mut self , tx_state : TxState , ctx : & ExecutionContext ) -> TxData {
594595 let mut tx_data = TxData :: default ( ) ;
595596
597+ // This transaction may have dropped tables.
598+ // After applying `merge_apply_deletes` and `merge_apply_inserts`,
599+ // any tables no longer referenced by `st_table` should be
600+ // removed from the committed state.
601+ let mut tables_to_drop = ThinVec :: < TableId > :: new ( ) ;
602+
596603 // First, apply deletes. This will free up space in the committed tables.
597- self . merge_apply_deletes ( & mut tx_data, tx_state. delete_tables ) ;
604+ self . merge_apply_deletes ( & mut tx_data, & mut tables_to_drop , tx_state. delete_tables ) ;
598605
599606 // Then, apply inserts. This will re-fill the holes freed by deletions
600607 // before allocating new pages.
601- self . merge_apply_inserts ( & mut tx_data, tx_state. insert_tables , tx_state. blob_store ) ;
608+ self . merge_apply_inserts (
609+ & mut tx_data,
610+ & mut tables_to_drop,
611+ tx_state. insert_tables ,
612+ tx_state. blob_store ,
613+ ) ;
602614
603615 // If the TX will be logged, record its projected tx offset,
604616 // then increment the counter.
@@ -607,10 +619,19 @@ impl CommittedState {
607619 self . next_tx_offset += 1 ;
608620 }
609621
622+ for table_id in tables_to_drop {
623+ self . tables . remove ( & table_id) ;
624+ }
625+
610626 tx_data
611627 }
612628
613- fn merge_apply_deletes ( & mut self , tx_data : & mut TxData , delete_tables : BTreeMap < TableId , DeleteTable > ) {
629+ fn merge_apply_deletes (
630+ & mut self ,
631+ tx_data : & mut TxData ,
632+ dropped_table_ids : & mut ThinVec < TableId > ,
633+ delete_tables : BTreeMap < TableId , DeleteTable > ,
634+ ) {
614635 for ( table_id, row_ptrs) in delete_tables {
615636 if let ( Some ( table) , blob_store, _) = self . get_table_and_blob_store_mut ( table_id) {
616637 let mut deletes = Vec :: with_capacity ( row_ptrs. len ( ) ) ;
@@ -626,6 +647,14 @@ impl CommittedState {
626647 let pv = table
627648 . delete ( blob_store, row_ptr, |row| row. to_product_value ( ) )
628649 . expect ( "Delete for non-existent row!" ) ;
650+
651+ if table_id == ST_TABLE_ID {
652+ let st_table_row =
653+ StTableRow :: deserialize ( ValueDeserializer :: from_ref ( & AlgebraicValue :: Product ( pv. clone ( ) ) ) )
654+ . expect ( "st_table row should deserialize" ) ;
655+ dropped_table_ids. push ( st_table_row. table_id ) ;
656+ }
657+
629658 deletes. push ( pv) ;
630659 }
631660
@@ -642,6 +671,7 @@ impl CommittedState {
642671 fn merge_apply_inserts (
643672 & mut self ,
644673 tx_data : & mut TxData ,
674+ dropped_table_ids : & mut ThinVec < TableId > ,
645675 insert_tables : BTreeMap < TableId , Table > ,
646676 tx_blob_store : impl BlobStore ,
647677 ) {
@@ -665,6 +695,15 @@ impl CommittedState {
665695 . insert ( page_pool, commit_blob_store, & pv)
666696 . expect ( "Failed to insert when merging commit" ) ;
667697
698+ // If we inserted a row back into `st_table`,
699+ // it means transaction only updates a row and do not drop the table.
700+ if table_id == ST_TABLE_ID {
701+ let st_table_row =
702+ StTableRow :: deserialize ( ValueDeserializer :: from_ref ( & AlgebraicValue :: Product ( pv. clone ( ) ) ) )
703+ . expect ( "st_table row should deserialize" ) ;
704+ dropped_table_ids. retain ( |& id| id != st_table_row. table_id ) ;
705+ }
706+
668707 inserts. push ( pv) ;
669708 }
670709
@@ -717,13 +756,6 @@ impl CommittedState {
717756 table. with_mut_schema ( |s| s. remove_index ( index_id) ) ;
718757 self . index_id_map . remove ( & index_id) ;
719758 }
720- // A table was removed. Add it back.
721- TableRemoved ( table_id, table) => {
722- // We don't need to deal with sub-components.
723- // That is, we don't need to add back indices and such.
724- // Instead, there will be separate pending schema changes like `IndexRemoved`.
725- self . tables . insert ( table_id, table) ;
726- }
727759 // A table was added. Remove it.
728760 TableAdded ( table_id) => {
729761 // We don't need to deal with sub-components.
0 commit comments