fix(snix/store): don't spawn tokio tasks in RedbPathInfoService.list

Fixes a panic in `list` impl of PathInfoService for fuse/virtiofs:
```
thread 'vring_worker' panicked at store/src/pathinfoservice/redb.rs:136:9:
there is no reactor running, must be called from the context of a Tokio 1.x runtime
```

Closes #147.

Change-Id: I2bed5157b30fa185276dcaefd35277159a01fe2d
Reviewed-on: https://cl.snix.dev/c/snix/+/30575
Reviewed-by: Florian Klink <flokli@flokli.de>
Tested-by: besadii
This commit is contained in:
rszyma 2025-06-22 14:18:13 +02:00
parent 3f5715fdf9
commit eee3d466ef

View file

@ -1,7 +1,8 @@
use super::{PathInfo, PathInfoService}; use super::{PathInfo, PathInfoService};
use crate::proto; use crate::proto;
use async_stream::try_stream;
use data_encoding::BASE64; use data_encoding::BASE64;
use futures::{StreamExt, stream::BoxStream}; use futures::stream::BoxStream;
use prost::Message; use prost::Message;
use redb::{Database, ReadableTable, TableDefinition}; use redb::{Database, ReadableTable, TableDefinition};
use snix_castore::{ use snix_castore::{
@ -9,7 +10,6 @@ use snix_castore::{
composition::{CompositionContext, ServiceBuilder}, composition::{CompositionContext, ServiceBuilder},
}; };
use std::{path::PathBuf, sync::Arc}; use std::{path::PathBuf, sync::Arc};
use tokio_stream::wrappers::ReceiverStream;
use tonic::async_trait; use tonic::async_trait;
use tracing::{instrument, warn}; use tracing::{instrument, warn};
@ -130,18 +130,13 @@ impl PathInfoService for RedbPathInfoService {
fn list(&self) -> BoxStream<'static, Result<PathInfo, Error>> { fn list(&self) -> BoxStream<'static, Result<PathInfo, Error>> {
let db = self.db.clone(); let db = self.db.clone();
let (tx, rx) = tokio::sync::mpsc::channel(50); Box::pin(try_stream! {
// Spawn a blocking task which writes all PathInfos to tx.
tokio::task::spawn_blocking({
move || -> Result<(), Error> {
let read_txn = db.begin_read()?; let read_txn = db.begin_read()?;
let table = read_txn.open_table(PATHINFO_TABLE)?; let table = read_txn.open_table(PATHINFO_TABLE)?;
for elem in table.iter()? { for elem in table.iter()? {
let elem = elem?; let elem = elem?;
tokio::runtime::Handle::current() yield {
.block_on(tx.send(Ok({
let path_info_proto = proto::PathInfo::decode( let path_info_proto = proto::PathInfo::decode(
elem.1.value().as_slice(), elem.1.value().as_slice(),
) )
@ -152,15 +147,9 @@ impl PathInfoService for RedbPathInfoService {
PathInfo::try_from(path_info_proto).map_err(|e| { PathInfo::try_from(path_info_proto).map_err(|e| {
Error::StorageError(format!("Invalid path info: {e}")) Error::StorageError(format!("Invalid path info: {e}"))
})? })?
})))
.map_err(|e| Error::StorageError(e.to_string()))?;
} }
Ok(())
} }
}); })
ReceiverStream::from(rx).boxed()
} }
} }