Skip to content

Commit e17509a

Browse files
committed
fix drop tables
1 parent 6bd815f commit e17509a

File tree

4 files changed

+67
-29
lines changed

4 files changed

+67
-29
lines changed

crates/datastore/src/locking_tx_datastore/committed_state.rs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use spacetimedb_table::{
4444
};
4545
use std::collections::BTreeMap;
4646
use 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 = thin_vec::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.

crates/datastore/src/locking_tx_datastore/datastore.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ pub struct TxMetrics {
675675
exec_metrics: ExecutionMetrics,
676676
}
677677

678+
#[derive(Default)]
678679
struct TableStats {
679680
/// The number of rows in the table after this transaction.
680681
///
@@ -715,16 +716,16 @@ impl TxMetrics {
715716
let mut table_stats =
716717
<HashMap<_, _, _> as HashCollectionExt>::with_capacity(tx_data.num_tables_affected());
717718
for (table_id, _) in tx_data.table_ids_and_names() {
718-
let table = committed_state
719-
.get_table(table_id)
720-
.expect("should have a table in committed state for one in tx data");
721719
table_stats.insert(
722720
table_id,
723-
TableStats {
724-
row_count: table.row_count,
725-
bytes_occupied_overestimate: table.bytes_occupied_overestimate(),
726-
num_indices: table.num_indices(),
727-
},
721+
committed_state
722+
.get_table(table_id)
723+
.map(|table| TableStats {
724+
row_count: table.row_count,
725+
bytes_occupied_overestimate: table.bytes_occupied_overestimate(),
726+
num_indices: table.num_indices(),
727+
})
728+
.unwrap_or_default(),
728729
);
729730
}
730731
table_stats
@@ -3082,9 +3083,7 @@ mod tests {
30823083
PendingSchemaChange::SequenceRemoved(..),
30833084
PendingSchemaChange::ConstraintRemoved(..),
30843085
PendingSchemaChange::ConstraintRemoved(..),
3085-
PendingSchemaChange::TableRemoved(removed_table_id, _)
30863086
]
3087-
if *removed_table_id == table_id
30883087
);
30893088
let _ = datastore.rollback_mut_tx(tx);
30903089

@@ -3096,7 +3095,17 @@ mod tests {
30963095
"Table should still exist",
30973096
);
30983097
assert_eq!(all_rows(&datastore, &tx, table_id), [row]);
3098+
let _ = datastore.rollback_mut_tx(tx);
3099+
3100+
let mut tx = begin_mut_tx(&datastore);
3101+
assert!(datastore.drop_table_mut_tx(&mut tx, table_id).is_ok());
3102+
commit(&datastore, tx)?;
30993103

3104+
let tx = begin_mut_tx(&datastore);
3105+
assert!(
3106+
!datastore.table_id_exists_mut_tx(&tx, &table_id),
3107+
"Table should be removed",
3108+
);
31003109
Ok(())
31013110
}
31023111

crates/datastore/src/locking_tx_datastore/mut_tx.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,15 +352,14 @@ impl MutTxId {
352352
)?;
353353
}
354354

355+
// Delete all rows in the table.
356+
let ptrs: Vec<_> = self.iter(table_id)?.map(|row| row.pointer()).collect();
357+
for ptr in ptrs {
358+
self.delete(table_id, ptr)?;
359+
}
360+
355361
// Delete the table and its rows and indexes from memory.
356362
self.tx_state.insert_tables.remove(&table_id);
357-
self.tx_state.delete_tables.remove(&table_id);
358-
let commit_table = self
359-
.committed_state_write_lock
360-
.tables
361-
.remove(&table_id)
362-
.expect("there should be a schema in the committed state if we reach here");
363-
self.push_schema_change(PendingSchemaChange::TableRemoved(table_id, commit_table));
364363

365364
Ok(())
366365
}

crates/datastore/src/locking_tx_datastore/tx_state.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ pub enum PendingSchemaChange {
9595
/// If adding this index caused the pointer map to be removed,
9696
/// it will be present here.
9797
IndexAdded(TableId, IndexId, Option<PointerMap>),
98-
/// The [`Table`] with [`TableId`] was removed.
99-
TableRemoved(TableId, Table),
10098
/// The table with [`TableId`] was added.
10199
TableAdded(TableId),
102100
/// The access of the table with [`TableId`] was changed.

0 commit comments

Comments
 (0)