Improved error handling (part 1)
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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!())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, ¶ms).await,
|
||||
#[cfg(feature = "postgres")]
|
||||
LookupStore::Store(Store::PostgreSQL(store)) => store.query(query, params).await,
|
||||
LookupStore::Store(Store::PostgreSQL(store)) => store.query(query, ¶ms).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, ¶ms).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
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user