use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex, RwLock, Weak};
use anyhow::{Result, Error};
use std::time::{Duration, Instant};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::collections::VecDeque;
use std::time::SystemTime;
use std::path::PathBuf;
use std::io::Write;
use std::io::Read;
#[derive(Debug)]
pub struct SharedMemoryRegion {
#[allow(dead_code)]
id: String,
data: Arc<Mutex<Vec<u8>>>,
readers: Arc<AtomicUsize>,
writers: Arc<AtomicUsize>,
#[allow(dead_code)]
created_at: Instant,
last_accessed: Arc<Mutex<Instant>>,
#[allow(dead_code)]
persistent: bool,
#[allow(dead_code)]
file_path: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct SharedMemoryConfig {
pub region_size: usize,
pub max_regions: usize,
pub gc_interval: Duration,
pub cleanup_timeout: Duration,
pub enable_persistence: bool,
pub persist_dir: Option<PathBuf>,
}
impl Default for SharedMemoryConfig {
fn default() -> Self {
Self {
region_size: 1024 * 1024, max_regions: 100,
gc_interval: Duration::from_secs(30),
cleanup_timeout: Duration::from_secs(300),
enable_persistence: false,
persist_dir: None,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct SharedMemoryStats {
pub total_regions: usize,
pub active_readers: usize,
pub active_writers: usize,
pub total_reads: u64,
pub total_writes: u64,
pub cache_hits: u64,
pub cache_misses: u64,
pub gc_runs: u64,
pub cleaned_regions: usize,
pub prefetch_requests: u64,
pub prefetch_hits: u64,
pub prefetch_misses: u64,
}
#[derive(Debug, Clone)]
pub struct SharedMemoryHandle {
region: Arc<SharedMemoryRegion>,
is_writer: bool,
cow_copy: Option<Arc<Mutex<Vec<u8>>>>,
}
#[derive(Debug, Clone)]
struct AccessPattern {
region_id: String,
offset: usize,
timestamp: Instant,
frequency: usize,
}
#[derive(Debug, Clone)]
struct PrefetchEntry {
data: Vec<u8>,
#[allow(dead_code)]
offset: usize,
timestamp: u64,
}
#[derive(Debug)]
pub struct SharedMemoryManager {
regions: Arc<Mutex<HashMap<String, Weak<SharedMemoryRegion>>>>,
config: SharedMemoryConfig,
stats: Arc<Mutex<SharedMemoryStats>>,
running: Arc<AtomicBool>,
access_patterns: Arc<Mutex<VecDeque<AccessPattern>>>,
prefetch_cache: Arc<Mutex<HashMap<String, PrefetchEntry>>>,
}
impl SharedMemoryManager {
pub fn new(config: SharedMemoryConfig) -> Self {
let manager: _ = Self {
regions: Arc::new(Mutex::new(HashMap::new())),
config,
stats: Arc::new(Mutex::new(SharedMemoryStats::default())),
running: Arc::new(Mutex::new(AtomicBool::new(true))),
access_patterns: Arc::new(Mutex::new(VecDeque::new())),
prefetch_cache: Arc::new(Mutex::new(HashMap::new())),
};
manager.start_gc_thread();
manager.start_prefetch_thread();
manager
}
pub fn create_region(
&self,
id: String,
size: Option<usize>,
) -> Result<SharedMemoryHandle> {
let size: _ = size.unwrap_or(self.config.region_size);
{
let regions: _ = self.regions.lock().unwrap();
if regions.contains_key(&id) {
return Err(anyhow::anyhow!("Region {} already exists", id));
}
}
let data: _ = Arc::new(Mutex::new(vec![0u8; size]));
let readers: _ = Arc::new(Mutex::new(AtomicUsize::new(0)));
let writers: _ = Arc::new(Mutex::new(AtomicUsize::new(1))); let last_accessed: _ = Arc::new(Mutex::new(Instant::now()));
let region: _ = Arc::new(Mutex::new(SharedMemoryRegion {
id: id.clone(),
data,
readers,
writers,
created_at: Instant::now(),
last_accessed,
persistent: self.config.enable_persistence,
file_path: self.config.persist_dir.as_ref().map(|dir| {
dir.join(format!("{}.bin", id))
}),
}));
{
let mut regions = self.regions.lock().unwrap();
regions.insert(id, Arc::downgrade(®ion));
}
{
let mut stats = self.stats.lock().unwrap();
stats.total_regions += 1;
}
Ok(SharedMemoryHandle {
region,
is_writer: true,
cow_copy: None,
})
}
pub fn get_or_create_region(
&self,
id: String,
size: Option<usize>,
) -> Result<SharedMemoryHandle> {
let existing: _ = {
let regions: _ = self.regions.lock().unwrap();
regions.get(&id).and_then(|weak| weak.upgrade())
};
if let Some(region) = existing {
return Ok(SharedMemoryHandle {
region,
is_writer: false,
cow_copy: None,
});
}
self.create_region(id, size)
}
pub fn read(&self, handle: &SharedMemoryHandle, offset: usize, size: usize) -> Result<Vec<u8>> {
{
let mut last_accessed = handle.region.last_accessed.lock().unwrap();
*last_accessed = Instant::now();
}
self.record_access_pattern(&handle.region.id, offset);
let data: _ = if handle.cow_copy.is_none() {
if let Ok(prefetched) = self.prefetch_data(&handle.region.id, offset, size) {
{
let mut stats = self.stats.lock().unwrap();
stats.cache_hits += 1;
stats.total_reads += 1;
}
Ok(prefetched)
} else {
self.read_from_region(handle, offset, size)
}
} else {
self.read_from_region(handle, offset, size)
};
data
}
fn read_from_region(&self, handle: &SharedMemoryHandle, offset: usize, size: usize) -> Result<Vec<u8>> {
handle.region.readers.fetch_add(1, Ordering::SeqCst);
let data: _ = if let Some(cow_copy) = &handle.cow_copy {
let cow_data: _ = cow_copy.lock().unwrap();
cow_data[offset..offset + size].to_vec()
} else {
let region_data: _ = handle.region.data.lock().unwrap();
if offset + size > region_data.len() {
handle.region.readers.fetch_sub(1, Ordering::SeqCst);
return Err(anyhow::anyhow!("Read would exceed region size"));
}
region_data[offset..offset + size].to_vec()
};
handle.region.readers.fetch_sub(1, Ordering::SeqCst);
{
let mut stats = self.stats.lock().unwrap();
stats.total_reads += 1;
if handle.cow_copy.is_none() {
stats.cache_misses += 1;
}
}
Ok(data)
}
pub fn write(
&self,
handle: &mut SharedMemoryHandle,
offset: usize,
data: &[u8],
) -> Result<()> {
{
let mut last_accessed = handle.region.last_accessed.lock().unwrap();
*last_accessed = Instant::now();
}
handle.region.writers.fetch_add(1, Ordering::SeqCst);
if !handle.is_writer && handle.cow_copy.is_none() {
let original_data: _ = {
let region_data: _ = handle.region.data.lock().unwrap();
region_data.clone()
};
handle.cow_copy = Some(Arc::new(Mutex::new(original_data)));
}
if let Some(cow_copy) = &handle.cow_copy {
let mut cow_data = cow_copy.lock().unwrap();
if offset + data.len() > cow_data.len() {
return Err(anyhow::anyhow!("Write would exceed region size"));
}
cow_data[offset..offset + data.len()].copy_from_slice(data);
} else {
if !handle.is_writer {
return Err(anyhow::anyhow!("Only writers can write to shared memory"));
}
let mut region_data = handle.region.data.lock().unwrap();
if offset + data.len() > region_data.len() {
return Err(anyhow::anyhow!("Write would exceed region size"));
}
region_data[offset..offset + data.len()].copy_from_slice(data);
}
handle.region.writers.fetch_sub(1, Ordering::SeqCst);
{
let mut stats = self.stats.lock().unwrap();
stats.total_writes += 1;
}
Ok(())
}
pub fn create_cow_copy(&self, handle: &mut SharedMemoryHandle) -> Result<()> {
if handle.is_writer {
return Err(anyhow::anyhow!("Writers don't need COW copies"));
}
if handle.cow_copy.is_some() {
return Ok(()); }
let original_data: _ = {
let region_data: _ = handle.region.data.lock().unwrap();
region_data.clone()
};
handle.cow_copy = Some(Arc::new(Mutex::new(original_data)));
Ok(())
}
pub fn compare_and_swap(
&self,
handle: &SharedMemoryHandle,
offset: usize,
expected: u8,
new_value: u8,
) -> Result<bool> {
if !handle.is_writer {
return Err(anyhow::anyhow!("Only writers can perform CAS"));
}
let mut region_data = handle.region.data.lock().unwrap();
if offset >= region_data.len() {
return Err(anyhow::anyhow!("Offset out of bounds"));
}
if region_data[offset] == expected {
region_data[offset] = new_value;
Ok(true)
} else {
Ok(false)
}
}
pub fn get_stats(&self) -> SharedMemoryStats {
self.stats.lock().unwrap().clone()
}
#[allow(dead_code)]
fn cleanup_regions(&self) {
let mut cleaned = 0;
let now: _ = Instant::now();
{
let mut regions = self.regions.lock().unwrap();
let ids_to_remove: Vec<String> = regions
.iter()
.filter_map(|(id, weak_region)| {
if weak_region.strong_count() == 0 {
Some(id.clone())
} else if let Some(region) = weak_region.upgrade() {
let last_accessed: _ = *region.last_accessed.lock().unwrap();
if now.duration_since(last_accessed) > self.config.cleanup_timeout {
Some(id.clone())
} else {
None
}
} else {
Some(id.clone())
}
})
.collect();
for id in ids_to_remove {
regions.remove(&id);
cleaned += 1;
}
}
if cleaned > 0 {
let mut stats = self.stats.lock().unwrap();
stats.gc_runs += 1;
stats.cleaned_regions += cleaned;
}
}
fn start_gc_thread(&self) {
let regions: _ = Arc::downgrade(&self.regions);
let config: _ = self.config.clone();
let running: _ = self.running.clone();
std::thread::spawn(move || {
while running.load(Ordering::SeqCst) {
std::thread::sleep(config.gc_interval);
if let Some(regions) = regions.upgrade() {
let mut regions = regions.lock().unwrap();
let now: _ = Instant::now();
let mut cleaned = 0;
let ids_to_remove: Vec<String> = regions
.iter()
.filter_map(|(id, weak_region)| {
if let Some(region) = weak_region.upgrade() {
let last_accessed: _ = *region.last_accessed.lock().unwrap();
if now.duration_since(last_accessed) > config.cleanup_timeout {
Some(id.clone())
} else {
None
}
} else {
Some(id.clone())
}
})
.collect();
for id in ids_to_remove {
regions.remove(&id);
cleaned += 1;
}
if cleaned > 0 {
}
}
}
});
}
pub fn shutdown(&self) {
self.running.store(false, Ordering::SeqCst);
}
fn record_access_pattern(&self, region_id: &str, offset: usize) {
let mut patterns = self.access_patterns.lock().unwrap();
let now: _ = Instant::now();
if let Some(pattern) = patterns.iter_mut().find(|p| p.region_id == region_id && p.offset == offset) {
pattern.timestamp = now;
pattern.frequency += 1;
} else {
patterns.push_back(AccessPattern {
region_id: region_id.to_string(),
offset,
timestamp: now,
frequency: 1,
});
if patterns.len() > 1000 {
patterns.pop_front();
}
}
}
fn prefetch_data(&self, region_id: &str, offset: usize, size: usize) -> Result<Vec<u8>> {
let cache_key: _ = format!("{}:{}:{}", region_id, offset, size);
{
let cache: _ = self.prefetch_cache.lock().unwrap();
if let Some(entry) = cache.get(&cache_key) {
if now_elapsed(&entry.timestamp) < Duration::from_secs(10) {
let mut stats = self.stats.lock().unwrap();
stats.prefetch_hits += 1;
return Ok(entry.data.clone());
}
}
}
let regions: _ = self.regions.lock().unwrap();
if let Some(weak_region) = regions.get(region_id) {
if let Some(region) = weak_region.upgrade() {
let data: _ = {
let region_data: _ = region.data.lock().unwrap();
if offset + size > region_data.len() {
return Err(anyhow::anyhow!("Prefetch would exceed region size"));
}
region_data[offset..offset + size].to_vec()
};
{
let mut cache = self.prefetch_cache.lock().unwrap();
cache.insert(cache_key, PrefetchEntry {
data: data.clone(),
offset,
timestamp: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
});
if cache.len() > 100 {
let keys_to_remove: Vec<String> = cache.keys()
.take(cache.len() - 100)
.cloned()
.collect();
for key in keys_to_remove {
cache.remove(&key);
}
}
}
let mut stats = self.stats.lock().unwrap();
stats.prefetch_misses += 1;
stats.prefetch_requests += 1;
return Ok(data);
}
}
let mut stats = self.stats.lock().unwrap();
stats.prefetch_requests += 1;
Err(anyhow::anyhow!("Region {} not found for prefetch", region_id))
}
fn start_prefetch_thread(&self) {
let regions: _ = Arc::downgrade(&self.regions);
let patterns: _ = Arc::downgrade(&self.access_patterns);
let running: _ = self.running.clone();
std::thread::spawn(move || {
while running.load(Ordering::SeqCst) {
std::thread::sleep(Duration::from_millis(100)); if let (Some(regions), Some(patterns)) = (regions.upgrade(), patterns.upgrade()) {
let patterns: _ = patterns.lock().unwrap();
let hot_patterns: Vec<&AccessPattern> = patterns.iter()
.filter(|p| p.frequency > 5)
.take(10)
.collect();
for pattern in hot_patterns {
if let Some(_) = regions.lock().unwrap().get(&pattern.region_id) {
}
}
}
}
});
}
}
fn now_elapsed(start: &u64) -> Duration {
let current: _ = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
Duration::from_secs(current - start)
}
impl Drop for SharedMemoryManager {
fn drop(&mut self) {
self.shutdown();
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_create_region() {
let config: _ = SharedMemoryConfig::default();
let manager: _ = SharedMemoryManager::new(config);
let mut handle = manager.create_region("test".to_string(), Some(1024)).unwrap();
manager.write(&mut handle, 0, b"hello world").unwrap();
let data: _ = manager.read(&handle, 0, 11).unwrap();
assert_eq!(data, b"hello world");
}
#[test]
fn test_cas_operation() {
let config: _ = SharedMemoryConfig::default();
let manager: _ = SharedMemoryManager::new(config);
let mut handle = manager.create_region("test".to_string(), Some(1024)).unwrap();
manager.write(&mut handle, 0, &[0]).unwrap();
let result: _ = manager.compare_and_swap(&handle, 0, 0, 1).unwrap();
assert!(result);
let data: _ = manager.read(&handle, 0, 1).unwrap();
assert_eq!(data[0], 1);
let result: _ = manager.compare_and_swap(&handle, 0, 0, 2).unwrap();
assert!(!result);
let data: _ = manager.read(&handle, 0, 1).unwrap();
assert_eq!(data[0], 1);
}
#[test]
fn test_get_or_create_region() {
let config: _ = SharedMemoryConfig::default();
let manager: _ = SharedMemoryManager::new(config);
let handle1: _ = manager.get_or_create_region("test".to_string(), Some(1024)).unwrap();
let handle2: _ = manager.get_or_create_region("test".to_string(), Some(1024)).unwrap();
assert_eq!(handle1.region.id, handle2.region.id);
}
#[test]
fn test_stats_tracking() {
let config: _ = SharedMemoryConfig::default();
let manager: _ = SharedMemoryManager::new(config);
let mut handle = manager.create_region("test".to_string(), Some(1024)).unwrap();
manager.write(&mut handle, 0, b"test").unwrap();
manager.read(&handle, 0, 4).unwrap();
let stats: _ = manager.get_stats();
assert_eq!(stats.total_regions, 1);
assert_eq!(stats.total_writes, 1);
assert_eq!(stats.total_reads, 1);
}
}