use super::multi_get_read::MultiGetRead;
use super::read_job::{self, ReadCtx, ReadMachine, ReadWork};
use crate::fs::{Fs, FsFile};
use crate::{UserKey, UserValue};
use alloc::sync::Arc;
use alloc::vec::Vec;
use self_cell::self_cell;
struct Machine<'a> {
read: MultiGetRead<'a, UserKey>,
work: ReadWork<'a>,
}
self_cell!(
struct Cell {
owner: Arc<ReadCtx<UserKey>>,
#[covariant]
dependent: Machine,
}
);
pub struct ResumableMultiGet {
cell: Cell,
backends: Vec<Arc<dyn Fs>>,
}
pub enum Step {
Pending(ResumableMultiGet),
Done(crate::Result<Vec<Option<UserValue>>>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ReadTag(usize);
pub struct BlockRequest {
pub tag: ReadTag,
pub backend: usize,
pub file: Arc<dyn FsFile>,
pub offset: u64,
pub buf: Vec<u8>,
}
pub struct ReadJob {
ctx: Arc<ReadCtx<UserKey>>,
job: read_job::Job,
}
impl ReadJob {
#[must_use]
pub fn run(self) -> JobOutcome {
JobOutcome(self.job.run(&self.ctx))
}
}
pub struct JobOutcome(read_job::JobDone);
impl ResumableMultiGet {
pub(crate) fn start(ctx: ReadCtx<UserKey>) -> Step {
let cell = Cell::new(Arc::new(ctx), |ctx| Machine {
read: MultiGetRead::new(ctx),
work: ReadWork::new(),
});
Self {
cell,
backends: Vec::new(),
}
.resume()
}
#[must_use]
pub fn resume(mut self) -> Step {
let answer = self
.cell
.with_dependent_mut(|_, machine| machine.read.pump(&mut machine.work));
match answer {
Some(answer) => Step::Done(answer),
None => Step::Pending(self),
}
}
pub fn take_reads(&mut self) -> Vec<BlockRequest> {
let backends = &mut self.backends;
self.cell.with_dependent_mut(|_, machine| {
machine
.work
.reads
.drain(..)
.map(|read| {
let backend = backends
.iter()
.position(|fs| Arc::ptr_eq(fs, read.fs))
.unwrap_or_else(|| {
backends.push(Arc::clone(read.fs));
backends.len() - 1
});
BlockRequest {
tag: ReadTag(read.tag),
backend,
file: read.file,
offset: read.offset,
buf: read.buf,
}
})
.collect()
})
}
pub fn take_jobs(&mut self) -> Vec<ReadJob> {
self.cell.with_dependent_mut(|ctx, machine| {
machine
.work
.jobs
.drain(..)
.map(|job| ReadJob {
ctx: Arc::clone(ctx),
job,
})
.collect()
})
}
#[must_use]
pub fn backend(&self, id: usize) -> Option<&Arc<dyn Fs>> {
self.backends.get(id)
}
pub fn complete_read(&mut self, tag: ReadTag, result: crate::io::Result<()>, buf: Vec<u8>) {
self.cell.with_dependent_mut(|_, machine| {
machine.read.read_done(crate::fs::ReadDone {
tag: tag.0,
buf,
result,
});
});
}
pub fn complete_job(&mut self, outcome: JobOutcome) {
self.cell.with_dependent_mut(|_, machine| {
machine.read.job_done(outcome.0, &mut machine.work);
});
}
}