use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use std::collections::VecDeque;
pub struct SmartMemoryPool {
string_buffers: Arc<Mutex<VecDeque<StringBuffer>>>,
object_buffers: Arc<Mutex<VecDeque<ObjectBuffer>>>,
config: PoolConfig,
stats: Arc<Mutex<MemoryStats>>,
}
#[derive(Debug)]
pub struct StringBuffer {
#[allow(dead_code)]
buffer: String,
last_used: Instant,
usage_count: usize,
}
#[derive(Debug)]
pub struct ObjectBuffer {
#[allow(dead_code)]
buffer: Vec<u8>,
last_used: Instant,
usage_count: usize,
}
#[derive(Debug, Clone)]
pub struct PoolConfig {
pub string_pool_size: usize,
pub object_pool_size: usize,
pub buffer_timeout: Duration,
pub min_usage_threshold: usize,
}
impl Default for PoolConfig {
fn default() -> Self {
Self {
string_pool_size: 100,
object_pool_size: 50,
buffer_timeout: Duration::from_secs(300), min_usage_threshold: 3,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MemoryStats {
pub strings_allocated: usize,
pub strings_reused: usize,
pub objects_allocated: usize,
pub objects_reused: usize,
pub total_memory_saved: usize,
pub gc_pressure_reduced: f64,
}
impl SmartMemoryPool {
pub fn new(config: PoolConfig) -> Self {
let pool: _ = Self {
string_buffers: Arc::new(Mutex::new(VecDeque::new())),
object_buffers: Arc::new(Mutex::new(VecDeque::new())),
config: config.clone(),
stats: Arc::new(Mutex::new(MemoryStats::default())),
};
pool.pre_warm();
pool
}
fn pre_warm(&self) {
{
let mut pool = self.string_buffers.lock().unwrap();
for _ in 0..(self.config.string_pool_size / 4) {
pool.push_back(StringBuffer {
buffer: String::with_capacity(1024),
last_used: Instant::now(),
usage_count: 0,
});
}
}
{
let mut pool = self.object_buffers.lock().unwrap();
for _ in 0..(self.config.object_pool_size / 4) {
pool.push_back(ObjectBuffer {
buffer: Vec::with_capacity(4096),
last_used: Instant::now(),
usage_count: 0,
});
}
}
}
#[allow(dead_code)]
pub fn get_string_buffer(&self, min_capacity: usize) -> StringBuffer {
let mut pool = self.string_buffers.lock().unwrap();
for i in (0..pool.len()).rev() {
if pool[i].buffer.capacity() >= min_capacity {
let buffer: _ = pool.remove(i).unwrap();
{
let mut stats = self.stats.lock().unwrap();
stats.strings_reused += 1;
}
return buffer;
}
}
{
let mut stats = self.stats.lock().unwrap();
stats.strings_allocated += 1;
}
StringBuffer {
buffer: String::with_capacity(min_capacity.max(1024)),
last_used: Instant::now(),
usage_count: 0,
}
}
#[allow(dead_code)]
pub fn return_string_buffer(&self, mut buffer: StringBuffer) {
buffer.usage_count += 1;
buffer.last_used = Instant::now();
let mut pool = self.string_buffers.lock().unwrap();
self.cleanup_string_pool(&mut pool);
if pool.len() < self.config.string_pool_size {
pool.push_back(buffer);
} else {
let saved_memory: _ = buffer.buffer.capacity();
let mut stats = self.stats.lock().unwrap();
stats.total_memory_saved += saved_memory;
}
}
#[allow(dead_code)]
pub fn get_object_buffer(&self, min_capacity: usize) -> ObjectBuffer {
let mut pool = self.object_buffers.lock().unwrap();
for i in (0..pool.len()).rev() {
if pool[i].buffer.capacity() >= min_capacity {
let buffer: _ = pool.remove(i).unwrap();
{
let mut stats = self.stats.lock().unwrap();
stats.objects_reused += 1;
}
return buffer;
}
}
{
let mut stats = self.stats.lock().unwrap();
stats.objects_allocated += 1;
}
ObjectBuffer {
buffer: Vec::with_capacity(min_capacity.max(4096)),
last_used: Instant::now(),
usage_count: 0,
}
}
#[allow(dead_code)]
pub fn return_object_buffer(&self, mut buffer: ObjectBuffer) {
buffer.usage_count += 1;
buffer.last_used = Instant::now();
let mut pool = self.object_buffers.lock().unwrap();
self.cleanup_object_pool(&mut pool);
if pool.len() < self.config.object_pool_size {
pool.push_back(buffer);
} else {
let saved_memory: _ = buffer.buffer.capacity();
let mut stats = self.stats.lock().unwrap();
stats.total_memory_saved += saved_memory;
}
}
fn cleanup_string_pool(&self, pool: &mut VecDeque<StringBuffer>) {
let mut to_remove = Vec::new();
for (i, buffer) in pool.iter().enumerate() {
if buffer.last_used.elapsed() > self.config.buffer_timeout
|| buffer.usage_count < self.config.min_usage_threshold
{
to_remove.push(i);
}
}
for &i in to_remove.iter().rev() {
pool.remove(i);
}
}
fn cleanup_object_pool(&self, pool: &mut VecDeque<ObjectBuffer>) {
let mut to_remove = Vec::new();
for (i, buffer) in pool.iter().enumerate() {
if buffer.last_used.elapsed() > self.config.buffer_timeout
|| buffer.usage_count < self.config.min_usage_threshold
{
to_remove.push(i);
}
}
for &i in to_remove.iter().rev() {
pool.remove(i);
}
}
pub fn get_stats(&self) -> MemoryStats {
self.stats.lock().unwrap().clone()
}
pub fn calculate_gc_pressure_reduction(&self) -> f64 {
let stats: _ = self.get_stats();
let total_allocations: _ = stats.strings_allocated + stats.objects_allocated;
let total_reuses: _ = stats.strings_reused + stats.objects_reused;
if total_allocations == 0 {
0.0
} else {
(total_reuses as f64 / total_allocations as f64) * 100.0
}
}
pub fn force_cleanup(&self) {
{
let mut pool = self.string_buffers.lock().unwrap();
self.cleanup_string_pool(&mut pool);
}
{
let mut pool = self.object_buffers.lock().unwrap();
self.cleanup_object_pool(&mut pool);
}
}
pub fn allocate_object_buffer(&self, size: usize) -> Option<super::memory::AllocationHandle> {
let _buffer: _ = self.get_object_buffer(size);
let layout: _ = std::alloc::Layout::from_size_align(size, 8).ok()?;
let ptr: _ = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
return None;
}
Some(super::memory::AllocationHandle { ptr, size })
}
pub fn try_deallocate_object_buffer(&self, ptr: *mut u8, size: usize) -> bool {
let layout: _ = unsafe {
std::alloc::Layout::from_size_align_unchecked(size, 8)
};
unsafe {
std::alloc::dealloc(ptr, layout);
}
true
}
}
#[allow(dead_code)]
pub struct PooledV8String {
string: String,
_pool: Arc<SmartMemoryPool>, }
impl PooledV8String {
#[allow(dead_code)]
pub fn new(pool: Arc<SmartMemoryPool>, value: &str) -> Self {
let mut buffer = pool.get_string_buffer(value.len());
let string: _ = std::mem::take(&mut buffer.buffer);
pool.return_string_buffer(buffer);
let mut result = Self {
string,
_pool: pool,
};
result.string.push_str(value);
result
}
#[allow(dead_code)]
pub fn as_str(&self) -> &str {
&self.string
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_memory_pool_creation() {
let pool: _ = SmartMemoryPool::new(PoolConfig::default());
let stats: _ = pool.get_stats();
assert_eq!(stats.strings_allocated, 0);
assert_eq!(stats.objects_allocated, 0);
}
#[test]
fn test_string_buffer_reuse() {
let pool: _ = SmartMemoryPool::new(PoolConfig {
string_pool_size: 10,
object_pool_size: 10,
buffer_timeout: Duration::from_secs(60),
min_usage_threshold: 1,
});
let buffer1: _ = pool.get_string_buffer(100);
pool.return_string_buffer(buffer1);
let stats: _ = pool.get_stats();
assert_eq!(stats.strings_allocated, 0); assert_eq!(stats.strings_reused, 1); let _buffer2: _ = pool.get_string_buffer(100);
let stats: _ = pool.get_stats();
assert_eq!(stats.strings_reused, 2);
}
#[test]
fn test_memory_stats() {
let pool: _ = SmartMemoryPool::new(PoolConfig {
string_pool_size: 0, object_pool_size: 0,
buffer_timeout: Duration::from_secs(60),
min_usage_threshold: 1,
});
let buffer: _ = pool.get_string_buffer(1024);
pool.return_string_buffer(buffer);
let stats: _ = pool.get_stats();
assert!(stats.strings_allocated > 0);
}
#[test]
fn test_gc_pressure_reduction() {
let pool: _ = SmartMemoryPool::new(PoolConfig {
string_pool_size: 10,
object_pool_size: 10,
buffer_timeout: Duration::from_secs(60),
min_usage_threshold: 1,
});
for _ in 0..5 {
let buffer: _ = pool.get_string_buffer(100);
pool.return_string_buffer(buffer);
}
let reduction: _ = pool.calculate_gc_pressure_reduction();
assert!(reduction >= 0.0);
}
}