test work
This commit is contained in:
@@ -45,6 +45,7 @@ impl Drop for TableDBUnlockedInner {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableDB {
|
||||
opened_column_count: u32,
|
||||
unlocked_inner: Arc<TableDBUnlockedInner>,
|
||||
}
|
||||
|
||||
@@ -56,11 +57,13 @@ impl TableDB {
|
||||
database: Database,
|
||||
encryption_key: Option<TypedSharedSecret>,
|
||||
decryption_key: Option<TypedSharedSecret>,
|
||||
opened_column_count: u32,
|
||||
) -> Self {
|
||||
let encrypt_info = encryption_key.map(|ek| CryptInfo::new(crypto.clone(), ek));
|
||||
let decrypt_info = decryption_key.map(|dk| CryptInfo::new(crypto.clone(), dk));
|
||||
|
||||
Self {
|
||||
opened_column_count,
|
||||
unlocked_inner: Arc::new(TableDBUnlockedInner {
|
||||
table,
|
||||
table_store,
|
||||
@@ -71,8 +74,12 @@ impl TableDB {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn try_new_from_weak_inner(weak_inner: Weak<TableDBUnlockedInner>) -> Option<Self> {
|
||||
pub(super) fn try_new_from_weak_inner(
|
||||
weak_inner: Weak<TableDBUnlockedInner>,
|
||||
opened_column_count: u32,
|
||||
) -> Option<Self> {
|
||||
weak_inner.upgrade().map(|table_db_unlocked_inner| Self {
|
||||
opened_column_count,
|
||||
unlocked_inner: table_db_unlocked_inner,
|
||||
})
|
||||
}
|
||||
@@ -82,6 +89,7 @@ impl TableDB {
|
||||
}
|
||||
|
||||
/// Get the total number of columns in the TableDB
|
||||
/// Not the number of columns that were opened, rather the total number that could be opened
|
||||
pub fn get_column_count(&self) -> VeilidAPIResult<u32> {
|
||||
let db = &self.unlocked_inner.database;
|
||||
db.num_columns().map_err(VeilidAPIError::from)
|
||||
@@ -144,8 +152,14 @@ impl TableDB {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the list of keys in a column of the TableDB
|
||||
/// Get the list of keys in a column of the TableDAB
|
||||
pub async fn get_keys(&self, col: u32) -> VeilidAPIResult<Vec<Vec<u8>>> {
|
||||
if col >= self.opened_column_count {
|
||||
apibail_generic!(format!(
|
||||
"Column exceeds opened column count {} >= {}",
|
||||
col, self.opened_column_count
|
||||
));
|
||||
}
|
||||
let db = self.unlocked_inner.database.clone();
|
||||
let mut out = Vec::new();
|
||||
db.iter_keys(col, None, |k| {
|
||||
@@ -165,6 +179,12 @@ impl TableDB {
|
||||
|
||||
/// Store a key with a value in a column in the TableDB. Performs a single transaction immediately.
|
||||
pub async fn store(&self, col: u32, key: &[u8], value: &[u8]) -> VeilidAPIResult<()> {
|
||||
if col >= self.opened_column_count {
|
||||
apibail_generic!(format!(
|
||||
"Column exceeds opened column count {} >= {}",
|
||||
col, self.opened_column_count
|
||||
));
|
||||
}
|
||||
let db = self.unlocked_inner.database.clone();
|
||||
let mut dbt = db.transaction();
|
||||
dbt.put(
|
||||
@@ -195,6 +215,12 @@ impl TableDB {
|
||||
|
||||
/// Read a key from a column in the TableDB immediately.
|
||||
pub async fn load(&self, col: u32, key: &[u8]) -> VeilidAPIResult<Option<Vec<u8>>> {
|
||||
if col >= self.opened_column_count {
|
||||
apibail_generic!(format!(
|
||||
"Column exceeds opened column count {} >= {}",
|
||||
col, self.opened_column_count
|
||||
));
|
||||
}
|
||||
let db = self.unlocked_inner.database.clone();
|
||||
let key = self.maybe_encrypt(key, true);
|
||||
Ok(db
|
||||
@@ -233,6 +259,12 @@ impl TableDB {
|
||||
|
||||
/// Delete key with from a column in the TableDB
|
||||
pub async fn delete(&self, col: u32, key: &[u8]) -> VeilidAPIResult<Option<Vec<u8>>> {
|
||||
if col >= self.opened_column_count {
|
||||
apibail_generic!(format!(
|
||||
"Column exceeds opened column count {} >= {}",
|
||||
col, self.opened_column_count
|
||||
));
|
||||
}
|
||||
let key = self.maybe_encrypt(key, true);
|
||||
|
||||
let db = self.unlocked_inner.database.clone();
|
||||
@@ -330,11 +362,19 @@ impl TableDBTransaction {
|
||||
}
|
||||
|
||||
/// Store a key with a value in a column in the TableDB
|
||||
pub fn store(&self, col: u32, key: &[u8], value: &[u8]) {
|
||||
pub fn store(&self, col: u32, key: &[u8], value: &[u8]) -> VeilidAPIResult<()> {
|
||||
if col >= self.db.opened_column_count {
|
||||
apibail_generic!(format!(
|
||||
"Column exceeds opened column count {} >= {}",
|
||||
col, self.db.opened_column_count
|
||||
));
|
||||
}
|
||||
|
||||
let key = self.db.maybe_encrypt(key, true);
|
||||
let value = self.db.maybe_encrypt(value, false);
|
||||
let mut inner = self.inner.lock();
|
||||
inner.dbt.as_mut().unwrap().put_owned(col, key, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Store a key in rkyv format with a value in a column in the TableDB
|
||||
@@ -343,12 +383,7 @@ impl TableDBTransaction {
|
||||
T: RkyvSerialize<DefaultVeilidRkyvSerializer>,
|
||||
{
|
||||
let value = to_rkyv(value)?;
|
||||
let key = self.db.maybe_encrypt(key, true);
|
||||
let value = self.db.maybe_encrypt(&value, false);
|
||||
|
||||
let mut inner = self.inner.lock();
|
||||
inner.dbt.as_mut().unwrap().put_owned(col, key, value);
|
||||
Ok(())
|
||||
self.store(col, key, &value)
|
||||
}
|
||||
|
||||
/// Store a key in rkyv format with a value in a column in the TableDB
|
||||
@@ -357,19 +392,22 @@ impl TableDBTransaction {
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let value = serde_json::to_vec(value).map_err(VeilidAPIError::internal)?;
|
||||
let key = self.db.maybe_encrypt(key, true);
|
||||
let value = self.db.maybe_encrypt(&value, false);
|
||||
|
||||
let mut inner = self.inner.lock();
|
||||
inner.dbt.as_mut().unwrap().put_owned(col, key, value);
|
||||
Ok(())
|
||||
self.store(col, key, &value)
|
||||
}
|
||||
|
||||
/// Delete key with from a column in the TableDB
|
||||
pub fn delete(&self, col: u32, key: &[u8]) {
|
||||
pub fn delete(&self, col: u32, key: &[u8]) -> VeilidAPIResult<()> {
|
||||
if col >= self.db.opened_column_count {
|
||||
apibail_generic!(format!(
|
||||
"Column exceeds opened column count {} >= {}",
|
||||
col, self.db.opened_column_count
|
||||
));
|
||||
}
|
||||
|
||||
let key = self.db.maybe_encrypt(key, true);
|
||||
let mut inner = self.inner.lock();
|
||||
inner.dbt.as_mut().unwrap().delete_owned(col, key);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -428,6 +428,7 @@ impl TableStore {
|
||||
}
|
||||
|
||||
pub(crate) fn on_table_db_drop(&self, table: String) {
|
||||
log_rtab!(debug "dropping table db: {}", table);
|
||||
let mut inner = self.inner.lock();
|
||||
if inner.opened.remove(&table).is_none() {
|
||||
unreachable!("should have removed an item");
|
||||
@@ -449,12 +450,21 @@ impl TableStore {
|
||||
|
||||
let table_name = self.name_get_or_create(name).await?;
|
||||
|
||||
// See if this table is already opened
|
||||
// See if this table is already opened, if so the column count must be the same
|
||||
{
|
||||
let mut inner = self.inner.lock();
|
||||
if let Some(table_db_weak_inner) = inner.opened.get(&table_name) {
|
||||
match TableDB::try_new_from_weak_inner(table_db_weak_inner.clone()) {
|
||||
match TableDB::try_new_from_weak_inner(table_db_weak_inner.clone(), column_count) {
|
||||
Some(tdb) => {
|
||||
// Ensure column count isnt bigger
|
||||
let existing_col_count = tdb.get_column_count()?;
|
||||
if column_count > existing_col_count {
|
||||
return Err(VeilidAPIError::generic(format!(
|
||||
"database must be closed before increasing column count {} -> {}",
|
||||
existing_col_count, column_count,
|
||||
)));
|
||||
}
|
||||
|
||||
return Ok(tdb);
|
||||
}
|
||||
None => {
|
||||
@@ -465,7 +475,7 @@ impl TableStore {
|
||||
}
|
||||
|
||||
// Open table db using platform-specific driver
|
||||
let db = match self
|
||||
let mut db = match self
|
||||
.table_store_driver
|
||||
.open(&table_name, column_count)
|
||||
.await
|
||||
@@ -481,6 +491,24 @@ impl TableStore {
|
||||
// Flush table names to disk
|
||||
self.flush().await;
|
||||
|
||||
// If more columns are available, open the low level db with the max column count but restrict the tabledb object to the number requested
|
||||
let existing_col_count = db.num_columns().map_err(VeilidAPIError::from)?;
|
||||
if existing_col_count > column_count {
|
||||
drop(db);
|
||||
db = match self
|
||||
.table_store_driver
|
||||
.open(&table_name, existing_col_count)
|
||||
.await
|
||||
{
|
||||
Ok(db) => db,
|
||||
Err(e) => {
|
||||
self.name_delete(name).await.expect("cleanup failed");
|
||||
self.flush().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Wrap low-level Database in TableDB object
|
||||
let mut inner = self.inner.lock();
|
||||
let table_db = TableDB::new(
|
||||
@@ -490,6 +518,7 @@ impl TableStore {
|
||||
db,
|
||||
inner.encryption_key.clone(),
|
||||
inner.encryption_key.clone(),
|
||||
column_count,
|
||||
);
|
||||
|
||||
// Keep track of opened DBs
|
||||
|
@@ -132,6 +132,41 @@ pub async fn test_store_delete_load(ts: TableStore) {
|
||||
assert_eq!(db.load(2, b"baz").await.unwrap(), Some(b"QWERTY".to_vec()));
|
||||
}
|
||||
|
||||
pub async fn test_transaction(ts: TableStore) {
|
||||
trace!("test_transaction");
|
||||
|
||||
let _ = ts.delete("test");
|
||||
let db = ts.open("test", 3).await.expect("should have opened");
|
||||
assert!(
|
||||
ts.delete("test").await.is_err(),
|
||||
"should fail because file is opened"
|
||||
);
|
||||
|
||||
let tx = db.transact();
|
||||
assert!(tx.store(0, b"aaa", b"a-value").is_ok());
|
||||
assert!(tx.store_json(1, b"bbb", &"b-value".to_owned()).is_ok());
|
||||
assert!(tx.store_rkyv(2, b"ccc", &"c-value".to_owned()).is_ok());
|
||||
assert!(tx.store(3, b"ddd", b"d-value").is_err());
|
||||
assert!(tx.store(0, b"ddd", b"d-value").is_ok());
|
||||
assert!(tx.delete(0, b"ddd").is_ok());
|
||||
assert!(tx.commit().await.is_ok());
|
||||
|
||||
let tx = db.transact();
|
||||
assert!(tx.delete(2, b"ccc").is_ok());
|
||||
tx.rollback();
|
||||
|
||||
assert_eq!(db.load(0, b"aaa").await, Ok(Some(b"a-value".to_vec())));
|
||||
assert_eq!(
|
||||
db.load_json::<String>(1, b"bbb").await,
|
||||
Ok(Some("b-value".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
db.load_rkyv::<String>(2, b"ccc").await,
|
||||
Ok(Some("c-value".to_owned()))
|
||||
);
|
||||
assert_eq!(db.load(0, b"ddd").await, Ok(None));
|
||||
}
|
||||
|
||||
pub async fn test_rkyv(vcrypto: CryptoSystemVersion, ts: TableStore) {
|
||||
trace!("test_rkyv");
|
||||
|
||||
@@ -268,6 +303,7 @@ pub async fn test_all() {
|
||||
test_protect_unprotect(vcrypto.clone(), ts.clone()).await;
|
||||
test_delete_open_delete(ts.clone()).await;
|
||||
test_store_delete_load(ts.clone()).await;
|
||||
test_transaction(ts.clone()).await;
|
||||
test_rkyv(vcrypto.clone(), ts.clone()).await;
|
||||
test_json(vcrypto, ts.clone()).await;
|
||||
let _ = ts.delete("test").await;
|
||||
|
Reference in New Issue
Block a user