Improved error handling (part 1)

This commit is contained in:
mdecimus
2024-07-11 18:44:51 +02:00
parent ea77a98260
commit 0c2a3f09fe
179 changed files with 3409 additions and 3048 deletions

View File

@@ -15,17 +15,19 @@ use crate::{
BitmapKey, IndexKey, Key, LogKey, SUBSPACE_COUNTER, SUBSPACE_QUOTA, U32_LEN,
};
use super::SqliteStore;
use super::{into_error, SqliteStore};
impl SqliteStore {
pub(crate) async fn write(&self, batch: Batch) -> crate::Result<AssignedIds> {
let mut conn = self.conn_pool.get()?;
pub(crate) async fn write(&self, batch: Batch) -> trc::Result<AssignedIds> {
let mut conn = self.conn_pool.get().map_err(into_error)?;
self.spawn_worker(move || {
let mut account_id = u32::MAX;
let mut collection = u8::MAX;
let mut document_id = u32::MAX;
let mut change_id = u64::MAX;
let trx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
let trx = conn
.transaction_with_behavior(TransactionBehavior::Immediate)
.map_err(into_error)?;
let mut result = AssignedIds::default();
for op in &batch.ops {
@@ -65,8 +67,10 @@ impl SqliteStore {
trx.prepare_cached(&format!(
"INSERT OR REPLACE INTO {} (k, v) VALUES (?, ?)",
table
))?
.execute([&key, value.resolve(&result)?.as_ref()])?;
))
.map_err(into_error)?
.execute([&key, value.resolve(&result)?.as_ref()])
.map_err(into_error)?;
}
ValueOp::AtomicAdd(by) => {
if *by >= 0 {
@@ -76,13 +80,17 @@ impl SqliteStore {
"ON CONFLICT(k) DO UPDATE SET v = v + excluded.v"
),
table
))?
.execute(params![&key, *by])?;
))
.map_err(into_error)?
.execute(params![&key, *by])
.map_err(into_error)?;
} else {
trx.prepare_cached(&format!(
"UPDATE {table} SET v = v + ? WHERE k = ?"
))?
.execute(params![*by, &key])?;
))
.map_err(into_error)?
.execute(params![*by, &key])
.map_err(into_error)?;
}
}
ValueOp::AddAndGet(by) => {
@@ -94,13 +102,17 @@ impl SqliteStore {
"excluded.v RETURNING v"
),
table
))?
.query_row(params![&key, &by], |row| row.get::<_, i64>(0))?,
))
.map_err(into_error)?
.query_row(params![&key, &by], |row| row.get::<_, i64>(0))
.map_err(into_error)?,
);
}
ValueOp::Clear => {
trx.prepare_cached(&format!("DELETE FROM {} WHERE k = ?", table))?
.execute([&key])?;
trx.prepare_cached(&format!("DELETE FROM {} WHERE k = ?", table))
.map_err(into_error)?
.execute([&key])
.map_err(into_error)?;
}
}
}
@@ -115,11 +127,15 @@ impl SqliteStore {
.serialize(0);
if *set {
trx.prepare_cached("INSERT OR IGNORE INTO i (k) VALUES (?)")?
.execute([&key])?;
trx.prepare_cached("INSERT OR IGNORE INTO i (k) VALUES (?)")
.map_err(into_error)?
.execute([&key])
.map_err(into_error)?;
} else {
trx.prepare_cached("DELETE FROM i WHERE k = ?")?
.execute([&key])?;
trx.prepare_cached("DELETE FROM i WHERE k = ?")
.map_err(into_error)?
.execute([&key])
.map_err(into_error)?;
}
}
Operation::Bitmap { class, set } => {
@@ -142,12 +158,17 @@ impl SqliteStore {
.serialize(0);
let key_len = begin.len();
let mut query =
trx.prepare_cached("SELECT k FROM b WHERE k >= ? AND k <= ?")?;
let mut rows = query.query([&begin, &end])?;
let mut query = trx
.prepare_cached("SELECT k FROM b WHERE k >= ? AND k <= ?")
.map_err(into_error)?;
let mut rows = query.query([&begin, &end]).map_err(into_error)?;
let mut found_ids = RoaringBitmap::new();
while let Some(row) = rows.next()? {
let key = row.get_ref(0)?.as_bytes()?;
while let Some(row) = rows.next().map_err(into_error)? {
let key = row
.get_ref(0)
.map_err(into_error)?
.as_bytes()
.map_err(into_error)?;
if key.len() == key_len {
found_ids.insert(key.deserialize_be_u32(key.len() - U32_LEN)?);
}
@@ -167,18 +188,24 @@ impl SqliteStore {
if *set {
if is_document_id {
trx.prepare_cached("INSERT INTO b (k) VALUES (?)")?
.execute(params![&key])?;
trx.prepare_cached("INSERT INTO b (k) VALUES (?)")
.map_err(into_error)?
.execute(params![&key])
.map_err(into_error)?;
} else {
trx.prepare_cached(&format!(
"INSERT OR IGNORE INTO {} (k) VALUES (?)",
table
))?
.execute(params![&key])?;
))
.map_err(into_error)?
.execute(params![&key])
.map_err(into_error)?;
}
} else {
trx.prepare_cached(&format!("DELETE FROM {} WHERE k = ?", table))?
.execute(params![&key])?;
trx.prepare_cached(&format!("DELETE FROM {} WHERE k = ?", table))
.map_err(into_error)?
.execute(params![&key])
.map_err(into_error)?;
};
}
Operation::Log { set } => {
@@ -189,8 +216,10 @@ impl SqliteStore {
}
.serialize(0);
trx.prepare_cached("INSERT OR REPLACE INTO l (k, v) VALUES (?, ?)")?
.execute([&key, set.resolve(&result)?.as_ref()])?;
trx.prepare_cached("INSERT OR REPLACE INTO l (k, v) VALUES (?, ?)")
.map_err(into_error)?
.execute([&key, set.resolve(&result).map_err(into_error)?.as_ref()])
.map_err(into_error)?;
}
Operation::AssertValue {
class,
@@ -206,31 +235,35 @@ impl SqliteStore {
let table = char::from(class.subspace(collection));
let matches = trx
.prepare_cached(&format!("SELECT v FROM {} WHERE k = ?", table))?
.prepare_cached(&format!("SELECT v FROM {} WHERE k = ?", table))
.map_err(into_error)?
.query_row([&key], |row| {
Ok(assert_value.matches(row.get_ref(0)?.as_bytes()?))
})
.optional()?
.optional()
.map_err(into_error)?
.unwrap_or_else(|| assert_value.is_none());
if !matches {
trx.rollback()?;
return Err(crate::Error::AssertValueFailed);
trx.rollback().map_err(into_error)?;
return Err(trc::Cause::AssertValue.into());
}
}
}
}
trx.commit().map(|_| result).map_err(Into::into)
trx.commit().map(|_| result).map_err(into_error)
})
.await
}
pub(crate) async fn purge_store(&self) -> crate::Result<()> {
let conn = self.conn_pool.get()?;
pub(crate) async fn purge_store(&self) -> trc::Result<()> {
let conn = self.conn_pool.get().map_err(into_error)?;
self.spawn_worker(move || {
for subspace in [SUBSPACE_QUOTA, SUBSPACE_COUNTER] {
conn.prepare_cached(&format!("DELETE FROM {} WHERE v = 0", char::from(subspace),))?
.execute([])?;
conn.prepare_cached(&format!("DELETE FROM {} WHERE v = 0", char::from(subspace),))
.map_err(into_error)?
.execute([])
.map_err(into_error)?;
}
Ok(())
@@ -238,14 +271,16 @@ impl SqliteStore {
.await
}
pub(crate) async fn delete_range(&self, from: impl Key, to: impl Key) -> crate::Result<()> {
let conn = self.conn_pool.get()?;
pub(crate) async fn delete_range(&self, from: impl Key, to: impl Key) -> trc::Result<()> {
let conn = self.conn_pool.get().map_err(into_error)?;
self.spawn_worker(move || {
conn.prepare_cached(&format!(
"DELETE FROM {} WHERE k >= ? AND k < ?",
char::from(from.subspace()),
))?
.execute([from.serialize(0), to.serialize(0)])?;
))
.map_err(into_error)?
.execute([from.serialize(0), to.serialize(0)])
.map_err(into_error)?;
Ok(())
})