use super::types::{MemoryIOMode, MemoryManagementStatistics};
use crate::backend::native::{
graph_file::buffers::{ReadBuffer, WriteBuffer},
types::{NativeBackendError, NativeResult},
};
#[cfg(feature = "native-v2")]
use memmap2::MmapMut;
pub struct MemoryResourceManager<'a> {
pub(crate) read_buffer: &'a mut ReadBuffer,
pub(crate) write_buffer: &'a mut WriteBuffer,
#[cfg(feature = "native-v2")]
pub(crate) mmap: &'a mut Option<MmapMut>,
}
impl<'a> MemoryResourceManager<'a> {
pub fn new(
read_buffer: &'a mut ReadBuffer,
write_buffer: &'a mut WriteBuffer,
#[cfg(feature = "native-v2")] mmap: &'a mut Option<MmapMut>,
) -> Self {
Self {
read_buffer,
write_buffer,
#[cfg(feature = "native-v2")]
mmap,
}
}
pub fn current_io_mode(&self) -> MemoryIOMode {
#[cfg(all(feature = "native-v2", feature = "v2_io_exclusive_mmap"))]
{
if self.mmap.is_some() {
return MemoryIOMode::MemoryMapped;
}
}
#[cfg(all(feature = "native-v2", feature = "v2_io_exclusive_std"))]
{
return MemoryIOMode::ExclusiveStd;
}
#[allow(unreachable_code)]
MemoryIOMode::Standard
}
pub fn flush_all_operations(&mut self, file: &mut std::fs::File) -> NativeResult<()> {
self.flush_write_buffer(file)?;
Ok(())
}
pub fn get_statistics(&self) -> MemoryManagementStatistics {
MemoryManagementStatistics {
read_buffer_capacity: self.read_buffer.capacity,
write_buffer_pending_ops: self.write_buffer.operations.len(),
mmap_enabled: self.mmap_enabled(),
io_mode: self.current_io_mode(),
}
}
pub fn mmap_enabled(&self) -> bool {
#[cfg(feature = "native-v2")]
{
self.mmap.is_some()
}
#[cfg(not(feature = "native-v2"))]
{
false
}
}
pub fn clear_write_buffer_safely(&mut self) {
if !self.write_buffer.operations.is_empty() {
let ops_count = self.write_buffer.operations.len();
if std::env::var("WRITEBUF_DEBUG").is_ok() {
println!(
"[MEMORY_MANAGER] Clearing {} pending write operations",
ops_count
);
}
self.write_buffer.operations.clear();
}
}
pub fn validate_header_region_protection(&self, offset: u64) -> NativeResult<()> {
const HEADER_SIZE: u64 = 1024; if offset < HEADER_SIZE {
return Err(NativeBackendError::CorruptNodeRecord {
node_id: -1,
reason: format!(
"Write attempted into protected header region: offset={}",
offset
),
});
}
Ok(())
}
pub(crate) fn flush_write_buffer(&mut self, file: &mut std::fs::File) -> NativeResult<()> {
use std::io::{Seek, SeekFrom, Write};
self.write_buffer
.operations
.sort_by_key(|(offset, _data)| *offset);
for (offset, data) in &self.write_buffer.operations {
file.seek(SeekFrom::Start(*offset))?;
file.write_all(data)?;
}
file.sync_all()?;
self.write_buffer.operations.clear();
Ok(())
}
}