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

@@ -6,16 +6,13 @@
use std::{borrow::Cow, ops::Range};
use trc::AddContext;
use utils::config::utils::ParseValue;
use crate::{BlobBackend, BlobStore, CompressionAlgo, Store};
impl BlobStore {
pub async fn get_blob(
&self,
key: &[u8],
range: Range<usize>,
) -> crate::Result<Option<Vec<u8>>> {
pub async fn get_blob(&self, key: &[u8], range: Range<usize>) -> trc::Result<Option<Vec<u8>>> {
let read_range = match self.compression {
CompressionAlgo::None => range.clone(),
CompressionAlgo::Lz4 => 0..usize::MAX,
@@ -33,7 +30,7 @@ impl BlobStore {
Store::MySQL(store) => store.get_blob(key, read_range).await,
#[cfg(feature = "rocks")]
Store::RocksDb(store) => store.get_blob(key, read_range).await,
Store::None => Err(crate::Error::InternalError("No store configured".into())),
Store::None => Err(trc::Cause::NotConfigured.into()),
},
BlobBackend::Fs(store) => store.get_blob(key, read_range).await,
#[cfg(feature = "s3")]
@@ -41,7 +38,7 @@ impl BlobStore {
};
let decompressed = match self.compression {
CompressionAlgo::Lz4 => match result? {
CompressionAlgo::Lz4 => match result.caused_by(trc::location!())? {
Some(data)
if data.last().copied().unwrap_or_default()
== CompressionAlgo::Lz4.marker() =>
@@ -50,14 +47,14 @@ impl BlobStore {
data.get(..data.len() - 1).unwrap_or_default(),
)
.map_err(|err| {
crate::Error::InternalError(format!(
"Failed to decompress LZ4 data: {}",
err
))
trc::Cause::Decompress
.reason(err)
.ctx(trc::Key::Key, key)
.ctx(trc::Key::CausedBy, trc::location!())
})?
}
Some(data) => {
tracing::debug!("Warning: Missing LZ4 marker for key: {key:?}");
trc::error!(BlobMissingMarker, Details = key);
data
}
None => return Ok(None),
@@ -77,7 +74,7 @@ impl BlobStore {
}
}
pub async fn put_blob(&self, key: &[u8], data: &[u8]) -> crate::Result<()> {
pub async fn put_blob(&self, key: &[u8], data: &[u8]) -> trc::Result<()> {
let data: Cow<[u8]> = match self.compression {
CompressionAlgo::None => data.into(),
CompressionAlgo::Lz4 => {
@@ -99,15 +96,16 @@ impl BlobStore {
Store::MySQL(store) => store.put_blob(key, data.as_ref()).await,
#[cfg(feature = "rocks")]
Store::RocksDb(store) => store.put_blob(key, data.as_ref()).await,
Store::None => Err(crate::Error::InternalError("No store configured".into())),
Store::None => Err(trc::Cause::NotConfigured.into()),
},
BlobBackend::Fs(store) => store.put_blob(key, data.as_ref()).await,
#[cfg(feature = "s3")]
BlobBackend::S3(store) => store.put_blob(key, data.as_ref()).await,
}
.caused_by(trc::location!())
}
pub async fn delete_blob(&self, key: &[u8]) -> crate::Result<bool> {
pub async fn delete_blob(&self, key: &[u8]) -> trc::Result<bool> {
match &self.backend {
BlobBackend::Store(store) => match store {
#[cfg(feature = "sqlite")]
@@ -120,12 +118,13 @@ impl BlobStore {
Store::MySQL(store) => store.delete_blob(key).await,
#[cfg(feature = "rocks")]
Store::RocksDb(store) => store.delete_blob(key).await,
Store::None => Err(crate::Error::InternalError("No store configured".into())),
Store::None => Err(trc::Cause::NotConfigured.into()),
},
BlobBackend::Fs(store) => store.delete_blob(key).await,
#[cfg(feature = "s3")]
BlobBackend::S3(store) => store.delete_blob(key).await,
}
.caused_by(trc::location!())
}
pub fn with_compression(self, compression: CompressionAlgo) -> Self {
@@ -149,7 +148,7 @@ impl CompressionAlgo {
}
impl ParseValue for CompressionAlgo {
fn parse_value(value: &str) -> utils::config::Result<Self> {
fn parse_value(value: &str) -> Result<Self, String> {
match value {
"lz4" => Ok(CompressionAlgo::Lz4),
//"zstd" => Ok(CompressionAlgo::Zstd),

View File

@@ -7,6 +7,7 @@
use std::fmt::Display;
use roaring::RoaringBitmap;
use trc::AddContext;
use crate::{
fts::{index::FtsDocument, FtsFilter},
@@ -19,12 +20,13 @@ impl FtsStore {
pub async fn index<T: Into<u8> + Display + Clone + std::fmt::Debug>(
&self,
document: FtsDocument<'_, T>,
) -> crate::Result<()> {
) -> trc::Result<()> {
match self {
FtsStore::Store(store) => store.fts_index(document).await,
#[cfg(feature = "elastic")]
FtsStore::ElasticSearch(store) => store.fts_index(document).await,
}
.caused_by( trc::location!())
}
pub async fn query<T: Into<u8> + Display + Clone + std::fmt::Debug>(
@@ -32,7 +34,7 @@ impl FtsStore {
account_id: u32,
collection: impl Into<u8>,
filters: Vec<FtsFilter<T>>,
) -> crate::Result<RoaringBitmap> {
) -> trc::Result<RoaringBitmap> {
match self {
FtsStore::Store(store) => store.fts_query(account_id, collection, filters).await,
#[cfg(feature = "elastic")]
@@ -40,6 +42,7 @@ impl FtsStore {
store.fts_query(account_id, collection, filters).await
}
}
.caused_by( trc::location!())
}
pub async fn remove(
@@ -47,7 +50,7 @@ impl FtsStore {
account_id: u32,
collection: u8,
document_ids: &impl DocumentSet,
) -> crate::Result<()> {
) -> trc::Result<()> {
match self {
FtsStore::Store(store) => store.fts_remove(account_id, collection, document_ids).await,
#[cfg(feature = "elastic")]
@@ -55,13 +58,15 @@ impl FtsStore {
store.fts_remove(account_id, collection, document_ids).await
}
}
.caused_by( trc::location!())
}
pub async fn remove_all(&self, account_id: u32) -> crate::Result<()> {
pub async fn remove_all(&self, account_id: u32) -> trc::Result<()> {
match self {
FtsStore::Store(store) => store.fts_remove_all(account_id).await,
#[cfg(feature = "elastic")]
FtsStore::ElasticSearch(store) => store.fts_remove_all(account_id).await,
}
.caused_by( trc::location!())
}
}

View File

@@ -4,6 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use trc::AddContext;
use utils::config::Rate;
use crate::{write::LookupClass, Row};
@@ -23,22 +24,25 @@ impl LookupStore {
&self,
query: &str,
params: Vec<Value<'_>>,
) -> crate::Result<T> {
) -> trc::Result<T> {
let result = match self {
#[cfg(feature = "sqlite")]
LookupStore::Store(Store::SQLite(store)) => store.query(query, params).await,
LookupStore::Store(Store::SQLite(store)) => store.query(query, &params).await,
#[cfg(feature = "postgres")]
LookupStore::Store(Store::PostgreSQL(store)) => store.query(query, params).await,
LookupStore::Store(Store::PostgreSQL(store)) => store.query(query, &params).await,
#[cfg(feature = "mysql")]
LookupStore::Store(Store::MySQL(store)) => store.query(query, params).await,
_ => Err(crate::Error::InternalError(
"Store does not support queries".into(),
)),
LookupStore::Store(Store::MySQL(store)) => store.query(query, &params).await,
_ => Err(trc::Cause::Unsupported.into_err()),
};
tracing::trace!( context = "store", event = "query", query = query, result = ?result);
trc::trace!(
SqlQuery,
Query = query.to_string(),
Parameters = params.as_slice(),
Result = &result,
);
result
result.caused_by( trc::location!())
}
pub async fn key_set(
@@ -46,7 +50,7 @@ impl LookupStore {
key: Vec<u8>,
value: Vec<u8>,
expires: Option<u64>,
) -> crate::Result<()> {
) -> trc::Result<()> {
match self {
LookupStore::Store(store) => {
let mut batch = BatchBuilder::new();
@@ -72,10 +76,9 @@ impl LookupStore {
)
.await
.map(|_| ()),
LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support key_set".into(),
)),
LookupStore::Memory(_) => Err(trc::Cause::Unsupported.into_err()),
}
.caused_by( trc::location!())
}
pub async fn counter_incr(
@@ -84,7 +87,7 @@ impl LookupStore {
value: i64,
expires: Option<u64>,
return_value: bool,
) -> crate::Result<i64> {
) -> trc::Result<i64> {
match self {
LookupStore::Store(store) => {
let mut batch = BatchBuilder::new();
@@ -121,13 +124,14 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.key_incr(key, value, expires).await,
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support counter_incr".into(),
)),
LookupStore::Query(_) | LookupStore::Memory(_) => {
Err(trc::Cause::Unsupported.into_err())
}
}
.caused_by( trc::location!())
}
pub async fn key_delete(&self, key: Vec<u8>) -> crate::Result<()> {
pub async fn key_delete(&self, key: Vec<u8>) -> trc::Result<()> {
match self {
LookupStore::Store(store) => {
let mut batch = BatchBuilder::new();
@@ -139,13 +143,14 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.key_delete(key).await,
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support key_set".into(),
)),
LookupStore::Query(_) | LookupStore::Memory(_) => {
Err(trc::Cause::Unsupported.into_err())
}
}
.caused_by( trc::location!())
}
pub async fn counter_delete(&self, key: Vec<u8>) -> crate::Result<()> {
pub async fn counter_delete(&self, key: Vec<u8>) -> trc::Result<()> {
match self {
LookupStore::Store(store) => {
let mut batch = BatchBuilder::new();
@@ -157,16 +162,17 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.key_delete(key).await,
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support key_set".into(),
)),
LookupStore::Query(_) | LookupStore::Memory(_) => {
Err(trc::Cause::Unsupported.into_err())
}
}
.caused_by( trc::location!())
}
pub async fn key_get<T: Deserialize + From<Value<'static>> + std::fmt::Debug + 'static>(
&self,
key: Vec<u8>,
) -> crate::Result<Option<T>> {
) -> trc::Result<Option<T>> {
match self {
LookupStore::Store(store) => store
.get_value::<LookupValue<T>>(ValueKey::from(ValueClass::Lookup(LookupClass::Key(
@@ -191,9 +197,10 @@ impl LookupStore {
.get(std::str::from_utf8(&key).unwrap_or_default())
.map(|value| T::from(value.clone()))),
}
.caused_by( trc::location!())
}
pub async fn counter_get(&self, key: Vec<u8>) -> crate::Result<i64> {
pub async fn counter_get(&self, key: Vec<u8>) -> trc::Result<i64> {
match self {
LookupStore::Store(store) => {
store
@@ -204,13 +211,14 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.counter_get(key).await,
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support counter_get".into(),
)),
LookupStore::Query(_) | LookupStore::Memory(_) => {
Err(trc::Cause::Unsupported.into_err())
}
}
.caused_by( trc::location!())
}
pub async fn key_exists(&self, key: Vec<u8>) -> crate::Result<bool> {
pub async fn key_exists(&self, key: Vec<u8>) -> trc::Result<bool> {
match self {
LookupStore::Store(store) => store
.get_value::<LookupValue<()>>(ValueKey::from(ValueClass::Lookup(LookupClass::Key(
@@ -232,6 +240,7 @@ impl LookupStore {
.get(std::str::from_utf8(&key).unwrap_or_default())
.is_some()),
}
.caused_by( trc::location!())
}
pub async fn is_rate_allowed(
@@ -239,7 +248,7 @@ impl LookupStore {
key: &[u8],
rate: &Rate,
soft_check: bool,
) -> crate::Result<Option<u64>> {
) -> trc::Result<Option<u64>> {
let now = now();
let range_start = now / rate.period.as_secs();
let range_end = (range_start * rate.period.as_secs()) + rate.period.as_secs();
@@ -251,9 +260,13 @@ impl LookupStore {
let requests = if !soft_check {
self.counter_incr(bucket, 1, expires_in.into(), true)
.await?
.await
.caused_by( trc::location!())?
} else {
self.counter_get(bucket).await? + 1
self.counter_get(bucket)
.await
.caused_by( trc::location!())?
+ 1
};
if requests <= rate.requests as i64 {
@@ -263,7 +276,7 @@ impl LookupStore {
}
}
pub async fn purge_lookup_store(&self) -> crate::Result<()> {
pub async fn purge_lookup_store(&self) -> trc::Result<()> {
match self {
LookupStore::Store(store) => {
// Delete expired keys and counters
@@ -276,9 +289,13 @@ impl LookupStore {
let mut expired_counters = Vec::new();
store
.iterate(IterateParams::new(from_key, to_key), |key, value| {
let expiry = value.deserialize_be_u64(0)?;
let expiry = value.deserialize_be_u64(0).caused_by( trc::location!())?;
if expiry == 0 {
if value.deserialize_be_u64(U64_LEN)? <= current_time {
if value
.deserialize_be_u64(U64_LEN)
.caused_by( trc::location!())?
<= current_time
{
expired_counters.push(key.to_vec());
}
} else if expiry <= current_time {
@@ -286,7 +303,8 @@ impl LookupStore {
}
Ok(true)
})
.await?;
.await
.caused_by( trc::location!())?;
if !expired_keys.is_empty() {
let mut batch = BatchBuilder::new();
@@ -296,12 +314,18 @@ impl LookupStore {
op: ValueOp::Clear,
});
if batch.ops.len() >= 1000 {
store.write(batch.build()).await?;
store
.write(batch.build())
.await
.caused_by( trc::location!())?;
batch = BatchBuilder::new();
}
}
if !batch.ops.is_empty() {
store.write(batch.build()).await?;
store
.write(batch.build())
.await
.caused_by( trc::location!())?;
}
}
@@ -317,12 +341,18 @@ impl LookupStore {
op: ValueOp::Clear,
});
if batch.ops.len() >= 1000 {
store.write(batch.build()).await?;
store
.write(batch.build())
.await
.caused_by( trc::location!())?;
batch = BatchBuilder::new();
}
}
if !batch.ops.is_empty() {
store.write(batch.build()).await?;
store
.write(batch.build())
.await
.caused_by( trc::location!())?;
}
}
}
@@ -348,10 +378,13 @@ enum LookupValue<T> {
}
impl<T: Deserialize> Deserialize for LookupValue<T> {
fn deserialize(bytes: &[u8]) -> crate::Result<Self> {
fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
bytes.deserialize_be_u64(0).and_then(|expires| {
Ok(if expires > now() {
LookupValue::Value(T::deserialize(bytes.get(U64_LEN..).unwrap_or_default())?)
LookupValue::Value(
T::deserialize(bytes.get(U64_LEN..).unwrap_or_default())
.caused_by( trc::location!())?,
)
} else {
LookupValue::None
})

View File

@@ -7,6 +7,7 @@
use std::ops::{BitAndAssign, Range};
use roaring::RoaringBitmap;
use trc::AddContext;
use crate::{
write::{
@@ -27,7 +28,7 @@ pub static ref BITMAPS: std::sync::Arc<parking_lot::Mutex<std::collections::Hash
}
impl Store {
pub async fn get_value<U>(&self, key: impl Key) -> crate::Result<Option<U>>
pub async fn get_value<U>(&self, key: impl Key) -> trc::Result<Option<U>>
where
U: Deserialize + 'static,
{
@@ -42,14 +43,15 @@ impl Store {
Self::MySQL(store) => store.get_value(key).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.get_value(key).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn get_bitmap(
&self,
key: BitmapKey<BitmapClass<u32>>,
) -> crate::Result<Option<RoaringBitmap>> {
) -> trc::Result<Option<RoaringBitmap>> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.get_bitmap(key).await,
@@ -61,17 +63,18 @@ impl Store {
Self::MySQL(store) => store.get_bitmap(key).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.get_bitmap(key).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn get_bitmaps_intersection(
&self,
keys: Vec<BitmapKey<BitmapClass<u32>>>,
) -> crate::Result<Option<RoaringBitmap>> {
) -> trc::Result<Option<RoaringBitmap>> {
let mut result: Option<RoaringBitmap> = None;
for key in keys {
if let Some(bitmap) = self.get_bitmap(key).await? {
if let Some(bitmap) = self.get_bitmap(key).await.caused_by( trc::location!())? {
if let Some(result) = &mut result {
result.bitand_assign(&bitmap);
if result.is_empty() {
@@ -90,8 +93,8 @@ impl Store {
pub async fn iterate<T: Key>(
&self,
params: IterateParams<T>,
cb: impl for<'x> FnMut(&'x [u8], &'x [u8]) -> crate::Result<bool> + Sync + Send,
) -> crate::Result<()> {
cb: impl for<'x> FnMut(&'x [u8], &'x [u8]) -> trc::Result<bool> + Sync + Send,
) -> trc::Result<()> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.iterate(params, cb).await,
@@ -103,14 +106,15 @@ impl Store {
Self::MySQL(store) => store.iterate(params, cb).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.iterate(params, cb).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn get_counter(
&self,
key: impl Into<ValueKey<ValueClass<u32>>> + Sync + Send,
) -> crate::Result<i64> {
) -> trc::Result<i64> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.get_counter(key).await,
@@ -122,11 +126,12 @@ impl Store {
Self::MySQL(store) => store.get_counter(key).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.get_counter(key).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn write(&self, batch: Batch) -> crate::Result<AssignedIds> {
pub async fn write(&self, batch: Batch) -> trc::Result<AssignedIds> {
#[cfg(feature = "test_mode")]
if std::env::var("PARANOID_WRITE").map_or(false, |v| v == "1") {
let mut account_id = u32::MAX;
@@ -184,8 +189,9 @@ impl Store {
Self::MySQL(store) => store.write(batch).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.write(batch).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
}?;
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())?;
for (key, class, document_id, set) in bitmaps {
let mut bitmaps = BITMAPS.lock();
@@ -225,11 +231,11 @@ impl Store {
Self::MySQL(store) => store.write(batch).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.write(batch).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
}
pub async fn purge_store(&self) -> crate::Result<()> {
pub async fn purge_store(&self) -> trc::Result<()> {
// Delete expired reports
let now = now();
self.delete_range(
@@ -239,7 +245,8 @@ impl Store {
expires: now,
})),
)
.await?;
.await
.caused_by( trc::location!())?;
self.delete_range(
ValueKey::from(ValueClass::Report(ReportClass::Tls { id: 0, expires: 0 })),
ValueKey::from(ValueClass::Report(ReportClass::Tls {
@@ -247,7 +254,8 @@ impl Store {
expires: now,
})),
)
.await?;
.await
.caused_by( trc::location!())?;
self.delete_range(
ValueKey::from(ValueClass::Report(ReportClass::Arf { id: 0, expires: 0 })),
ValueKey::from(ValueClass::Report(ReportClass::Arf {
@@ -255,7 +263,8 @@ impl Store {
expires: now,
})),
)
.await?;
.await
.caused_by( trc::location!())?;
match self {
#[cfg(feature = "sqlite")]
@@ -268,11 +277,12 @@ impl Store {
Self::MySQL(store) => store.purge_store().await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.purge_store().await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn delete_range(&self, from: impl Key, to: impl Key) -> crate::Result<()> {
pub async fn delete_range(&self, from: impl Key, to: impl Key) -> trc::Result<()> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.delete_range(from, to).await,
@@ -284,8 +294,9 @@ impl Store {
Self::MySQL(store) => store.delete_range(from, to).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.delete_range(from, to).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn delete_documents(
@@ -295,7 +306,7 @@ impl Store {
collection: u8,
collection_offset: Option<usize>,
document_ids: &impl DocumentSet,
) -> crate::Result<()> {
) -> trc::Result<()> {
// Serialize keys
let (from_key, to_key) = if collection_offset.is_some() {
(
@@ -340,14 +351,17 @@ impl Store {
Ok(true)
},
)
.await?;
.await
.caused_by( trc::location!())?;
// Remove keys
let mut batch = BatchBuilder::new();
for key in delete_keys {
if batch.ops.len() >= 1000 {
self.write(std::mem::take(&mut batch).build()).await?;
self.write(std::mem::take(&mut batch).build())
.await
.caused_by( trc::location!())?;
}
batch.ops.push(Operation::Value {
class: ValueClass::Any(AnyClass { subspace, key }),
@@ -356,13 +370,15 @@ impl Store {
}
if !batch.is_empty() {
self.write(batch.build()).await?;
self.write(batch.build())
.await
.caused_by( trc::location!())?;
}
Ok(())
}
pub async fn purge_account(&self, account_id: u32) -> crate::Result<()> {
pub async fn purge_account(&self, account_id: u32) -> trc::Result<()> {
for subspace in [
SUBSPACE_BITMAP_ID,
SUBSPACE_BITMAP_TAG,
@@ -380,7 +396,8 @@ impl Store {
key: KeySerializer::new(U32_LEN).write(account_id + 1).finalize(),
},
)
.await?;
.await
.caused_by( trc::location!())?;
}
for (from_class, to_class) in [
@@ -411,17 +428,14 @@ impl Store {
class: to_class,
},
)
.await?;
.await
.caused_by( trc::location!())?;
}
Ok(())
}
pub async fn get_blob(
&self,
key: &[u8],
range: Range<usize>,
) -> crate::Result<Option<Vec<u8>>> {
pub async fn get_blob(&self, key: &[u8], range: Range<usize>) -> trc::Result<Option<Vec<u8>>> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.get_blob(key, range).await,
@@ -433,11 +447,12 @@ impl Store {
Self::MySQL(store) => store.get_blob(key, range).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.get_blob(key, range).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn put_blob(&self, key: &[u8], data: &[u8]) -> crate::Result<()> {
pub async fn put_blob(&self, key: &[u8], data: &[u8]) -> trc::Result<()> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.put_blob(key, data).await,
@@ -449,11 +464,12 @@ impl Store {
Self::MySQL(store) => store.put_blob(key, data).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.put_blob(key, data).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
pub async fn delete_blob(&self, key: &[u8]) -> crate::Result<bool> {
pub async fn delete_blob(&self, key: &[u8]) -> trc::Result<bool> {
match self {
#[cfg(feature = "sqlite")]
Self::SQLite(store) => store.delete_blob(key).await,
@@ -465,8 +481,9 @@ impl Store {
Self::MySQL(store) => store.delete_blob(key).await,
#[cfg(feature = "rocks")]
Self::RocksDb(store) => store.delete_blob(key).await,
Self::None => Err(crate::Error::InternalError("No store configured".into())),
Self::None => Err(trc::Cause::NotConfigured.into()),
}
.caused_by( trc::location!())
}
#[cfg(feature = "test_mode")]
@@ -551,7 +568,7 @@ impl Store {
self.iterate(
IterateParams::new(from_key, to_key).ascending().no_values(),
|key, _| {
let account_id = key.deserialize_be_u32(0)?;
let account_id = key.deserialize_be_u32(0).caused_by( trc::location!())?;
if account_id != last_account_id {
last_account_id = account_id;
batch.with_account_id(account_id);
@@ -563,7 +580,9 @@ impl Store {
key.get(U32_LEN..U32_LEN + BLOB_HASH_LEN).unwrap(),
)
.unwrap(),
until: key.deserialize_be_u64(key.len() - U64_LEN)?,
until: key
.deserialize_be_u64(key.len() - U64_LEN)
.caused_by( trc::location!())?,
}),
op: ValueOp::Clear,
});
@@ -588,7 +607,7 @@ impl Store {
let mut expired_counters = Vec::new();
self.iterate(IterateParams::new(from_key, to_key), |key, value| {
let expiry = value.deserialize_be_u64(0)?;
let expiry = value.deserialize_be_u64(0).caused_by( trc::location!())?;
if expiry == 0 {
expired_counters.push(key.to_vec());
} else if expiry != u64::MAX {