use super::CopyQueue;
use crate::memory_management::{ManagedMemoryHandle, release_or_leak};
use crate::server::ServerError;
use crate::storage::ComputeStorage;
use crate::storage::StorageHandle;
use alloc::vec::Vec;
#[derive(Debug)]
pub struct Relocation {
moves: Vec<Move>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetRoom {
Held,
MayAllocate,
}
#[derive(Debug)]
pub struct Landed {
moves: Vec<Move>,
}
#[derive(Debug, Clone)]
pub struct StorageCopy {
pub source: StorageHandle,
pub target: StorageHandle,
}
#[derive(Debug)]
pub(crate) struct Move {
pub allocation: ManagedMemoryHandle,
pub target: ManagedMemoryHandle,
pub copy: Option<StorageCopy>,
}
impl Relocation {
pub(crate) fn new(moves: Vec<Move>) -> Self {
Self { moves }
}
pub fn len(&self) -> usize {
self.moves.len()
}
pub fn is_empty(&self) -> bool {
self.moves.is_empty()
}
pub fn copy<Storage: ComputeStorage>(
self,
storage: &mut Storage,
queue: &mut dyn CopyQueue<Storage>,
) -> Result<Landed, ServerError> {
queue.wait_device()?;
let enqueued = self
.moves
.iter()
.filter_map(|relocated| relocated.copy.as_ref())
.try_for_each(|copy| queue.copy(storage, copy));
if let Err(err) = queue.wait_copies() {
release_or_leak(self, &err);
enqueued?;
return Err(err);
}
enqueued?;
Ok(Landed { moves: self.moves })
}
}
impl Landed {
pub(crate) fn into_moves(self) -> Vec<Move> {
self.moves
}
}
#[cfg(all(test, feature = "storage-bytes"))]
mod tests {
use super::*;
use crate::{driver::DriverError, server::IoError, storage::BytesStorage};
struct FailedWait;
impl CopyQueue<BytesStorage> for FailedWait {
fn wait_device(&mut self) -> Result<(), ServerError> {
Ok(())
}
fn copy(&mut self, _: &mut BytesStorage, _: &StorageCopy) -> Result<(), IoError> {
Ok(())
}
fn wait_copies(&mut self) -> Result<(), ServerError> {
Err(DriverError::new("wait", 201).into())
}
}
#[test]
fn failed_wait_keeps_pending_relocation_reserved() {
let mut storage = BytesStorage::default();
let source = ManagedMemoryHandle::new();
let target = ManagedMemoryHandle::new();
let relocation = Relocation::new(alloc::vec![Move {
allocation: source.clone(),
target: target.clone(),
copy: Some(StorageCopy {
source: storage.alloc(4).unwrap(),
target: storage.alloc(4).unwrap(),
}),
}]);
assert!(relocation.copy(&mut storage, &mut FailedWait).is_err());
assert!(!source.is_free());
assert!(!target.is_free());
}
}