diff --git a/Cargo.lock b/Cargo.lock index a52f79f9..54d28e93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2787,6 +2787,9 @@ dependencies = [ "keyvaluedb", "keyvaluedb-shared-tests", "parking_lot 0.12.1", + "tokio 1.23.0", + "wasm-bindgen-futures", + "wasm-bindgen-test", ] [[package]] @@ -2815,6 +2818,7 @@ dependencies = [ "rusqlite", "sysinfo", "tempfile", + "tokio 1.23.0", ] [[package]] @@ -2822,6 +2826,7 @@ name = "keyvaluedb-web" version = "0.1.0" dependencies = [ "console_log", + "flume", "futures", "js-sys", "keyvaluedb", diff --git a/external/keyvaluedb b/external/keyvaluedb index e30d0058..3408e0b2 160000 --- a/external/keyvaluedb +++ b/external/keyvaluedb @@ -1 +1 @@ -Subproject commit e30d0058defd9cfd7bd546bb177228edda8076ab +Subproject commit 3408e0b2ae3df0088e0714bc23fb33c82a58e22c diff --git a/veilid-core/src/intf/table_db.rs b/veilid-core/src/intf/table_db.rs index 23f789c7..a6bb6b5d 100644 --- a/veilid-core/src/intf/table_db.rs +++ b/veilid-core/src/intf/table_db.rs @@ -17,13 +17,19 @@ pub struct TableDBInner { database: Database, } +impl fmt::Debug for TableDBInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TableDBInner(table={})", self.table) + } +} + impl Drop for TableDBInner { fn drop(&mut self) { self.table_store.on_table_db_drop(self.table.clone()); } } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct TableDB { inner: Arc>, } @@ -68,12 +74,12 @@ impl TableDB { } /// Start a TableDB write transaction. The transaction object must be committed or rolled back before dropping. - pub fn transact<'a>(&'a self) -> TableDBTransaction<'a> { + pub fn transact(&self) -> TableDBTransaction { let dbt = { let db = &self.inner.lock().database; db.transaction() }; - TableDBTransaction::new(self, dbt) + TableDBTransaction::new(self.clone(), dbt) } /// Store a key with a value in a column in the TableDB. Performs a single transaction immediately. @@ -172,31 +178,54 @@ impl TableDB { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// A TableDB transaction -/// Atomically commits a group of writes or deletes to the TableDB -pub struct TableDBTransaction<'a> { - db: &'a TableDB, +struct TableDBTransactionInner { dbt: Option, - _phantom: core::marker::PhantomData<&'a ()>, } -impl<'a> TableDBTransaction<'a> { - fn new(db: &'a TableDB, dbt: DBTransaction) -> Self { +impl fmt::Debug for TableDBTransactionInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "TableDBTransactionInner({})", + match &self.dbt { + Some(dbt) => format!("len={}", dbt.ops.len()), + None => "".to_owned(), + } + ) + } +} + +/// A TableDB transaction +/// Atomically commits a group of writes or deletes to the TableDB +#[derive(Debug, Clone)] +pub struct TableDBTransaction { + db: TableDB, + inner: Arc>, +} + +impl TableDBTransaction { + fn new(db: TableDB, dbt: DBTransaction) -> Self { Self { db, - dbt: Some(dbt), - _phantom: Default::default(), + inner: Arc::new(Mutex::new(TableDBTransactionInner { dbt: Some(dbt) })), } } /// Commit the transaction. Performs all actions atomically. pub fn commit(mut self) -> EyreResult<()> { + let dbt = { + let inner = self.inner.lock(); + inner + .dbt + .take() + .ok_or_else(|| Err(eyre!("transaction already completed")))? + }; self.db .inner .lock() .database - .write(self.dbt.take().unwrap()) - .wrap_err("commit failed") + .write(dbt) + .wrap_err("commit failed, transaction lost") } /// Rollback the transaction. Does nothing to the TableDB. @@ -235,7 +264,7 @@ impl<'a> TableDBTransaction<'a> { } } -impl<'a> Drop for TableDBTransaction<'a> { +impl Drop for TableDBTransactionInner { fn drop(&mut self) { if self.dbt.is_some() { warn!("Dropped transaction without commit or rollback"); diff --git a/veilid-flutter/lib/veilid.dart b/veilid-flutter/lib/veilid.dart index e87ecfc7..a83918d3 100644 --- a/veilid-flutter/lib/veilid.dart +++ b/veilid-flutter/lib/veilid.dart @@ -1847,6 +1847,14 @@ abstract class VeilidRoutingContext { Future appMessage(String target, Uint8List message); } +///////////////////////////////////// +/// VeilidTableDB +abstract class VeilidTableDB { + int getColumnCount(); + List getKeys(); + VeilidTableDBTransaction transact() +} + ////////////////////////////////////// /// Veilid singleton factory @@ -1874,6 +1882,10 @@ abstract class Veilid { // App calls Future appCallReply(String id, Uint8List message); + // TableStore + Future openTableDB(String name, int columnCount); + Future deleteTableDB(String name); + // Misc String veilidVersionString(); VeilidVersion veilidVersion();